/* * Copyright (c) 2020 Siddharth Chandrasekaran * * SPDX-License-Identifier: Apache-2.0 */ #include #include #include #include #include #include #include "osdp_common.h" LOG_MODULE_REGISTER(osdp, CONFIG_OSDP_LOG_LEVEL); #ifdef CONFIG_OSDP_SC_ENABLED #ifdef CONFIG_OSDP_MODE_PD #define OSDP_KEY_STRING CONFIG_OSDP_PD_SCBK #else #define OSDP_KEY_STRING CONFIG_OSDP_MASTER_KEY #endif #else #define OSDP_KEY_STRING "" #endif /* CONFIG_OSDP_SC_ENABLED */ struct osdp_device { struct ring_buf rx_buf; struct ring_buf tx_buf; #ifdef CONFIG_OSDP_MODE_PD int rx_event_data; struct k_fifo rx_event_fifo; #endif uint8_t rx_fbuf[OSDP_PACKET_BUF_SIZE]; uint8_t tx_fbuf[OSDP_PACKET_BUF_SIZE]; struct uart_config dev_config; const struct device *dev; int wait_for_mark; uint8_t last_byte; }; static struct osdp osdp_ctx; static struct osdp_pd osdp_pd_ctx[CONFIG_OSDP_NUM_CONNECTED_PD]; static struct osdp_device osdp_device; static struct k_thread osdp_refresh_thread; static K_THREAD_STACK_DEFINE(osdp_thread_stack, CONFIG_OSDP_THREAD_STACK_SIZE); static void osdp_handle_in_byte(struct osdp_device *p, uint8_t *buf, int len) { if (p->wait_for_mark) { /* Check for new packet beginning with [FF,53,...] sequence */ if (p->last_byte == 0xFF && buf[0] == 0x53) { buf[0] = 0xFF; ring_buf_put(&p->rx_buf, buf, 1); /* put last byte */ buf[0] = 0x53; ring_buf_put(&p->rx_buf, buf, len); /* put rest */ p->wait_for_mark = 0; /* Mark found. Clear flag */ } p->last_byte = buf[0]; return; } ring_buf_put(&p->rx_buf, buf, len); } static void osdp_uart_isr(const struct device *dev, void *user_data) { size_t len; uint8_t buf[64]; struct osdp_device *p = user_data; while (uart_irq_update(dev) && uart_irq_is_pending(dev)) { if (uart_irq_rx_ready(dev)) { len = uart_fifo_read(dev, buf, sizeof(buf)); if (len > 0) { osdp_handle_in_byte(p, buf, len); } } if (uart_irq_tx_ready(dev)) { len = ring_buf_get(&p->tx_buf, buf, 1); if (!len) { uart_irq_tx_disable(dev); } else { uart_fifo_fill(dev, buf, 1); } } } #ifdef CONFIG_OSDP_MODE_PD if (p->wait_for_mark == 0) { /* wake osdp_refresh thread */ k_fifo_put(&p->rx_event_fifo, &p->rx_event_data); } #endif } static int osdp_uart_receive(void *data, uint8_t *buf, int len) { struct osdp_device *p = data; return (int)ring_buf_get(&p->rx_buf, buf, len); } static int osdp_uart_send(void *data, uint8_t *buf, int len) { int sent = 0; struct osdp_device *p = data; sent = (int)ring_buf_put(&p->tx_buf, buf, len); uart_irq_tx_enable(p->dev); return sent; } static void osdp_uart_flush(void *data) { struct osdp_device *p = data; p->wait_for_mark = 1; ring_buf_reset(&p->tx_buf); ring_buf_reset(&p->rx_buf); } struct osdp *osdp_get_ctx() { return &osdp_ctx; } static struct osdp *osdp_build_ctx(struct osdp_channel *channel) { int i; struct osdp *ctx; struct osdp_pd *pd; int pd_adddres[CONFIG_OSDP_NUM_CONNECTED_PD] = {0}; #ifdef CONFIG_OSDP_MODE_PD pd_adddres[0] = CONFIG_OSDP_PD_ADDRESS; #else if (osdp_extract_address(pd_adddres)) { return NULL; } #endif ctx = &osdp_ctx; ctx->num_pd = CONFIG_OSDP_NUM_CONNECTED_PD; ctx->pd = &osdp_pd_ctx[0]; SET_CURRENT_PD(ctx, 0); for (i = 0; i < CONFIG_OSDP_NUM_CONNECTED_PD; i++) { pd = osdp_to_pd(ctx, i); pd->idx = i; pd->seq_number = -1; pd->osdp_ctx = ctx; pd->address = pd_adddres[i]; pd->baud_rate = CONFIG_OSDP_UART_BAUD_RATE; if (IS_ENABLED(CONFIG_OSDP_SKIP_MARK_BYTE)) { SET_FLAG(pd, PD_FLAG_PKT_SKIP_MARK); } memcpy(&pd->channel, channel, sizeof(struct osdp_channel)); k_mem_slab_init(&pd->cmd.slab, pd->cmd.slab_buf, sizeof(union osdp_ephemeral_data), CONFIG_OSDP_PD_COMMAND_QUEUE_SIZE); } return ctx; } void osdp_refresh(void *arg1, void *arg2, void *arg3) { struct osdp *ctx = osdp_get_ctx(); while (1) { #ifdef CONFIG_OSDP_MODE_PD k_fifo_get(&osdp_device.rx_event_fifo, K_FOREVER); #else k_msleep(50); #endif osdp_update(ctx); } } static int osdp_init(void) { int len; uint8_t c, *key = NULL, key_buf[16]; struct osdp *ctx; struct osdp_device *p = &osdp_device; struct osdp_channel channel = { .send = osdp_uart_send, .recv = osdp_uart_receive, .flush = osdp_uart_flush, .data = &osdp_device, }; #ifdef CONFIG_OSDP_MODE_PD k_fifo_init(&p->rx_event_fifo); #endif ring_buf_init(&p->rx_buf, sizeof(p->rx_fbuf), p->rx_fbuf); ring_buf_init(&p->tx_buf, sizeof(p->tx_fbuf), p->tx_fbuf); /* init OSDP uart device */ p->dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_osdp_uart)); if (!device_is_ready(p->dev)) { LOG_ERR("UART dev is not ready"); k_panic(); } /* configure uart device to 8N1 */ p->dev_config.baudrate = CONFIG_OSDP_UART_BAUD_RATE; p->dev_config.data_bits = UART_CFG_DATA_BITS_8; p->dev_config.parity = UART_CFG_PARITY_NONE; p->dev_config.stop_bits = UART_CFG_STOP_BITS_1; p->dev_config.flow_ctrl = UART_CFG_FLOW_CTRL_NONE; uart_configure(p->dev, &p->dev_config); uart_irq_rx_disable(p->dev); uart_irq_tx_disable(p->dev); uart_irq_callback_user_data_set(p->dev, osdp_uart_isr, p); /* Drain UART fifo and set channel to wait for mark byte */ while (uart_irq_rx_ready(p->dev)) { uart_fifo_read(p->dev, &c, 1); } p->wait_for_mark = 1; /* Both TX and RX are interrupt driven */ uart_irq_rx_enable(p->dev); /* setup OSDP */ ctx = osdp_build_ctx(&channel); if (ctx == NULL) { LOG_ERR("OSDP build ctx failed!"); k_panic(); } if (IS_ENABLED(CONFIG_OSDP_SC_ENABLED)) { if (strcmp(OSDP_KEY_STRING, "NONE") != 0) { len = strlen(OSDP_KEY_STRING); if (len != 32) { LOG_ERR("Key string length must be 32"); k_panic(); } len = hex2bin(OSDP_KEY_STRING, 32, key_buf, 16); if (len != 16) { LOG_ERR("Failed to parse key buffer"); k_panic(); } key = key_buf; } } if (osdp_setup(ctx, key)) { LOG_ERR("Failed to setup OSDP device!"); k_panic(); } LOG_INF("OSDP init okay!"); /* kick off refresh thread */ k_thread_create(&osdp_refresh_thread, osdp_thread_stack, CONFIG_OSDP_THREAD_STACK_SIZE, osdp_refresh, NULL, NULL, NULL, K_PRIO_COOP(2), 0, K_NO_WAIT); return 0; } SYS_INIT(osdp_init, POST_KERNEL, 10);