1 /*
2 * Copyright (c) 2024 Alexandre Bailon
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/drivers/gpio.h>
8 #include <zephyr/logging/log.h>
9 LOG_MODULE_DECLARE(coap);
10
11 #include "coap_utils.h"
12 #include "led.h"
13
14 #ifdef CONFIG_OT_COAP_SAMPLE_SERVER
15 struct led_rsc_data {
16 const struct gpio_dt_spec gpio;
17 int state;
18 };
19
20 struct led_rsc_ctx {
21 struct led_rsc_data *led;
22 int count;
23 };
24 #endif
25
26 static const struct json_obj_descr json_led_state_descr[] = {
27 JSON_OBJ_DESCR_PRIM(struct json_led_state, led_id, JSON_TOK_NUMBER),
28 JSON_OBJ_DESCR_PRIM(struct json_led_state, state, JSON_TOK_NUMBER),
29 };
30
31 static const struct json_obj_descr json_led_get_descr[] = {
32 JSON_OBJ_DESCR_PRIM(struct json_led_get, device_id, JSON_TOK_STRING),
33 JSON_OBJ_DESCR_OBJ_ARRAY(struct json_led_get, leds, JSON_MAX_LED, count,
34 json_led_state_descr, ARRAY_SIZE(json_led_state_descr)),
35 };
36
37 K_SEM_DEFINE(led_get_sem, 0, 1);
38
39 #ifdef CONFIG_OT_COAP_SAMPLE_SERVER
led_init(otCoapResource * rsc)40 static int led_init(otCoapResource *rsc)
41 {
42 struct led_rsc_ctx *led_ctx = rsc->mContext;
43 int ret;
44
45 LOG_INF("Initializing the LED");
46 for (int i = 0; i < led_ctx->count; i++) {
47 struct led_rsc_data *led = &led_ctx->led[i];
48
49 if (!gpio_is_ready_dt(&led->gpio)) {
50 return -ENODEV;
51 }
52
53 ret = gpio_pin_configure_dt(&led->gpio, GPIO_OUTPUT);
54 if (ret) {
55 LOG_ERR("Failed to configure the GPIO");
56 return ret;
57 }
58 }
59
60 return 0;
61 }
62
led_handler_put(void * ctx,uint8_t * buf,int size)63 static int led_handler_put(void *ctx, uint8_t *buf, int size)
64 {
65 struct json_led_state led_data;
66 struct led_rsc_ctx *led_ctx = ctx;
67 struct led_rsc_data *led;
68 int ret = -EINVAL;
69
70 json_obj_parse(buf, size, json_led_state_descr, ARRAY_SIZE(json_led_state_descr),
71 &led_data);
72
73 if (led_data.led_id >= led_ctx->count) {
74 LOG_ERR("Invalid led id: %x", led_data.led_id);
75 return -EINVAL;
76 }
77 led = &led_ctx->led[led_data.led_id];
78
79 switch (led_data.state) {
80 case LED_MSG_STATE_ON:
81 ret = gpio_pin_set_dt(&led->gpio, 1);
82 led->state = 1;
83 break;
84 case LED_MSG_STATE_OFF:
85 ret = gpio_pin_set_dt(&led->gpio, 0);
86 led->state = 0;
87 break;
88 case LED_MSG_STATE_TOGGLE:
89 led->state = 1 - led->state;
90 ret = gpio_pin_set_dt(&led->gpio, led->state);
91 break;
92 default:
93 LOG_ERR("Set an unsupported LED state: %x", led_data.state);
94 }
95
96 return ret;
97 }
98
led_handler_get(void * ctx,otMessage * msg,const otMessageInfo * msg_info)99 static int led_handler_get(void *ctx, otMessage *msg, const otMessageInfo *msg_info)
100 {
101 uint8_t buf[COAP_MAX_BUF_SIZE];
102 struct led_rsc_ctx *led_ctx = ctx;
103
104 struct json_led_get led_data = {
105 .device_id = coap_device_id(),
106 };
107
108 for (int i = 0; i < led_ctx->count; i++) {
109 led_data.leds[i].led_id = i;
110 led_data.leds[i].state = led_ctx->led[i].state;
111 }
112 led_data.count = led_ctx->count;
113
114 json_obj_encode_buf(json_led_get_descr, ARRAY_SIZE(json_led_get_descr), &led_data, buf,
115 COAP_MAX_BUF_SIZE);
116
117 return coap_resp_send(msg, msg_info, buf, strlen(buf) + 1);
118 }
119
led_handler(void * ctx,otMessage * msg,const otMessageInfo * msg_info)120 static void led_handler(void *ctx, otMessage *msg, const otMessageInfo *msg_info)
121 {
122 coap_req_handler(ctx, msg, msg_info, led_handler_put, led_handler_get);
123 }
124
125 #define DEFINE_LED_CTX(node_id) \
126 { \
127 .gpio = GPIO_DT_SPEC_GET(node_id, gpios), \
128 .state = 0, \
129 },
130
131 #define DEFINE_LEDS_CTX(inst, compat, ...) DT_FOREACH_CHILD(DT_INST(inst, compat), DEFINE_LED_CTX)
132
133 static struct led_rsc_data led_rsc_data[] = {
134 DT_COMPAT_FOREACH_STATUS_OKAY_VARGS(gpio_leds, DEFINE_LEDS_CTX)};
135
136 static struct led_rsc_ctx led_rsc_ctx = {
137 .led = led_rsc_data,
138 .count = ARRAY_SIZE(led_rsc_data),
139 };
140
141 static otCoapResource led_rsc = {
142 .mUriPath = LED_URI,
143 .mHandler = led_handler,
144 .mContext = &led_rsc_ctx,
145 .mNext = NULL,
146 };
147
coap_led_reg_rsc(void)148 void coap_led_reg_rsc(void)
149 {
150 otInstance *ot = openthread_get_default_instance();
151
152 LOG_INF("Registering LED rsc");
153 led_init(&led_rsc);
154 otCoapAddResource(ot, &led_rsc);
155 }
156 #endif /* CONFIG_OT_COAP_SAMPLE_SERVER */
157
coap_led_send_req_cb(void * ctx,otMessage * msg,const otMessageInfo * msg_info,otError error)158 static void coap_led_send_req_cb(void *ctx, otMessage *msg, const otMessageInfo *msg_info,
159 otError error)
160 {
161 }
162
coap_led_set_state(const char * addr,int led_id,int state)163 int coap_led_set_state(const char *addr, int led_id, int state)
164 {
165 uint8_t buf[COAP_MAX_BUF_SIZE];
166
167 struct json_led_state led_data = {
168 .led_id = led_id,
169 .state = state,
170 };
171
172 json_obj_encode_buf(json_led_state_descr, ARRAY_SIZE(json_led_state_descr), &led_data, buf,
173 COAP_MAX_BUF_SIZE);
174
175 return coap_put_req_send(addr, LED_URI, buf, strlen(buf) + 1, coap_led_send_req_cb, NULL);
176 }
177
coap_led_get_state_cb(void * ctx,otMessage * msg,const otMessageInfo * msg_info,otError error)178 static void coap_led_get_state_cb(void *ctx, otMessage *msg, const otMessageInfo *msg_info,
179 otError error)
180 {
181 uint8_t buf[COAP_MAX_BUF_SIZE];
182 int len = COAP_MAX_BUF_SIZE;
183 struct json_led_get *led = (struct json_led_get *)ctx;
184 int ret;
185
186 ret = coap_get_data(msg, buf, &len);
187 if (ret) {
188 led->count = 0;
189 goto exit;
190 }
191
192 json_obj_parse(buf, len, json_led_get_descr, ARRAY_SIZE(json_led_get_descr), led);
193 exit:
194 k_sem_give(&led_get_sem);
195 }
196
coap_led_get_state(const char * addr,int led_id,int * state)197 int coap_led_get_state(const char *addr, int led_id, int *state)
198 {
199 struct json_led_get led;
200 int ret;
201
202 ret = coap_get_req_send(addr, LED_URI, NULL, 0, coap_led_get_state_cb, &led);
203 if (ret) {
204 return ret;
205 }
206
207 ret = k_sem_take(&led_get_sem, K_FOREVER);
208 if (ret) {
209 return ret;
210 }
211
212 if (led_id >= led.count) {
213 return -ENODEV;
214 }
215
216 *state = led.leds[led_id].state;
217 return ret;
218 }
219