/* * Copyright (c) 2018 Prevas A/S * * SPDX-License-Identifier: Apache-2.0 */ #include #include #include #include #include #if DT_HAS_COMPAT_STATUS_OKAY(atmel_sam_afec) #define DT_DRV_COMPAT atmel_sam_afec #elif DT_HAS_COMPAT_STATUS_OKAY(atmel_sam0_adc) #define DT_DRV_COMPAT atmel_sam0_adc #elif DT_HAS_COMPAT_STATUS_OKAY(microchip_xec_adc) #define DT_DRV_COMPAT microchip_xec_adc #elif DT_HAS_COMPAT_STATUS_OKAY(nordic_nrf_adc) #define DT_DRV_COMPAT nordic_nrf_adc #elif DT_HAS_COMPAT_STATUS_OKAY(nordic_nrf_saadc) #define DT_DRV_COMPAT nordic_nrf_saadc #elif DT_HAS_COMPAT_STATUS_OKAY(nxp_kinetis_adc12) #define DT_DRV_COMPAT nxp_kinetis_adc12 #elif DT_HAS_COMPAT_STATUS_OKAY(nxp_kinetis_adc16) #define DT_DRV_COMPAT nxp_kinetis_adc16 #elif DT_HAS_COMPAT_STATUS_OKAY(st_stm32_adc) #define DT_DRV_COMPAT st_stm32_adc #else #error No known devicetree compatible match for ADC shell #endif #define LOG_LEVEL CONFIG_LOG_DEFAULT_LEVEL #include LOG_MODULE_REGISTER(adc_shell); struct adc_hdl { char *device_name; struct adc_channel_cfg channel_config; uint8_t resolution; }; #define ADC_HDL_LIST_ENTRY(inst) \ { \ .device_name = DT_INST_LABEL(inst), \ .channel_config = { \ .gain = ADC_GAIN_1, \ .reference = ADC_REF_INTERNAL, \ .acquisition_time = ADC_ACQ_TIME_DEFAULT, \ .channel_id = 0, \ }, \ .resolution = 0, \ } /* * TODO generalize with a more flexible for-each macro that doesn't * assume a semicolon separator. */ struct adc_hdl adc_list[] = { #if DT_NODE_HAS_STATUS(DT_DRV_INST(0), okay) ADC_HDL_LIST_ENTRY(0), #endif #if DT_NODE_HAS_STATUS(DT_DRV_INST(1), okay) ADC_HDL_LIST_ENTRY(1), #endif #if DT_NODE_HAS_STATUS(DT_DRV_INST(2), okay) ADC_HDL_LIST_ENTRY(2), #endif }; struct args_index { int8_t adc; int8_t parent_adc; uint8_t channel; uint8_t conf; uint8_t acq_unit; }; struct args_number { uint8_t help; uint8_t channel; uint8_t acq_time; uint8_t resolution; uint8_t read; }; static const struct args_index args_indx = { .adc = -1, .parent_adc = -2, .channel = 1, .conf = 1, .acq_unit = 2, }; static const struct args_number args_no = { .help = 1, .channel = 2, .acq_time = 3, .resolution = 2, .read = 2, }; /** get_adc_from_list returns the number entry of the adc in the adc_list, * returns -ENODEV if it doesn't exist */ static int get_adc_from_list(char *name) { int adc_idx; for (adc_idx = 0; adc_idx < ARRAY_SIZE(adc_list); adc_idx++) { if (!strcmp(name, adc_list[adc_idx].device_name)) { return adc_idx; } } return -ENODEV; } static int cmd_adc_channel(const struct shell *shell, size_t argc, char **argv) { int retval = 0; struct device *adc_dev; int chosen_adc; if (argc != args_no.channel) { shell_fprintf(shell, SHELL_NORMAL, "Usage: channel \n"); return 0; } chosen_adc = get_adc_from_list(argv[args_indx.adc]); if (chosen_adc < 0) { shell_error(shell, "Device not in device list"); return -EINVAL; } adc_dev = device_get_binding(adc_list[chosen_adc].device_name); if (adc_dev == NULL) { shell_error(shell, "ADC device not found"); return -ENODEV; } if (!isdigit((unsigned char)argv[args_indx.conf][0])) { shell_error(shell, " must be digits"); return -EINVAL; } adc_list[chosen_adc].channel_config.channel_id = (uint8_t)strtol(argv[args_indx.conf], NULL, 10); retval = adc_channel_setup(adc_dev, &adc_list[chosen_adc].channel_config); LOG_DBG("Channel setup returned %i\n", retval); return retval; } struct gain_string_to_enum { char *string; enum adc_gain gain; }; static const struct gain_string_to_enum gain_list[] = { { .string = "ADC_GAIN_1_6", .gain = ADC_GAIN_1_6 }, { .string = "ADC_GAIN_1_5", .gain = ADC_GAIN_1_5 }, { .string = "ADC_GAIN_1_4", .gain = ADC_GAIN_1_4 }, { .string = "ADC_GAIN_1_3", .gain = ADC_GAIN_1_3 }, { .string = "ADC_GAIN_1_2", .gain = ADC_GAIN_1_2 }, { .string = "ADC_GAIN_2_3", .gain = ADC_GAIN_2_3 }, { .string = "ADC_GAIN_1", .gain = ADC_GAIN_1 }, { .string = "ADC_GAIN_2", .gain = ADC_GAIN_2 }, { .string = "ADC_GAIN_3", .gain = ADC_GAIN_3 }, { .string = "ADC_GAIN_4", .gain = ADC_GAIN_4 }, { .string = "ADC_GAIN_8", .gain = ADC_GAIN_8 }, { .string = "ADC_GAIN_16", .gain = ADC_GAIN_16 }, { .string = "ADC_GAIN_32", .gain = ADC_GAIN_32 }, { .string = "ADC_GAIN_64", .gain = ADC_GAIN_64 } }; static int cmd_adc_gain(const struct shell *shell, size_t argc, char **argv) { int retval = -EINVAL; struct device *adc_dev; int chosen_adc; int i; chosen_adc = get_adc_from_list(argv[args_indx.parent_adc]); if (chosen_adc < 0) { shell_error(shell, "Device not in device list"); return -EINVAL; } adc_dev = device_get_binding(adc_list[chosen_adc].device_name); if (adc_dev == NULL) { shell_error(shell, "ADC device not found"); return -ENODEV; } for (i = 0; i < ARRAY_SIZE(gain_list); i++) { if (!strcmp(argv[0], gain_list[i].string)) { adc_list[chosen_adc].channel_config.gain = gain_list[i].gain; retval = adc_channel_setup(adc_dev, &adc_list[chosen_adc].channel_config); LOG_DBG("Channel setup returned %i\n", retval); break; } } return retval; } static int cmd_adc_acq(const struct shell *shell, size_t argc, char **argv) { int retval = 0; struct device *adc_dev; int chosen_adc; uint16_t acq_time; if (argc != args_no.acq_time) { shell_fprintf(shell, SHELL_NORMAL, "Usage: acq_time