添加rtthread相关代码
This commit is contained in:
		
							
								
								
									
										35
									
								
								riscv/rtthread/components/drivers/misc/SConscript
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										35
									
								
								riscv/rtthread/components/drivers/misc/SConscript
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,35 @@ | ||||
| from building import * | ||||
|  | ||||
| cwd = GetCurrentDir() | ||||
| src = [] | ||||
| CPPPATH = [cwd + '/../include'] | ||||
| group = [] | ||||
|  | ||||
| if GetDepend(['RT_USING_ADC']): | ||||
|     src = src + ['adc.c'] | ||||
|  | ||||
| if GetDepend(['RT_USING_DAC']): | ||||
|     src = src + ['dac.c'] | ||||
|  | ||||
| if GetDepend(['RT_USING_PWM']): | ||||
|     src = src + ['rt_drv_pwm.c'] | ||||
|  | ||||
| if GetDepend(['RT_USING_PULSE_ENCODER']): | ||||
|     src = src + ['pulse_encoder.c'] | ||||
|  | ||||
| if GetDepend(['RT_USING_INPUT_CAPTURE']): | ||||
|     src = src + ['rt_inputcapture.c'] | ||||
|  | ||||
| if GetDepend(['RT_USING_NULL']): | ||||
|     src = src + ['rt_null.c'] | ||||
|  | ||||
| if GetDepend(['RT_USING_ZERO']): | ||||
|     src = src + ['rt_zero.c'] | ||||
|  | ||||
| if GetDepend(['RT_USING_RANDOM']): | ||||
|     src = src + ['rt_random.c'] | ||||
|  | ||||
| if len(src): | ||||
|     group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) | ||||
|  | ||||
| Return('group') | ||||
							
								
								
									
										295
									
								
								riscv/rtthread/components/drivers/misc/adc.c
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										295
									
								
								riscv/rtthread/components/drivers/misc/adc.c
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,295 @@ | ||||
| /* | ||||
|  * Copyright (c) 2006-2023, RT-Thread Development Team | ||||
|  * | ||||
|  * SPDX-License-Identifier: Apache-2.0 | ||||
|  * | ||||
|  * Change Logs: | ||||
|  * Date           Author       Notes | ||||
|  * 2018-05-07     aozima       the first version | ||||
|  * 2018-11-16     Ernest Chen  add finsh command and update adc function | ||||
|  * 2022-05-11     Stanley Lwin add finsh voltage conversion command | ||||
|  */ | ||||
|  | ||||
| #include <rtthread.h> | ||||
| #include <rtdevice.h> | ||||
|  | ||||
| #include <string.h> | ||||
| #include <stdlib.h> | ||||
|  | ||||
| #define DBG_TAG "adc" | ||||
| #define DBG_LVL DBG_INFO | ||||
| #include <rtdbg.h> | ||||
|  | ||||
| static rt_ssize_t _adc_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size) | ||||
| { | ||||
|     rt_err_t result = RT_EOK; | ||||
|     rt_size_t i; | ||||
|     struct rt_adc_device *adc = (struct rt_adc_device *)dev; | ||||
|     rt_uint32_t *value = (rt_uint32_t *)buffer; | ||||
|  | ||||
|     for (i = 0; i < size; i += sizeof(int)) | ||||
|     { | ||||
|         result = adc->ops->convert(adc, pos + i, value); | ||||
|         if (result != RT_EOK) | ||||
|         { | ||||
|             return 0; | ||||
|         } | ||||
|         value++; | ||||
|     } | ||||
|  | ||||
|     return i; | ||||
| } | ||||
|  | ||||
| static rt_err_t _adc_control(rt_device_t dev, int cmd, void *args) | ||||
| { | ||||
|     rt_err_t result = -RT_EINVAL; | ||||
|     rt_adc_device_t adc = (struct rt_adc_device *)dev; | ||||
|  | ||||
|     if (cmd == RT_ADC_CMD_ENABLE && adc->ops->enabled) | ||||
|     { | ||||
|         result = adc->ops->enabled(adc, (rt_uint32_t)args, RT_TRUE); | ||||
|     } | ||||
|     else if (cmd == RT_ADC_CMD_DISABLE && adc->ops->enabled) | ||||
|     { | ||||
|         result = adc->ops->enabled(adc, (rt_uint32_t)args, RT_FALSE); | ||||
|     } | ||||
|     else if (cmd == RT_ADC_CMD_GET_RESOLUTION && adc->ops->get_resolution && args) | ||||
|     { | ||||
|         rt_uint8_t resolution = adc->ops->get_resolution(adc); | ||||
|         if(resolution != 0) | ||||
|         { | ||||
|             *((rt_uint8_t*)args) = resolution; | ||||
|             LOG_D("resolution: %d bits", resolution); | ||||
|             result = RT_EOK; | ||||
|         } | ||||
|     } | ||||
|     else if (cmd == RT_ADC_CMD_GET_VREF && adc->ops->get_vref && args) | ||||
|     { | ||||
|         rt_int16_t value = adc->ops->get_vref(adc); | ||||
|         if(value != 0) | ||||
|         { | ||||
|             *((rt_int16_t *) args) = value; | ||||
|             result = RT_EOK; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     return result; | ||||
| } | ||||
|  | ||||
| #ifdef RT_USING_DEVICE_OPS | ||||
| const static struct rt_device_ops adc_ops = | ||||
| { | ||||
|     RT_NULL, | ||||
|     RT_NULL, | ||||
|     RT_NULL, | ||||
|     _adc_read, | ||||
|     RT_NULL, | ||||
|     _adc_control, | ||||
| }; | ||||
| #endif | ||||
|  | ||||
| rt_err_t rt_hw_adc_register(rt_adc_device_t device, const char *name, const struct rt_adc_ops *ops, const void *user_data) | ||||
| { | ||||
|     rt_err_t result = RT_EOK; | ||||
|     RT_ASSERT(ops != RT_NULL && ops->convert != RT_NULL); | ||||
|  | ||||
|     device->parent.type = RT_Device_Class_ADC; | ||||
|     device->parent.rx_indicate = RT_NULL; | ||||
|     device->parent.tx_complete = RT_NULL; | ||||
|  | ||||
| #ifdef RT_USING_DEVICE_OPS | ||||
|     device->parent.ops         = &adc_ops; | ||||
| #else | ||||
|     device->parent.init        = RT_NULL; | ||||
|     device->parent.open        = RT_NULL; | ||||
|     device->parent.close       = RT_NULL; | ||||
|     device->parent.read        = _adc_read; | ||||
|     device->parent.write       = RT_NULL; | ||||
|     device->parent.control     = _adc_control; | ||||
| #endif | ||||
|     device->ops = ops; | ||||
|     device->parent.user_data = (void *)user_data; | ||||
|  | ||||
|     result = rt_device_register(&device->parent, name, RT_DEVICE_FLAG_RDWR); | ||||
|  | ||||
|     return result; | ||||
| } | ||||
|  | ||||
| rt_uint32_t rt_adc_read(rt_adc_device_t dev, rt_int8_t channel) | ||||
| { | ||||
|     rt_uint32_t value; | ||||
|  | ||||
|     RT_ASSERT(dev); | ||||
|  | ||||
|     dev->ops->convert(dev, channel, &value); | ||||
|  | ||||
|     return value; | ||||
| } | ||||
|  | ||||
| rt_err_t rt_adc_enable(rt_adc_device_t dev, rt_int8_t channel) | ||||
| { | ||||
|     rt_err_t result = RT_EOK; | ||||
|  | ||||
|     RT_ASSERT(dev); | ||||
|  | ||||
|     if (dev->ops->enabled != RT_NULL) | ||||
|     { | ||||
|         result = dev->ops->enabled(dev, channel, RT_TRUE); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         result = -RT_ENOSYS; | ||||
|     } | ||||
|  | ||||
|     return result; | ||||
| } | ||||
|  | ||||
| rt_err_t rt_adc_disable(rt_adc_device_t dev, rt_int8_t channel) | ||||
| { | ||||
|     rt_err_t result = RT_EOK; | ||||
|  | ||||
|     RT_ASSERT(dev); | ||||
|  | ||||
|     if (dev->ops->enabled != RT_NULL) | ||||
|     { | ||||
|         result = dev->ops->enabled(dev, channel, RT_FALSE); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         result = -RT_ENOSYS; | ||||
|     } | ||||
|  | ||||
|     return result; | ||||
| } | ||||
|  | ||||
| rt_int16_t rt_adc_voltage(rt_adc_device_t dev, rt_int8_t channel) | ||||
| { | ||||
|     rt_uint32_t value = 0; | ||||
|     rt_int16_t vref = 0, voltage = 0; | ||||
|     rt_uint8_t resolution = 0; | ||||
|  | ||||
|     RT_ASSERT(dev); | ||||
|  | ||||
|     /*get the resolution in bits*/ | ||||
|     if (_adc_control((rt_device_t) dev, RT_ADC_CMD_GET_RESOLUTION, &resolution) != RT_EOK) | ||||
|     { | ||||
|         goto _voltage_exit; | ||||
|     } | ||||
|  | ||||
|     /*get the reference voltage*/ | ||||
|     if (_adc_control((rt_device_t) dev, RT_ADC_CMD_GET_VREF, &vref) != RT_EOK) | ||||
|     { | ||||
|         goto _voltage_exit; | ||||
|     } | ||||
|  | ||||
|     /*read the value and convert to voltage*/ | ||||
|     dev->ops->convert(dev, channel, &value); | ||||
|     voltage = value * vref / (1 << resolution); | ||||
|  | ||||
| _voltage_exit: | ||||
|     return voltage; | ||||
| } | ||||
|  | ||||
| #ifdef RT_USING_FINSH | ||||
|  | ||||
| static int adc(int argc, char **argv) | ||||
| { | ||||
|     int value = 0; | ||||
|     rt_int16_t voltage = 0; | ||||
|     rt_err_t result = -RT_ERROR; | ||||
|     static rt_adc_device_t adc_device = RT_NULL; | ||||
|     char *result_str; | ||||
|  | ||||
|     if (argc > 1) | ||||
|     { | ||||
|         if (!strcmp(argv[1], "probe")) | ||||
|         { | ||||
|             if (argc == 3) | ||||
|             { | ||||
|                 adc_device = (rt_adc_device_t)rt_device_find(argv[2]); | ||||
|                 result_str = (adc_device == RT_NULL) ? "failure" : "success"; | ||||
|                 rt_kprintf("probe %s %s \n", argv[2], result_str); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 rt_kprintf("adc probe <device name>   - probe adc by name\n"); | ||||
|             } | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             if (adc_device == RT_NULL) | ||||
|             { | ||||
|                 rt_kprintf("Please using 'adc probe <device name>' first\n"); | ||||
|                 return -RT_ERROR; | ||||
|             } | ||||
|             if (!strcmp(argv[1], "enable")) | ||||
|             { | ||||
|                 if (argc == 3) | ||||
|                 { | ||||
|                     result = rt_adc_enable(adc_device, atoi(argv[2])); | ||||
|                     result_str = (result == RT_EOK) ? "success" : "failure"; | ||||
|                     rt_kprintf("%s channel %d enables %s \n", adc_device->parent.parent.name, (rt_base_t)atoi(argv[2]), result_str); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     rt_kprintf("adc enable <channel>   - enable adc channel\n"); | ||||
|                 } | ||||
|             } | ||||
|             else if (!strcmp(argv[1], "read")) | ||||
|             { | ||||
|                 if (argc == 3) | ||||
|                 { | ||||
|                     value = rt_adc_read(adc_device, atoi(argv[2])); | ||||
|                     rt_kprintf("%s channel %d  read value is 0x%08X \n", adc_device->parent.parent.name, (rt_base_t)atoi(argv[2]), value); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     rt_kprintf("adc read <channel>     - read adc value on the channel\n"); | ||||
|                 } | ||||
|             } | ||||
|             else if (!strcmp(argv[1], "disable")) | ||||
|             { | ||||
|                 if (argc == 3) | ||||
|                 { | ||||
|                     result = rt_adc_disable(adc_device, atoi(argv[2])); | ||||
|                     result_str = (result == RT_EOK) ? "success" : "failure"; | ||||
|                     rt_kprintf("%s channel %d disable %s \n", adc_device->parent.parent.name, (rt_base_t)atoi(argv[2]), result_str); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     rt_kprintf("adc disable <channel>  - disable adc channel\n"); | ||||
|                 } | ||||
|             } | ||||
|             else if (!strcmp(argv[1], "voltage")) | ||||
|             { | ||||
|                 if(argc == 3) | ||||
|                 { | ||||
|                     voltage = rt_adc_voltage(adc_device, atoi(argv[2])); | ||||
|                     rt_kprintf("%s channel %d voltage is %d.%03dV \n", adc_device->parent.parent.name, (rt_base_t)atoi(argv[2]), voltage / 1000, voltage % 1000); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     rt_kprintf("adc convert voltage <channel> \n"); | ||||
|                 } | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 rt_kprintf("Unknown command. Please enter 'adc' for help\n"); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         rt_kprintf("Usage: \n"); | ||||
|         rt_kprintf("adc probe <device name> - probe adc by name\n"); | ||||
|         rt_kprintf("adc read <channel>      - read adc value on the channel\n"); | ||||
|         rt_kprintf("adc disable <channel>   - disable adc channel\n"); | ||||
|         rt_kprintf("adc enable <channel>    - enable adc channel\n"); | ||||
|  | ||||
|         result = -RT_ERROR; | ||||
|     } | ||||
|     return RT_EOK; | ||||
| } | ||||
| MSH_CMD_EXPORT(adc, adc [option]); | ||||
|  | ||||
| #endif /* RT_USING_FINSH */ | ||||
							
								
								
									
										234
									
								
								riscv/rtthread/components/drivers/misc/dac.c
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										234
									
								
								riscv/rtthread/components/drivers/misc/dac.c
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,234 @@ | ||||
| /* | ||||
|  * Copyright (c) 2006-2023, RT-Thread Development Team | ||||
|  * | ||||
|  * SPDX-License-Identifier: Apache-2.0 | ||||
|  * | ||||
|  * Change Logs: | ||||
|  * Date           Author       Notes | ||||
|  * 2020-06-19     thread-liu   the first version | ||||
|  */ | ||||
|  | ||||
| #include <rtdevice.h> | ||||
|  | ||||
| #include <string.h> | ||||
| #include <stdlib.h> | ||||
|  | ||||
| #define DBG_TAG "dac" | ||||
| #define DBG_LVL DBG_INFO | ||||
| #include <rtdbg.h> | ||||
|  | ||||
| static rt_ssize_t _dac_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size) | ||||
| { | ||||
|     rt_err_t result = RT_EOK; | ||||
|     rt_size_t i; | ||||
|     struct rt_dac_device *dac = (struct rt_dac_device *)dev; | ||||
|     rt_uint32_t *value = (rt_uint32_t *)buffer; | ||||
|  | ||||
|     for (i = 0; i < size; i += sizeof(int)) | ||||
|     { | ||||
|         result = dac->ops->convert(dac, pos + i, value); | ||||
|         if (result != RT_EOK) | ||||
|         { | ||||
|             return 0; | ||||
|         } | ||||
|         value++; | ||||
|     } | ||||
|  | ||||
|     return i; | ||||
| } | ||||
|  | ||||
| static rt_err_t _dac_control(rt_device_t dev, int cmd, void *args) | ||||
| { | ||||
|     rt_err_t result = -RT_EINVAL; | ||||
|     rt_dac_device_t dac = (struct rt_dac_device *)dev; | ||||
|  | ||||
|     if (cmd == RT_DAC_CMD_ENABLE && dac->ops->enabled) | ||||
|     { | ||||
|         result = dac->ops->enabled(dac, (rt_uint32_t)args); | ||||
|     } | ||||
|     else if (cmd == RT_DAC_CMD_DISABLE && dac->ops->enabled) | ||||
|     { | ||||
|         result = dac->ops->disabled(dac, (rt_uint32_t)args); | ||||
|     } | ||||
|     else if (cmd == RT_DAC_CMD_GET_RESOLUTION && dac->ops->get_resolution) | ||||
|     { | ||||
|         rt_uint8_t resolution = dac->ops->get_resolution(dac); | ||||
|         if(resolution != 0) | ||||
|         { | ||||
|             *((rt_uint8_t*)args) = resolution; | ||||
|             LOG_D("resolution: %d bits", resolution); | ||||
|             result = RT_EOK; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     return result; | ||||
| } | ||||
|  | ||||
| #ifdef RT_USING_DEVICE_OPS | ||||
| const static struct rt_device_ops dac_ops = | ||||
| { | ||||
|     RT_NULL, | ||||
|     RT_NULL, | ||||
|     RT_NULL, | ||||
|     RT_NULL, | ||||
|     _dac_write, | ||||
|     _dac_control, | ||||
| }; | ||||
| #endif | ||||
|  | ||||
| rt_err_t rt_hw_dac_register(rt_dac_device_t device, const char *name, const struct rt_dac_ops *ops, const void *user_data) | ||||
| { | ||||
|     rt_err_t result = RT_EOK; | ||||
|     RT_ASSERT(ops != RT_NULL && ops->convert != RT_NULL); | ||||
|  | ||||
|     device->parent.type = RT_Device_Class_DAC; | ||||
|     device->parent.rx_indicate = RT_NULL; | ||||
|     device->parent.tx_complete = RT_NULL; | ||||
|  | ||||
| #ifdef RT_USING_DEVICE_OPS | ||||
|     device->parent.ops         = &dac_ops; | ||||
| #else | ||||
|     device->parent.init        = RT_NULL; | ||||
|     device->parent.open        = RT_NULL; | ||||
|     device->parent.close       = RT_NULL; | ||||
|     device->parent.read        = RT_NULL; | ||||
|     device->parent.write       = _dac_write; | ||||
|     device->parent.control     = _dac_control; | ||||
| #endif | ||||
|     device->ops = ops; | ||||
|     device->parent.user_data = (void *)user_data; | ||||
|  | ||||
|     result = rt_device_register(&device->parent, name, RT_DEVICE_FLAG_RDWR); | ||||
|  | ||||
|     return result; | ||||
| } | ||||
|  | ||||
| rt_err_t rt_dac_write(rt_dac_device_t dev, rt_uint32_t channel, rt_uint32_t value) | ||||
| { | ||||
|     RT_ASSERT(dev); | ||||
|  | ||||
|     return dev->ops->convert(dev, channel, &value); | ||||
| } | ||||
|  | ||||
| rt_err_t rt_dac_enable(rt_dac_device_t dev, rt_uint32_t channel) | ||||
| { | ||||
|     rt_err_t result = RT_EOK; | ||||
|  | ||||
|     RT_ASSERT(dev); | ||||
|     if (dev->ops->enabled != RT_NULL) | ||||
|     { | ||||
|         result = dev->ops->enabled(dev, channel); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         result = -RT_ENOSYS; | ||||
|     } | ||||
|  | ||||
|     return result; | ||||
| } | ||||
|  | ||||
| rt_err_t rt_dac_disable(rt_dac_device_t dev, rt_uint32_t channel) | ||||
| { | ||||
|     rt_err_t result = RT_EOK; | ||||
|  | ||||
|     RT_ASSERT(dev); | ||||
|     if (dev->ops->disabled != RT_NULL) | ||||
|     { | ||||
|         result = dev->ops->disabled(dev, channel); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         result = -RT_ENOSYS; | ||||
|     } | ||||
|  | ||||
|     return result; | ||||
| } | ||||
|  | ||||
| #ifdef RT_USING_FINSH | ||||
|  | ||||
| static int dac(int argc, char **argv) | ||||
| { | ||||
|     int result = RT_EOK; | ||||
|     static rt_dac_device_t dac_device = RT_NULL; | ||||
|     char *result_str; | ||||
|  | ||||
|     if (argc > 1) | ||||
|     { | ||||
|         if (!strcmp(argv[1], "probe")) | ||||
|         { | ||||
|             if (argc == 3) | ||||
|             { | ||||
|                 dac_device = (rt_dac_device_t)rt_device_find(argv[2]); | ||||
|                 result_str = (dac_device == RT_NULL) ? "failure" : "success"; | ||||
|                 rt_kprintf("probe %s %s \n", argv[2], result_str); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 rt_kprintf("dac probe <dac_name>   - probe dac by name\n"); | ||||
|             } | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             if (dac_device == RT_NULL) | ||||
|             { | ||||
|                 rt_kprintf("Please using 'dac probe <dac_name>' first\n"); | ||||
|                 return -RT_ERROR; | ||||
|             } | ||||
|             if (!strcmp(argv[1], "enable")) | ||||
|             { | ||||
|                 if (argc == 3) | ||||
|                 { | ||||
|                     result = rt_dac_enable(dac_device, atoi(argv[2])); | ||||
|                     result_str = (result == RT_EOK) ? "success" : "failure"; | ||||
|                     rt_kprintf("%s channel %d enables %s \n", dac_device->parent.parent.name, atoi(argv[2]), result_str); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     rt_kprintf("dac enable <channel>   - enable dac channel\n"); | ||||
|                 } | ||||
|             } | ||||
|             else if (!strcmp(argv[1], "write")) | ||||
|             { | ||||
|                 if (argc == 4) | ||||
|                 { | ||||
|                     rt_dac_write(dac_device, atoi(argv[2]), atoi(argv[3])); | ||||
|                     rt_kprintf("%s channel %d write value is %d \n", dac_device->parent.parent.name, atoi(argv[2]), atoi(argv[3])); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     rt_kprintf("dac write <channel> <value>     - write dac value on the channel\n"); | ||||
|                 } | ||||
|             } | ||||
|             else if (!strcmp(argv[1], "disable")) | ||||
|             { | ||||
|                 if (argc == 3) | ||||
|                 { | ||||
|                     result = rt_dac_disable(dac_device, atoi(argv[2])); | ||||
|                     result_str = (result == RT_EOK) ? "success" : "failure"; | ||||
|                     rt_kprintf("%s channel %d disable %s \n", dac_device->parent.parent.name, atoi(argv[2]), result_str); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     rt_kprintf("dac disable <channel>  - disable dac channel\n"); | ||||
|                 } | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 rt_kprintf("Unknown command. Please enter 'dac' for help\n"); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         rt_kprintf("Usage: \n"); | ||||
|         rt_kprintf("dac probe <dac_name>           - probe dac by name\n"); | ||||
|         rt_kprintf("dac write <channel> <value>    - write dac value on the channel\n"); | ||||
|         rt_kprintf("dac disable <channel>          - disable dac channel\n"); | ||||
|         rt_kprintf("dac enable <channel>           - enable dac channel\n"); | ||||
|         result = -RT_ERROR; | ||||
|     } | ||||
|     return RT_EOK; | ||||
| } | ||||
| MSH_CMD_EXPORT(dac, dac function); | ||||
|  | ||||
| #endif /* RT_USING_FINSH */ | ||||
							
								
								
									
										135
									
								
								riscv/rtthread/components/drivers/misc/pulse_encoder.c
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										135
									
								
								riscv/rtthread/components/drivers/misc/pulse_encoder.c
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,135 @@ | ||||
| /* | ||||
|  * Copyright (c) 2006-2023, RT-Thread Development Team | ||||
|  * | ||||
|  * SPDX-License-Identifier: Apache-2.0 | ||||
|  * | ||||
|  * Change Logs: | ||||
|  * Date           Author       Notes | ||||
|  * 2019-08-08     balanceTWK   the first version | ||||
|  */ | ||||
|  | ||||
| #include <rtdevice.h> | ||||
|  | ||||
| static rt_err_t rt_pulse_encoder_init(struct rt_device *dev) | ||||
| { | ||||
|     struct rt_pulse_encoder_device *pulse_encoder; | ||||
|  | ||||
|     pulse_encoder = (struct rt_pulse_encoder_device *)dev; | ||||
|     if (pulse_encoder->ops->init) | ||||
|     { | ||||
|         return pulse_encoder->ops->init(pulse_encoder); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         return -RT_ENOSYS; | ||||
|     } | ||||
| } | ||||
|  | ||||
| static rt_err_t rt_pulse_encoder_open(struct rt_device *dev, rt_uint16_t oflag) | ||||
| { | ||||
|     struct rt_pulse_encoder_device *pulse_encoder; | ||||
|  | ||||
|     pulse_encoder = (struct rt_pulse_encoder_device *)dev; | ||||
|     if (pulse_encoder->ops->control) | ||||
|     { | ||||
|         return pulse_encoder->ops->control(pulse_encoder, PULSE_ENCODER_CMD_ENABLE, RT_NULL); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         return -RT_ENOSYS; | ||||
|     } | ||||
| } | ||||
|  | ||||
| static rt_err_t rt_pulse_encoder_close(struct rt_device *dev) | ||||
| { | ||||
|     struct rt_pulse_encoder_device *pulse_encoder; | ||||
|  | ||||
|     pulse_encoder = (struct rt_pulse_encoder_device *)dev; | ||||
|     if (pulse_encoder->ops->control) | ||||
|     { | ||||
|         return pulse_encoder->ops->control(pulse_encoder, PULSE_ENCODER_CMD_DISABLE, RT_NULL); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         return -RT_ENOSYS; | ||||
|     } | ||||
| } | ||||
|  | ||||
| static rt_ssize_t rt_pulse_encoder_read(struct rt_device *dev, rt_off_t pos, void *buffer, rt_size_t size) | ||||
| { | ||||
|     struct rt_pulse_encoder_device *pulse_encoder; | ||||
|  | ||||
|     pulse_encoder = (struct rt_pulse_encoder_device *)dev; | ||||
|     if (pulse_encoder->ops->get_count) | ||||
|     { | ||||
|         *(rt_int32_t *)buffer = pulse_encoder->ops->get_count(pulse_encoder); | ||||
|     } | ||||
|     return 1; | ||||
| } | ||||
|  | ||||
| static rt_err_t rt_pulse_encoder_control(struct rt_device *dev, int cmd, void *args) | ||||
| { | ||||
|     rt_err_t result; | ||||
|     struct rt_pulse_encoder_device *pulse_encoder; | ||||
|  | ||||
|     result = RT_EOK; | ||||
|     pulse_encoder = (struct rt_pulse_encoder_device *)dev; | ||||
|     switch (cmd) | ||||
|     { | ||||
|     case PULSE_ENCODER_CMD_CLEAR_COUNT: | ||||
|         result = pulse_encoder->ops->clear_count(pulse_encoder); | ||||
|         break; | ||||
|     case PULSE_ENCODER_CMD_GET_TYPE: | ||||
|         *(enum rt_pulse_encoder_type *)args = pulse_encoder->type; | ||||
|         break; | ||||
|     case PULSE_ENCODER_CMD_ENABLE: | ||||
|     case PULSE_ENCODER_CMD_DISABLE: | ||||
|         result = pulse_encoder->ops->control(pulse_encoder, cmd, args); | ||||
|         break; | ||||
|     default: | ||||
|         result = -RT_ENOSYS; | ||||
|         break; | ||||
|     } | ||||
|  | ||||
|     return result; | ||||
| } | ||||
|  | ||||
| #ifdef RT_USING_DEVICE_OPS | ||||
| const static struct rt_device_ops pulse_encoder_ops = | ||||
| { | ||||
|     rt_pulse_encoder_init, | ||||
|     rt_pulse_encoder_open, | ||||
|     rt_pulse_encoder_close, | ||||
|     rt_pulse_encoder_read, | ||||
|     RT_NULL, | ||||
|     rt_pulse_encoder_control | ||||
| }; | ||||
| #endif | ||||
|  | ||||
| rt_err_t rt_device_pulse_encoder_register(struct rt_pulse_encoder_device *pulse_encoder, const char *name, void *user_data) | ||||
| { | ||||
|     struct rt_device *device; | ||||
|  | ||||
|     RT_ASSERT(pulse_encoder != RT_NULL); | ||||
|     RT_ASSERT(pulse_encoder->ops != RT_NULL); | ||||
|  | ||||
|     device = &(pulse_encoder->parent); | ||||
|  | ||||
|     device->type        = RT_Device_Class_Miscellaneous; | ||||
|     device->rx_indicate = RT_NULL; | ||||
|     device->tx_complete = RT_NULL; | ||||
|  | ||||
| #ifdef RT_USING_DEVICE_OPS | ||||
|     device->ops         = &pulse_encoder_ops; | ||||
| #else | ||||
|     device->init        = rt_pulse_encoder_init; | ||||
|     device->open        = rt_pulse_encoder_open; | ||||
|     device->close       = rt_pulse_encoder_close; | ||||
|     device->read        = rt_pulse_encoder_read; | ||||
|     device->write       = RT_NULL; | ||||
|     device->control     = rt_pulse_encoder_control; | ||||
| #endif | ||||
|     device->user_data   = user_data; | ||||
|  | ||||
|     return rt_device_register(device, name, RT_DEVICE_FLAG_RDONLY | RT_DEVICE_FLAG_STANDALONE); | ||||
| } | ||||
							
								
								
									
										454
									
								
								riscv/rtthread/components/drivers/misc/rt_drv_pwm.c
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										454
									
								
								riscv/rtthread/components/drivers/misc/rt_drv_pwm.c
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,454 @@ | ||||
| /* | ||||
|  * Copyright (c) 2006-2023, RT-Thread Development Team | ||||
|  * | ||||
|  * SPDX-License-Identifier: Apache-2.0 | ||||
|  * | ||||
|  * Change Logs: | ||||
|  * Date           Author       Notes | ||||
|  * 2018-05-07     aozima       the first version | ||||
|  * 2022-05-14     Stanley Lwin add pwm function | ||||
|  * 2022-07-25     liYony       fix complementary outputs and add usage information in finsh | ||||
|  * 2022-08-31     liYony       Add complementary output section to framework for management | ||||
|  * 2022-09-24     qiyu         Add dead-time and phase configuration | ||||
|  * 2023-12-23     1ridic       Add second-level command completion | ||||
|  */ | ||||
|  | ||||
| #include <rtdevice.h> | ||||
|  | ||||
| static rt_err_t _pwm_control(rt_device_t dev, int cmd, void *args) | ||||
| { | ||||
|     rt_err_t result = RT_EOK; | ||||
|     struct rt_device_pwm *pwm = (struct rt_device_pwm *)dev; | ||||
|     struct rt_pwm_configuration *configuration = (struct rt_pwm_configuration *)args; | ||||
|  | ||||
|     switch (cmd) | ||||
|     { | ||||
|     case PWMN_CMD_ENABLE: | ||||
|         configuration->complementary = RT_TRUE; | ||||
|         break; | ||||
|     case PWMN_CMD_DISABLE: | ||||
|         configuration->complementary = RT_FALSE; | ||||
|         break; | ||||
|     default: | ||||
|         if (pwm->ops->control) | ||||
|             result = pwm->ops->control(pwm, cmd, args); | ||||
|         break; | ||||
|     } | ||||
|  | ||||
|     return result; | ||||
| } | ||||
|  | ||||
| /* | ||||
| pos: channel | ||||
| void *buffer: rt_uint32_t pulse[size] | ||||
| size : number of pulse, only set to sizeof(rt_uint32_t). | ||||
| */ | ||||
| static rt_ssize_t _pwm_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size) | ||||
| { | ||||
|     rt_err_t result = RT_EOK; | ||||
|     struct rt_device_pwm *pwm = (struct rt_device_pwm *)dev; | ||||
|     rt_uint32_t *pulse = (rt_uint32_t *)buffer; | ||||
|     struct rt_pwm_configuration configuration = {0}; | ||||
|  | ||||
|     configuration.channel = (pos > 0) ? (pos) : (-pos); | ||||
|  | ||||
|     if (pwm->ops->control) | ||||
|     { | ||||
|         result = pwm->ops->control(pwm, PWM_CMD_GET,  &configuration); | ||||
|         if (result != RT_EOK) | ||||
|         { | ||||
|             return 0; | ||||
|         } | ||||
|  | ||||
|         *pulse = configuration.pulse; | ||||
|     } | ||||
|  | ||||
|     return size; | ||||
| } | ||||
|  | ||||
| /* | ||||
| pos: channel | ||||
| void *buffer: rt_uint32_t pulse[size] | ||||
| size : number of pulse, only set to sizeof(rt_uint32_t). | ||||
| */ | ||||
| static rt_ssize_t _pwm_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size) | ||||
| { | ||||
|     rt_err_t result = RT_EOK; | ||||
|     struct rt_device_pwm *pwm = (struct rt_device_pwm *)dev; | ||||
|     rt_uint32_t *pulse = (rt_uint32_t *)buffer; | ||||
|     struct rt_pwm_configuration configuration = {0}; | ||||
|  | ||||
|     configuration.channel = (pos > 0) ? (pos) : (-pos); | ||||
|  | ||||
|     if (pwm->ops->control) | ||||
|     { | ||||
|         result = pwm->ops->control(pwm, PWM_CMD_GET, &configuration); | ||||
|         if (result != RT_EOK) | ||||
|         { | ||||
|             return 0; | ||||
|         } | ||||
|  | ||||
|         configuration.pulse = *pulse; | ||||
|  | ||||
|         result = pwm->ops->control(pwm, PWM_CMD_SET, &configuration); | ||||
|         if (result != RT_EOK) | ||||
|         { | ||||
|             return 0; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     return size; | ||||
| } | ||||
|  | ||||
| #ifdef RT_USING_DEVICE_OPS | ||||
| static const struct rt_device_ops pwm_device_ops = | ||||
| { | ||||
|     RT_NULL, | ||||
|     RT_NULL, | ||||
|     RT_NULL, | ||||
|     _pwm_read, | ||||
|     _pwm_write, | ||||
|     _pwm_control | ||||
| }; | ||||
| #endif /* RT_USING_DEVICE_OPS */ | ||||
|  | ||||
| rt_err_t rt_device_pwm_register(struct rt_device_pwm *device, const char *name, const struct rt_pwm_ops *ops, const void *user_data) | ||||
| { | ||||
|     rt_err_t result = RT_EOK; | ||||
|  | ||||
|     rt_memset(device, 0, sizeof(struct rt_device_pwm)); | ||||
|  | ||||
| #ifdef RT_USING_DEVICE_OPS | ||||
|     device->parent.ops = &pwm_device_ops; | ||||
| #else | ||||
|     device->parent.init = RT_NULL; | ||||
|     device->parent.open = RT_NULL; | ||||
|     device->parent.close = RT_NULL; | ||||
|     device->parent.read  = _pwm_read; | ||||
|     device->parent.write = _pwm_write; | ||||
|     device->parent.control = _pwm_control; | ||||
| #endif /* RT_USING_DEVICE_OPS */ | ||||
|  | ||||
|     device->parent.type         = RT_Device_Class_PWM; | ||||
|     device->ops                 = ops; | ||||
|     device->parent.user_data    = (void *)user_data; | ||||
|  | ||||
|     result = rt_device_register(&device->parent, name, RT_DEVICE_FLAG_RDWR); | ||||
|  | ||||
|     return result; | ||||
| } | ||||
|  | ||||
| rt_err_t rt_pwm_enable(struct rt_device_pwm *device, int channel) | ||||
| { | ||||
|     rt_err_t result = RT_EOK; | ||||
|     struct rt_pwm_configuration configuration = {0}; | ||||
|  | ||||
|     if (!device) | ||||
|     { | ||||
|         return -RT_EIO; | ||||
|     } | ||||
|  | ||||
|     /* Make it is positive num forever */ | ||||
|     configuration.channel = (channel > 0) ? (channel) : (-channel); | ||||
|  | ||||
|     /* If channel is a positive number (0 ~ n), it means using normal output pin. | ||||
|      * If channel is a negative number (0 ~ -n), it means using complementary output pin. */ | ||||
|     if (channel > 0) | ||||
|     { | ||||
|         result = rt_device_control(&device->parent, PWMN_CMD_DISABLE, &configuration); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         result = rt_device_control(&device->parent, PWMN_CMD_ENABLE, &configuration); | ||||
|     } | ||||
|  | ||||
|     result = rt_device_control(&device->parent, PWM_CMD_ENABLE, &configuration); | ||||
|  | ||||
|     return result; | ||||
| } | ||||
|  | ||||
| rt_err_t rt_pwm_disable(struct rt_device_pwm *device, int channel) | ||||
| { | ||||
|     rt_err_t result = RT_EOK; | ||||
|     struct rt_pwm_configuration configuration = {0}; | ||||
|  | ||||
|     if (!device) | ||||
|     { | ||||
|         return -RT_EIO; | ||||
|     } | ||||
|  | ||||
|     /* Make it is positive num forever */ | ||||
|     configuration.channel = (channel > 0) ? (channel) : (-channel); | ||||
|  | ||||
|     /* If channel is a positive number (0 ~ n), it means using normal output pin. | ||||
|      * If channel is a negative number (0 ~ -n), it means using complementary output pin. */ | ||||
|     if (channel > 0) | ||||
|     { | ||||
|         result = rt_device_control(&device->parent, PWMN_CMD_DISABLE, &configuration); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         result = rt_device_control(&device->parent, PWMN_CMD_ENABLE, &configuration); | ||||
|     } | ||||
|  | ||||
|     result = rt_device_control(&device->parent, PWM_CMD_DISABLE, &configuration); | ||||
|  | ||||
|     return result; | ||||
| } | ||||
|  | ||||
| rt_err_t rt_pwm_set(struct rt_device_pwm *device, int channel, rt_uint32_t period, rt_uint32_t pulse) | ||||
| { | ||||
|     rt_err_t result = RT_EOK; | ||||
|     struct rt_pwm_configuration configuration = {0}; | ||||
|  | ||||
|     if (!device) | ||||
|     { | ||||
|         return -RT_EIO; | ||||
|     } | ||||
|  | ||||
|     configuration.channel = (channel > 0) ? (channel) : (-channel); | ||||
|     configuration.period = period; | ||||
|     configuration.pulse = pulse; | ||||
|     result = rt_device_control(&device->parent, PWM_CMD_SET, &configuration); | ||||
|  | ||||
|     return result; | ||||
| } | ||||
|  | ||||
| rt_err_t rt_pwm_set_period(struct rt_device_pwm *device, int channel, rt_uint32_t period) | ||||
| { | ||||
|     rt_err_t result = RT_EOK; | ||||
|     struct rt_pwm_configuration configuration = {0}; | ||||
|  | ||||
|     if (!device) | ||||
|     { | ||||
|         return -RT_EIO; | ||||
|     } | ||||
|  | ||||
|     configuration.channel = (channel > 0) ? (channel) : (-channel); | ||||
|     configuration.period = period; | ||||
|     result = rt_device_control(&device->parent, PWM_CMD_SET_PERIOD, &configuration); | ||||
|  | ||||
|     return result; | ||||
| } | ||||
|  | ||||
| rt_err_t rt_pwm_set_pulse(struct rt_device_pwm *device, int channel, rt_uint32_t pulse) | ||||
| { | ||||
|     rt_err_t result = RT_EOK; | ||||
|     struct rt_pwm_configuration configuration = {0}; | ||||
|  | ||||
|     if (!device) | ||||
|     { | ||||
|         return -RT_EIO; | ||||
|     } | ||||
|  | ||||
|     configuration.channel = (channel > 0) ? (channel) : (-channel); | ||||
|     configuration.pulse = pulse; | ||||
|     result = rt_device_control(&device->parent, PWM_CMD_SET_PULSE, &configuration); | ||||
|  | ||||
|     return result; | ||||
| } | ||||
|  | ||||
| rt_err_t rt_pwm_set_dead_time(struct rt_device_pwm *device, int channel, rt_uint32_t dead_time) | ||||
| { | ||||
|     rt_err_t result = RT_EOK; | ||||
|     struct rt_pwm_configuration configuration = {0}; | ||||
|  | ||||
|     if (!device) | ||||
|     { | ||||
|         return -RT_EIO; | ||||
|     } | ||||
|  | ||||
|     configuration.channel = (channel > 0) ? (channel) : (-channel); | ||||
|     configuration.dead_time = dead_time; | ||||
|     result = rt_device_control(&device->parent, PWM_CMD_SET_DEAD_TIME, &configuration); | ||||
|  | ||||
|     return result; | ||||
| } | ||||
|  | ||||
|  | ||||
| rt_err_t rt_pwm_set_phase(struct rt_device_pwm *device, int channel, rt_uint32_t phase) | ||||
| { | ||||
|     rt_err_t result = RT_EOK; | ||||
|     struct rt_pwm_configuration configuration = {0}; | ||||
|  | ||||
|     if (!device) | ||||
|     { | ||||
|         return -RT_EIO; | ||||
|     } | ||||
|  | ||||
|     configuration.channel = (channel > 0) ? (channel) : (-channel); | ||||
|     configuration.phase = phase; | ||||
|     result = rt_device_control(&device->parent, PWM_CMD_SET_PHASE, &configuration); | ||||
|  | ||||
|     return result; | ||||
| } | ||||
|  | ||||
| static rt_err_t rt_pwm_get(struct rt_device_pwm *device, struct rt_pwm_configuration *cfg) | ||||
| { | ||||
|     rt_err_t result = RT_EOK; | ||||
|  | ||||
|     if (!device) | ||||
|     { | ||||
|         return -RT_EIO; | ||||
|     } | ||||
|  | ||||
|     result = rt_device_control(&device->parent, PWM_CMD_GET, cfg); | ||||
|  | ||||
|     return result; | ||||
| } | ||||
|  | ||||
| #ifdef RT_USING_FINSH | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| #include <finsh.h> | ||||
|  | ||||
| enum pwm_list_parameters | ||||
| { | ||||
|     PWM_LIST_PROBE = 1, | ||||
|     PWM_LIST_ENABLE, | ||||
|     PWM_LIST_DISABLE, | ||||
|     PWM_LIST_GET, | ||||
|     PWM_LIST_SET, | ||||
|     PWM_LIST_PHASE, | ||||
|     PWM_LIST_DEAD_TIME, | ||||
| }; | ||||
|  | ||||
| CMD_OPTIONS_STATEMENT(pwm_list) | ||||
|  | ||||
| static int pwm_list(int argc, char **argv) | ||||
| { | ||||
|     rt_err_t result = -RT_ERROR; | ||||
|     char *result_str; | ||||
|     static struct rt_device_pwm *pwm_device = RT_NULL; | ||||
|     struct rt_pwm_configuration cfg = {0}; | ||||
|  | ||||
|     if (argc > 1) | ||||
|     { | ||||
|         if (MSH_OPT_ID_GET(pwm_list) == PWM_LIST_PROBE) | ||||
|         { | ||||
|             if (argc == 3) | ||||
|             { | ||||
|                 pwm_device = (struct rt_device_pwm *)rt_device_find(argv[2]); | ||||
|                 result_str = (pwm_device == RT_NULL) ? "failure" : "success"; | ||||
|                 rt_kprintf("probe %s %s\n", argv[2], result_str); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 rt_kprintf("pwm probe <device name>                  - probe pwm by name\n"); | ||||
|             } | ||||
|         } | ||||
|         else if (pwm_device == RT_NULL) | ||||
|         { | ||||
|             rt_kprintf("Please using 'pwm probe <device name>' first.\n"); | ||||
|             return -RT_ERROR; | ||||
|         } | ||||
|  | ||||
|         switch (MSH_OPT_ID_GET(pwm_list)) | ||||
|         { | ||||
|         case PWM_LIST_ENABLE: | ||||
|             if (argc == 3) | ||||
|             { | ||||
|                 result = rt_pwm_enable(pwm_device, atoi(argv[2])); | ||||
|                 result_str = (result == RT_EOK) ? "success" : "failure"; | ||||
|                 rt_kprintf("%s channel %d is enabled %s \n", pwm_device->parent.parent.name, atoi(argv[2]), result_str); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 rt_kprintf("pwm enable <channel>                     - enable pwm channel\n"); | ||||
|                 rt_kprintf("    e.g. MSH >pwm enable  1              - PWM_CH1  nomal\n"); | ||||
|                 rt_kprintf("    e.g. MSH >pwm enable -1              - PWM_CH1N complememtary\n"); | ||||
|             } | ||||
|             break; | ||||
|  | ||||
|         case PWM_LIST_DISABLE: | ||||
|             if (argc == 3) | ||||
|             { | ||||
|                 result = rt_pwm_disable(pwm_device, atoi(argv[2])); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 rt_kprintf("pwm disable <channel>                    - disable pwm channel\n"); | ||||
|             } | ||||
|             break; | ||||
|  | ||||
|         case PWM_LIST_GET: | ||||
|             cfg.channel = atoi(argv[2]); | ||||
|             result = rt_pwm_get(pwm_device, &cfg); | ||||
|             if (result == RT_EOK) | ||||
|             { | ||||
|                 rt_kprintf("Info of device [%s] channel [%d]:\n", pwm_device, atoi(argv[2])); | ||||
|                 rt_kprintf("period      : %d\n", cfg.period); | ||||
|                 rt_kprintf("pulse       : %d\n", cfg.pulse); | ||||
|                 rt_kprintf("Duty cycle  : %d%%\n", (int)(((double)(cfg.pulse) / (cfg.period)) * 100)); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 rt_kprintf("Get info of device: [%s] error.\n", pwm_device); | ||||
|             } | ||||
|             break; | ||||
|  | ||||
|         case PWM_LIST_SET: | ||||
|             if (argc == 5) | ||||
|             { | ||||
|                 result = rt_pwm_set(pwm_device, atoi(argv[2]), atoi(argv[3]), atoi(argv[4])); | ||||
|                 rt_kprintf("pwm info set on %s at channel %d\n", pwm_device, (rt_base_t)atoi(argv[2])); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 rt_kprintf("Set info of device: [%s] error\n", pwm_device); | ||||
|                 rt_kprintf("Usage: pwm set <channel> <period> <pulse>\n"); | ||||
|             } | ||||
|             break; | ||||
|  | ||||
|         case PWM_LIST_PHASE: | ||||
|             if (argc == 4) | ||||
|             { | ||||
|                 result = rt_pwm_set_phase(pwm_device, atoi(argv[2]), atoi(argv[3])); | ||||
|                 result_str = (result == RT_EOK) ? "success" : "failure"; | ||||
|                 rt_kprintf("%s phase is set %d \n", pwm_device->parent.parent.name, (rt_base_t)atoi(argv[3])); | ||||
|             } | ||||
|             break; | ||||
|  | ||||
|         case PWM_LIST_DEAD_TIME: | ||||
|             if (argc == 4) | ||||
|             { | ||||
|                 result = rt_pwm_set_dead_time(pwm_device, atoi(argv[2]), atoi(argv[3])); | ||||
|                 result_str = (result == RT_EOK) ? "success" : "failure"; | ||||
|                 rt_kprintf("%s dead_time is set %d \n", pwm_device->parent.parent.name, (rt_base_t)atoi(argv[3])); | ||||
|             } | ||||
|             break; | ||||
|  | ||||
|         default: | ||||
|             goto _usage; | ||||
|         } | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         goto _usage; | ||||
|     } | ||||
|     return result; | ||||
|  | ||||
| _usage: | ||||
|     rt_kprintf("Usage: \n"); | ||||
|     rt_kprintf("pwm probe      <device name>                - probe pwm by name\n"); | ||||
|     rt_kprintf("pwm enable     <channel>                    - enable pwm channel\n"); | ||||
|     rt_kprintf("pwm disable    <channel>                    - disable pwm channel\n"); | ||||
|     rt_kprintf("pwm get        <channel>                    - get pwm channel info\n"); | ||||
|     rt_kprintf("pwm set        <channel> <period> <pulse>   - set pwm channel info\n"); | ||||
|     rt_kprintf("pwm phase      <channel> <phase>            - set pwm phase\n"); | ||||
|     rt_kprintf("pwm dead_time  <channel> <dead_time>        - set pwm dead time\n"); | ||||
|     result = -RT_ERROR; | ||||
|     return result; | ||||
| } | ||||
| CMD_OPTIONS_NODE_START(pwm_list) | ||||
| CMD_OPTIONS_NODE(PWM_LIST_PROBE, probe, probe pwm by name) | ||||
| CMD_OPTIONS_NODE(PWM_LIST_ENABLE, enable, enable pwm channel) | ||||
| CMD_OPTIONS_NODE(PWM_LIST_DISABLE, disable, disable pwm channel) | ||||
| CMD_OPTIONS_NODE(PWM_LIST_GET, get, get pwm channel info) | ||||
| CMD_OPTIONS_NODE(PWM_LIST_SET, set, set pwm channel info) | ||||
| CMD_OPTIONS_NODE(PWM_LIST_PHASE, phase, set pwm phase) | ||||
| CMD_OPTIONS_NODE(PWM_LIST_DEAD_TIME, dead_time, set pwm dead time) | ||||
| CMD_OPTIONS_NODE_END | ||||
| MSH_CMD_EXPORT_ALIAS(pwm_list, pwm, control pwm device, optenable); | ||||
|  | ||||
| #endif /* RT_USING_FINSH */ | ||||
							
								
								
									
										197
									
								
								riscv/rtthread/components/drivers/misc/rt_inputcapture.c
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										197
									
								
								riscv/rtthread/components/drivers/misc/rt_inputcapture.c
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,197 @@ | ||||
| /* | ||||
|  * Copyright (c) 2006-2023, RT-Thread Development Team | ||||
|  * | ||||
|  * SPDX-License-Identifier: Apache-2.0 | ||||
|  * | ||||
|  * Change Logs: | ||||
|  * Date           Author       Notes | ||||
|  * 2019-08-13     balanceTWK   the first version | ||||
|  */ | ||||
|  | ||||
| #include <rtdevice.h> | ||||
|  | ||||
| #define DBG_TAG "incap" | ||||
| #define DBG_LVL DBG_WARNING | ||||
| #include <rtdbg.h> | ||||
|  | ||||
| static rt_err_t rt_inputcapture_init(struct rt_device *dev) | ||||
| { | ||||
|     rt_err_t ret; | ||||
|     struct rt_inputcapture_device *inputcapture; | ||||
|  | ||||
|     RT_ASSERT(dev != RT_NULL); | ||||
|  | ||||
|     ret = RT_EOK; | ||||
|     inputcapture = (struct rt_inputcapture_device *)dev; | ||||
|     inputcapture->watermark = RT_INPUT_CAPTURE_RB_SIZE / 2; | ||||
|     if (inputcapture->ops->init) | ||||
|     { | ||||
|         ret = inputcapture->ops->init(inputcapture); | ||||
|     } | ||||
|  | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| static rt_err_t rt_inputcapture_open(struct rt_device *dev, rt_uint16_t oflag) | ||||
| { | ||||
|     rt_err_t ret; | ||||
|     struct rt_inputcapture_device *inputcapture; | ||||
|  | ||||
|     RT_ASSERT(dev != RT_NULL); | ||||
|  | ||||
|     ret = RT_EOK; | ||||
|     inputcapture = (struct rt_inputcapture_device *)dev; | ||||
|     if (inputcapture->ringbuff == RT_NULL) | ||||
|     { | ||||
|         inputcapture->ringbuff = rt_ringbuffer_create(sizeof(struct rt_inputcapture_data) * RT_INPUT_CAPTURE_RB_SIZE); | ||||
|     } | ||||
|     if (inputcapture->ops->open) | ||||
|     { | ||||
|         ret = inputcapture->ops->open(inputcapture); | ||||
|     } | ||||
|  | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| static rt_err_t rt_inputcapture_close(struct rt_device *dev) | ||||
| { | ||||
|     rt_err_t ret; | ||||
|     struct rt_inputcapture_device *inputcapture; | ||||
|  | ||||
|     RT_ASSERT(dev != RT_NULL); | ||||
|  | ||||
|     ret = -RT_ERROR; | ||||
|     inputcapture = (struct rt_inputcapture_device *)dev; | ||||
|  | ||||
|     if (inputcapture->ops->close) | ||||
|     { | ||||
|         ret = inputcapture->ops->close(inputcapture); | ||||
|     } | ||||
|  | ||||
|     if (ret != RT_EOK) | ||||
|     { | ||||
|         return ret; | ||||
|     } | ||||
|  | ||||
|     if (inputcapture->ringbuff) | ||||
|     { | ||||
|         rt_ringbuffer_destroy(inputcapture->ringbuff); | ||||
|         inputcapture->ringbuff = RT_NULL; | ||||
|     } | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| static rt_ssize_t rt_inputcapture_read(struct rt_device *dev, | ||||
|                                  rt_off_t          pos, | ||||
|                                  void             *buffer, | ||||
|                                  rt_size_t         size) | ||||
| { | ||||
|     rt_size_t receive_size; | ||||
|     struct rt_inputcapture_device *inputcapture; | ||||
|  | ||||
|     RT_ASSERT(dev != RT_NULL); | ||||
|  | ||||
|     inputcapture = (struct rt_inputcapture_device *)dev; | ||||
|     receive_size = rt_ringbuffer_get(inputcapture->ringbuff, (rt_uint8_t *)buffer, sizeof(struct rt_inputcapture_data) * size); | ||||
|  | ||||
|     return receive_size / sizeof(struct rt_inputcapture_data); | ||||
| } | ||||
|  | ||||
| static rt_err_t rt_inputcapture_control(struct rt_device *dev, int cmd, void *args) | ||||
| { | ||||
|     rt_err_t result; | ||||
|     struct rt_inputcapture_device *inputcapture; | ||||
|  | ||||
|     RT_ASSERT(dev != RT_NULL); | ||||
|  | ||||
|     result = RT_EOK; | ||||
|     inputcapture = (struct rt_inputcapture_device *)dev; | ||||
|     switch (cmd) | ||||
|     { | ||||
|     case INPUTCAPTURE_CMD_CLEAR_BUF: | ||||
|         if (inputcapture->ringbuff) | ||||
|         { | ||||
|             rt_ringbuffer_reset(inputcapture->ringbuff); | ||||
|         } | ||||
|         break; | ||||
|     case INPUTCAPTURE_CMD_SET_WATERMARK: | ||||
|         inputcapture->watermark = *(rt_size_t *)args; | ||||
|         break; | ||||
|     default: | ||||
|         result = -RT_ENOSYS; | ||||
|         break; | ||||
|     } | ||||
|  | ||||
|     return result; | ||||
| } | ||||
|  | ||||
| #ifdef RT_USING_DEVICE_OPS | ||||
| const static struct rt_device_ops inputcapture_ops = | ||||
| { | ||||
|     rt_inputcapture_init, | ||||
|     rt_inputcapture_open, | ||||
|     rt_inputcapture_close, | ||||
|     rt_inputcapture_read, | ||||
|     RT_NULL, | ||||
|     rt_inputcapture_control | ||||
| }; | ||||
| #endif | ||||
|  | ||||
| rt_err_t rt_device_inputcapture_register(struct rt_inputcapture_device *inputcapture, const char *name, void *user_data) | ||||
| { | ||||
|     struct rt_device *device; | ||||
|  | ||||
|     RT_ASSERT(inputcapture != RT_NULL); | ||||
|     RT_ASSERT(inputcapture->ops != RT_NULL); | ||||
|     RT_ASSERT(inputcapture->ops->get_pulsewidth != RT_NULL); | ||||
|  | ||||
|     device = &(inputcapture->parent); | ||||
|  | ||||
|     device->type        = RT_Device_Class_Miscellaneous; | ||||
|     device->rx_indicate = RT_NULL; | ||||
|     device->tx_complete = RT_NULL; | ||||
|     inputcapture->ringbuff = RT_NULL; | ||||
|  | ||||
| #ifdef RT_USING_DEVICE_OPS | ||||
|     device->ops         = &inputcapture_ops; | ||||
| #else | ||||
|     device->init        = rt_inputcapture_init; | ||||
|     device->open        = rt_inputcapture_open; | ||||
|     device->close       = rt_inputcapture_close; | ||||
|     device->read        = rt_inputcapture_read; | ||||
|     device->write       = RT_NULL; | ||||
|     device->control     = rt_inputcapture_control; | ||||
| #endif | ||||
|     device->user_data   = user_data; | ||||
|  | ||||
|     return rt_device_register(device, name, RT_DEVICE_FLAG_RDONLY | RT_DEVICE_FLAG_STANDALONE); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * This function is ISR for inputcapture interrupt. | ||||
|  * level: RT_TRUE denotes high level pulse, and RT_FALSE denotes low level pulse. | ||||
|  */ | ||||
| void rt_hw_inputcapture_isr(struct rt_inputcapture_device *inputcapture, rt_bool_t level) | ||||
| { | ||||
|     struct rt_inputcapture_data data; | ||||
|     rt_size_t receive_size; | ||||
|     if (inputcapture->ops->get_pulsewidth(inputcapture, &data.pulsewidth_us) != RT_EOK) | ||||
|     { | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     data.is_high = level; | ||||
|     if (rt_ringbuffer_put(inputcapture->ringbuff, (rt_uint8_t *)&data, sizeof(struct rt_inputcapture_data)) == 0) | ||||
|     { | ||||
|         LOG_W("inputcapture ringbuffer doesn't have enough space."); | ||||
|     } | ||||
|  | ||||
|     receive_size =  rt_ringbuffer_data_len(inputcapture->ringbuff) / sizeof(struct rt_inputcapture_data); | ||||
|  | ||||
|     if (receive_size >= inputcapture->watermark) | ||||
|     { | ||||
|         /* indicate to upper layer application */ | ||||
|         if (inputcapture->parent.rx_indicate != RT_NULL) | ||||
|             inputcapture->parent.rx_indicate(&inputcapture->parent, receive_size); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										74
									
								
								riscv/rtthread/components/drivers/misc/rt_null.c
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										74
									
								
								riscv/rtthread/components/drivers/misc/rt_null.c
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,74 @@ | ||||
| /* | ||||
|  * Copyright (c) 2011-2023, Shanghai Real-Thread Electronic Technology Co.,Ltd | ||||
|  * | ||||
|  * Change Logs: | ||||
|  * Date           Author       Notes | ||||
|  * 2020-12-03     quanzhao     the first version | ||||
|  */ | ||||
|  | ||||
| #include <time.h> | ||||
| #include <string.h> | ||||
| #include <rtthread.h> | ||||
|  | ||||
| static struct rt_device null_dev; | ||||
|  | ||||
| static rt_ssize_t null_read    (rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size) | ||||
| { | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| static rt_ssize_t null_write   (rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size) | ||||
| { | ||||
|     return size; | ||||
| } | ||||
|  | ||||
| static rt_err_t  null_control (rt_device_t dev, int cmd, void *args) | ||||
| { | ||||
|     return RT_EOK; | ||||
| } | ||||
|  | ||||
| #ifdef RT_USING_DEVICE_OPS | ||||
| const static struct rt_device_ops null_ops = | ||||
| { | ||||
|     RT_NULL, | ||||
|     RT_NULL, | ||||
|     RT_NULL, | ||||
|     null_read, | ||||
|     null_write, | ||||
|     null_control | ||||
| }; | ||||
| #endif | ||||
|  | ||||
| int null_device_init(void) | ||||
| { | ||||
|     static rt_bool_t init_ok = RT_FALSE; | ||||
|  | ||||
|     if (init_ok) | ||||
|     { | ||||
|         return 0; | ||||
|     } | ||||
|     RT_ASSERT(!rt_device_find("null")); | ||||
|     null_dev.type    = RT_Device_Class_Miscellaneous; | ||||
|  | ||||
| #ifdef RT_USING_DEVICE_OPS | ||||
|     null_dev.ops     = &null_ops; | ||||
| #else | ||||
|     null_dev.init    = RT_NULL; | ||||
|     null_dev.open    = RT_NULL; | ||||
|     null_dev.close   = RT_NULL; | ||||
|     null_dev.read    = null_read; | ||||
|     null_dev.write   = null_write; | ||||
|     null_dev.control = null_control; | ||||
| #endif | ||||
|  | ||||
|     /* no private */ | ||||
|     null_dev.user_data = RT_NULL; | ||||
|  | ||||
|     rt_device_register(&null_dev, "null", RT_DEVICE_FLAG_RDWR); | ||||
|  | ||||
|     init_ok = RT_TRUE; | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
| INIT_DEVICE_EXPORT(null_device_init); | ||||
|  | ||||
							
								
								
									
										159
									
								
								riscv/rtthread/components/drivers/misc/rt_random.c
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										159
									
								
								riscv/rtthread/components/drivers/misc/rt_random.c
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,159 @@ | ||||
| /* | ||||
|  * Copyright (c) 2011-2023, Shanghai Real-Thread Electronic Technology Co.,Ltd | ||||
|  * | ||||
|  * Change Logs: | ||||
|  * Date           Author       Notes | ||||
|  * 2020-12-18     quanzhao     the first version | ||||
|  */ | ||||
|  | ||||
| #include <time.h> | ||||
| #include <string.h> | ||||
| #include <rtthread.h> | ||||
|  | ||||
| static struct rt_device random_dev; | ||||
| static unsigned long seed; | ||||
|  | ||||
| static rt_uint16_t calc_random(void) | ||||
| { | ||||
|     seed = 214013L * seed + 2531011L; | ||||
|     return (seed >> 16) & 0x7FFF;   /* return bits 16~30 */ | ||||
| } | ||||
|  | ||||
| static rt_ssize_t random_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size) | ||||
| { | ||||
|     rt_uint16_t rand = calc_random(); | ||||
|     ssize_t ret = sizeof(rand); | ||||
|     rt_memcpy(buffer, &rand, ret); | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| static rt_ssize_t random_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size) | ||||
| { | ||||
|     ssize_t ret = sizeof(seed); | ||||
|     rt_memcpy(&seed, buffer, ret); | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| static rt_err_t  random_control(rt_device_t dev, int cmd, void *args) | ||||
| { | ||||
|     return RT_EOK; | ||||
| } | ||||
|  | ||||
| #ifdef RT_USING_DEVICE_OPS | ||||
| const static struct rt_device_ops random_ops = | ||||
| { | ||||
|     RT_NULL, | ||||
|     RT_NULL, | ||||
|     RT_NULL, | ||||
|     random_read, | ||||
|     random_write, | ||||
|     random_control | ||||
| }; | ||||
| #endif | ||||
|  | ||||
| int random_device_init(void) | ||||
| { | ||||
|     static rt_bool_t init_ok = RT_FALSE; | ||||
|  | ||||
|     if (init_ok) | ||||
|     { | ||||
|         return 0; | ||||
|     } | ||||
|     RT_ASSERT(!rt_device_find("random")); | ||||
|     random_dev.type    = RT_Device_Class_Miscellaneous; | ||||
|  | ||||
| #ifdef RT_USING_DEVICE_OPS | ||||
|     random_dev.ops     = &random_ops; | ||||
| #else | ||||
|     random_dev.init    = RT_NULL; | ||||
|     random_dev.open    = RT_NULL; | ||||
|     random_dev.close   = RT_NULL; | ||||
|     random_dev.read    = random_read; | ||||
|     random_dev.write   = random_write; | ||||
|     random_dev.control = random_control; | ||||
| #endif | ||||
|  | ||||
|     /* no private */ | ||||
|     random_dev.user_data = RT_NULL; | ||||
|  | ||||
|     rt_device_register(&random_dev, "random", RT_DEVICE_FLAG_RDWR); | ||||
|  | ||||
|     init_ok = RT_TRUE; | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
| INIT_DEVICE_EXPORT(random_device_init); | ||||
|  | ||||
| static struct rt_device urandom_dev; | ||||
| static unsigned long useed; | ||||
|  | ||||
| static rt_uint16_t calc_urandom(void) | ||||
| { | ||||
|     useed = 214013L * useed + 2531011L; | ||||
|     return (useed >> 16) & 0x7FFF;   /* return bits 16~30 */ | ||||
| } | ||||
|  | ||||
| static rt_ssize_t random_uread(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size) | ||||
| { | ||||
|     rt_uint16_t rand = calc_urandom(); | ||||
|     ssize_t ret = sizeof(rand); | ||||
|     rt_memcpy(buffer, &rand, ret); | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| static rt_ssize_t random_uwrite(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size) | ||||
| { | ||||
|     ssize_t ret = sizeof(useed); | ||||
|     rt_memcpy(&useed, buffer, ret); | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| static rt_err_t random_ucontrol(rt_device_t dev, int cmd, void *args) | ||||
| { | ||||
|     return RT_EOK; | ||||
| } | ||||
|  | ||||
| #ifdef RT_USING_DEVICE_OPS | ||||
| const static struct rt_device_ops urandom_ops = | ||||
| { | ||||
|     RT_NULL, | ||||
|     RT_NULL, | ||||
|     RT_NULL, | ||||
|     random_uread, | ||||
|     random_uwrite, | ||||
|     random_ucontrol | ||||
| }; | ||||
| #endif | ||||
|  | ||||
| int urandom_device_init(void) | ||||
| { | ||||
|     static rt_bool_t init_ok = RT_FALSE; | ||||
|  | ||||
|     if (init_ok) | ||||
|     { | ||||
|         return 0; | ||||
|     } | ||||
|     RT_ASSERT(!rt_device_find("urandom")); | ||||
|     urandom_dev.type    = RT_Device_Class_Miscellaneous; | ||||
|  | ||||
| #ifdef RT_USING_DEVICE_OPS | ||||
|     urandom_dev.ops     = &urandom_ops; | ||||
| #else | ||||
|     urandom_dev.init    = RT_NULL; | ||||
|     urandom_dev.open    = RT_NULL; | ||||
|     urandom_dev.close   = RT_NULL; | ||||
|     urandom_dev.read    = random_uread; | ||||
|     urandom_dev.write   = random_uwrite; | ||||
|     urandom_dev.control = random_ucontrol; | ||||
| #endif | ||||
|  | ||||
|     /* no private */ | ||||
|     urandom_dev.user_data = RT_NULL; | ||||
|  | ||||
|     rt_device_register(&urandom_dev, "urandom", RT_DEVICE_FLAG_RDWR); | ||||
|  | ||||
|     init_ok = RT_TRUE; | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
| INIT_DEVICE_EXPORT(urandom_device_init); | ||||
							
								
								
									
										75
									
								
								riscv/rtthread/components/drivers/misc/rt_zero.c
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										75
									
								
								riscv/rtthread/components/drivers/misc/rt_zero.c
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,75 @@ | ||||
| /* | ||||
|  * Copyright (c) 2011-2023, Shanghai Real-Thread Electronic Technology Co.,Ltd | ||||
|  * | ||||
|  * Change Logs: | ||||
|  * Date           Author       Notes | ||||
|  * 2020-12-03     quanzhao     the first version | ||||
|  */ | ||||
|  | ||||
| #include <time.h> | ||||
| #include <string.h> | ||||
| #include <rtthread.h> | ||||
|  | ||||
| static struct rt_device zero_dev; | ||||
|  | ||||
| static rt_ssize_t zero_read    (rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size) | ||||
| { | ||||
|     rt_memset(buffer, 0, size); | ||||
|     return size; | ||||
| } | ||||
|  | ||||
| static rt_ssize_t zero_write   (rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size) | ||||
| { | ||||
|     return size; | ||||
| } | ||||
|  | ||||
| static rt_err_t  zero_control (rt_device_t dev, int cmd, void *args) | ||||
| { | ||||
|     return RT_EOK; | ||||
| } | ||||
|  | ||||
| #ifdef RT_USING_DEVICE_OPS | ||||
| const static struct rt_device_ops zero_ops = | ||||
| { | ||||
|     RT_NULL, | ||||
|     RT_NULL, | ||||
|     RT_NULL, | ||||
|     zero_read, | ||||
|     zero_write, | ||||
|     zero_control | ||||
| }; | ||||
| #endif | ||||
|  | ||||
| int zero_device_init(void) | ||||
| { | ||||
|     static rt_bool_t init_ok = RT_FALSE; | ||||
|  | ||||
|     if (init_ok) | ||||
|     { | ||||
|         return 0; | ||||
|     } | ||||
|     RT_ASSERT(!rt_device_find("zero")); | ||||
|     zero_dev.type    = RT_Device_Class_Miscellaneous; | ||||
|  | ||||
| #ifdef RT_USING_DEVICE_OPS | ||||
|     zero_dev.ops     = &zero_ops; | ||||
| #else | ||||
|     zero_dev.init    = RT_NULL; | ||||
|     zero_dev.open    = RT_NULL; | ||||
|     zero_dev.close   = RT_NULL; | ||||
|     zero_dev.read    = zero_read; | ||||
|     zero_dev.write   = zero_write; | ||||
|     zero_dev.control = zero_control; | ||||
| #endif | ||||
|  | ||||
|     /* no private */ | ||||
|     zero_dev.user_data = RT_NULL; | ||||
|  | ||||
|     rt_device_register(&zero_dev, "zero", RT_DEVICE_FLAG_RDWR); | ||||
|  | ||||
|     init_ok = RT_TRUE; | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
| INIT_DEVICE_EXPORT(zero_device_init); | ||||
|  | ||||
		Reference in New Issue
	
	Block a user