blob: da054c3e71c0d93e441ef824ab993972bcd7514a [file] [log] [blame]
/*
* Copyright (c) 2024 Alexandre Bailon
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/drivers/gpio.h>
#include <zephyr/logging/log.h>
LOG_MODULE_DECLARE(coap);
#include "coap_utils.h"
#include "button.h"
struct btn_rsc_data {
const struct gpio_dt_spec gpio;
};
struct btn_rsc_ctx {
struct btn_rsc_data *btn;
int count;
};
static const struct json_obj_descr json_btn_state_descr[] = {
JSON_OBJ_DESCR_PRIM(struct json_btn_state, btn_id, JSON_TOK_NUMBER),
JSON_OBJ_DESCR_PRIM(struct json_btn_state, state, JSON_TOK_NUMBER),
};
static const struct json_obj_descr json_btn_get_descr[] = {
JSON_OBJ_DESCR_PRIM(struct json_btn_get, device_id, JSON_TOK_STRING),
JSON_OBJ_DESCR_OBJ_ARRAY(struct json_btn_get, btns, JSON_MAX_BTN, count,
json_btn_state_descr, ARRAY_SIZE(json_btn_state_descr)),
};
static K_SEM_DEFINE(btn_get_sem, 0, 1);
#ifdef CONFIG_OT_COAP_SAMPLE_SERVER
static int btn_handler_get(void *ctx, otMessage *msg, const otMessageInfo *msg_info)
{
uint8_t buf[COAP_MAX_BUF_SIZE];
struct btn_rsc_ctx *btn_ctx = ctx;
struct json_btn_get btn_data = {
.device_id = coap_device_id(),
};
for (int i = 0; i < btn_ctx->count; i++) {
btn_data.btns[i].btn_id = i;
btn_data.btns[i].state = gpio_pin_get_dt(&btn_ctx->btn[i].gpio);
}
btn_data.count = btn_ctx->count;
json_obj_encode_buf(json_btn_get_descr, ARRAY_SIZE(json_btn_get_descr), &btn_data, buf,
COAP_MAX_BUF_SIZE);
return coap_resp_send(msg, msg_info, buf, strlen(buf) + 1);
}
static void btn_handler(void *ctx, otMessage *msg, const otMessageInfo *msg_info)
{
coap_req_handler(ctx, msg, msg_info, NULL, btn_handler_get);
}
#define DEFINE_BTN_CTX(node_id) \
{ \
.gpio = GPIO_DT_SPEC_GET(node_id, gpios), \
},
#define DEFINE_BTNS_CTX(inst, compat, ...) DT_FOREACH_CHILD(DT_INST(inst, compat), DEFINE_BTN_CTX)
static struct btn_rsc_data btn_rsc_data[] = {
DT_COMPAT_FOREACH_STATUS_OKAY_VARGS(gpio_keys, DEFINE_BTNS_CTX)};
static struct btn_rsc_ctx btn_rsc_ctx = {
.btn = btn_rsc_data,
.count = ARRAY_SIZE(btn_rsc_data),
};
static otCoapResource btn_rsc = {
.mUriPath = BTN_URI,
.mHandler = btn_handler,
.mContext = &btn_rsc_ctx,
.mNext = NULL,
};
static int button_init_rsc(otCoapResource *rsc)
{
int ret = 0;
struct btn_rsc_ctx *btn_ctx = rsc->mContext;
const struct gpio_dt_spec *gpio;
LOG_INF("Initializing the buttons");
for (int i = 0; i < btn_ctx->count; i++) {
gpio = &btn_ctx->btn[i].gpio;
ret = button_init(gpio);
if (ret) {
break;
}
}
return ret;
}
void coap_btn_reg_rsc(void)
{
otInstance *ot = openthread_get_default_instance();
button_init_rsc(&btn_rsc);
LOG_INF("Registering button rsc");
otCoapAddResource(ot, &btn_rsc);
}
#endif /* CONFIG_OT_COAP_SAMPLE_SERVER */
int button_init(const struct gpio_dt_spec *gpio)
{
int ret;
if (!gpio_is_ready_dt(gpio)) {
LOG_ERR("Error: button device %s is not ready\n", gpio->port->name);
return -ENODEV;
}
ret = gpio_pin_configure_dt(gpio, GPIO_INPUT);
if (ret != 0) {
LOG_ERR("Error %d: failed to configure %s pin %d\n", ret, gpio->port->name,
gpio->pin);
return ret;
}
ret = gpio_pin_interrupt_configure_dt(gpio, GPIO_INT_EDGE_TO_ACTIVE);
if (ret != 0) {
LOG_ERR("Error %d: failed to configure interrupt on %s pin %d\n", ret,
gpio->port->name, gpio->pin);
return ret;
}
return 0;
}
static void coap_btn_get_state_cb(void *ctx, otMessage *msg, const otMessageInfo *msg_info,
otError error)
{
uint8_t buf[COAP_MAX_BUF_SIZE];
int len = COAP_MAX_BUF_SIZE;
struct json_btn_get *btn = (struct json_btn_get *)ctx;
int ret;
ret = coap_get_data(msg, buf, &len);
if (ret) {
btn->count = 0;
goto exit;
}
json_obj_parse(buf, len, json_btn_get_descr, ARRAY_SIZE(json_btn_get_descr), btn);
exit:
k_sem_give(&btn_get_sem);
}
int coap_btn_get_state(const char *addr, int btn_id, int *state)
{
struct json_btn_get btn;
int ret;
ret = coap_get_req_send(addr, BTN_URI, NULL, 0, coap_btn_get_state_cb, &btn);
if (ret) {
return ret;
}
ret = k_sem_take(&btn_get_sem, K_FOREVER);
if (ret) {
return ret;
}
if (btn_id >= btn.count) {
return -ENODEV;
}
*state = btn.btns[btn_id].state;
return ret;
}