Repository: incubator-mynewt-core Updated Branches: refs/heads/develop cf8600229 -> b99324aa6
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/b99324aa/mgmt/newtmgr/nmgr_os/src/newtmgr_os.c ---------------------------------------------------------------------- diff --git a/mgmt/newtmgr/nmgr_os/src/newtmgr_os.c b/mgmt/newtmgr/nmgr_os/src/newtmgr_os.c new file mode 100644 index 0000000..6c1a12f --- /dev/null +++ b/mgmt/newtmgr/nmgr_os/src/newtmgr_os.c @@ -0,0 +1,326 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include <os/os.h> +#include <os/endian.h> + +#include <assert.h> +#include <string.h> + +#include <hal/hal_system.h> + +#include <newtmgr/newtmgr.h> + +#include <console/console.h> +#include <util/datetime.h> +#include <reboot/log_reboot.h> + +#include "nmgr_os/nmgr_os.h" + +static struct os_callout_func nmgr_reset_callout; + +static int nmgr_def_echo(struct nmgr_jbuf *); +static int nmgr_def_console_echo(struct nmgr_jbuf *); +static int nmgr_def_taskstat_read(struct nmgr_jbuf *njb); +static int nmgr_def_mpstat_read(struct nmgr_jbuf *njb); +static int nmgr_datetime_get(struct nmgr_jbuf *njb); +static int nmgr_datetime_set(struct nmgr_jbuf *njb); +static int nmgr_reset(struct nmgr_jbuf *njb); + +static const struct nmgr_handler nmgr_def_group_handlers[] = { + [NMGR_ID_ECHO] = { + nmgr_def_echo, nmgr_def_echo + }, + [NMGR_ID_CONS_ECHO_CTRL] = { + nmgr_def_console_echo, nmgr_def_console_echo + }, + [NMGR_ID_TASKSTATS] = { + nmgr_def_taskstat_read, NULL + }, + [NMGR_ID_MPSTATS] = { + nmgr_def_mpstat_read, NULL + }, + [NMGR_ID_DATETIME_STR] = { + nmgr_datetime_get, nmgr_datetime_set + }, + [NMGR_ID_RESET] = { + NULL, nmgr_reset + }, +}; + +#define NMGR_DEF_GROUP_SZ \ + (sizeof(nmgr_def_group_handlers) / sizeof(nmgr_def_group_handlers[0])) + +static struct nmgr_group nmgr_def_group = { + .ng_handlers = (struct nmgr_handler *)nmgr_def_group_handlers, + .ng_handlers_count = NMGR_DEF_GROUP_SZ, + .ng_group_id = NMGR_GROUP_ID_DEFAULT +}; + +static int +nmgr_def_echo(struct nmgr_jbuf *njb) +{ + uint8_t echo_buf[128]; + struct json_attr_t attrs[] = { + { "d", t_string, .addr.string = (char *) &echo_buf[0], + .len = sizeof(echo_buf) }, + { NULL }, + }; + struct json_value jv; + int rc; + + rc = json_read_object((struct json_buffer *) njb, attrs); + if (rc != 0) { + goto err; + } + + json_encode_object_start(&njb->njb_enc); + JSON_VALUE_STRINGN(&jv, (char *) echo_buf, strlen((char *) echo_buf)); + json_encode_object_entry(&njb->njb_enc, "r", &jv); + json_encode_object_finish(&njb->njb_enc); + + return (0); +err: + return (rc); +} + +static int +nmgr_def_console_echo(struct nmgr_jbuf *njb) +{ + long long int echo_on = 1; + int rc; + struct json_attr_t attrs[3] = { + [0] = { + .attribute = "echo", + .type = t_integer, + .addr.integer = &echo_on, + .nodefault = 1 + }, + [1] = { + .attribute = NULL + } + }; + + rc = json_read_object(&njb->njb_buf, attrs); + if (rc) { + return OS_EINVAL; + } + + if (echo_on) { + console_echo(1); + } else { + console_echo(0); + } + return (0); +} + +static int +nmgr_def_taskstat_read(struct nmgr_jbuf *njb) +{ + struct os_task *prev_task; + struct os_task_info oti; + struct json_value jv; + + json_encode_object_start(&njb->njb_enc); + JSON_VALUE_INT(&jv, NMGR_ERR_EOK); + json_encode_object_entry(&njb->njb_enc, "rc", &jv); + + json_encode_object_key(&njb->njb_enc, "tasks"); + json_encode_object_start(&njb->njb_enc); + + prev_task = NULL; + while (1) { + prev_task = os_task_info_get_next(prev_task, &oti); + if (prev_task == NULL) { + break; + } + + json_encode_object_key(&njb->njb_enc, oti.oti_name); + + json_encode_object_start(&njb->njb_enc); + JSON_VALUE_UINT(&jv, oti.oti_prio); + json_encode_object_entry(&njb->njb_enc, "prio", &jv); + JSON_VALUE_UINT(&jv, oti.oti_taskid); + json_encode_object_entry(&njb->njb_enc, "tid", &jv); + JSON_VALUE_UINT(&jv, oti.oti_state); + json_encode_object_entry(&njb->njb_enc, "state", &jv); + JSON_VALUE_UINT(&jv, oti.oti_stkusage); + json_encode_object_entry(&njb->njb_enc, "stkuse", &jv); + JSON_VALUE_UINT(&jv, oti.oti_stksize); + json_encode_object_entry(&njb->njb_enc, "stksiz", &jv); + JSON_VALUE_UINT(&jv, oti.oti_cswcnt); + json_encode_object_entry(&njb->njb_enc, "cswcnt", &jv); + JSON_VALUE_UINT(&jv, oti.oti_runtime); + json_encode_object_entry(&njb->njb_enc, "runtime", &jv); + JSON_VALUE_UINT(&jv, oti.oti_last_checkin); + json_encode_object_entry(&njb->njb_enc, "last_checkin", &jv); + JSON_VALUE_UINT(&jv, oti.oti_next_checkin); + json_encode_object_entry(&njb->njb_enc, "next_checkin", &jv); + json_encode_object_finish(&njb->njb_enc); + } + json_encode_object_finish(&njb->njb_enc); + json_encode_object_finish(&njb->njb_enc); + + return (0); +} + +static int +nmgr_def_mpstat_read(struct nmgr_jbuf *njb) +{ + struct os_mempool *prev_mp; + struct os_mempool_info omi; + struct json_value jv; + + json_encode_object_start(&njb->njb_enc); + JSON_VALUE_INT(&jv, NMGR_ERR_EOK); + json_encode_object_entry(&njb->njb_enc, "rc", &jv); + + json_encode_object_key(&njb->njb_enc, "mpools"); + json_encode_object_start(&njb->njb_enc); + + prev_mp = NULL; + while (1) { + prev_mp = os_mempool_info_get_next(prev_mp, &omi); + if (prev_mp == NULL) { + break; + } + + json_encode_object_key(&njb->njb_enc, omi.omi_name); + + json_encode_object_start(&njb->njb_enc); + JSON_VALUE_UINT(&jv, omi.omi_block_size); + json_encode_object_entry(&njb->njb_enc, "blksiz", &jv); + JSON_VALUE_UINT(&jv, omi.omi_num_blocks); + json_encode_object_entry(&njb->njb_enc, "nblks", &jv); + JSON_VALUE_UINT(&jv, omi.omi_num_free); + json_encode_object_entry(&njb->njb_enc, "nfree", &jv); + json_encode_object_finish(&njb->njb_enc); + } + + json_encode_object_finish(&njb->njb_enc); + json_encode_object_finish(&njb->njb_enc); + + return (0); +} + +static int +nmgr_datetime_get(struct nmgr_jbuf *njb) +{ + struct os_timeval tv; + struct os_timezone tz; + char buf[DATETIME_BUFSIZE]; + struct json_value jv; + int rc; + + json_encode_object_start(&njb->njb_enc); + JSON_VALUE_INT(&jv, NMGR_ERR_EOK); + json_encode_object_entry(&njb->njb_enc, "rc", &jv); + + /* Display the current datetime */ + rc = os_gettimeofday(&tv, &tz); + assert(rc == 0); + rc = format_datetime(&tv, &tz, buf, DATETIME_BUFSIZE); + if (rc) { + rc = OS_EINVAL; + goto err; + } + + JSON_VALUE_STRING(&jv, buf) + json_encode_object_entry(&njb->njb_enc, "datetime", &jv); + json_encode_object_finish(&njb->njb_enc); + + return OS_OK; +err: + return (rc); +} + +static int +nmgr_datetime_set(struct nmgr_jbuf *njb) +{ + struct os_timeval tv; + struct os_timezone tz; + struct json_value jv; + char buf[DATETIME_BUFSIZE]; + int rc = OS_OK; + const struct json_attr_t datetime_write_attr[2] = { + [0] = { + .attribute = "datetime", + .type = t_string, + .addr.string = buf, + .len = sizeof(buf), + }, + [1] = { + .attribute = "rc", + .type = t_uinteger, + + } + }; + + rc = json_read_object(&njb->njb_buf, datetime_write_attr); + if (rc) { + rc = OS_EINVAL; + goto out; + } + + /* Set the current datetime */ + rc = parse_datetime(buf, &tv, &tz); + if (!rc) { + rc = os_settimeofday(&tv, &tz); + if (rc) { + rc = OS_EINVAL; + goto out; + } + } else { + rc = OS_EINVAL; + goto out; + } + +out: + json_encode_object_start(&njb->njb_enc); + JSON_VALUE_INT(&jv, rc); + json_encode_object_entry(&njb->njb_enc, "rc", &jv); + json_encode_object_finish(&njb->njb_enc); + return OS_OK; +} + +static void +nmgr_reset_tmo(void *arg) +{ + system_reset(); +} + +static int +nmgr_reset(struct nmgr_jbuf *njb) +{ + log_reboot(SOFT_REBOOT); + os_callout_reset(&nmgr_reset_callout.cf_c, OS_TICKS_PER_SEC / 4); + + nmgr_jbuf_setoerr(njb, 0); + + return OS_OK; +} + +int +nmgr_os_groups_register(struct os_eventq *nmgr_evq) +{ + os_callout_func_init(&nmgr_reset_callout, nmgr_evq, nmgr_reset_tmo, NULL); + + return nmgr_group_register(&nmgr_def_group); +} + http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/b99324aa/mgmt/newtmgr/pkg.yml ---------------------------------------------------------------------- diff --git a/mgmt/newtmgr/pkg.yml b/mgmt/newtmgr/pkg.yml new file mode 100644 index 0000000..1bde967 --- /dev/null +++ b/mgmt/newtmgr/pkg.yml @@ -0,0 +1,42 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +pkg.name: mgmt/newtmgr +pkg.description: Server-side newtmgr functionality. +pkg.author: "Apache Mynewt <d...@mynewt.incubator.apache.org>" +pkg.homepage: "http://mynewt.apache.org/" +pkg.keywords: + +pkg.deps: + - hw/hal + - kernel/os + - encoding/json + - mgmt/newtmgr/nmgr_os + - libs/util + - sys/shell + - sys/reboot + +pkg.deps.NEWTMGR_BLE_HOST: + - mgmt/newtmgr/transport/ble + +pkg.apis: + - newtmgr + +pkg.init_function: nmgr_pkg_init +pkg.init_stage: 5 http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/b99324aa/mgmt/newtmgr/src/newtmgr.c ---------------------------------------------------------------------- diff --git a/mgmt/newtmgr/src/newtmgr.c b/mgmt/newtmgr/src/newtmgr.c new file mode 100644 index 0000000..9b90296 --- /dev/null +++ b/mgmt/newtmgr/src/newtmgr.c @@ -0,0 +1,694 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include <assert.h> +#include <string.h> + +#include "syscfg/syscfg.h" +#include "sysinit/sysinit.h" +#include "os/os.h" +#include "os/endian.h" + +#include "shell/shell.h" +#include "newtmgr/newtmgr.h" +#include "nmgr_os/nmgr_os.h" + +os_stack_t newtmgr_stack[OS_STACK_ALIGN(MYNEWT_VAL(NEWTMGR_STACK_SIZE))]; + +struct nmgr_transport g_nmgr_shell_transport; + +struct os_mutex g_nmgr_group_list_lock; + +static struct os_eventq g_nmgr_evq; +static struct os_task g_nmgr_task; + +STAILQ_HEAD(, nmgr_group) g_nmgr_group_list = + STAILQ_HEAD_INITIALIZER(g_nmgr_group_list); + +/* JSON buffer for NMGR task + */ +static struct nmgr_jbuf nmgr_task_jbuf; + +int +nmgr_group_list_lock(void) +{ + int rc; + + if (!os_started()) { + return (0); + } + + rc = os_mutex_pend(&g_nmgr_group_list_lock, OS_WAIT_FOREVER); + if (rc != 0) { + goto err; + } + + return (0); +err: + return (rc); +} + +int +nmgr_group_list_unlock(void) +{ + int rc; + + if (!os_started()) { + return (0); + } + + rc = os_mutex_release(&g_nmgr_group_list_lock); + if (rc != 0) { + goto err; + } + + return (0); +err: + return (rc); +} + + +int +nmgr_group_register(struct nmgr_group *group) +{ + int rc; + + rc = nmgr_group_list_lock(); + if (rc != 0) { + goto err; + } + + STAILQ_INSERT_TAIL(&g_nmgr_group_list, group, ng_next); + + rc = nmgr_group_list_unlock(); + if (rc != 0) { + goto err; + } + + + return (0); +err: + return (rc); +} + +static struct nmgr_group * +nmgr_find_group(uint16_t group_id) +{ + struct nmgr_group *group; + int rc; + + group = NULL; + + rc = nmgr_group_list_lock(); + if (rc != 0) { + goto err; + } + + STAILQ_FOREACH(group, &g_nmgr_group_list, ng_next) { + if (group->ng_group_id == group_id) { + break; + } + } + + rc = nmgr_group_list_unlock(); + if (rc != 0) { + goto err; + } + + return (group); +err: + return (NULL); +} + +static struct nmgr_handler * +nmgr_find_handler(uint16_t group_id, uint16_t handler_id) +{ + struct nmgr_group *group; + struct nmgr_handler *handler; + + group = nmgr_find_group(group_id); + if (!group) { + goto err; + } + + if (handler_id >= group->ng_handlers_count) { + goto err; + } + + handler = &group->ng_handlers[handler_id]; + + return (handler); +err: + return (NULL); +} + +int +nmgr_rsp_extend(struct nmgr_hdr *hdr, struct os_mbuf *rsp, void *data, + uint16_t len) +{ + int rc; + + rc = os_mbuf_append(rsp, data, len); + if (rc != 0) { + goto err; + } + hdr->nh_len += len; + + return (0); +err: + return (rc); +} + +static char +nmgr_jbuf_read_next(struct json_buffer *jb) +{ + struct nmgr_jbuf *njb; + char c; + int rc; + + njb = (struct nmgr_jbuf *) jb; + + if (njb->njb_off + 1 > njb->njb_end) { + return '\0'; + } + + rc = os_mbuf_copydata(njb->njb_in_m, njb->njb_off, 1, &c); + if (rc == -1) { + c = '\0'; + } + ++njb->njb_off; + + return (c); +} + +static char +nmgr_jbuf_read_prev(struct json_buffer *jb) +{ + struct nmgr_jbuf *njb; + char c; + int rc; + + njb = (struct nmgr_jbuf *) jb; + + if (njb->njb_off == 0) { + return '\0'; + } + + --njb->njb_off; + rc = os_mbuf_copydata(njb->njb_in_m, njb->njb_off, 1, &c); + if (rc == -1) { + c = '\0'; + } + + return (c); +} + +static int +nmgr_jbuf_readn(struct json_buffer *jb, char *buf, int size) +{ + struct nmgr_jbuf *njb; + int read; + int left; + int rc; + + njb = (struct nmgr_jbuf *) jb; + + left = njb->njb_end - njb->njb_off; + read = size > left ? left : size; + + rc = os_mbuf_copydata(njb->njb_in_m, njb->njb_off, read, buf); + if (rc != 0) { + goto err; + } + + return (read); +err: + return (rc); +} + +int +nmgr_jbuf_write(void *arg, char *data, int len) +{ + struct nmgr_jbuf *njb; + int rc; + + njb = (struct nmgr_jbuf *) arg; + + rc = nmgr_rsp_extend(njb->njb_hdr, njb->njb_out_m, data, len); + if (rc != 0) { + assert(0); + goto err; + } + + return (0); +err: + return (rc); +} + +static int +nmgr_jbuf_init(struct nmgr_jbuf *njb) +{ + memset(njb, 0, sizeof(*njb)); + + njb->njb_buf.jb_read_next = nmgr_jbuf_read_next; + njb->njb_buf.jb_read_prev = nmgr_jbuf_read_prev; + njb->njb_buf.jb_readn = nmgr_jbuf_readn; + njb->njb_enc.je_write = nmgr_jbuf_write; + njb->njb_enc.je_arg = njb; + + return (0); +} + +static void +nmgr_jbuf_setibuf(struct nmgr_jbuf *njb, struct os_mbuf *m, + uint16_t off, uint16_t len) +{ + njb->njb_off = off; + njb->njb_end = off + len; + njb->njb_in_m = m; + njb->njb_enc.je_wr_commas = 0; +} + +static void +nmgr_jbuf_setobuf(struct nmgr_jbuf *njb, struct nmgr_hdr *hdr, + struct os_mbuf *m) +{ + njb->njb_out_m = m; + njb->njb_hdr = hdr; +} + +void +nmgr_jbuf_setoerr(struct nmgr_jbuf *njb, int errcode) +{ + struct json_value jv; + + json_encode_object_start(&njb->njb_enc); + JSON_VALUE_INT(&jv, errcode); + json_encode_object_entry(&njb->njb_enc, "rc", &jv); + json_encode_object_finish(&njb->njb_enc); +} + +static struct nmgr_hdr* +nmgr_init_rsp(struct os_mbuf *m, struct nmgr_hdr *src) +{ + struct nmgr_hdr *hdr; + + hdr = (struct nmgr_hdr *) os_mbuf_extend(m, sizeof(struct nmgr_hdr)); + if (!hdr) { + return NULL; + } + memcpy(hdr, src, sizeof(*hdr)); + hdr->nh_len = 0; + hdr->nh_flags = 0; + hdr->nh_op = (src->nh_op == NMGR_OP_READ) ? NMGR_OP_READ_RSP : + NMGR_OP_WRITE_RSP; + hdr->nh_group = src->nh_group; + hdr->nh_seq = src->nh_seq; + hdr->nh_id = src->nh_id; + + nmgr_jbuf_setobuf(&nmgr_task_jbuf, hdr, m); + + return hdr; +} + +static void +nmgr_send_err_rsp(struct nmgr_transport *nt, struct os_mbuf *m, + struct nmgr_hdr *hdr, int rc) +{ + hdr = nmgr_init_rsp(m, hdr); + if (!hdr) { + return; + } + nmgr_jbuf_setoerr(&nmgr_task_jbuf, rc); + hdr->nh_len = htons(hdr->nh_len); + hdr->nh_flags = NMGR_F_JSON_RSP_COMPLETE; + nt->nt_output(nt, nmgr_task_jbuf.njb_out_m); +} + +static int +nmgr_send_rspfrag(struct nmgr_transport *nt, struct nmgr_hdr *rsp_hdr, + struct os_mbuf *rsp, struct os_mbuf *req, uint16_t len, + uint16_t *offset) { + + struct os_mbuf *rspfrag; + int rc; + + rspfrag = NULL; + + rspfrag = os_msys_get_pkthdr(len, OS_MBUF_USRHDR_LEN(req)); + if (!rspfrag) { + rc = NMGR_ERR_ENOMEM; + goto err; + } + + /* Copy the request packet header into the response. */ + memcpy(OS_MBUF_USRHDR(rspfrag), OS_MBUF_USRHDR(req), OS_MBUF_USRHDR_LEN(req)); + + if (os_mbuf_append(rspfrag, rsp_hdr, sizeof(struct nmgr_hdr))) { + rc = NMGR_ERR_ENOMEM; + goto err; + } + + if (os_mbuf_appendfrom(rspfrag, rsp, *offset, len)) { + rc = NMGR_ERR_ENOMEM; + goto err; + } + + *offset += len; + + len = htons(len); + + if (os_mbuf_copyinto(rspfrag, offsetof(struct nmgr_hdr, nh_len), &len, sizeof(len))) { + rc = NMGR_ERR_ENOMEM; + goto err; + } + + nt->nt_output(nt, rspfrag); + + return NMGR_ERR_EOK; +err: + if (rspfrag) { + os_mbuf_free_chain(rspfrag); + } + return rc; +} + +static int +nmgr_rsp_fragment(struct nmgr_transport *nt, struct nmgr_hdr *rsp_hdr, + struct os_mbuf *rsp, struct os_mbuf *req) { + + uint16_t offset; + uint16_t len; + uint16_t mtu; + int rc; + + offset = sizeof(struct nmgr_hdr); + len = rsp_hdr->nh_len; + + mtu = nt->nt_get_mtu(req) - sizeof(struct nmgr_hdr); + + do { + if (len <= mtu) { + rsp_hdr->nh_flags |= NMGR_F_JSON_RSP_COMPLETE; + } else { + len = mtu; + } + + rc = nmgr_send_rspfrag(nt, rsp_hdr, rsp, req, len, &offset); + if (rc) { + goto err; + } + + len = rsp_hdr->nh_len - offset + sizeof(struct nmgr_hdr); + + } while (!((rsp_hdr->nh_flags & NMGR_F_JSON_RSP_COMPLETE) == + NMGR_F_JSON_RSP_COMPLETE)); + + return NMGR_ERR_EOK; +err: + return rc; +} + +static void +nmgr_handle_req(struct nmgr_transport *nt, struct os_mbuf *req) +{ + struct os_mbuf *rsp; + struct nmgr_handler *handler; + struct nmgr_hdr *rsp_hdr; + struct nmgr_hdr hdr; + int off; + uint16_t len; + int rc; + + rsp_hdr = NULL; + + rsp = os_msys_get_pkthdr(512, OS_MBUF_USRHDR_LEN(req)); + if (!rsp) { + rc = os_mbuf_copydata(req, 0, sizeof(hdr), &hdr); + if (rc < 0) { + goto err_norsp; + } + rsp = req; + req = NULL; + goto err; + } + + /* Copy the request packet header into the response. */ + memcpy(OS_MBUF_USRHDR(rsp), OS_MBUF_USRHDR(req), OS_MBUF_USRHDR_LEN(req)); + + off = 0; + len = OS_MBUF_PKTHDR(req)->omp_len; + + while (off < len) { + rc = os_mbuf_copydata(req, off, sizeof(hdr), &hdr); + if (rc < 0) { + rc = NMGR_ERR_EINVAL; + goto err_norsp; + } + + hdr.nh_len = ntohs(hdr.nh_len); + + handler = nmgr_find_handler(ntohs(hdr.nh_group), hdr.nh_id); + if (!handler) { + rc = NMGR_ERR_ENOENT; + goto err; + } + + /* Build response header apriori. Then pass to the handlers + * to fill out the response data, and adjust length & flags. + */ + rsp_hdr = nmgr_init_rsp(rsp, &hdr); + if (!rsp_hdr) { + rc = NMGR_ERR_ENOMEM; + goto err_norsp; + } + + /* + * Setup state for JSON encoding. + */ + nmgr_jbuf_setibuf(&nmgr_task_jbuf, req, off + sizeof(hdr), hdr.nh_len); + + if (hdr.nh_op == NMGR_OP_READ) { + if (handler->nh_read) { + rc = handler->nh_read(&nmgr_task_jbuf); + } else { + rc = NMGR_ERR_ENOENT; + } + } else if (hdr.nh_op == NMGR_OP_WRITE) { + if (handler->nh_write) { + rc = handler->nh_write(&nmgr_task_jbuf); + } else { + rc = NMGR_ERR_ENOENT; + } + } else { + rc = NMGR_ERR_EINVAL; + } + + if (rc != 0) { + goto err; + } + + off += sizeof(hdr) + OS_ALIGN(hdr.nh_len, 4); + rc = nmgr_rsp_fragment(nt, rsp_hdr, rsp, req); + if (rc) { + goto err; + } + } + + os_mbuf_free_chain(rsp); + os_mbuf_free_chain(req); + return; +err: + OS_MBUF_PKTHDR(rsp)->omp_len = rsp->om_len = 0; + nmgr_send_err_rsp(nt, rsp, &hdr, rc); + os_mbuf_free_chain(req); + return; +err_norsp: + os_mbuf_free_chain(rsp); + os_mbuf_free_chain(req); + return; +} + + +void +nmgr_process(struct nmgr_transport *nt) +{ + struct os_mbuf *m; + + while (1) { + m = os_mqueue_get(&nt->nt_imq); + if (!m) { + break; + } + + nmgr_handle_req(nt, m); + } +} + +void +nmgr_task(void *arg) +{ + struct nmgr_transport *nt; + struct os_event *ev; + struct os_callout_func *ocf; + + nmgr_jbuf_init(&nmgr_task_jbuf); + + while (1) { + ev = os_eventq_get(&g_nmgr_evq); + switch (ev->ev_type) { + case OS_EVENT_T_MQUEUE_DATA: + nt = (struct nmgr_transport *) ev->ev_arg; + nmgr_process(nt); + break; + case OS_EVENT_T_TIMER: + ocf = (struct os_callout_func *)ev; + ocf->cf_func(CF_ARG(ocf)); + break; + } + } +} + +int +nmgr_transport_init(struct nmgr_transport *nt, + nmgr_transport_out_func_t output_func, + nmgr_transport_get_mtu_func_t get_mtu_func) +{ + int rc; + + nt->nt_output = output_func; + nt->nt_get_mtu = get_mtu_func; + + rc = os_mqueue_init(&nt->nt_imq, nt); + if (rc != 0) { + goto err; + } + + return (0); +err: + return (rc); +} + +/** + * Transfers an incoming request to the newtmgr task. The caller relinquishes + * ownership of the supplied mbuf upon calling this function, whether this + * function succeeds or fails. + * + * @param nt The transport that the request was received + * over. + * @param req An mbuf containing the newtmgr request. + * + * @return 0 on success; nonzero on failure. + */ +int +nmgr_rx_req(struct nmgr_transport *nt, struct os_mbuf *req) +{ + int rc; + + rc = os_mqueue_put(&nt->nt_imq, &g_nmgr_evq, req); + if (rc != 0) { + os_mbuf_free_chain(req); + } + + return rc; +} + +static uint16_t +nmgr_shell_get_mtu(struct os_mbuf *m) { + return NMGR_MAX_MTU; +} + +static int +nmgr_shell_out(struct nmgr_transport *nt, struct os_mbuf *m) +{ + int rc; + + rc = shell_nlip_output(m); + if (rc != 0) { + goto err; + } + + return (0); +err: + return (rc); +} + +static int +nmgr_shell_in(struct os_mbuf *m, void *arg) +{ + struct nmgr_transport *nt; + int rc; + + nt = (struct nmgr_transport *) arg; + + rc = os_mqueue_put(&nt->nt_imq, &g_nmgr_evq, m); + if (rc != 0) { + goto err; + } + + return (0); +err: + return (rc); +} + + +int +nmgr_task_init(void) +{ + int rc; + + os_eventq_init(&g_nmgr_evq); + + rc = nmgr_transport_init(&g_nmgr_shell_transport, nmgr_shell_out, + nmgr_shell_get_mtu); + if (rc != 0) { + goto err; + } + + rc = shell_nlip_input_register(nmgr_shell_in, + (void *) &g_nmgr_shell_transport); + if (rc != 0) { + goto err; + } + + rc = os_task_init(&g_nmgr_task, "newtmgr", nmgr_task, NULL, + MYNEWT_VAL(NEWTMGR_TASK_PRIO), OS_WAIT_FOREVER, + newtmgr_stack, OS_STACK_ALIGN(MYNEWT_VAL(NEWTMGR_STACK_SIZE))); + if (rc != 0) { + goto err; + } + + rc = nmgr_os_groups_register(&g_nmgr_evq); + if (rc != 0) { + goto err; + } + + return (0); +err: + return (rc); +} + +void +nmgr_pkg_init(void) +{ + int rc; + + rc = nmgr_task_init(); + SYSINIT_PANIC_ASSERT(rc == 0); +} http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/b99324aa/mgmt/newtmgr/syscfg.yml ---------------------------------------------------------------------- diff --git a/mgmt/newtmgr/syscfg.yml b/mgmt/newtmgr/syscfg.yml new file mode 100644 index 0000000..07a7f1a --- /dev/null +++ b/mgmt/newtmgr/syscfg.yml @@ -0,0 +1,13 @@ +# Package: mgmt/newtmgr + +syscfg.defs: + NEWTMGR_TASK_PRIO: + description: 'TBD' + type: 'task_priority' + value: 'any' + NEWTMGR_STACK_SIZE: + description: 'TBD' + value: 512 + NEWTMGR_BLE_HOST: + description: 'TBD' + value: 0 http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/b99324aa/mgmt/newtmgr/transport/ble/include/nmgrble/newtmgr_ble.h ---------------------------------------------------------------------- diff --git a/mgmt/newtmgr/transport/ble/include/nmgrble/newtmgr_ble.h b/mgmt/newtmgr/transport/ble/include/nmgrble/newtmgr_ble.h new file mode 100644 index 0000000..252cb5f --- /dev/null +++ b/mgmt/newtmgr/transport/ble/include/nmgrble/newtmgr_ble.h @@ -0,0 +1,42 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _NEWTMGR_BLE_H_ +#define _NEWTMGR_BLE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +struct nmgr_hdr; + +int +nmgr_ble_proc_mq_evt(struct os_event *ev); + +int +nmgr_ble_gatt_svr_init(void); + +void +nmgr_ble_update_rsp_len(struct os_mbuf *req, uint16_t *len, uint8_t *flags); + +#ifdef __cplusplus +} +#endif + +#endif /* _NETMGR_H */ http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/b99324aa/mgmt/newtmgr/transport/ble/pkg.yml ---------------------------------------------------------------------- diff --git a/mgmt/newtmgr/transport/ble/pkg.yml b/mgmt/newtmgr/transport/ble/pkg.yml new file mode 100644 index 0000000..45c71e1 --- /dev/null +++ b/mgmt/newtmgr/transport/ble/pkg.yml @@ -0,0 +1,33 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +pkg.name: mgmt/newtmgr/transport/ble +pkg.description: BLE transport newtmgr functionality. +pkg.author: "Apache Mynewt <d...@mynewt.incubator.apache.org>" +pkg.homepage: "http://mynewt.apache.org/" +pkg.keywords: + - ble + - bluetooth + +pkg.deps: + - kernel/os + - net/nimble/host + +pkg.init_function: newtmgr_ble_pkg_init +pkg.init_stage: 5 http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/b99324aa/mgmt/newtmgr/transport/ble/src/newtmgr_ble.c ---------------------------------------------------------------------- diff --git a/mgmt/newtmgr/transport/ble/src/newtmgr_ble.c b/mgmt/newtmgr/transport/ble/src/newtmgr_ble.c new file mode 100644 index 0000000..817673d --- /dev/null +++ b/mgmt/newtmgr/transport/ble/src/newtmgr_ble.c @@ -0,0 +1,261 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include <assert.h> +#include <stdio.h> +#include <string.h> +#include "sysinit/sysinit.h" +#include "host/ble_hs.h" +#include "newtmgr/newtmgr.h" +#include "os/endian.h" +#include "console/console.h" + +/* nmgr ble mqueue */ +struct os_mqueue ble_nmgr_mq; + +/* ble nmgr transport */ +struct nmgr_transport ble_nt; + +/* ble nmgr attr handle */ +uint16_t g_ble_nmgr_attr_handle; + +/** + * The vendor specific "newtmgr" service consists of one write no-rsp + * characteristic for newtmgr requests: a single-byte characteristic that can + * only accepts write-without-response commands. The contents of each write + * command contains an NMP request. NMP responses are sent back in the form of + * unsolicited notifications from the same characteristic. + */ + +/* {8D53DC1D-1DB7-4CD3-868B-8A527460AA84} */ +const uint8_t gatt_svr_svc_newtmgr[16] = { + 0x84, 0xaa, 0x60, 0x74, 0x52, 0x8a, 0x8b, 0x86, + 0xd3, 0x4c, 0xb7, 0x1d, 0x1d, 0xdc, 0x53, 0x8d +}; + +/* {DA2E7828-FBCE-4E01-AE9E-261174997C48} */ +const uint8_t gatt_svr_chr_newtmgr[16] = { + 0x48, 0x7c, 0x99, 0x74, 0x11, 0x26, 0x9e, 0xae, + 0x01, 0x4e, 0xce, 0xfb, 0x28, 0x78, 0x2e, 0xda +}; + +static int +gatt_svr_chr_access_newtmgr(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, void *arg); + +static const struct ble_gatt_svc_def gatt_svr_svcs[] = { + { + /* Service: newtmgr */ + .type = BLE_GATT_SVC_TYPE_PRIMARY, + .uuid128 = (void *)gatt_svr_svc_newtmgr, + .characteristics = (struct ble_gatt_chr_def[]) { { + /* Characteristic: Write No Rsp */ + .uuid128 = (void *)gatt_svr_chr_newtmgr, + .access_cb = gatt_svr_chr_access_newtmgr, + .flags = BLE_GATT_CHR_F_WRITE_NO_RSP, + .val_handle = &g_ble_nmgr_attr_handle, + }, { + 0, /* No more characteristics in this service */ + } }, + }, + + { + 0, /* No more services */ + }, +}; + +static int +gatt_svr_chr_access_newtmgr(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, void *arg) +{ + int rc; + struct os_mbuf *m_req; + + switch (ctxt->op) { + case BLE_GATT_ACCESS_OP_WRITE_CHR: + /* Try to reuse the BLE packet mbuf as the newtmgr request. This + * requires a two-byte usrhdr to hold the BLE connection handle so + * that the newtmgr response can be sent to the correct peer. If + * it is not possible to reuse the mbuf, then allocate a new one + * and copy the request contents. + */ + if (OS_MBUF_USRHDR_LEN(ctxt->om) >= sizeof (conn_handle)) { + /* Sufficient usrhdr space already present. */ + m_req = ctxt->om; + ctxt->om = NULL; + } else if (OS_MBUF_LEADINGSPACE(ctxt->om) >= + sizeof (conn_handle)) { + + /* Usrhdr isn't present, but there is enough leading space to + * add one. + */ + m_req = ctxt->om; + ctxt->om = NULL; + + m_req->om_pkthdr_len += sizeof (conn_handle); + } else { + /* The mbuf can't be reused. Allocate a new one and perform a + * copy. Don't set ctxt->om to NULL; let the NimBLE host free + * it. + */ + m_req = os_msys_get_pkthdr(OS_MBUF_PKTLEN(ctxt->om), + sizeof (conn_handle)); + if (!m_req) { + return BLE_ATT_ERR_INSUFFICIENT_RES; + } + rc = os_mbuf_appendfrom(m_req, ctxt->om, 0, + OS_MBUF_PKTLEN(ctxt->om)); + if (rc) { + return BLE_ATT_ERR_INSUFFICIENT_RES; + } + } + + /* Write the connection handle to the newtmgr request usrhdr. This + * is necessary so that we later know who to send the newtmgr + * response to. + */ + memcpy(OS_MBUF_USRHDR(m_req), &conn_handle, sizeof(conn_handle)); + + rc = nmgr_rx_req(&ble_nt, m_req); + if (rc != 0) { + return BLE_ATT_ERR_UNLIKELY; + } + return 0; + + default: + assert(0); + return BLE_ATT_ERR_UNLIKELY; + } +} + +uint16_t +nmgr_ble_get_mtu(struct os_mbuf *req) { + + uint16_t conn_handle; + uint16_t mtu; + + memcpy(&conn_handle, OS_MBUF_USRHDR(req), sizeof (conn_handle)); + mtu = ble_att_mtu(conn_handle); + if (!mtu) { + assert(0); + } + + /* 3 is the number of bytes for ATT notification base */ + mtu = mtu - 3; + + return (mtu); +} + +/** + * Nmgr ble process mqueue event + * Gets an event from the nmgr mqueue and does a notify with the response + * + * @param eventq + * @return 0 on success; non-zero on failure + */ + +int +nmgr_ble_proc_mq_evt(struct os_event *ev) +{ + struct os_mbuf *m_resp; + uint16_t conn_handle; + int rc; + + rc = 0; + switch (ev->ev_type) { + case OS_EVENT_T_MQUEUE_DATA: + if (ev->ev_arg != &ble_nmgr_mq) { + rc = -1; + goto done; + } + + while (1) { + m_resp = os_mqueue_get(&ble_nmgr_mq); + if (!m_resp) { + break; + } + assert(OS_MBUF_USRHDR_LEN(m_resp) >= sizeof (conn_handle)); + memcpy(&conn_handle, OS_MBUF_USRHDR(m_resp), + sizeof (conn_handle)); + ble_gattc_notify_custom(conn_handle, g_ble_nmgr_attr_handle, + m_resp); + } + break; + + default: + rc = -1; + goto done; + } + +done: + return rc; +} + +static int +nmgr_ble_out(struct nmgr_transport *nt, struct os_mbuf *m) +{ + int rc; + + rc = os_mqueue_put(&ble_nmgr_mq, ble_hs_cfg.parent_evq, m); + if (rc != 0) { + goto err; + } + + return (0); +err: + return (rc); +} + +/** + * Nmgr ble GATT server initialization + * + * @param eventq + * @return 0 on success; non-zero on failure + */ +int +nmgr_ble_gatt_svr_init(void) +{ + int rc; + + rc = ble_gatts_count_cfg(gatt_svr_svcs); + if (rc != 0) { + goto err; + } + + rc = ble_gatts_add_svcs(gatt_svr_svcs); + if (rc != 0) { + return rc; + } + + os_mqueue_init(&ble_nmgr_mq, &ble_nmgr_mq); + + rc = nmgr_transport_init(&ble_nt, nmgr_ble_out, nmgr_ble_get_mtu); + +err: + return rc; +} + +void +newtmgr_ble_pkg_init(void) +{ + int rc; + + rc = nmgr_ble_gatt_svr_init(); + SYSINIT_PANIC_ASSERT(rc == 0); +} http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/b99324aa/mgmt/oicmgr/include/newtmgr/newtmgr.h ---------------------------------------------------------------------- diff --git a/mgmt/oicmgr/include/newtmgr/newtmgr.h b/mgmt/oicmgr/include/newtmgr/newtmgr.h new file mode 100644 index 0000000..32d16e5 --- /dev/null +++ b/mgmt/oicmgr/include/newtmgr/newtmgr.h @@ -0,0 +1,120 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _NEWTMGR_H_ +#define _NEWTMGR_H_ + +#include <json/json.h> +#include <inttypes.h> +#include <os/os.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* MTU for newtmgr responses */ +#define NMGR_MAX_MTU 1024 + +#ifndef STR +/* Stringification of constants */ +#define STR(x) #x +#endif + +/* First 64 groups are reserved for system level newtmgr commands. + * Per-user commands are then defined after group 64. + */ +#define NMGR_GROUP_ID_DEFAULT (0) +#define NMGR_GROUP_ID_IMAGE (1) +#define NMGR_GROUP_ID_STATS (2) +#define NMGR_GROUP_ID_CONFIG (3) +#define NMGR_GROUP_ID_LOGS (4) +#define NMGR_GROUP_ID_CRASH (5) +#define NMGR_GROUP_ID_SPLIT (6) +#define NMGR_GROUP_ID_PERUSER (64) + +#define NMGR_OP_READ (0) +#define NMGR_OP_READ_RSP (1) +#define NMGR_OP_WRITE (2) +#define NMGR_OP_WRITE_RSP (3) + + +/** + * Newtmgr JSON error codes + */ +#define NMGR_ERR_EOK (0) +#define NMGR_ERR_EUNKNOWN (1) +#define NMGR_ERR_ENOMEM (2) +#define NMGR_ERR_EINVAL (3) +#define NMGR_ERR_ETIMEOUT (4) +#define NMGR_ERR_ENOENT (5) +#define NMGR_ERR_EPERUSER (256) + +struct nmgr_hdr { + uint8_t nh_op; /* NMGR_OP_XXX */ + uint8_t nh_flags; + uint16_t nh_len; /* length of the payload */ + uint16_t nh_group; /* NMGR_GROUP_XXX */ + uint8_t nh_seq; /* sequence number */ + uint8_t nh_id; /* message ID within group */ +}; + +struct nmgr_jbuf { + /* json_buffer must be first element in the structure */ + struct json_buffer njb_buf; + struct json_encoder njb_enc; + char *njb_in; + uint16_t njb_in_off; + uint16_t njb_in_end; + char *njb_out; + uint16_t njb_out_off; + uint16_t njb_out_end; +}; +int nmgr_jbuf_setoerr(struct nmgr_jbuf *njb, int errcode); + +typedef int (*nmgr_handler_func_t)(struct nmgr_jbuf *); + +#define NMGR_HANDLER_FUNC(__name) \ + int __name(struct nmgr_hdr *nmr, struct os_mbuf *req, uint16_t srcoff, \ + struct os_mbuf *rsp) + +struct nmgr_handler { + nmgr_handler_func_t nh_read; + nmgr_handler_func_t nh_write; +}; + +struct nmgr_group { + struct nmgr_handler *ng_handlers; + uint16_t ng_handlers_count; + uint16_t ng_group_id; + STAILQ_ENTRY(nmgr_group) ng_next; +}; + +#define NMGR_GROUP_SET_HANDLERS(__group, __handlers) \ + (__group)->ng_handlers = (__handlers); \ + (__group)->ng_handlers_count = (sizeof((__handlers)) / \ + sizeof(struct nmgr_handler)); + +int nmgr_oic_init(uint8_t, os_stack_t *, uint16_t); +int nmgr_group_register(struct nmgr_group *group); + +#ifdef __cplusplus +} +#endif + +#endif /* _NETMGR_H */ http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/b99324aa/mgmt/oicmgr/pkg.yml ---------------------------------------------------------------------- diff --git a/mgmt/oicmgr/pkg.yml b/mgmt/oicmgr/pkg.yml new file mode 100644 index 0000000..5458034 --- /dev/null +++ b/mgmt/oicmgr/pkg.yml @@ -0,0 +1,40 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +pkg.name: mgmt/oicmgr +pkg.description: Server-side newtmgr functionality for OIC +pkg.author: "Apache Mynewt <d...@mynewt.incubator.apache.org>" +pkg.homepage: "http://mynewt.apache.org/" +pkg.keywords: + +pkg.deps: + - kernel/os + - net/oic + - encoding/json + - mgmt/newtmgr/nmgr_os + - libs/util + - test/testutil + - sys/shell + - sys/reboot + +pkg.cflags: + - -DOC_SERVER + +pkg.apis: + - newtmgr http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/b99324aa/mgmt/oicmgr/src/newtmgr.c ---------------------------------------------------------------------- diff --git a/mgmt/oicmgr/src/newtmgr.c b/mgmt/oicmgr/src/newtmgr.c new file mode 100644 index 0000000..136545f --- /dev/null +++ b/mgmt/oicmgr/src/newtmgr.c @@ -0,0 +1,500 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include <os/os.h> +#include <os/endian.h> + +#include <assert.h> +#include <string.h> + +#include <newtmgr/newtmgr.h> +#include <nmgr_os/nmgr_os.h> + +#include <oic/oc_api.h> + +#define NMGR_OC_EVENT (OS_EVENT_T_PERUSER) +#define NMGR_OC_TIMER (OS_EVENT_T_PERUSER + 1) + +struct nmgr_state { + struct os_mutex ns_group_lock; + STAILQ_HEAD(, nmgr_group) ns_groups; + struct os_eventq ns_evq; + struct os_event ns_oc_event; + struct os_callout ns_oc_timer; + struct os_task ns_task; + struct nmgr_jbuf ns_jbuf; /* JSON buffer for NMGR task */ + char ns_rsp[NMGR_MAX_MTU]; +}; + +static struct nmgr_state nmgr_state = { + .ns_groups = STAILQ_HEAD_INITIALIZER(nmgr_state.ns_groups), + .ns_oc_event.ev_type = NMGR_OC_EVENT, + .ns_oc_timer.c_ev.ev_type = NMGR_OC_TIMER, + .ns_oc_timer.c_evq = &nmgr_state.ns_evq +}; + +static void nmgr_oic_get(oc_request_t *request, oc_interface_mask_t interface); +static void nmgr_oic_put(oc_request_t *request, oc_interface_mask_t interface); + +int +nmgr_group_list_lock(void) +{ + int rc; + + if (!os_started()) { + return (0); + } + + rc = os_mutex_pend(&nmgr_state.ns_group_lock, OS_WAIT_FOREVER); + if (rc != 0) { + goto err; + } + + return (0); +err: + return (rc); +} + +int +nmgr_group_list_unlock(void) +{ + int rc; + + if (!os_started()) { + return (0); + } + + rc = os_mutex_release(&nmgr_state.ns_group_lock); + if (rc != 0) { + goto err; + } + + return (0); +err: + return (rc); +} + + +int +nmgr_group_register(struct nmgr_group *group) +{ + int rc; + + rc = nmgr_group_list_lock(); + if (rc != 0) { + goto err; + } + + STAILQ_INSERT_TAIL(&nmgr_state.ns_groups, group, ng_next); + + rc = nmgr_group_list_unlock(); + if (rc != 0) { + goto err; + } + + return (0); +err: + return (rc); +} + +static struct nmgr_group * +nmgr_find_group(uint16_t group_id) +{ + struct nmgr_group *group; + int rc; + + group = NULL; + + rc = nmgr_group_list_lock(); + if (rc != 0) { + goto err; + } + + STAILQ_FOREACH(group, &nmgr_state.ns_groups, ng_next) { + if (group->ng_group_id == group_id) { + break; + } + } + + rc = nmgr_group_list_unlock(); + if (rc != 0) { + goto err; + } + + return (group); +err: + return (NULL); +} + +static struct nmgr_handler * +nmgr_find_handler(uint16_t group_id, uint16_t handler_id) +{ + struct nmgr_group *group; + struct nmgr_handler *handler; + + group = nmgr_find_group(group_id); + if (!group) { + goto err; + } + + if (handler_id >= group->ng_handlers_count) { + goto err; + } + + handler = &group->ng_handlers[handler_id]; + + return (handler); +err: + return (NULL); +} + +int +nmgr_rsp_extend(struct nmgr_hdr *hdr, struct os_mbuf *rsp, void *data, + uint16_t len) +{ + int rc; + + rc = os_mbuf_append(rsp, data, len); + if (rc != 0) { + goto err; + } + hdr->nh_len += len; + + return (0); +err: + return (rc); +} + +static char +nmgr_jbuf_read_next(struct json_buffer *jb) +{ + struct nmgr_jbuf *njb; + char c; + + njb = (struct nmgr_jbuf *) jb; + + if (njb->njb_in_off + 1 > njb->njb_in_end) { + return '\0'; + } + + c = njb->njb_in[njb->njb_in_off]; + ++njb->njb_in_off; + + return (c); +} + +static char +nmgr_jbuf_read_prev(struct json_buffer *jb) +{ + struct nmgr_jbuf *njb; + char c; + + njb = (struct nmgr_jbuf *) jb; + + if (njb->njb_in_off == 0) { + return '\0'; + } + + --njb->njb_in_off; + c = njb->njb_in[njb->njb_in_off]; + + return (c); +} + +static int +nmgr_jbuf_readn(struct json_buffer *jb, char *buf, int size) +{ + struct nmgr_jbuf *njb; + int read; + int left; + + njb = (struct nmgr_jbuf *) jb; + + left = njb->njb_in_end - njb->njb_in_off; + read = size > left ? left : size; + + memcpy(buf, njb->njb_in + njb->njb_in_off, read); + + return (read); +} + +static int +nmgr_jbuf_write(void *arg, char *data, int len) +{ + struct nmgr_jbuf *njb; + int rc; + + njb = (struct nmgr_jbuf *) arg; + + if (njb->njb_out_off + len >= njb->njb_out_end) { + assert(0); + goto err; + } + memcpy(njb->njb_out + njb->njb_out_off, data, len); + njb->njb_out_off += len; + njb->njb_out[njb->njb_out_off] = '\0'; + + return (0); +err: + return (rc); +} + +static void +nmgr_jbuf_init(struct nmgr_jbuf *njb) +{ + memset(njb, 0, sizeof(*njb)); + + njb->njb_buf.jb_read_next = nmgr_jbuf_read_next; + njb->njb_buf.jb_read_prev = nmgr_jbuf_read_prev; + njb->njb_buf.jb_readn = nmgr_jbuf_readn; + njb->njb_enc.je_write = nmgr_jbuf_write; + njb->njb_enc.je_arg = njb; +} + +static void +nmgr_jbuf_setibuf(struct nmgr_jbuf *njb, char *ptr, uint16_t len) +{ + njb->njb_in_off = 0; + njb->njb_in_end = len; + njb->njb_in = ptr; + njb->njb_enc.je_wr_commas = 0; +} + +static void +nmgr_jbuf_setobuf(struct nmgr_jbuf *njb, char *ptr, uint16_t maxlen) +{ + njb->njb_out = ptr; + njb->njb_out_off = 0; + njb->njb_out_end = maxlen; + njb->njb_out[0] = '\0'; +} + +int +nmgr_jbuf_setoerr(struct nmgr_jbuf *njb, int errcode) +{ + struct json_value jv; + + json_encode_object_start(&njb->njb_enc); + JSON_VALUE_INT(&jv, errcode); + json_encode_object_entry(&njb->njb_enc, "rc", &jv); + json_encode_object_finish(&njb->njb_enc); + + return (0); +} + +static struct nmgr_handler * +nmgr_oic_find_handler(const char *q, int qlen) +{ + int grp = -1; + int id = -1; + char *str; + char *eptr; + int slen; + + slen = oc_ri_get_query_value(q, qlen, "gr", &str); + if (slen > 0) { + grp = strtoul(str, &eptr, 0); + if (*eptr != '\0' && *eptr != '&') { + return NULL; + } + } + slen = oc_ri_get_query_value(q, qlen, "id", &str); + if (slen > 0) { + id = strtoul(str, &eptr, 0); + if (*eptr != '\0' && *eptr != '&') { + return NULL; + } + } + return nmgr_find_handler(grp, id); +} + +static void +nmgr_oic_op(oc_request_t *req, oc_interface_mask_t mask, int isset) +{ + struct nmgr_state *ns = &nmgr_state; + struct nmgr_handler *handler; + oc_rep_t *data; + int rc; + + if (!req->query_len) { + goto bad_req; + } + + handler = nmgr_oic_find_handler(req->query, req->query_len); + if (!handler) { + goto bad_req; + } + + /* + * Setup state for JSON encoding. + */ + nmgr_jbuf_setobuf(&ns->ns_jbuf, ns->ns_rsp, sizeof(ns->ns_rsp)); + + data = req->request_payload; + if (data) { + if (data->type != STRING) { + goto bad_req; + } + nmgr_jbuf_setibuf(&ns->ns_jbuf, oc_string(data->value_string), + oc_string_len(data->value_string)); + } else { + nmgr_jbuf_setibuf(&ns->ns_jbuf, NULL, 0); + } + + if (!isset) { + if (handler->nh_read) { + rc = handler->nh_read(&ns->ns_jbuf); + } else { + goto bad_req; + } + } else { + if (handler->nh_write) { + rc = handler->nh_write(&ns->ns_jbuf); + } else { + goto bad_req; + } + } + if (rc) { + goto bad_req; + } + + oc_rep_start_root_object(); + switch (mask) { + case OC_IF_BASELINE: + oc_process_baseline_interface(req->resource); + case OC_IF_RW: + oc_rep_set_text_string(root, "key", ns->ns_rsp); + break; + default: + break; + } + oc_rep_end_root_object(); + oc_send_response(req, OC_STATUS_OK); + + return; +bad_req: + oc_send_response(req, OC_STATUS_BAD_REQUEST); +} + +static void +nmgr_oic_get(oc_request_t *req, oc_interface_mask_t mask) +{ + nmgr_oic_op(req, mask, 0); +} + +static void +nmgr_oic_put(oc_request_t *req, oc_interface_mask_t mask) +{ + nmgr_oic_op(req, mask, 1); +} + +static void +nmgr_app_init(void) +{ + oc_init_platform("MyNewt", NULL, NULL); + oc_add_device("/oic/d", "oic.d.light", "MynewtLed", "1.0", "1.0", NULL, + NULL); +} + +static void +nmgr_register_resources(void) +{ + uint8_t mode; + oc_resource_t *res = NULL; + char name[12]; + + snprintf(name, sizeof(name), "/nmgr"); + res = oc_new_resource(name, 1, 0); + oc_resource_bind_resource_type(res, "x.mynewt.nmgr"); + mode = OC_IF_RW; + oc_resource_bind_resource_interface(res, mode); + oc_resource_set_default_interface(res, mode); + oc_resource_set_discoverable(res); + oc_resource_set_request_handler(res, OC_GET, nmgr_oic_get); + oc_resource_set_request_handler(res, OC_PUT, nmgr_oic_put); + oc_add_resource(res); +} + +static const oc_handler_t nmgr_oc_handler = { + .init = nmgr_app_init, + .register_resources = nmgr_register_resources +}; + +void +oc_signal_main_loop(void) +{ + struct nmgr_state *ns = &nmgr_state; + + os_eventq_put(&ns->ns_evq, &ns->ns_oc_event); +} + +void +nmgr_oic_task(void *arg) +{ + struct nmgr_state *ns = &nmgr_state; + struct os_event *ev; + struct os_callout_func *ocf; + os_time_t next_event; + + nmgr_jbuf_init(&ns->ns_jbuf); + + oc_main_init((oc_handler_t *)&nmgr_oc_handler); + while (1) { + ev = os_eventq_get(&ns->ns_evq); + switch (ev->ev_type) { + case NMGR_OC_EVENT: + case NMGR_OC_TIMER: + next_event = oc_main_poll(); + if (next_event) { + os_callout_reset(&ns->ns_oc_timer, next_event - os_time_get()); + } else { + os_callout_stop(&ns->ns_oc_timer); + } + break; + case OS_EVENT_T_TIMER: + ocf = (struct os_callout_func *)ev; + ocf->cf_func(CF_ARG(ocf)); + break; + } + } +} + +int +nmgr_oic_init(uint8_t prio, os_stack_t *stack_ptr, uint16_t stack_len) +{ + struct nmgr_state *ns = &nmgr_state; + int rc; + + os_eventq_init(&ns->ns_evq); + + rc = os_task_init(&ns->ns_task, "newtmgr_oic", nmgr_oic_task, NULL, prio, + OS_WAIT_FOREVER, stack_ptr, stack_len); + if (rc != 0) { + goto err; + } + + rc = nmgr_os_groups_register(&ns->ns_evq); + if (rc != 0) { + goto err; + } + + return (0); +err: + return (rc); +} http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/b99324aa/mgmt/oicmgr/syscfg.yml ---------------------------------------------------------------------- diff --git a/mgmt/oicmgr/syscfg.yml b/mgmt/oicmgr/syscfg.yml new file mode 100644 index 0000000..5bf2332 --- /dev/null +++ b/mgmt/oicmgr/syscfg.yml @@ -0,0 +1,10 @@ +# Package: mgmt/newtmgr_oic + +syscfg.defs: + ### These should be renamed with a proper prefix. + NEWTMGR: + description: 'TBD' + value: 1 + OC_SERVER: + description: 'TBD' + value: 1 http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/b99324aa/test/crash_test/pkg.yml ---------------------------------------------------------------------- diff --git a/test/crash_test/pkg.yml b/test/crash_test/pkg.yml index b9ca425..c2ec845 100644 --- a/test/crash_test/pkg.yml +++ b/test/crash_test/pkg.yml @@ -30,7 +30,6 @@ pkg.req_apis.CRASH_TEST_NEWTMGR: - newtmgr pkg.deps.CRASH_TEST_NEWTMGR: - - libs/newtmgr - encoding/json pkg.init_function: crash_test_init