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