374 lines
		
	
	
		
			9.0 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			374 lines
		
	
	
		
			9.0 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
| /*
 | |
|  * Copyright (c) 2006-2023, RT-Thread Development Team
 | |
|  *
 | |
|  * SPDX-License-Identifier: Apache-2.0
 | |
|  *
 | |
|  * Change Logs:
 | |
|  * Date           Author       Notes
 | |
|  * 2015-01-20     Bernard      the first version
 | |
|  * 2021-02-06     Meco Man     fix RT_ENOSYS code in negative
 | |
|  * 2022-04-29     WangQiang    add pin operate command in MSH
 | |
|  */
 | |
| 
 | |
| #include <drivers/pin.h>
 | |
| 
 | |
| static struct rt_device_pin _hw_pin;
 | |
| static rt_ssize_t _pin_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
 | |
| {
 | |
|     struct rt_device_pin_value *value;
 | |
|     struct rt_device_pin *pin = (struct rt_device_pin *)dev;
 | |
| 
 | |
|     /* check parameters */
 | |
|     RT_ASSERT(pin != RT_NULL);
 | |
| 
 | |
|     value = (struct rt_device_pin_value *)buffer;
 | |
|     if (value == RT_NULL || size != sizeof(*value))
 | |
|         return 0;
 | |
| 
 | |
|     value->value = pin->ops->pin_read(dev, value->pin);
 | |
|     return size;
 | |
| }
 | |
| 
 | |
| static rt_ssize_t _pin_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
 | |
| {
 | |
|     struct rt_device_pin_value *value;
 | |
|     struct rt_device_pin *pin = (struct rt_device_pin *)dev;
 | |
| 
 | |
|     /* check parameters */
 | |
|     RT_ASSERT(pin != RT_NULL);
 | |
| 
 | |
|     value = (struct rt_device_pin_value *)buffer;
 | |
|     if (value == RT_NULL || size != sizeof(*value))
 | |
|         return 0;
 | |
| 
 | |
|     pin->ops->pin_write(dev, (rt_base_t)value->pin, (rt_base_t)value->value);
 | |
| 
 | |
|     return size;
 | |
| }
 | |
| 
 | |
| static rt_err_t _pin_control(rt_device_t dev, int cmd, void *args)
 | |
