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
|
@ -41,45 +41,6 @@ int64_t osdp_millis_since(int64_t last)
|
|||
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
|
||||
|
||||
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/sys/__assert.h>
|
||||
|
||||
#define STR(x) #x
|
||||
|
||||
#define OSDP_RESP_TOUT_MS (200)
|
||||
|
||||
#define OSDP_CMD_SLAB_BUF_SIZE \
|
||||
(sizeof(struct osdp_cmd) * CONFIG_OSDP_PD_COMMAND_QUEUE_SIZE)
|
||||
#define OSDP_QUEUE_SLAB_SIZE \
|
||||
(sizeof(union osdp_ephemeral_data) * CONFIG_OSDP_PD_COMMAND_QUEUE_SIZE)
|
||||
|
||||
#define ISSET_FLAG(p, f) (((p)->flags & (f)) == (f))
|
||||
#define SET_FLAG(p, f) ((p)->flags |= (f))
|
||||
|
@ -311,6 +313,12 @@ enum osdp_pd_cap_function_code_e {
|
|||
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
|
||||
* representation.
|
||||
|
@ -379,15 +387,10 @@ struct osdp_channel {
|
|||
void (*flush)(void *data);
|
||||
};
|
||||
|
||||
struct osdp_cmd_queue {
|
||||
struct osdp_queue {
|
||||
sys_slist_t queue;
|
||||
struct k_mem_slab slab;
|
||||
uint8_t slab_buf[OSDP_CMD_SLAB_BUF_SIZE];
|
||||
};
|
||||
|
||||
struct osdp_notifiers {
|
||||
int (*keypress)(int address, uint8_t key);
|
||||
int (*cardread)(int address, int format, uint8_t *data, int len);
|
||||
uint8_t slab_buf[OSDP_QUEUE_SLAB_SIZE];
|
||||
};
|
||||
|
||||
#ifdef CONFIG_OSDP_SC_ENABLED
|
||||
|
@ -435,7 +438,16 @@ struct osdp_pd {
|
|||
uint8_t cmd_data[OSDP_COMMAND_DATA_MAX_LEN];
|
||||
|
||||
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
|
||||
int64_t sc_tstamp;
|
||||
struct osdp_secure_channel sc;
|
||||
|
@ -451,7 +463,9 @@ struct osdp {
|
|||
#ifdef CONFIG_OSDP_SC_ENABLED
|
||||
uint8_t sc_master_key[16];
|
||||
#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 */
|
||||
|
@ -468,11 +482,6 @@ int64_t osdp_millis_now(void);
|
|||
int64_t osdp_millis_since(int64_t last);
|
||||
void osdp_dump(const char *head, uint8_t *buf, int 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 */
|
||||
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 pd_offset = 0;
|
||||
|
@ -288,6 +322,7 @@ static int cp_decode_response(struct osdp_pd *pd, uint8_t *buf, int len)
|
|||
uint32_t temp32;
|
||||
struct osdp *ctx = pd_to_osdp(pd);
|
||||
int i, ret = OSDP_CP_ERR_GENERIC, pos = 0, t1, t2;
|
||||
struct osdp_event event;
|
||||
|
||||
if (len < 1) {
|
||||
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;
|
||||
break;
|
||||
case REPLY_KEYPPAD:
|
||||
if (len < REPLY_KEYPPAD_DATA_LEN) {
|
||||
if (len < REPLY_KEYPPAD_DATA_LEN || !ctx->event_callback) {
|
||||
break;
|
||||
}
|
||||
pos++; /* reader number; skip */
|
||||
t1 = buf[pos++]; /* key length */
|
||||
if ((len - REPLY_KEYPPAD_DATA_LEN) != t1) {
|
||||
event.type = OSDP_EVENT_KEYPRESS;
|
||||
event.keypress.reader_no = buf[pos++];
|
||||
event.keypress.length = buf[pos++];
|
||||
if ((len - REPLY_KEYPPAD_DATA_LEN) != event.keypress.length) {
|
||||
break;
|
||||
}
|
||||
if (ctx->notifier.keypress) {
|
||||
for (i = 0; i < t1; i++) {
|
||||
t2 = buf[pos + i]; /* key data */
|
||||
ctx->notifier.keypress(pd->idx, t2);
|
||||
}
|
||||
for (i = 0; i < event.keypress.length; i++) {
|
||||
event.keypress.data[i] = buf[pos + i];
|
||||
}
|
||||
ctx->event_callback(ctx->event_callback_arg, pd->idx, &event);
|
||||
ret = OSDP_CP_ERR_NONE;
|
||||
break;
|
||||
case REPLY_RAW:
|
||||
if (len < REPLY_RAW_DATA_LEN) {
|
||||
if (len < REPLY_RAW_DATA_LEN || !ctx->event_callback) {
|
||||
break;
|
||||
}
|
||||
pos++; /* reader number; skip */
|
||||
t1 = buf[pos++]; /* format */
|
||||
t2 = buf[pos++]; /* length LSB */
|
||||
t2 |= buf[pos++] << 8; /* length MSB */
|
||||
if ((len - REPLY_RAW_DATA_LEN) != t2) {
|
||||
event.type = OSDP_EVENT_CARDREAD;
|
||||
event.cardread.reader_no = buf[pos++];
|
||||
event.cardread.format = buf[pos++];
|
||||
event.cardread.length = buf[pos++]; /* bits LSB */
|
||||
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;
|
||||
}
|
||||
if (ctx->notifier.cardread) {
|
||||
ctx->notifier.cardread(pd->idx, t1, buf + pos, t2);
|
||||
for (i = 0; i < t1; i++) {
|
||||
event.cardread.data[i] = buf[pos + i];
|
||||
}
|
||||
ctx->event_callback(ctx->event_callback_arg, pd->idx, &event);
|
||||
ret = OSDP_CP_ERR_NONE;
|
||||
break;
|
||||
case REPLY_FMT:
|
||||
if (len < REPLY_FMT_DATA_LEN) {
|
||||
if (len < REPLY_FMT_DATA_LEN || !ctx->event_callback) {
|
||||
break;
|
||||
}
|
||||
pos++; /* reader number; skip */
|
||||
pos++; /* skip one byte -- TODO: handle reader direction */
|
||||
t1 = buf[pos++]; /* Key length */
|
||||
if ((len - REPLY_FMT_DATA_LEN) != t1) {
|
||||
event.type = OSDP_EVENT_CARDREAD;
|
||||
event.cardread.reader_no = buf[pos++];
|
||||
event.cardread.direction = buf[pos++];
|
||||
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;
|
||||
}
|
||||
if (ctx->notifier.cardread) {
|
||||
ctx->notifier.cardread(pd->idx, OSDP_CARD_FMT_ASCII,
|
||||
buf + pos, t1);
|
||||
for (i = 0; i < event.cardread.length; i++) {
|
||||
event.cardread.data[i] = buf[pos + i];
|
||||
}
|
||||
ctx->event_callback(ctx->event_callback_arg, pd->idx, &event);
|
||||
ret = OSDP_CP_ERR_NONE;
|
||||
break;
|
||||
case REPLY_BUSY:
|
||||
|
@ -593,8 +634,8 @@ static void cp_flush_command_queue(struct osdp_pd *pd)
|
|||
{
|
||||
struct osdp_cmd *cmd;
|
||||
|
||||
while (osdp_cmd_dequeue(pd, &cmd) == 0) {
|
||||
osdp_cmd_free(pd, cmd);
|
||||
while (cp_cmd_dequeue(pd, &cmd) == 0) {
|
||||
cp_cmd_free(pd, cmd);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -638,13 +679,13 @@ static int cp_phy_state_update(struct osdp_pd *pd)
|
|||
ret = OSDP_CP_ERR_GENERIC;
|
||||
break;
|
||||
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 */
|
||||
break;
|
||||
}
|
||||
pd->cmd_id = cmd->id;
|
||||
memcpy(pd->cmd_data, cmd, sizeof(struct osdp_cmd));
|
||||
osdp_cmd_free(pd, cmd);
|
||||
cp_cmd_free(pd, cmd);
|
||||
/* fall-thru */
|
||||
case OSDP_CP_PHY_STATE_SEND_CMD:
|
||||
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 */
|
||||
}
|
||||
|
||||
c = osdp_cmd_alloc(pd);
|
||||
c = cp_cmd_alloc(pd);
|
||||
if (c == NULL) {
|
||||
return OSDP_CP_ERR_GENERIC;
|
||||
}
|
||||
|
||||
c->id = cmd;
|
||||
osdp_cmd_enqueue(pd, c);
|
||||
cp_cmd_enqueue(pd, c);
|
||||
SET_FLAG(pd, PD_FLAG_AWAIT_RESP);
|
||||
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++) {
|
||||
pd = osdp_to_pd(ctx, i);
|
||||
p = osdp_cmd_alloc(pd);
|
||||
p = cp_cmd_alloc(pd);
|
||||
if (p == NULL) {
|
||||
return -1;
|
||||
}
|
||||
p->id = CMD_KEYSET;
|
||||
memcpy(&p->keyset, &cmd, sizeof(struct osdp_cmd_keyset));
|
||||
osdp_cmd_enqueue(pd, p);
|
||||
cp_cmd_enqueue(pd, p);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -925,23 +966,12 @@ int osdp_setup(struct osdp *ctx, uint8_t *key)
|
|||
|
||||
/* --- 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();
|
||||
|
||||
ctx->notifier.keypress = cb;
|
||||
|
||||
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;
|
||||
ctx->event_callback = cb;
|
||||
ctx->event_callback_arg = arg;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
p = osdp_cmd_alloc(osdp_to_pd(ctx, pd));
|
||||
p = cp_cmd_alloc(osdp_to_pd(ctx, pd));
|
||||
if (p == NULL) {
|
||||
return -1;
|
||||
}
|
||||
memcpy(p, cmd, sizeof(struct osdp_cmd));
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -111,14 +111,93 @@ static struct osdp_pd_cap osdp_pd_cap[] = {
|
|||
{ -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)
|
||||
{
|
||||
int ret = OSDP_PD_ERR_GENERIC;
|
||||
int i, pos = 0;
|
||||
struct osdp_cmd *cmd;
|
||||
struct osdp_cmd cmd;
|
||||
struct osdp_event *event;
|
||||
|
||||
pd->reply_id = 0;
|
||||
pd->cmd_id = buf[pos++];
|
||||
pd->cmd_id = cmd.id = buf[pos++];
|
||||
len--;
|
||||
|
||||
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) {
|
||||
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;
|
||||
break;
|
||||
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;
|
||||
break;
|
||||
case CMD_OUT:
|
||||
if (len != CMD_OUT_DATA_LEN) {
|
||||
if (len != CMD_OUT_DATA_LEN || !pd->command_callback) {
|
||||
break;
|
||||
}
|
||||
cmd = osdp_cmd_alloc(pd);
|
||||
if (cmd == NULL) {
|
||||
LOG_ERR("cmd alloc error");
|
||||
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;
|
||||
ret = OSDP_PD_ERR_REPLY;
|
||||
if (!do_command_callback(pd, &cmd)) {
|
||||
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;
|
||||
ret = OSDP_PD_ERR_NONE;
|
||||
break;
|
||||
case CMD_LED:
|
||||
if (len != CMD_LED_DATA_LEN) {
|
||||
if (len != CMD_LED_DATA_LEN || !pd->command_callback) {
|
||||
break;
|
||||
}
|
||||
cmd = osdp_cmd_alloc(pd);
|
||||
if (cmd == NULL) {
|
||||
LOG_ERR("cmd alloc error");
|
||||
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++];
|
||||
ret = OSDP_PD_ERR_REPLY;
|
||||
if (!do_command_callback(pd, &cmd)) {
|
||||
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;
|
||||
ret = OSDP_PD_ERR_NONE;
|
||||
break;
|
||||
case CMD_BUZ:
|
||||
if (len != CMD_BUZ_DATA_LEN) {
|
||||
if (len != CMD_BUZ_DATA_LEN || !pd->command_callback) {
|
||||
break;
|
||||
}
|
||||
cmd = osdp_cmd_alloc(pd);
|
||||
if (cmd == NULL) {
|
||||
LOG_ERR("cmd alloc error");
|
||||
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++];
|
||||
ret = OSDP_PD_ERR_REPLY;
|
||||
if (!do_command_callback(pd, &cmd)) {
|
||||
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;
|
||||
ret = OSDP_PD_ERR_NONE;
|
||||
break;
|
||||
case CMD_TEXT:
|
||||
if (len < CMD_TEXT_DATA_LEN) {
|
||||
if (len < CMD_TEXT_DATA_LEN || !pd->command_callback) {
|
||||
break;
|
||||
}
|
||||
cmd = osdp_cmd_alloc(pd);
|
||||
if (cmd == NULL) {
|
||||
LOG_ERR("cmd alloc error");
|
||||
cmd.id = OSDP_CMD_TEXT;
|
||||
cmd.text.reader = buf[pos++];
|
||||
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;
|
||||
}
|
||||
cmd->id = OSDP_CMD_TEXT;
|
||||
cmd->text.reader = buf[pos++];
|
||||
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) {
|
||||
osdp_cmd_free(pd, cmd);
|
||||
for (i = 0; i < cmd.text.length; i++) {
|
||||
cmd.text.data[i] = buf[pos++];
|
||||
}
|
||||
ret = OSDP_PD_ERR_REPLY;
|
||||
if (!do_command_callback(pd, &cmd)) {
|
||||
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;
|
||||
ret = OSDP_PD_ERR_NONE;
|
||||
break;
|
||||
case CMD_COMSET:
|
||||
if (len != CMD_COMSET_DATA_LEN) {
|
||||
if (len != CMD_COMSET_DATA_LEN || !pd->command_callback) {
|
||||
break;
|
||||
}
|
||||
cmd = osdp_cmd_alloc(pd);
|
||||
if (cmd == NULL) {
|
||||
LOG_ERR("cmd alloc error");
|
||||
break;
|
||||
}
|
||||
cmd->id = OSDP_CMD_COMSET;
|
||||
cmd->comset.address = buf[pos++];
|
||||
cmd->comset.baud_rate = buf[pos++];
|
||||
cmd->comset.baud_rate |= buf[pos++] << 8;
|
||||
cmd->comset.baud_rate |= buf[pos++] << 16;
|
||||
cmd->comset.baud_rate |= buf[pos++] << 24;
|
||||
if (cmd->comset.address >= 0x7F ||
|
||||
(cmd->comset.baud_rate != 9600 &&
|
||||
cmd->comset.baud_rate != 38400 &&
|
||||
cmd->comset.baud_rate != 115200)) {
|
||||
cmd.id = OSDP_CMD_COMSET;
|
||||
cmd.comset.address = buf[pos++];
|
||||
cmd.comset.baud_rate = buf[pos++];
|
||||
cmd.comset.baud_rate |= buf[pos++] << 8;
|
||||
cmd.comset.baud_rate |= buf[pos++] << 16;
|
||||
cmd.comset.baud_rate |= buf[pos++] << 24;
|
||||
if (cmd.comset.address >= 0x7F ||
|
||||
(cmd.comset.baud_rate != 9600 &&
|
||||
cmd.comset.baud_rate != 19200 &&
|
||||
cmd.comset.baud_rate != 38400 &&
|
||||
cmd.comset.baud_rate != 115200 &&
|
||||
cmd.comset.baud_rate != 230400)) {
|
||||
LOG_ERR("COMSET Failed! command discarded");
|
||||
cmd->comset.address = pd->address;
|
||||
cmd->comset.baud_rate = pd->baud_rate;
|
||||
cmd.comset.address = pd->address;
|
||||
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;
|
||||
ret = OSDP_PD_ERR_NONE;
|
||||
break;
|
||||
|
@ -317,17 +396,18 @@ static int pd_decode_command(struct osdp_pd *pd, uint8_t *buf, int len)
|
|||
buf[pos], buf[pos + 1]);
|
||||
break;
|
||||
}
|
||||
cmd = osdp_cmd_alloc(pd);
|
||||
if (cmd == NULL) {
|
||||
LOG_ERR("cmd alloc error");
|
||||
cmd.id = OSDP_CMD_KEYSET;
|
||||
cmd.keyset.type = buf[pos++];
|
||||
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;
|
||||
}
|
||||
cmd->id = OSDP_CMD_KEYSET;
|
||||
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);
|
||||
memcpy(pd->sc.scbk, cmd.keyset.data, 16);
|
||||
CLEAR_FLAG(pd, PD_FLAG_SC_USE_SCBKD);
|
||||
CLEAR_FLAG(pd, PD_FLAG_INSTALL_MODE);
|
||||
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
|
||||
* subsys/settings
|
||||
*/
|
||||
cmd = osdp_cmd_get_last(pd);
|
||||
if (cmd == NULL || cmd->id != OSDP_CMD_COMSET) {
|
||||
LOG_ERR("Failed to fetch queue tail for COMSET");
|
||||
break;
|
||||
}
|
||||
|
||||
cmd = (struct osdp_cmd *)pd->cmd_data;
|
||||
buf[len++] = pd->reply_id;
|
||||
buf[len++] = cmd->comset.address;
|
||||
buf[len++] = BYTE_0(cmd->comset.baud_rate);
|
||||
|
@ -771,15 +846,25 @@ int osdp_setup(struct osdp *ctx, uint8_t *key)
|
|||
|
||||
/* --- 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);
|
||||
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue