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 * 2015-01-20 Bernard the first version
9 * 2021-02-06 Meco Man fix RT_ENOSYS code in negative
10 * 2022-04-29 WangQiang add pin operate command in MSH
11 */
12
13 #include <drivers/dev_pin.h>
14
15 static struct rt_device_pin _hw_pin;
_pin_read(rt_device_t dev,rt_off_t pos,void * buffer,rt_size_t size)16 static rt_ssize_t _pin_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
17 {
18 struct rt_device_pin_value *value;
19 struct rt_device_pin *pin = (struct rt_device_pin *)dev;
20
21 /* check parameters */
22 RT_ASSERT(pin != RT_NULL);
23
24 value = (struct rt_device_pin_value *)buffer;
25 if (value == RT_NULL || size != sizeof(*value))
26 return 0;
27
28 value->value = pin->ops->pin_read(dev, value->pin);
29 return size;
30 }
31
_pin_write(rt_device_t dev,rt_off_t pos,const void * buffer,rt_size_t size)32 static rt_ssize_t _pin_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
33 {
34 struct rt_device_pin_value *value;
35 struct rt_device_pin *pin = (struct rt_device_pin *)dev;
36
37 /* check parameters */
38 RT_ASSERT(pin != RT_NULL);
39
40 value = (struct rt_device_pin_value *)buffer;
41 if (value == RT_NULL || size != sizeof(*value))
42 return 0;
43
44 pin->ops->pin_write(dev, (rt_base_t)value->pin, (rt_base_t)value->value);
45
46 return size;
47 }
48
_pin_control(rt_device_t dev,int cmd,void * args)49 static rt_err_t _pin_control(rt_device_t dev, int cmd, void *args)
50 {
51 struct rt_device_pin_mode *mode;
52 struct rt_device_pin *pin = (struct rt_device_pin *)dev;
53
54 /* check parameters */
55 RT_ASSERT(pin != RT_NULL);
56
57 mode = (struct rt_device_pin_mode *)args;
58 if (mode == RT_NULL)
59 return -RT_ERROR;
60
61 pin->ops->pin_mode(dev, (rt_base_t)mode->pin, (rt_base_t)mode->mode);
62
63 return 0;
64 }
65
66 #ifdef RT_USING_DEVICE_OPS
67 const static struct rt_device_ops pin_ops =
68 {
69 RT_NULL,
70 RT_NULL,
71 RT_NULL,
72 _pin_read,
73 _pin_write,
74 _pin_control
75 };
76 #endif
77
rt_device_pin_register(const char * name,const struct rt_pin_ops * ops,void * user_data)78 int rt_device_pin_register(const char *name, const struct rt_pin_ops *ops, void *user_data)
79 {
80 _hw_pin.parent.type = RT_Device_Class_Pin;
81 _hw_pin.parent.rx_indicate = RT_NULL;
82 _hw_pin.parent.tx_complete = RT_NULL;
83
84 #ifdef RT_USING_DEVICE_OPS
85 _hw_pin.parent.ops = &pin_ops;
86 #else
87 _hw_pin.parent.init = RT_NULL;
88 _hw_pin.parent.open = RT_NULL;
89 _hw_pin.parent.close = RT_NULL;
90 _hw_pin.parent.read = _pin_read;
91 _hw_pin.parent.write = _pin_write;
92 _hw_pin.parent.control = _pin_control;
93 #endif
94
95 _hw_pin.ops = ops;
96 _hw_pin.parent.user_data = user_data;
97
98 /* register a character device */
99 rt_device_register(&_hw_pin.parent, name, RT_DEVICE_FLAG_RDWR);
100
101 return 0;
102 }
103
rt_pin_attach_irq(rt_base_t pin,rt_uint8_t mode,void (* hdr)(void * args),void * args)104 rt_err_t rt_pin_attach_irq(rt_base_t pin, rt_uint8_t mode,
105 void (*hdr)(void *args), void *args)
106 {
107 RT_ASSERT(_hw_pin.ops != RT_NULL);
108 if (_hw_pin.ops->pin_attach_irq)
109 {
110 return _hw_pin.ops->pin_attach_irq(&_hw_pin.parent, pin, mode, hdr, args);
111 }
112 return -RT_ENOSYS;
113 }
114
rt_pin_detach_irq(rt_base_t pin)115 rt_err_t rt_pin_detach_irq(rt_base_t pin)
116 {
117 RT_ASSERT(_hw_pin.ops != RT_NULL);
118 if (_hw_pin.ops->pin_detach_irq)
119 {
120 return _hw_pin.ops->pin_detach_irq(&_hw_pin.parent, pin);
121 }
122 return -RT_ENOSYS;
123 }
124
rt_pin_irq_enable(rt_base_t pin,rt_uint8_t enabled)125 rt_err_t rt_pin_irq_enable(rt_base_t pin, rt_uint8_t enabled)
126 {
127 RT_ASSERT(_hw_pin.ops != RT_NULL);
128 if (_hw_pin.ops->pin_irq_enable)
129 {
130 return _hw_pin.ops->pin_irq_enable(&_hw_pin.parent, pin, enabled);
131 }
132 return -RT_ENOSYS;
133 }
134
rt_pin_debounce(rt_base_t pin,rt_uint32_t debounce)135 rt_err_t rt_pin_debounce(rt_base_t pin, rt_uint32_t debounce)
136 {
137 RT_ASSERT(_hw_pin.ops != RT_NULL);
138 if (_hw_pin.ops->pin_debounce)
139 {
140 return _hw_pin.ops->pin_debounce(&_hw_pin.parent, pin, debounce);
141 }
142 return -RT_ENOSYS;
143 }
144
145 /* RT-Thread Hardware PIN APIs */
rt_pin_mode(rt_base_t pin,rt_uint8_t mode)146 void rt_pin_mode(rt_base_t pin, rt_uint8_t mode)
147 {
148 RT_ASSERT(_hw_pin.ops != RT_NULL);
149 _hw_pin.ops->pin_mode(&_hw_pin.parent, pin, mode);
150 }
151
rt_pin_write(rt_base_t pin,rt_ssize_t value)152 void rt_pin_write(rt_base_t pin, rt_ssize_t value)
153 {
154 RT_ASSERT(_hw_pin.ops != RT_NULL);
155 _hw_pin.ops->pin_write(&_hw_pin.parent, pin, value);
156 }
157
rt_pin_read(rt_base_t pin)158 rt_ssize_t rt_pin_read(rt_base_t pin)
159 {
160 RT_ASSERT(_hw_pin.ops != RT_NULL);
161 return _hw_pin.ops->pin_read(&_hw_pin.parent, pin);
162 }
163
164 /* Get pin number by name, such as PA.0, P0.12 */
rt_pin_get(const char * name)165 rt_base_t rt_pin_get(const char *name)
166 {
167 RT_ASSERT(_hw_pin.ops != RT_NULL);
168
169 if (_hw_pin.ops->pin_get == RT_NULL)
170 {
171 return -RT_ENOSYS;
172 }
173 return _hw_pin.ops->pin_get(name);
174 }
175
176 #ifdef RT_USING_FINSH
177 #include <string.h>
178 #include <stdlib.h>
179 #include <ctype.h>
180 #include <finsh.h>
181 #include <msh_parse.h>
182
183 /*
184 * convert function for port name
185 */
_pin_cmd_conv(const char * name)186 static rt_base_t _pin_cmd_conv(const char *name)
187 {
188 return rt_pin_get(name);
189 }
190
_pin_cmd_print_usage(void)191 static void _pin_cmd_print_usage(void)
192 {
193 rt_kprintf("pin [option] GPIO\n");
194 rt_kprintf(" num: get pin number from hardware pin\n");
195 rt_kprintf(" mode: set pin mode to output/input/input_pullup/input_pulldown/output_od\n");
196 rt_kprintf(" e.g. MSH >pin mode GPIO output\n");
197 rt_kprintf(" read: read pin level of hardware pin\n");
198 rt_kprintf(" e.g. MSH >pin read GPIO\n");
199 rt_kprintf(" write: write pin level(high/low or on/off) to hardware pin\n");
200 rt_kprintf(" e.g. MSH >pin write GPIO high\n");
201 rt_kprintf(" help: this help list\n");
202 rt_kprintf("GPIO e.g.:");
203 rt_pin_get(" ");
204 }
205
206 /* e.g. MSH >pin num PA.16 */
_pin_cmd_get(int argc,char * argv[])207 static void _pin_cmd_get(int argc, char *argv[])
208 {
209 rt_base_t pin;
210 if (argc < 3)
211 {
212 _pin_cmd_print_usage();
213 return;
214 }
215 pin = _pin_cmd_conv(argv[2]);
216 if (pin < 0)
217 {
218 rt_kprintf("Parameter invalid : %s!\n", argv[2]);
219 _pin_cmd_print_usage();
220 return ;
221 }
222 rt_kprintf("%s : %d\n", argv[2], pin);
223 }
224
225 /* e.g. MSH >pin mode PA.16 output */
_pin_cmd_mode(int argc,char * argv[])226 static void _pin_cmd_mode(int argc, char *argv[])
227 {
228 rt_base_t pin;
229 rt_base_t mode;
230 if (argc < 4)
231 {
232 _pin_cmd_print_usage();
233 return;
234 }
235 if (!msh_isint(argv[2]))
236 {
237 pin = _pin_cmd_conv(argv[2]);
238 if (pin < 0)
239 {
240 rt_kprintf("Parameter invalid : %s!\n", argv[2]);
241 _pin_cmd_print_usage();
242 return;
243 }
244 }
245 else
246 {
247 pin = atoi(argv[2]);
248 }
249 if (0 == rt_strcmp("output", argv[3]))
250 {
251 mode = PIN_MODE_OUTPUT;
252 }
253 else if (0 == rt_strcmp("input", argv[3]))
254 {
255 mode = PIN_MODE_INPUT;
256 }
257 else if (0 == rt_strcmp("input_pullup", argv[3]))
258 {
259 mode = PIN_MODE_INPUT_PULLUP;
260 }
261 else if (0 == rt_strcmp("input_pulldown", argv[3]))
262 {
263 mode = PIN_MODE_INPUT_PULLDOWN;
264 }
265 else if (0 == rt_strcmp("output_od", argv[3]))
266 {
267 mode = PIN_MODE_OUTPUT_OD;
268 }
269 else
270 {
271 _pin_cmd_print_usage();
272 return;
273 }
274
275 rt_pin_mode(pin, mode);
276 }
277
278 /* e.g. MSH >pin read PA.16 */
_pin_cmd_read(int argc,char * argv[])279 static void _pin_cmd_read(int argc, char *argv[])
280 {
281 rt_base_t pin;
282 rt_uint8_t value;
283 if (argc < 3)
284 {
285 _pin_cmd_print_usage();
286 return;
287 }
288 if (!msh_isint(argv[2]))
289 {
290 pin = _pin_cmd_conv(argv[2]);
291 if (pin < 0)
292 {
293 rt_kprintf("Parameter invalid : %s!\n", argv[2]);
294 _pin_cmd_print_usage();
295 return;
296 }
297 }
298 else
299 {
300 pin = atoi(argv[2]);
301 }
302 value = rt_pin_read(pin);
303 if (value == PIN_HIGH)
304 {
305 rt_kprintf("pin[%d] = high\n", pin);
306 }
307 else
308 {
309 rt_kprintf("pin[%d] = low\n", pin);
310 }
311 }
312
313 /* e.g. MSH >pin write PA.16 high */
_pin_cmd_write(int argc,char * argv[])314 static void _pin_cmd_write(int argc, char *argv[])
315 {
316 rt_base_t pin;
317 rt_uint8_t value;
318 if (argc < 4)
319 {
320 _pin_cmd_print_usage();
321 return;
322 }
323 if (!msh_isint(argv[2]))
324 {
325 pin = _pin_cmd_conv(argv[2]);
326 if (pin < 0)
327 {
328 rt_kprintf("Parameter invalid : %s!\n", argv[2]);
329 _pin_cmd_print_usage();
330 return;
331 }
332 }
333 else
334 {
335 pin = atoi(argv[2]);
336 }
337 if ((0 == rt_strcmp("high", argv[3])) || (0 == rt_strcmp("on", argv[3])))
338 {
339 value = PIN_HIGH;
340 }
341 else if ((0 == rt_strcmp("low", argv[3])) || (0 == rt_strcmp("off", argv[3])))
342 {
343 value = PIN_LOW;
344 }
345 else
346 {
347 _pin_cmd_print_usage();
348 return;
349 }
350 rt_pin_write(pin, value);
351 }
352
_pin_cmd(int argc,char * argv[])353 static void _pin_cmd(int argc, char *argv[])
354 {
355 if (argc < 3)
356 {
357 _pin_cmd_print_usage();
358 return ;
359 }
360 if (0 == rt_strcmp("num", argv[1]))
361 {
362 _pin_cmd_get(argc, argv);
363 }
364 else if (0 == rt_strcmp("mode", argv[1]))
365 {
366 _pin_cmd_mode(argc, argv);
367 }
368 else if (0 == rt_strcmp("read", argv[1]))
369 {
370 _pin_cmd_read(argc, argv);
371 }
372 else if (0 == rt_strcmp("write", argv[1]))
373 {
374 _pin_cmd_write(argc, argv);
375 }
376 else
377 {
378 _pin_cmd_print_usage();
379 return;
380 }
381 }
382 MSH_CMD_EXPORT_ALIAS(_pin_cmd, pin, pin [option]);
383 #endif /* RT_USING_FINSH */
384