/* * Copyright (c) 2006-2021, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2019-08-13 balanceTWK the first version */ #include #define DBG_TAG "incap" #define DBG_LVL DBG_WARNING #include static rt_err_t rt_inputcapture_init(struct rt_device *dev) { rt_err_t ret; struct rt_inputcapture_device *inputcapture; RT_ASSERT(dev != RT_NULL); ret = RT_EOK; inputcapture = (struct rt_inputcapture_device *)dev; inputcapture->watermark = RT_INPUT_CAPTURE_RB_SIZE / 2; if (inputcapture->ops->init) { ret = inputcapture->ops->init(inputcapture); } return ret; } static rt_err_t rt_inputcapture_open(struct rt_device *dev, rt_uint16_t oflag) { rt_err_t ret; struct rt_inputcapture_device *inputcapture; RT_ASSERT(dev != RT_NULL); ret = RT_EOK; inputcapture = (struct rt_inputcapture_device *)dev; if (inputcapture->ringbuff == RT_NULL) { inputcapture->ringbuff = rt_ringbuffer_create(sizeof(struct rt_inputcapture_data) * RT_INPUT_CAPTURE_RB_SIZE); } if (inputcapture->ops->open) { ret = inputcapture->ops->open(inputcapture); } return ret; } static rt_err_t rt_inputcapture_close(struct rt_device *dev) { rt_err_t ret; struct rt_inputcapture_device *inputcapture; RT_ASSERT(dev != RT_NULL); ret = -RT_ERROR; inputcapture = (struct rt_inputcapture_device *)dev; if (inputcapture->ops->close) { ret = inputcapture->ops->close(inputcapture); } if (ret != RT_EOK) { return ret; } if (inputcapture->ringbuff) { rt_ringbuffer_destroy(inputcapture->ringbuff); inputcapture->ringbuff = RT_NULL; } return ret; } static rt_size_t rt_inputcapture_read(struct rt_device *dev, rt_off_t pos, void *buffer, rt_size_t size) { rt_size_t receive_size; struct rt_inputcapture_device *inputcapture; RT_ASSERT(dev != RT_NULL); inputcapture = (struct rt_inputcapture_device *)dev; receive_size = rt_ringbuffer_get(inputcapture->ringbuff, (rt_uint8_t *)buffer, sizeof(struct rt_inputcapture_data) * size); return receive_size / sizeof(struct rt_inputcapture_data); } static rt_err_t rt_inputcapture_control(struct rt_device *dev, int cmd, void *args) { rt_err_t result; struct rt_inputcapture_device *inputcapture; RT_ASSERT(dev != RT_NULL); result = RT_EOK; inputcapture = (struct rt_inputcapture_device *)dev; switch (cmd) { case INPUTCAPTURE_CMD_CLEAR_BUF: if (inputcapture->ringbuff) { rt_ringbuffer_reset(inputcapture->ringbuff); } break; case INPUTCAPTURE_CMD_SET_WATERMARK: inputcapture->watermark = *(rt_size_t *)args; break; default: result = -RT_ENOSYS; break; } return result; } #ifdef RT_USING_DEVICE_OPS const static struct rt_device_ops inputcapture_ops = { rt_inputcapture_init, rt_inputcapture_open, rt_inputcapture_close, rt_inputcapture_read, RT_NULL, rt_inputcapture_control }; #endif rt_err_t rt_device_inputcapture_register(struct rt_inputcapture_device *inputcapture, const char *name, void *user_data) { struct rt_device *device; RT_ASSERT(inputcapture != RT_NULL); RT_ASSERT(inputcapture->ops != RT_NULL); RT_ASSERT(inputcapture->ops->get_pulsewidth != RT_NULL); device = &(inputcapture->parent); device->type = RT_Device_Class_Miscellaneous; device->rx_indicate = RT_NULL; device->tx_complete = RT_NULL; inputcapture->ringbuff = RT_NULL; #ifdef RT_USING_DEVICE_OPS device->ops = &inputcapture_ops; #else device->init = rt_inputcapture_init; device->open = rt_inputcapture_open; device->close = rt_inputcapture_close; device->read = rt_inputcapture_read; device->write = RT_NULL; device->control = rt_inputcapture_control; #endif device->user_data = user_data; return rt_device_register(device, name, RT_DEVICE_FLAG_RDONLY | RT_DEVICE_FLAG_STANDALONE); } /** * This function is ISR for inputcapture interrupt. * level: RT_TRUE denotes high level pulse, and RT_FALSE denotes low level pulse. */ void rt_hw_inputcapture_isr(struct rt_inputcapture_device *inputcapture, rt_bool_t level) { struct rt_inputcapture_data data; rt_size_t receive_size; if (inputcapture->ops->get_pulsewidth(inputcapture, &data.pulsewidth_us) != RT_EOK) { return; } data.is_high = level; if (rt_ringbuffer_put(inputcapture->ringbuff, (rt_uint8_t *)&data, sizeof(struct rt_inputcapture_data)) == 0) { LOG_W("inputcapture ringbuffer doesn't have enough space."); } receive_size = rt_ringbuffer_data_len(inputcapture->ringbuff) / sizeof(struct rt_inputcapture_data); if (receive_size >= inputcapture->watermark) { /* indicate to upper layer application */ if (inputcapture->parent.rx_indicate != RT_NULL) inputcapture->parent.rx_indicate(&inputcapture->parent, receive_size); } }