2015-01-19 14:18:16 +08:00
|
|
|
/*
|
2022-05-30 18:00:26 +08:00
|
|
|
* Copyright (c) 2006-2022, RT-Thread Development Team
|
2015-01-19 14:18:16 +08:00
|
|
|
*
|
2018-10-14 19:37:18 +08:00
|
|
|
* SPDX-License-Identifier: Apache-2.0
|
2015-01-19 14:18:16 +08:00
|
|
|
*
|
|
|
|
* Change Logs:
|
|
|
|
* Date Author Notes
|
|
|
|
* 2015-01-20 Bernard the first version
|
2021-02-06 02:27:18 +08:00
|
|
|
* 2021-02-06 Meco Man fix RT_ENOSYS code in negative
|
2022-05-30 18:00:26 +08:00
|
|
|
* 2022-04-29 WangQiang add pin operate command in MSH
|
2015-01-19 14:18:16 +08:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <drivers/pin.h>
|
|
|
|
|
|
|
|
static struct rt_device_pin _hw_pin;
|
2023-02-06 07:35:33 +08:00
|
|
|
static rt_ssize_t _pin_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
|
2015-01-19 14:18:16 +08:00
|
|
|
{
|
2023-02-27 10:17:51 +08:00
|
|
|
struct rt_device_pin_value *value;
|
2015-01-19 16:56:43 +08:00
|
|
|
struct rt_device_pin *pin = (struct rt_device_pin *)dev;
|
2015-01-19 14:18:16 +08:00
|
|
|
|
|
|
|
/* check parameters */
|
|
|
|
RT_ASSERT(pin != RT_NULL);
|
|
|
|
|
2023-02-27 10:17:51 +08:00
|
|
|
value = (struct rt_device_pin_value *)buffer;
|
|
|
|
if (value == RT_NULL || size != sizeof(*value))
|
2022-05-30 18:00:26 +08:00
|
|
|
return 0;
|
2015-01-19 14:18:16 +08:00
|
|
|
|
2023-02-27 10:17:51 +08:00
|
|
|
value->value = pin->ops->pin_read(dev, value->pin);
|
2015-01-19 14:18:16 +08:00
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2023-02-06 07:35:33 +08:00
|
|
|
static rt_ssize_t _pin_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
|
2015-01-19 14:18:16 +08:00
|
|
|
{
|
2023-02-27 10:17:51 +08:00
|
|
|
struct rt_device_pin_value *value;
|
2015-01-19 16:56:43 +08:00
|
|
|
struct rt_device_pin *pin = (struct rt_device_pin *)dev;
|
2015-01-19 14:18:16 +08:00
|
|
|
|
|
|
|
/* check parameters */
|
|
|
|
RT_ASSERT(pin != RT_NULL);
|
|
|
|
|
2023-02-27 10:17:51 +08:00
|
|
|
value = (struct rt_device_pin_value *)buffer;
|
|
|
|
if (value == RT_NULL || size != sizeof(*value))
|
2022-05-30 18:00:26 +08:00
|
|
|
return 0;
|
2015-01-19 14:18:16 +08:00
|
|
|
|
2023-02-27 10:17:51 +08:00
|
|
|
pin->ops->pin_write(dev, (rt_base_t)value->pin, (rt_base_t)value->value);
|
2015-01-19 14:18:16 +08:00
|
|
|
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2021-04-17 18:01:20 +08:00
|
|
|
static rt_err_t _pin_control(rt_device_t dev, int cmd, void *args)
|
2015-01-19 14:18:16 +08:00
|
|
|
{
|
2015-01-19 16:56:43 +08:00
|
|
|
struct rt_device_pin_mode *mode;
|
|
|
|
struct rt_device_pin *pin = (struct rt_device_pin *)dev;
|
2015-01-19 14:18:16 +08:00
|
|
|
|
|
|
|
/* check parameters */
|
|
|
|
RT_ASSERT(pin != RT_NULL);
|
|
|
|
|
2022-05-30 18:00:26 +08:00
|
|
|
mode = (struct rt_device_pin_mode *)args;
|
|
|
|
if (mode == RT_NULL)
|
|
|
|
return -RT_ERROR;
|
2015-01-19 14:18:16 +08:00
|
|
|
|
|
|
|
pin->ops->pin_mode(dev, (rt_base_t)mode->pin, (rt_base_t)mode->mode);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-06-10 17:59:17 +08:00
|
|
|
#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
|
|
|
|
|
2015-01-19 16:56:43 +08:00
|
|
|
int rt_device_pin_register(const char *name, const struct rt_pin_ops *ops, void *user_data)
|
2015-01-19 14:18:16 +08:00
|
|
|
{
|
2022-04-06 21:12:39 +08:00
|
|
|
_hw_pin.parent.type = RT_Device_Class_Pin;
|
2015-01-19 16:56:43 +08:00
|
|
|
_hw_pin.parent.rx_indicate = RT_NULL;
|
|
|
|
_hw_pin.parent.tx_complete = RT_NULL;
|
2015-01-19 14:18:16 +08:00
|
|
|
|
2018-06-10 17:59:17 +08:00
|
|
|
#ifdef RT_USING_DEVICE_OPS
|
|
|
|
_hw_pin.parent.ops = &pin_ops;
|
|
|
|
#else
|
2015-01-19 16:56:43 +08:00
|
|
|
_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;
|
2018-06-10 17:59:17 +08:00
|
|
|
#endif
|
2015-01-19 14:18:16 +08:00
|
|
|
|
|
|
|
_hw_pin.ops = ops;
|
2015-01-19 16:56:43 +08:00
|
|
|
_hw_pin.parent.user_data = user_data;
|
2015-01-19 14:18:16 +08:00
|
|
|
|
2015-01-19 16:56:43 +08:00
|
|
|
/* register a character device */
|
2015-03-23 09:38:09 +08:00
|
|
|
rt_device_register(&_hw_pin.parent, name, RT_DEVICE_FLAG_RDWR);
|
2015-01-19 14:18:16 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2023-02-27 10:17:51 +08:00
|
|
|
rt_err_t rt_pin_attach_irq(rt_base_t pin, rt_uint8_t mode,
|
2022-05-30 18:00:26 +08:00
|
|
|
void (*hdr)(void *args), void *args)
|
2017-03-10 15:07:28 +08:00
|
|
|
{
|
|
|
|
RT_ASSERT(_hw_pin.ops != RT_NULL);
|
2022-05-30 18:00:26 +08:00
|
|
|
if (_hw_pin.ops->pin_attach_irq)
|
2017-03-10 15:07:28 +08:00
|
|
|
{
|
|
|
|
return _hw_pin.ops->pin_attach_irq(&_hw_pin.parent, pin, mode, hdr, args);
|
|
|
|
}
|
2021-02-06 02:27:18 +08:00
|
|
|
return -RT_ENOSYS;
|
2017-03-10 15:07:28 +08:00
|
|
|
}
|
2021-04-17 18:01:20 +08:00
|
|
|
|
2023-02-27 10:17:51 +08:00
|
|
|
rt_err_t rt_pin_detach_irq(rt_base_t pin)
|
2017-03-10 15:07:28 +08:00
|
|
|
{
|
|
|
|
RT_ASSERT(_hw_pin.ops != RT_NULL);
|
2022-05-30 18:00:26 +08:00
|
|
|
if (_hw_pin.ops->pin_detach_irq)
|
2017-03-10 15:07:28 +08:00
|
|
|
{
|
2018-06-26 22:18:58 +08:00
|
|
|
return _hw_pin.ops->pin_detach_irq(&_hw_pin.parent, pin);
|
2017-03-10 15:07:28 +08:00
|
|
|
}
|
2021-02-06 02:27:18 +08:00
|
|
|
return -RT_ENOSYS;
|
2017-03-10 15:07:28 +08:00
|
|
|
}
|
2018-06-10 17:59:17 +08:00
|
|
|
|
2023-02-27 10:17:51 +08:00
|
|
|
rt_err_t rt_pin_irq_enable(rt_base_t pin, rt_uint8_t enabled)
|
2017-03-10 15:07:28 +08:00
|
|
|
{
|
|
|
|
RT_ASSERT(_hw_pin.ops != RT_NULL);
|
2022-05-30 18:00:26 +08:00
|
|
|
if (_hw_pin.ops->pin_irq_enable)
|
2017-03-10 15:07:28 +08:00
|
|
|
{
|
2017-03-14 10:26:49 +08:00
|
|
|
return _hw_pin.ops->pin_irq_enable(&_hw_pin.parent, pin, enabled);
|
2017-03-10 15:07:28 +08:00
|
|
|
}
|
2021-02-06 02:27:18 +08:00
|
|
|
return -RT_ENOSYS;
|
2017-03-10 15:07:28 +08:00
|
|
|
}
|
2018-06-10 17:59:17 +08:00
|
|
|
|
2015-01-19 14:18:16 +08:00
|
|
|
/* RT-Thread Hardware PIN APIs */
|
2023-02-27 10:17:51 +08:00
|
|
|
void rt_pin_mode(rt_base_t pin, rt_uint8_t mode)
|
2015-01-19 14:18:16 +08:00
|
|
|
{
|
2017-03-10 15:07:28 +08:00
|
|
|
RT_ASSERT(_hw_pin.ops != RT_NULL);
|
2015-01-19 14:18:16 +08:00
|
|
|
_hw_pin.ops->pin_mode(&_hw_pin.parent, pin, mode);
|
|
|
|
}
|
|
|
|
|
2023-02-27 10:17:51 +08:00
|
|
|
void rt_pin_write(rt_base_t pin, rt_uint8_t value)
|
2015-01-19 14:18:16 +08:00
|
|
|
{
|
2017-03-10 15:07:28 +08:00
|
|
|
RT_ASSERT(_hw_pin.ops != RT_NULL);
|
2015-01-19 14:18:16 +08:00
|
|
|
_hw_pin.ops->pin_write(&_hw_pin.parent, pin, value);
|
|
|
|
}
|
|
|
|
|
2023-02-27 10:17:51 +08:00
|
|
|
rt_int8_t rt_pin_read(rt_base_t pin)
|
2015-01-19 14:18:16 +08:00
|
|
|
{
|
2017-03-10 15:07:28 +08:00
|
|
|
RT_ASSERT(_hw_pin.ops != RT_NULL);
|
2015-01-19 14:18:16 +08:00
|
|
|
return _hw_pin.ops->pin_read(&_hw_pin.parent, pin);
|
|
|
|
}
|
2022-05-30 18:00:26 +08:00
|
|
|
|
2023-02-27 10:17:51 +08:00
|
|
|
/* Get pin number by name, such as PA.0, P0.12 */
|
2020-09-11 11:14:53 +08:00
|
|
|
rt_base_t rt_pin_get(const char *name)
|
|
|
|
{
|
|
|
|
RT_ASSERT(_hw_pin.ops != RT_NULL);
|
2021-03-08 18:19:04 +08:00
|
|
|
|
2022-05-30 18:00:26 +08:00
|
|
|
if (name[0] != 'P' && name[0] != 'p')
|
|
|
|
{
|
|
|
|
return -RT_EINVAL;
|
|
|
|
}
|
|
|
|
if (_hw_pin.ops->pin_get == RT_NULL)
|
2020-09-11 11:14:53 +08:00
|
|
|
{
|
|
|
|
return -RT_ENOSYS;
|
|
|
|
}
|
|
|
|
return _hw_pin.ops->pin_get(name);
|
|
|
|
}
|
2022-05-30 18:00:26 +08:00
|
|
|
|
|
|
|
#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
|
|
|
|
* support PE02, PE2, PE.02, PE.2, pe02, pe2, pe.02, pe.2
|
|
|
|
*/
|
|
|
|
static rt_base_t _pin_cmd_conv(const char *name)
|
|
|
|
{
|
|
|
|
int size = 0;
|
|
|
|
char format_name[6] = { 0 };
|
|
|
|
format_name[0] = toupper(name[0]);
|
|
|
|
format_name[1] = toupper(name[1]);
|
|
|
|
|
|
|
|
size = rt_strlen(name);
|
|
|
|
size = (size > 5) ? 5 : size;
|
|
|
|
size -= 2;
|
|
|
|
if (name[2] != '.')
|
|
|
|
{
|
|
|
|
format_name[2] = '.';
|
|
|
|
}
|
|
|
|
strncat(format_name, name + 2, size);
|
|
|
|
return rt_pin_get(format_name);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void _pin_cmd_print_usage(void)
|
|
|
|
{
|
|
|
|
rt_kprintf("pin [option]\n");
|
|
|
|
rt_kprintf(" num: get pin number from hardware pin\n");
|
|
|
|
rt_kprintf(" num can be PE02, PE2, PE.02, PE.2, pe02, pe2, pe.02, pe.2\n");
|
|
|
|
rt_kprintf(" e.g. MSH >pin num PA.16\n");
|
|
|
|
rt_kprintf(" mode: set pin mode to output/input/input_pullup/input_pulldown/output_od\n e.g. MSH >pin mode PA.16 output\n");
|
|
|
|
rt_kprintf(" read: read pin level of hardware pin\n e.g. MSH >pin read PA.16\n");
|
|
|
|
rt_kprintf(" write: write pin level(high/low or on/off) to hardware pin\n e.g. MSH >pin write PA.16 high\n");
|
|
|
|
rt_kprintf(" help: this help list\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 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;
|
2023-02-27 10:17:51 +08:00
|
|
|
rt_uint8_t value;
|
2022-05-30 18:00:26 +08:00
|
|
|
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] = on\n", pin);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
rt_kprintf("pin[%d] = off\n", pin);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* e.g. MSH >pin write PA.16 high */
|
|
|
|
static void _pin_cmd_write(int argc, char *argv[])
|
|
|
|
{
|
|
|
|
rt_base_t pin;
|
2023-02-27 10:17:51 +08:00
|
|
|
rt_uint8_t value;
|
2022-05-30 18:00:26 +08:00
|
|
|
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 */
|