1 /*
2 * Copyright (c) 2006-2023, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2019-08-13 balanceTWK the first version
9 */
10
11 #include <rtdevice.h>
12
13 #define DBG_TAG "incap"
14 #define DBG_LVL DBG_WARNING
15 #include <rtdbg.h>
16
rt_inputcapture_init(struct rt_device * dev)17 static rt_err_t rt_inputcapture_init(struct rt_device *dev)
18 {
19 rt_err_t ret;
20 struct rt_inputcapture_device *inputcapture;
21
22 RT_ASSERT(dev != RT_NULL);
23
24 ret = RT_EOK;
25 inputcapture = (struct rt_inputcapture_device *)dev;
26 inputcapture->watermark = RT_INPUT_CAPTURE_RB_SIZE / 2;
27 if (inputcapture->ops->init)
28 {
29 ret = inputcapture->ops->init(inputcapture);
30 }
31
32 return ret;
33 }
34
rt_inputcapture_open(struct rt_device * dev,rt_uint16_t oflag)35 static rt_err_t rt_inputcapture_open(struct rt_device *dev, rt_uint16_t oflag)
36 {
37 rt_err_t ret;
38 struct rt_inputcapture_device *inputcapture;
39
40 RT_ASSERT(dev != RT_NULL);
41
42 ret = RT_EOK;
43 inputcapture = (struct rt_inputcapture_device *)dev;
44 if (inputcapture->ringbuff == RT_NULL)
45 {
46 inputcapture->ringbuff = rt_ringbuffer_create(sizeof(struct rt_inputcapture_data) * RT_INPUT_CAPTURE_RB_SIZE);
47 }
48 if (inputcapture->ops->open)
49 {
50 ret = inputcapture->ops->open(inputcapture);
51 }
52
53 return ret;
54 }
55
rt_inputcapture_close(struct rt_device * dev)56 static rt_err_t rt_inputcapture_close(struct rt_device *dev)
57 {
58 rt_err_t ret;
59 struct rt_inputcapture_device *inputcapture;
60
61 RT_ASSERT(dev != RT_NULL);
62
63 ret = -RT_ERROR;
64 inputcapture = (struct rt_inputcapture_device *)dev;
65
66 if (inputcapture->ops->close)
67 {
68 ret = inputcapture->ops->close(inputcapture);
69 }
70
71 if (ret != RT_EOK)
72 {
73 return ret;
74 }
75
76 if (inputcapture->ringbuff)
77 {
78 rt_ringbuffer_destroy(inputcapture->ringbuff);
79 inputcapture->ringbuff = RT_NULL;
80 }
81 return ret;
82 }
83
rt_inputcapture_read(struct rt_device * dev,rt_off_t pos,void * buffer,rt_size_t size)84 static rt_ssize_t rt_inputcapture_read(struct rt_device *dev,
85 rt_off_t pos,
86 void *buffer,
87 rt_size_t size)
88 {
89 rt_size_t receive_size;
90 struct rt_inputcapture_device *inputcapture;
91
92 RT_ASSERT(dev != RT_NULL);
93
94 inputcapture = (struct rt_inputcapture_device *)dev;
95 receive_size = rt_ringbuffer_get(inputcapture->ringbuff, (rt_uint8_t *)buffer, sizeof(struct rt_inputcapture_data) * size);
96
97 return receive_size / sizeof(struct rt_inputcapture_data);
98 }
99
rt_inputcapture_control(struct rt_device * dev,int cmd,void * args)100 static rt_err_t rt_inputcapture_control(struct rt_device *dev, int cmd, void *args)
101 {
102 rt_err_t result;
103 struct rt_inputcapture_device *inputcapture;
104
105 RT_ASSERT(dev != RT_NULL);
106
107 result = RT_EOK;
108 inputcapture = (struct rt_inputcapture_device *)dev;
109 switch (cmd)
110 {
111 case INPUTCAPTURE_CMD_CLEAR_BUF:
112 if (inputcapture->ringbuff)
113 {
114 rt_ringbuffer_reset(inputcapture->ringbuff);
115 }
116 break;
117 case INPUTCAPTURE_CMD_SET_WATERMARK:
118 inputcapture->watermark = *(rt_size_t *)args;
119 break;
120 default:
121 result = -RT_ENOSYS;
122 break;
123 }
124
125 return result;
126 }
127
128 #ifdef RT_USING_DEVICE_OPS
129 const static struct rt_device_ops inputcapture_ops =
130 {
131 rt_inputcapture_init,
132 rt_inputcapture_open,
133 rt_inputcapture_close,
134 rt_inputcapture_read,
135 RT_NULL,
136 rt_inputcapture_control
137 };
138 #endif
139
rt_device_inputcapture_register(struct rt_inputcapture_device * inputcapture,const char * name,void * user_data)140 rt_err_t rt_device_inputcapture_register(struct rt_inputcapture_device *inputcapture, const char *name, void *user_data)
141 {
142 struct rt_device *device;
143
144 RT_ASSERT(inputcapture != RT_NULL);
145 RT_ASSERT(inputcapture->ops != RT_NULL);
146 RT_ASSERT(inputcapture->ops->get_pulsewidth != RT_NULL);
147
148 device = &(inputcapture->parent);
149
150 device->type = RT_Device_Class_Miscellaneous;
151 device->rx_indicate = RT_NULL;
152 device->tx_complete = RT_NULL;
153 inputcapture->ringbuff = RT_NULL;
154
155 #ifdef RT_USING_DEVICE_OPS
156 device->ops = &inputcapture_ops;
157 #else
158 device->init = rt_inputcapture_init;
159 device->open = rt_inputcapture_open;
160 device->close = rt_inputcapture_close;
161 device->read = rt_inputcapture_read;
162 device->write = RT_NULL;
163 device->control = rt_inputcapture_control;
164 #endif
165 device->user_data = user_data;
166
167 return rt_device_register(device, name, RT_DEVICE_FLAG_RDONLY | RT_DEVICE_FLAG_STANDALONE);
168 }
169
170 /**
171 * This function is ISR for inputcapture interrupt.
172 * level: RT_TRUE denotes high level pulse, and RT_FALSE denotes low level pulse.
173 */
rt_hw_inputcapture_isr(struct rt_inputcapture_device * inputcapture,rt_bool_t level)174 void rt_hw_inputcapture_isr(struct rt_inputcapture_device *inputcapture, rt_bool_t level)
175 {
176 struct rt_inputcapture_data data;
177 rt_size_t receive_size;
178 if (inputcapture->ops->get_pulsewidth(inputcapture, &data.pulsewidth_us) != RT_EOK)
179 {
180 return;
181 }
182
183 data.is_high = level;
184 if (rt_ringbuffer_put(inputcapture->ringbuff, (rt_uint8_t *)&data, sizeof(struct rt_inputcapture_data)) == 0)
185 {
186 LOG_W("inputcapture ringbuffer doesn't have enough space.");
187 }
188
189 receive_size = rt_ringbuffer_data_len(inputcapture->ringbuff) / sizeof(struct rt_inputcapture_data);
190
191 if (receive_size >= inputcapture->watermark)
192 {
193 /* indicate to upper layer application */
194 if (inputcapture->parent.rx_indicate != RT_NULL)
195 inputcapture->parent.rx_indicate(&inputcapture->parent, receive_size);
196 }
197 }
198