/* * Copyright (c) 2018 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ #include #include #include #include "platform-zephyr.h" /** * Diagnostics mode variables. * */ static bool sDiagMode; otError otPlatDiagProcess(otInstance *aInstance, uint8_t argc, char *argv[], char *aOutput, size_t aOutputMaxLen) { ARG_UNUSED(argc); ARG_UNUSED(aInstance); /* Add more platform specific diagnostics features here. */ snprintk(aOutput, aOutputMaxLen, "diag feature '%s' is not supported\r\n", argv[0]); return OT_ERROR_NOT_IMPLEMENTED; } void otPlatDiagModeSet(bool aMode) { sDiagMode = aMode; if (!sDiagMode) { otPlatRadioSleep(NULL); } } bool otPlatDiagModeGet(void) { return sDiagMode; } void otPlatDiagChannelSet(uint8_t aChannel) { ARG_UNUSED(aChannel); } void otPlatDiagTxPowerSet(int8_t aTxPower) { ARG_UNUSED(aTxPower); } void otPlatDiagRadioReceived(otInstance *aInstance, otRadioFrame *aFrame, otError aError) { ARG_UNUSED(aInstance); ARG_UNUSED(aFrame); ARG_UNUSED(aError); } otError otPlatDiagRadioTransmitCarrier(otInstance *aInstance, bool aEnable) { if (!otPlatDiagModeGet()) { return OT_ERROR_INVALID_STATE; } return platformRadioTransmitCarrier(aInstance, aEnable); } void otPlatDiagAlarmCallback(otInstance *aInstance) { ARG_UNUSED(aInstance); } /* * To enable gpio diag commands, in Devicetree create `openthread` node in `/options/` path * with `compatible = "openthread,config"` property and `diag-gpios` property, * which should contain array of GPIO pin's configuration properties containing controller phandles, * pin numbers and pin flags. e.g: * * options { * openthread { * compatible = "openthread,config"; * diag-gpios = <&gpio0 0 GPIO_ACTIVE_HIGH>, * <&gpio1 0 GPIO_ACTIVE_LOW>; * }; * }; * * To enable reading current gpio pin mode, define * `CONFIG_GPIO_GET_DIRECTION` in prj.conf. * * Note: `` in `diag gpio` commands is an index of diag-gpios array. For example shown above, * `ot diag gpio mode 0` will return current mode of pin nmb 0 controlled by `gpio0` controller. */ #if DT_HAS_COMPAT_STATUS_OKAY(openthread_config) && \ DT_NODE_HAS_PROP(DT_COMPAT_GET_ANY_STATUS_OKAY(openthread_config), diag_gpios) static const struct gpio_dt_spec gpio_spec[] = { DT_FOREACH_PROP_ELEM_SEP(DT_COMPAT_GET_ANY_STATUS_OKAY(openthread_config), diag_gpios, GPIO_DT_SPEC_GET_BY_IDX, (,))}; static otError gpio_get_spec(uint32_t gpio_idx, const struct gpio_dt_spec **spec) { if (gpio_idx >= ARRAY_SIZE(gpio_spec)) { return OT_ERROR_INVALID_ARGS; } *spec = &gpio_spec[gpio_idx]; if (!otPlatDiagModeGet()) { return OT_ERROR_INVALID_STATE; } if (!gpio_is_ready_dt(*spec)) { return OT_ERROR_INVALID_ARGS; } const struct gpio_driver_config *const cfg = (const struct gpio_driver_config *)((*spec)->port->config); if ((cfg->port_pin_mask & (gpio_port_pins_t)BIT((*spec)->pin)) == 0U) { return OT_ERROR_INVALID_ARGS; } return OT_ERROR_NONE; } otError otPlatDiagGpioSet(uint32_t aGpio, bool aValue) { const struct gpio_dt_spec *spec; otError error; error = gpio_get_spec(aGpio, &spec); if (error != OT_ERROR_NONE) { return error; } #if defined(CONFIG_GPIO_GET_DIRECTION) if (gpio_pin_is_output_dt(spec) != 1) { return OT_ERROR_INVALID_STATE; } #endif if (gpio_pin_set_dt(spec, (int)aValue) != 0) { return OT_ERROR_FAILED; } return OT_ERROR_NONE; } otError otPlatDiagGpioGet(uint32_t aGpio, bool *aValue) { const struct gpio_dt_spec *spec; otError error; int rv; error = gpio_get_spec(aGpio, &spec); if (error != OT_ERROR_NONE) { return error; } if (aValue == NULL) { return OT_ERROR_INVALID_ARGS; } #if defined(CONFIG_GPIO_GET_DIRECTION) if (gpio_pin_is_input_dt(spec) != 1) { return OT_ERROR_INVALID_STATE; } #endif rv = gpio_pin_get_dt(spec); if (rv < 0) { return OT_ERROR_FAILED; } *aValue = (bool)rv; return OT_ERROR_NONE; } otError otPlatDiagGpioSetMode(uint32_t aGpio, otGpioMode aMode) { const struct gpio_dt_spec *spec; otError error; int rv = 0; error = gpio_get_spec(aGpio, &spec); if (error != OT_ERROR_NONE) { return error; } switch (aMode) { case OT_GPIO_MODE_INPUT: rv = gpio_pin_configure_dt(spec, GPIO_INPUT); break; case OT_GPIO_MODE_OUTPUT: rv = gpio_pin_configure_dt(spec, GPIO_OUTPUT); break; default: return OT_ERROR_INVALID_ARGS; } if (rv != 0) { return OT_ERROR_FAILED; } return OT_ERROR_NONE; } #if defined(CONFIG_GPIO_GET_DIRECTION) otError otPlatDiagGpioGetMode(uint32_t aGpio, otGpioMode *aMode) { const struct gpio_dt_spec *spec; otError error; gpio_port_pins_t pins_in, pins_out; error = gpio_get_spec(aGpio, &spec); if (error != OT_ERROR_NONE) { return error; } if (aMode == NULL) { return OT_ERROR_INVALID_ARGS; } if (gpio_port_get_direction(spec->port, BIT(spec->pin), &pins_in, &pins_out) < 0) { return OT_ERROR_FAILED; } if (((gpio_port_pins_t)BIT(spec->pin) & pins_in) != 0U) { *aMode = OT_GPIO_MODE_INPUT; } else if (((gpio_port_pins_t)BIT(spec->pin) & pins_out) != 0U) { *aMode = OT_GPIO_MODE_OUTPUT; } else { return OT_ERROR_FAILED; } return OT_ERROR_NONE; } #endif /* CONFIG_GPIO_GET_DIRECTION */ #endif /* DT_HAS_COMPAT_STATUS_OKAY(openthread_config) && \ * DT_NODE_HAS_PROP(DT_COMPAT_GET_ANY_STATUS_OKAY(openthread_config), diag_gpios) */