| {
 | |
|     struct rt_device_pin_mode *mode;
 | |
|     struct rt_device_pin *pin = (struct rt_device_pin *)dev;
 | |
| 
 | |
|     /* check parameters */
 | |
|     RT_ASSERT(pin != RT_NULL);
 | |
| 
 | |
|     mode = (struct rt_device_pin_mode *)args;
 | |
|     if (mode == RT_NULL)
 | |
|         return -RT_ERROR;
 | |
| 
 | |
|     pin->ops->pin_mode(dev, (rt_base_t)mode->pin, (rt_base_t)mode->mode);
 | |
| 
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| #ifdef RT_USING_DEVICE_OPS
 | |
| const static struct rt_device_ops pin_ops =
 | |
| {
 | |
|     RT_NULL,
 | |
|     RT_NULL,
 | |
|     RT_NULL,
 | |
|     _pin_read,
 | |
|     _pin_write,
 | |
|     _pin_control
 | |
| };
 | |
| #endif
 | |
| 
 | |
| int rt_device_pin_register(const char *name, const struct rt_pin_ops *ops, void *user_data)
 | |
| {
 | |
|     _hw_pin.parent.type         = RT_Device_Class_Pin;
 | |
|     _hw_pin.parent.rx_indicate  = RT_NULL;
 | |
|     _hw_pin.parent.tx_complete  = RT_NULL;
 | |
| 
 | |
| #ifdef RT_USING_DEVICE_OPS
 | |
|     _hw_pin.parent.ops          = &pin_ops;
 | |
| #else
 | |
|     _hw_pin.parent.init         = RT_NULL;
 | |
|     _hw_pin.parent.open         = RT_NULL;
 | |
|     _hw_pin.parent.close        = RT_NULL;
 | |
|     _hw_pin.parent.read         = _pin_read;
 | |
|     _hw_pin.parent.write        = _pin_write;
 | |
|     _hw_pin.parent.control      = _pin_control;
 | |
| #endif
 | |
| 
 | |
|     _hw_pin.ops                 = ops;
 | |
|     _hw_pin.parent.user_data    = user_data;
 | |
| 
 | |
|     /* register a character device */
 | |
|     rt_device_register(&_hw_pin.parent, name, RT_DEVICE_FLAG_RDWR);
 | |
| 
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| rt_err_t rt_pin_attach_irq(rt_base_t pin, rt_uint8_t mode,
 | |
|                            void (*hdr)(void *args), void *args)
 | |
| {
 | |
|     RT_ASSERT(_hw_pin.ops != RT_NULL);
 | |
|     if (_hw_pin.ops->pin_attach_irq)
 | |
|     {
 | |
|         return _hw_pin.ops->pin_attach_irq(&_hw_pin.parent, pin, mode, hdr, args);
 | |
|     }
 | |
|     return -RT_ENOSYS;
 | |
| }
 | |
| 
 | |
| rt_err_t rt_pin_detach_irq(rt_base_t pin)
 | |
| {
 | |
|     RT_ASSERT(_hw_pin.ops != RT_NULL);
 | |
|     if (_hw_pin.ops->pin_detach_irq)
 | |
|     {
 | |
|         return _hw_pin.ops->pin_detach_irq(&_hw_pin.parent, pin);
 | |
|     }
 | |
|     return -RT_ENOSYS;
 | |
| }
 | |
| 
 | |
| rt_err_t rt_pin_irq_enable(rt_base_t pin, rt_uint8_t enabled)
 | |
| {
 | |
|     RT_ASSERT(_hw_pin.ops != RT_NULL);
 | |
|     if (_hw_pin.ops->pin_irq_enable)
 | |
|     {
 | |
|         return _hw_pin.ops->pin_irq_enable(&_hw_pin.parent, pin, enabled);
 | |
|     }
 | |
|     return -RT_ENOSYS;
 | |
| }
 | |
| 
 | |
| /* RT-Thread Hardware PIN APIs */
 | |
| void rt_pin_mode(rt_base_t pin, rt_uint8_t mode)
 | |
| {
 | |
|     RT_ASSERT(_hw_pin.ops != RT_NULL);
 | |
|     _hw_pin.ops->pin_mode(&_hw_pin.parent, pin, mode);
 | |
| }
 | |
| 
 | |
| void rt_pin_write(rt_base_t pin, rt_ssize_t value)
 | |
| {
 | |
|     RT_ASSERT(_hw_pin.ops != RT_NULL);
 | |
|     _hw_pin.ops->pin_write(&_hw_pin.parent, pin, value);
 | |
| }
 | |
| 
 | |
| rt_ssize_t rt_pin_read(rt_base_t pin)
 | |
| {
 | |
|     RT_ASSERT(_hw_pin.ops != RT_NULL);
 | |
|     return _hw_pin.ops->pin_read(&_hw_pin.parent, pin);
 | |
| }
 | |
| 
 | |
| /* Get pin number by name, such as PA.0, P0.12 */
 | |
| rt_base_t rt_pin_get(const char *name)
 | |
| {
 | |
|     RT_ASSERT(_hw_pin.ops != RT_NULL);
 | |
| 
 | |
|     if (_hw_pin.ops->pin_get == RT_NULL)
 | |
|     {
 | |
|         return -RT_ENOSYS;
 | |
|     }
 | |
|     return _hw_pin.ops->pin_get(name);
 | |
| }
 | |
| 
 | |
| #ifdef RT_USING_FINSH
 | |
| #include <string.h>
 | |
| #include <stdlib.h>
 | |
| #include <ctype.h>
 | |
| #include <finsh.h>
 | |
| #include <msh_parse.h>
 | |
| 
 | |
| /*
 | |
|  * convert function for port name
 | |
|  */
 | |
| static rt_base_t _pin_cmd_conv(const char *name)
 | |
| {
 | |
|     return rt_pin_get(name);
 | |
| }
 | |
| 
 | |
| static void _pin_cmd_print_usage(void)
 | |
| {
 | |
|     rt_kprintf("pin [option] GPIO\n");
 | |
|     rt_kprintf("     num:      get pin number from hardware pin\n");
 | |
|     rt_kprintf("     mode:     set pin mode to output/input/input_pullup/input_pulldown/output_od\n");
 | |
|     rt_kprintf("               e.g. MSH >pin mode GPIO output\n");
 | |
|     rt_kprintf("     read:     read pin level of hardware pin\n");
 | |
|     rt_kprintf("               e.g. MSH >pin read GPIO\n");
 | |
|     rt_kprintf("     write:    write pin level(high/low or on/off) to hardware pin\n");
 | |
|     rt_kprintf("               e.g. MSH >pin write GPIO high\n");
 | |
|     rt_kprintf("     help:     this help list\n");
 | |
|     rt_kprintf("GPIO e.g.:");
 | |
|     rt_pin_get(" ");
 | |
| }
 | |
| 
 | |
| /* e.g. MSH >pin num PA.16 */
 | |
| static void _pin_cmd_get(int argc, char *argv[])
 | |
| {
 | |
|     rt_base_t pin;
 | |
|     if (argc < 3)
 | |
|     {
 | |
|         _pin_cmd_print_usage();
 | |
|         return;
 | |
|     }
 | |
|     pin = _pin_cmd_conv(argv[2]);
 | |
|     if (pin < 0)
 | |
|     {
 | |
|         rt_kprintf("Parameter invalid : %s!\n", argv[2]);
 | |
|         _pin_cmd_print_usage();
 | |
|         return ;
 | |
|     }
 | |
|     rt_kprintf("%s : %d\n", argv[2], pin);
 | |
| }
 | |
| 
 | |
| /* e.g. MSH >pin mode PA.16 output */
 | |
| static void _pin_cmd_mode(int argc, char *argv[])
 | |
| {
 | |
|     rt_base_t pin;
 | |
|     rt_base_t mode;
 | |
|     if (argc < 4)
 | |
|     {
 | |
|         _pin_cmd_print_usage();
 | |
|         return;
 | |
|     }
 | |
|     if (!msh_isint(argv[2]))
 | |
|     {
 | |
|         pin = _pin_cmd_conv(argv[2]);
 | |
|         if (pin < 0)
 | |
|         {
 | |
|             rt_kprintf("Parameter invalid : %s!\n", argv[2]);
 | |
|             _pin_cmd_print_usage();
 | |
|             return;
 | |
|         }
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         pin = atoi(argv[2]);
 | |
|     }
 | |
|     if (0 == rt_strcmp("output", argv[3]))
 | |
|     {
 | |
|         mode = PIN_MODE_OUTPUT;
 | |
|     }
 | |
|     else if (0 == rt_strcmp("input", argv[3]))
 | |
|     {
 | |
|         mode = PIN_MODE_INPUT;
 | |
|     }
 | |
|     else if (0 == rt_strcmp("input_pullup", argv[3]))
 | |
|     {
 | |
|         mode = PIN_MODE_INPUT_PULLUP;
 | |
|     }
 | |
|     else if (0 == rt_strcmp("input_pulldown", argv[3]))
 | |
|     {
 | |
|         mode = PIN_MODE_INPUT_PULLDOWN;
 | |
|     }
 | |
|     else if (0 == rt_strcmp("output_od", argv[3]))
 | |
|     {
 | |
|         mode = PIN_MODE_OUTPUT_OD;
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         _pin_cmd_print_usage();
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     rt_pin_mode(pin, mode);
 | |
| }
 | |
| 
 | |
| /* e.g. MSH >pin read PA.16 */
 | |
| static void _pin_cmd_read(int argc, char *argv[])
 | |
| {
 | |
|     rt_base_t pin;
 | |
|     rt_uint8_t value;
 | |
|     if (argc < 3)
 | |
|     {
 | |
|         _pin_cmd_print_usage();
 | |
|         return;
 | |
|     }
 | |
|     if (!msh_isint(argv[2]))
 | |
|     {
 | |
|         pin = _pin_cmd_conv(argv[2]);
 | |
|         if (pin < 0)
 | |
|         {
 | |
|             rt_kprintf("Parameter invalid : %s!\n", argv[2]);
 | |
|             _pin_cmd_print_usage();
 | |
|             return;
 | |
|         }
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         pin = atoi(argv[2]);
 | |
|     }
 | |
|     value = rt_pin_read(pin);
 | |
|     if (value == PIN_HIGH)
 | |
|     {
 | |
|         rt_kprintf("pin[%d] = high\n", pin);
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         rt_kprintf("pin[%d] = low\n", pin);
 | |
|     }
 | |
| }
 | |
| 
 | |
| /* e.g. MSH >pin write PA.16 high */
 | |
| static void _pin_cmd_write(int argc, char *argv[])
 | |
| {
 | |
|     rt_base_t pin;
 | |
|     rt_uint8_t value;
 | |
|     if (argc < 4)
 | |
|     {
 | |
|         _pin_cmd_print_usage();
 | |
|         return;
 | |
|     }
 | |
|     if (!msh_isint(argv[2]))
 | |
|     {
 | |
|         pin = _pin_cmd_conv(argv[2]);
 | |
|         if (pin < 0)
 | |
|         {
 | |
|             rt_kprintf("Parameter invalid : %s!\n", argv[2]);
 | |
|             _pin_cmd_print_usage();
 | |
|             return;
 | |
|         }
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         pin = atoi(argv[2]);
 | |
|     }
 | |
|     if ((0 == rt_strcmp("high", argv[3])) || (0 == rt_strcmp("on", argv[3])))
 | |
|     {
 | |
|         value = PIN_HIGH;
 | |
|     }
 | |
|     else if ((0 == rt_strcmp("low", argv[3])) || (0 == rt_strcmp("off", argv[3])))
 | |
|     {
 | |
|         value = PIN_LOW;
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         _pin_cmd_print_usage();
 | |
|         return;
 | |
|     }
 | |
|     rt_pin_write(pin, value);
 | |
| }
 | |
| 
 | |
| static void _pin_cmd(int argc, char *argv[])
 | |
| {
 | |
|     if (argc < 3)
 | |
|     {
 | |
|         _pin_cmd_print_usage();
 | |
|         return ;
 | |
|     }
 | |
|     if (0 == rt_strcmp("num", argv[1]))
 | |
|     {
 | |
|         _pin_cmd_get(argc, argv);
 | |
|     }
 | |
|     else if (0 == rt_strcmp("mode", argv[1]))
 | |
|     {
 | |
|         _pin_cmd_mode(argc, argv);
 | |
|     }
 | |
|     else if (0 == rt_strcmp("read", argv[1]))
 | |
|     {
 | |
|         _pin_cmd_read(argc, argv);
 | |
|     }
 | |
|     else if (0 == rt_strcmp("write", argv[1]))
 | |
|     {
 | |
|         _pin_cmd_write(argc, argv);
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         _pin_cmd_print_usage();
 | |
|         return;
 | |
|     }
 | |
| }
 | |
| MSH_CMD_EXPORT_ALIAS(_pin_cmd, pin, pin [option]);
 | |
| #endif /* RT_USING_FINSH */
 |