blob: 1d2d1acf950da7dc3e7b20adf133a5e57ac8fa58 [file] [log] [blame]
/****************************************************************************
* apps/examples/shv-test/shv_test.c
*
* SPDX-License-Identifier: Apache-2.0
*
* 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.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <shv/tree/shv_tree.h>
#include <shv/tree/shv_file_node.h>
#include <shv/tree/shv_connection.h>
#include <shv/tree/shv_methods.h>
#include <shv/tree/shv_clayer_posix.h>
#include <shv/tree/shv_dotdevice_node.h>
#include <shv/tree/shv_dotapp_node.h>
#include <nuttx/config.h>
#include <stdio.h>
#include <signal.h>
#include <semaphore.h>
#include <stdbool.h>
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
static int shv_nuttxtesting_set(struct shv_con_ctx *shv_ctx,
struct shv_node *item, int rid);
static int shv_nuttxtesting_get(struct shv_con_ctx *shv_ctx,
struct shv_node *item, int rid);
static int shv_nuttxtesting_art(struct shv_con_ctx *shv_ctx,
struct shv_node *item, int rid);
static void quit_handler(int signum);
static void print_help(char *name);
static struct shv_node *shv_tree_create_dynamically(int mode);
static void attention_cb(struct shv_con_ctx *shv_ctx,
enum shv_attention_reason r);
/****************************************************************************
* Private Data
****************************************************************************/
/* An execution barrier */
static sem_t running;
/* Testing variable */
static int g_testing_val;
/* ------------------------- ROOT METHODS --------------------------------- */
static const struct shv_method_des * const shv_dev_root_dmap_items[] =
{
&shv_dmap_item_dir,
&shv_dmap_item_ls,
};
static const struct shv_dmap shv_dev_root_dmap =
SHV_CREATE_NODE_DMAP(root, shv_dev_root_dmap_items);
/* ----------------------- nuttxtesting METHODS -------------------------- */
static const struct shv_method_des shv_dev_nuttxtesting_dmap_item_set =
{
.name = "setTestingVal",
.method = shv_nuttxtesting_set
};
static const struct shv_method_des shv_dev_nuttxtesting_dmap_item_get =
{
.name = "getTestingVal",
.method = shv_nuttxtesting_get
};
static const struct shv_method_des shv_dev_nuttxtesting_dmap_item_art =
{
.name = "asciiArt",
.method = shv_nuttxtesting_art
};
static const struct shv_method_des *const shv_dev_nuttxtesting_dmap_items[] =
{
&shv_dev_nuttxtesting_dmap_item_art,
&shv_dmap_item_dir,
&shv_dev_nuttxtesting_dmap_item_get,
&shv_dmap_item_ls,
&shv_dev_nuttxtesting_dmap_item_set
};
static const struct shv_dmap shv_dev_nuttxtesting_dmap =
SHV_CREATE_NODE_DMAP(nuttxtesting, shv_dev_nuttxtesting_dmap_items);
/* ------------------- Static const tree root creation ------------------- */
/* First, define all static nodes */
static const struct shv_dotdevice_node shv_static_node_dotdevice =
{
.shv_node =
{
.name = ".device",
.dir = UL_CAST_UNQ1(struct shv_dmap *, &shv_dotdevice_dmap),
.children =
{
.mode = (SHV_NLIST_MODE_GSA | SHV_NLIST_MODE_STATIC)
}
},
.devops =
{
.reset = shv_dotdevice_node_posix_reset,
.uptime = shv_dotdevice_node_posix_uptime
},
.name = "SHV Compatible Device",
.serial_number = "0xDEADBEEF",
.version = "0.1.0"
};
static const struct shv_dotapp_node shv_static_node_dotapp =
{
.shv_node =
{
.name = ".app",
.dir = UL_CAST_UNQ1(struct shv_dmap *, &shv_dotapp_dmap),
.children =
{
.mode = (SHV_NLIST_MODE_GSA | SHV_NLIST_MODE_STATIC)
}
},
.appops =
{
.date = NULL /* As of September 25, date parsing not implemented yet */
},
.name = "NuttX libshvc example",
.version = "1.0.0"
};
static const struct shv_node shv_static_node_nuttxtesting =
{
.name = "nuttxTesting",
.dir = UL_CAST_UNQ1(struct shv_dmap *, &shv_dev_nuttxtesting_dmap),
.children =
{
.mode = (SHV_NLIST_MODE_GSA | SHV_NLIST_MODE_STATIC)
}
};
/* Now, define tree root's children */
const struct shv_node *const shv_static_tree_root_items[] =
{
&shv_static_node_dotapp.shv_node,
&shv_static_node_dotdevice.shv_node,
&shv_static_node_nuttxtesting
};
/* Construct the root. Yes, it's a bit cumbersome,
* but an automated code generator should have no problem with this!
*/
const struct shv_node shv_static_tree_root =
{
.dir = UL_CAST_UNQ1(struct shv_dmap *, &shv_dev_root_dmap),
.children =
{
.mode = (SHV_NLIST_MODE_GSA | SHV_NLIST_MODE_STATIC),
.list =
{
.gsa =
{
.root =
{
.items = (void **)shv_static_tree_root_items,
.count = sizeof(shv_static_tree_root_items) /
sizeof(shv_static_tree_root_items[0]),
.alloc_count = 0,
}
}
}
}
};
/****************************************************************************
* Private Functions
****************************************************************************/
static int shv_nuttxtesting_set(struct shv_con_ctx *shv_ctx,
struct shv_node *item, int rid)
{
shv_unpack_data(&shv_ctx->unpack_ctx, &g_testing_val, 0);
printf("Testing val set to %d\n", g_testing_val);
shv_send_empty_response(shv_ctx, rid);
return 0;
}
static int shv_nuttxtesting_get(struct shv_con_ctx *shv_ctx,
struct shv_node *item, int rid)
{
shv_unpack_data(&shv_ctx->unpack_ctx, 0, 0);
shv_send_int(shv_ctx, rid, g_testing_val);
return 0;
}
static int shv_nuttxtesting_art(struct shv_con_ctx *shv_ctx,
struct shv_node *item, int rid)
{
/* Generated from https://budavariam.github.io/asciiart-text/ */
shv_unpack_data(&shv_ctx->unpack_ctx, 0, 0);
puts(" ____ _ ___ __");
puts(" / __ || | | \\ \\ / /");
puts(" \\___ \\| |_| |\\ \\ / / ");
puts(" ___) | _ | \\ V / ");
puts(" |____/|_| |_| \\_/ ");
shv_send_int(shv_ctx, rid, 0);
return 0;
}
static struct shv_node *shv_tree_create_dynamically(int mode)
{
struct shv_node *tree_root;
struct shv_dotapp_node *dotapp_node;
struct shv_node *nuttxtesting_node;
struct shv_dotdevice_node *dotdevice_node;
tree_root = shv_tree_node_new("", &shv_dev_root_dmap, mode);
if (tree_root == NULL)
{
return NULL;
}
dotapp_node = shv_tree_dotapp_node_new(&shv_dotapp_dmap, mode);
if (dotapp_node == NULL)
{
free(tree_root);
return NULL;
}
dotapp_node->name = "NuttX libshvc example";
dotapp_node->version = "1.0.0";
shv_tree_add_child(tree_root, &dotapp_node->shv_node);
dotdevice_node = shv_tree_dotdevice_node_new(&shv_dotdevice_dmap, mode);
if (dotdevice_node == NULL)
{
free(tree_root);
free(dotapp_node);
return NULL;
}
dotdevice_node->name = "SHV Compatible Device";
dotdevice_node->serial_number = "0xDEADBEEF";
dotdevice_node->version = "0.1.0";
shv_tree_add_child(tree_root, &dotdevice_node->shv_node);
nuttxtesting_node = shv_tree_node_new("nuttxTesting",
&shv_dev_nuttxtesting_dmap, mode);
if (nuttxtesting_node == NULL)
{
free(tree_root);
free(dotapp_node);
free(dotdevice_node);
return NULL;
}
shv_tree_add_child(tree_root, nuttxtesting_node);
return tree_root;
}
static void quit_handler(int signum)
{
puts("Stopping SHV FW Updater!");
sem_post(&running);
}
static void print_help(char *name)
{
printf("%s: [OPTIONS]\n", name);
puts("Silicon Heaven NuttX example");
puts("Showcases the tree creation.");
puts("Mandatory options:");
puts(" -a <0-2>: chooses the tree alloc type:");
puts(" 0: GAVL");
puts(" 1: GSA");
puts(" 2: GSA_STATIC: GSA with .rodata placed nodes");
puts(" -m <mount-point>: mount point in the SHV broker");
puts(" -i <ip-addr>: IPv4 address of the SHV broker");
puts(" -p <passwd>: password to access the SHV broker");
puts(" -t <port>: TCP/IP port of the SHV broker");
puts(" -u <user>: user to access the SHV broker");
puts("Nonmandatory options:");
puts(" -h: print help");
}
static void attention_cb(struct shv_con_ctx *shv_ctx,
enum shv_attention_reason r)
{
if (r == SHV_ATTENTION_ERROR)
{
printf("Error occurred in SHV, the reason is: %s\n",
shv_errno_str(shv_ctx));
sem_post(&running);
}
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: main
****************************************************************************/
int main(int argc, char *argv[])
{
/* Define the SHV Communication parameters */
int ret;
int opt;
struct shv_connection connection;
const struct shv_node *tree_root;
struct shv_con_ctx *ctx;
int alloc_mode = SHV_NLIST_MODE_GAVL;
const char *user = NULL;
const char *passwd = NULL;
const char *mount = NULL;
const char *ip = NULL;
const char *port_s = NULL;
int port = 0;
/* Initialize the communication. But only if parameters are passed. */
while ((opt = getopt(argc, argv, "a:hm:i:p:t:u:")) != -1)
{
switch (opt)
{
case 'a':
alloc_mode = atoi(optarg);
break;
case 'h':
print_help(argv[0]);
return 0;
case 'm':
mount = optarg;
break;
case 'i':
ip = optarg;
break;
case 'p':
passwd = optarg;
break;
case 't':
port_s = optarg;
port = atoi(port_s);
break;
case 'u':
user = optarg;
break;
case '?':
print_help(argv[0]);
return 1;
}
}
if (!user || !passwd || !mount || !ip || !port_s)
{
print_help(argv[0]);
return 1;
}
shv_connection_init(&connection, SHV_TLAYER_TCPIP);
connection.broker_user = user;
connection.broker_password = passwd;
connection.broker_mount = mount;
connection.reconnect_period = 10;
connection.reconnect_retries = 0;
if (shv_connection_tcpip_init(&connection, ip, port) < 0)
{
fprintf(stderr, "Have you supplied valid params to shv_connection?\n");
return 1;
}
puts("SHV Connection Init OK");
if (alloc_mode != SHV_NLIST_MODE_STATIC)
{
tree_root = shv_tree_create_dynamically(alloc_mode);
if (tree_root == NULL)
{
fprintf(stderr, "Can't create the SHV tree.");
return 1;
}
}
else
{
tree_root = &shv_static_tree_root;
}
puts("SHV Tree created!");
ctx = shv_com_init((struct shv_node *)tree_root, &connection,
attention_cb);
if (ctx == NULL)
{
fprintf(stderr, "Can't establish the comm with the broker.\n");
return 1;
}
ret = shv_create_process_thread(99, ctx);
if (ret < 0)
{
fprintf(stderr, "%s\n", shv_errno_str(ctx));
free(ctx);
return 1;
}
sem_init(&running, 0, 0);
signal(SIGTERM, quit_handler);
sem_wait(&running);
puts("Close the communication");
shv_com_destroy(ctx);
shv_tree_destroy(tree_root);
return 0;
}