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