| /*
* sai-device conf.c
*
* Copyright (C) 2019 - 2020 Andy Green <andy@warmcat.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation:
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
#if defined(WIN32) /* complaints about getenv */
#define _CRT_SECURE_NO_WARNINGS
#define read _read
#define close _close
#endif
#include <libwebsockets.h>
#include <string.h>
#include <signal.h>
#include <time.h>
#include <fcntl.h>
#include "j-private.h"
/*
* We read the JSON config using lws_struct... instrument the related structures
*/
static const lws_struct_map_t lsm_sai_jig_gpio[] = {
LSM_UNSIGNED (sai_jig_gpio_t, chip_idx, "chip_idx"),
LSM_UNSIGNED (sai_jig_gpio_t, offset, "offset"),
LSM_UNSIGNED (sai_jig_gpio_t, safe, "safe"),
LSM_STRING_PTR (sai_jig_gpio_t, name, "name"),
LSM_STRING_PTR (sai_jig_gpio_t, wire, "wire"),
};
static const lws_struct_map_t lsm_sai_jig_seq_item[] = {
LSM_STRING_PTR (sai_jig_seq_item_t, gpio_name, "gpio_name"),
LSM_UNSIGNED (sai_jig_seq_item_t, value, "value"),
};
static const lws_struct_map_t lsm_sai_jig_sequence[] = {
LSM_STRING_PTR (sai_jig_sequence_t, name, "name"),
LSM_LIST (sai_jig_sequence_t, seq_owner,
sai_jig_seq_item_t, list,
NULL, lsm_sai_jig_seq_item, "seq"),
};
static const lws_struct_map_t lsm_sai_jig_target[] = {
LSM_STRING_PTR (sai_jig_target_t, name, "name"),
LSM_LIST (sai_jig_target_t, gpio_owner, sai_jig_gpio_t, list,
NULL, lsm_sai_jig_gpio, "gpios"),
LSM_LIST (sai_jig_target_t, seq_owner, sai_jig_sequence_t, list,
NULL, lsm_sai_jig_sequence, "sequences"),
};
static const lws_struct_map_t lsm_sai_jig[] = {
LSM_STRING_PTR (sai_jig_t, iface, "iface"),
LSM_UNSIGNED (sai_jig_t, port, "port"),
LSM_LIST (sai_jig_t, target_owner, sai_jig_target_t, list,
NULL, lsm_sai_jig_target, "targets"),
};
static const lws_struct_map_t lsm_jig_schema[] = {
LSM_SCHEMA (sai_jig_t, NULL, lsm_sai_jig, "sai-jig"),
};
int
saij_config_global(const char *d)
{
unsigned char buf[128];
lws_struct_args_t a;
struct lejp_ctx ctx;
int n, m, fd;
memset(&a, 0, sizeof(a));
a.map_st[0] = lsm_jig_schema;
a.map_entries_st[0] = LWS_ARRAY_SIZE(lsm_jig_schema);
a.ac_block_size = 512;
#if defined(WIN32)
lws_snprintf((char *)buf, sizeof(buf) - 1, "%s\\conf", d);
#else
lws_snprintf((char *)buf, sizeof(buf) - 1, "%s/conf", d);
#endif
fd = lws_open((char *)buf, O_RDONLY);
if (fd < 0) {
lwsl_err("Cannot open %s\n", (char *)buf);
return 2;
}
lwsl_info("%s: %s\n", __func__, (char *)buf);
lws_struct_json_init_parse(&ctx, NULL, &a);
do {
n = (int)read(fd, buf, sizeof(buf));
if (!n)
break;
m = lejp_parse(&ctx, buf, n);
} while (m == LEJP_CONTINUE);
if (m < 0 || !a.dest) {
lwsl_notice("%s: line %d: JSON decode failed '%s'\n",
__func__, ctx.line, lejp_error_to_string(m));
goto bail1;
}
close(fd);
n = (int)ctx.line;
lejp_destruct(&ctx);
jig = a.dest;
/*
* Resolve namespace names to objects and find and fail out on any
* inconsistencies.
*
* For each target...
*/
lws_start_foreach_dll(struct lws_dll2 *, p, jig->target_owner.head) {
sai_jig_target_t *t =
lws_container_of(p, sai_jig_target_t, list);
/* ... for each gpio in the target */
lws_start_foreach_dll(struct lws_dll2 *, z,
t->gpio_owner.head) {
sai_jig_gpio_t *g = lws_container_of(z, sai_jig_gpio_t,
list);
lwsl_notice("%s: gpio '%s' -> %s (%d:%d)\n", t->name,
g->name, g->wire, g->chip_idx, g->offset);
if (!jig->chip[g->chip_idx]) {
if (g->chip_idx >=
(int)LWS_ARRAY_SIZE(jig->chip)) {
lwsl_err("%s: chip idx %d too big\n",
__func__, g->chip_idx);
goto bail1;
}
jig->chip[g->chip_idx] =
gpiod_chip_open_by_number((unsigned int)g->chip_idx);
if (!jig->chip[g->chip_idx]) {
lwsl_err("%s: unable to open chip %d\n",
__func__, g->chip_idx);
goto bail1;
}
}
g->line = gpiod_chip_get_line(jig->chip[g->chip_idx],
(unsigned int)g->offset);
if (!g->line) {
lwsl_err("%s: unable to get gpio line %d\n",
__func__, g->offset);
goto bail1;
}
n = gpiod_line_request_output(g->line, "sai-jig", 0);
if (n) {
lwsl_err("%s: unable to request line %d: %d\n",
__func__, g->offset, errno);
goto bail1;
}
gpiod_line_set_value(g->line, g->safe);
} lws_end_foreach_dll(z);
/* ... list supported target sequences as URLs... */
lws_start_foreach_dll(struct lws_dll2 *, q, t->seq_owner.head) {
sai_jig_sequence_t *s = lws_container_of(q,
sai_jig_sequence_t, list);
lwsl_notice("http://address:%u/%s/%s\n", jig->port,
t->name, s->name);
/* ... and for each sequence element in the sequence */
lws_start_foreach_dll(struct lws_dll2 *, w,
s->seq_owner.head) {
sai_jig_seq_item_t *i = lws_container_of(w,
sai_jig_seq_item_t, list);
if (i->gpio_name) {
i->gpio = lws_dll2_search_sz_pl(
&t->gpio_owner, i->gpio_name,
strlen(i->gpio_name),
sai_jig_gpio_t, list, name);
if (!i->gpio) {
lwsl_err("%s: %s unknown\n",
__func__, i->gpio_name);
}
}
} lws_end_foreach_dll(w);
} lws_end_foreach_dll(q);
} lws_end_foreach_dll(p);
return 0;
bail1:
lwsac_free(&a.ac);
return 1;
}
void
saij_config_destroy(sai_jig_t **jig)
{
lwsac_free(&(*jig)->ac_conf);
*jig = NULL;
}
|