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