1 /*
2  * Copyright (c) 2018 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/kernel.h>
8 #include <zephyr/drivers/gpio.h>
9 
10 #include <openthread/platform/diag.h>
11 
12 #include "platform-zephyr.h"
13 
14 /**
15  * Diagnostics mode variables.
16  *
17  */
18 static bool sDiagMode;
19 
otPlatDiagProcess(otInstance * aInstance,uint8_t argc,char * argv[],char * aOutput,size_t aOutputMaxLen)20 otError otPlatDiagProcess(otInstance *aInstance,
21 			  uint8_t argc,
22 			  char   *argv[],
23 			  char   *aOutput,
24 			  size_t  aOutputMaxLen)
25 {
26 	ARG_UNUSED(argc);
27 	ARG_UNUSED(aInstance);
28 
29 	/* Add more platform specific diagnostics features here. */
30 	snprintk(aOutput, aOutputMaxLen,
31 		 "diag feature '%s' is not supported\r\n", argv[0]);
32 
33 	return OT_ERROR_NOT_IMPLEMENTED;
34 }
35 
otPlatDiagModeSet(bool aMode)36 void otPlatDiagModeSet(bool aMode)
37 {
38 	sDiagMode = aMode;
39 
40 	if (!sDiagMode) {
41 		otPlatRadioSleep(NULL);
42 	}
43 }
44 
otPlatDiagModeGet(void)45 bool otPlatDiagModeGet(void)
46 {
47 	return sDiagMode;
48 }
49 
otPlatDiagChannelSet(uint8_t aChannel)50 void otPlatDiagChannelSet(uint8_t aChannel)
51 {
52 	ARG_UNUSED(aChannel);
53 }
54 
otPlatDiagTxPowerSet(int8_t aTxPower)55 void otPlatDiagTxPowerSet(int8_t aTxPower)
56 {
57 	ARG_UNUSED(aTxPower);
58 }
59 
otPlatDiagRadioReceived(otInstance * aInstance,otRadioFrame * aFrame,otError aError)60 void otPlatDiagRadioReceived(otInstance *aInstance,
61 			     otRadioFrame *aFrame,
62 			     otError aError)
63 {
64 	ARG_UNUSED(aInstance);
65 	ARG_UNUSED(aFrame);
66 	ARG_UNUSED(aError);
67 }
68 
otPlatDiagRadioTransmitCarrier(otInstance * aInstance,bool aEnable)69 otError otPlatDiagRadioTransmitCarrier(otInstance *aInstance, bool aEnable)
70 {
71 	if (!otPlatDiagModeGet()) {
72 		return OT_ERROR_INVALID_STATE;
73 	}
74 
75 	return platformRadioTransmitCarrier(aInstance, aEnable);
76 }
77 
otPlatDiagAlarmCallback(otInstance * aInstance)78 void otPlatDiagAlarmCallback(otInstance *aInstance)
79 {
80 	ARG_UNUSED(aInstance);
81 }
82 
83 /*
84  * To enable gpio diag commands, in Devicetree create `openthread` node in `/options/` path
85  * with `compatible = "openthread,config"` property and `diag-gpios` property,
86  * which should contain array of GPIO pin's configuration properties containing controller phandles,
87  * pin numbers and pin flags. e.g:
88  *
89  * options {
90  *	openthread {
91  *		compatible = "openthread,config";
92  *		diag-gpios = <&gpio0 0 GPIO_ACTIVE_HIGH>,
93  *			     <&gpio1 0 GPIO_ACTIVE_LOW>;
94  *	};
95  * };
96  *
97  * To enable reading current gpio pin mode, define
98  * `CONFIG_GPIO_GET_DIRECTION` in prj.conf.
99  *
100  * Note: `<gpio>` in `diag gpio` commands is an index of diag-gpios array. For example shown above,
101  * `ot diag gpio mode 0` will return current mode of pin nmb 0 controlled by `gpio0` controller.
102  */
103 #if DT_HAS_COMPAT_STATUS_OKAY(openthread_config) && \
104 	DT_NODE_HAS_PROP(DT_COMPAT_GET_ANY_STATUS_OKAY(openthread_config), diag_gpios)
105 
106 static const struct gpio_dt_spec gpio_spec[] = {
107 	DT_FOREACH_PROP_ELEM_SEP(DT_COMPAT_GET_ANY_STATUS_OKAY(openthread_config),
108 				 diag_gpios, GPIO_DT_SPEC_GET_BY_IDX, (,))};
109 
gpio_get_spec(uint32_t gpio_idx,const struct gpio_dt_spec ** spec)110 static otError gpio_get_spec(uint32_t gpio_idx, const struct gpio_dt_spec **spec)
111 {
112 	if (gpio_idx >= ARRAY_SIZE(gpio_spec)) {
113 		return OT_ERROR_INVALID_ARGS;
114 	}
115 
116 	*spec = &gpio_spec[gpio_idx];
117 
118 	if (!otPlatDiagModeGet()) {
119 		return OT_ERROR_INVALID_STATE;
120 	}
121 
122 	if (!gpio_is_ready_dt(*spec)) {
123 		return OT_ERROR_INVALID_ARGS;
124 	}
125 
126 	const struct gpio_driver_config *const cfg =
127 		(const struct gpio_driver_config *)((*spec)->port->config);
128 
129 	if ((cfg->port_pin_mask & (gpio_port_pins_t)BIT((*spec)->pin)) == 0U) {
130 		return OT_ERROR_INVALID_ARGS;
131 	}
132 
133 	return OT_ERROR_NONE;
134 }
135 
otPlatDiagGpioSet(uint32_t aGpio,bool aValue)136 otError otPlatDiagGpioSet(uint32_t aGpio, bool aValue)
137 {
138 	const struct gpio_dt_spec *spec;
139 	otError error;
140 
141 	error = gpio_get_spec(aGpio, &spec);
142 
143 	if (error != OT_ERROR_NONE) {
144 		return error;
145 	}
146 
147 #if defined(CONFIG_GPIO_GET_DIRECTION)
148 	if (gpio_pin_is_output_dt(spec) != 1) {
149 		return OT_ERROR_INVALID_STATE;
150 	}
151 #endif
152 
153 	if (gpio_pin_set_dt(spec, (int)aValue) != 0) {
154 		return OT_ERROR_FAILED;
155 	}
156 
157 	return OT_ERROR_NONE;
158 }
159 
otPlatDiagGpioGet(uint32_t aGpio,bool * aValue)160 otError otPlatDiagGpioGet(uint32_t aGpio, bool *aValue)
161 {
162 	const struct gpio_dt_spec *spec;
163 	otError error;
164 	int rv;
165 
166 	error = gpio_get_spec(aGpio, &spec);
167 
168 	if (error != OT_ERROR_NONE) {
169 		return error;
170 	}
171 
172 	if (aValue == NULL) {
173 		return OT_ERROR_INVALID_ARGS;
174 	}
175 
176 #if defined(CONFIG_GPIO_GET_DIRECTION)
177 	if (gpio_pin_is_input_dt(spec) != 1) {
178 		return OT_ERROR_INVALID_STATE;
179 	}
180 #endif
181 
182 	rv = gpio_pin_get_dt(spec);
183 	if (rv < 0) {
184 		return OT_ERROR_FAILED;
185 	}
186 	*aValue = (bool)rv;
187 
188 	return OT_ERROR_NONE;
189 }
190 
otPlatDiagGpioSetMode(uint32_t aGpio,otGpioMode aMode)191 otError otPlatDiagGpioSetMode(uint32_t aGpio, otGpioMode aMode)
192 {
193 	const struct gpio_dt_spec *spec;
194 	otError error;
195 	int rv = 0;
196 
197 	error = gpio_get_spec(aGpio, &spec);
198 
199 	if (error != OT_ERROR_NONE) {
200 		return error;
201 	}
202 
203 	switch (aMode) {
204 	case OT_GPIO_MODE_INPUT:
205 		rv = gpio_pin_configure_dt(spec, GPIO_INPUT);
206 		break;
207 
208 	case OT_GPIO_MODE_OUTPUT:
209 		rv = gpio_pin_configure_dt(spec, GPIO_OUTPUT);
210 		break;
211 
212 	default:
213 		return OT_ERROR_INVALID_ARGS;
214 	}
215 
216 	if (rv != 0) {
217 		return OT_ERROR_FAILED;
218 	}
219 
220 	return OT_ERROR_NONE;
221 }
222 
223 #if defined(CONFIG_GPIO_GET_DIRECTION)
otPlatDiagGpioGetMode(uint32_t aGpio,otGpioMode * aMode)224 otError otPlatDiagGpioGetMode(uint32_t aGpio, otGpioMode *aMode)
225 {
226 	const struct gpio_dt_spec *spec;
227 	otError error;
228 	gpio_port_pins_t pins_in, pins_out;
229 
230 	error = gpio_get_spec(aGpio, &spec);
231 
232 	if (error != OT_ERROR_NONE) {
233 		return error;
234 	}
235 	if (aMode == NULL) {
236 		return OT_ERROR_INVALID_ARGS;
237 	}
238 
239 	if (gpio_port_get_direction(spec->port, BIT(spec->pin), &pins_in, &pins_out) < 0) {
240 		return OT_ERROR_FAILED;
241 	}
242 
243 	if (((gpio_port_pins_t)BIT(spec->pin) & pins_in) != 0U) {
244 		*aMode = OT_GPIO_MODE_INPUT;
245 	} else if (((gpio_port_pins_t)BIT(spec->pin) & pins_out) != 0U) {
246 		*aMode = OT_GPIO_MODE_OUTPUT;
247 	} else {
248 		return OT_ERROR_FAILED;
249 	}
250 
251 	return OT_ERROR_NONE;
252 }
253 #endif /* CONFIG_GPIO_GET_DIRECTION */
254 #endif /* DT_HAS_COMPAT_STATUS_OKAY(openthread_config) && \
255 	* DT_NODE_HAS_PROP(DT_COMPAT_GET_ANY_STATUS_OKAY(openthread_config), diag_gpios)
256 	*/
257