/* * Copyright (c) 2006-2022, 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 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_status *status; struct rt_device_pin *pin = (struct rt_device_pin *)dev; /* check parameters */ RT_ASSERT(pin != RT_NULL); status = (struct rt_device_pin_status *)buffer; if (status == RT_NULL || size != sizeof(*status)) return 0; status->status = pin->ops->pin_read(dev, status->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_status *status; struct rt_device_pin *pin = (struct rt_device_pin *)dev; /* check parameters */ RT_ASSERT(pin != RT_NULL); status = (struct rt_device_pin_status *)buffer; if (status == RT_NULL || size != sizeof(*status)) return 0; pin->ops->pin_write(dev, (rt_base_t)status->pin, (rt_base_t)status->status); 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_int32_t pin, rt_uint32_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_int32_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_uint32_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_base_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_base_t value) { RT_ASSERT(_hw_pin.ops != RT_NULL); _hw_pin.ops->pin_write(&_hw_pin.parent, pin, value); } int rt_pin_read(rt_base_t pin) { RT_ASSERT(_hw_pin.ops != RT_NULL); return _hw_pin.ops->pin_read(&_hw_pin.parent, pin); } rt_base_t rt_pin_get(const char *name) { RT_ASSERT(_hw_pin.ops != RT_NULL); if (name[0] != 'P' && name[0] != 'p') { return -RT_EINVAL; } if (_hw_pin.ops->pin_get == RT_NULL) { return -RT_ENOSYS; } return _hw_pin.ops->pin_get(name); } #ifdef RT_USING_FINSH #include #include #include #include #include /* * 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; rt_base_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] = 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; rt_base_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 */