Soletta™ Framework
Framework for making IoT devices

Full online documentation | C API Index
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
/src/samples/flow/c-api/simple-c-type.c
/*
* This file is part of the Soletta (TM) Project
*
* Copyright (C) 2015 Intel Corporation. All rights reserved.
*
* Licensed 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 <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include "soletta.h"
static struct sol_flow_node *flow;
static struct sol_flow_builder *builder;
static struct sol_flow_node_type *mytype;
/*
* isodd is a very simplistic type, it only handle a single event and
* has no storage/context. All it does is get an integer and send a
* boolean true if that number is odd, sending false if it's even.
*/
static int
isodd(struct sol_flow_node *node, const struct sol_flow_simple_c_type_event *ev, void *data)
{
int32_t val;
int r;
/* we only handle events for port input. */
if (ev->type != SOL_FLOW_SIMPLE_C_TYPE_EVENT_TYPE_PROCESS_PORT_IN)
return 0;
/* get the integer value from irange and check if it worked */
if (r < 0)
return r;
/* we use port index '0' here, after all we have a single port */
return sol_flow_send_bool_packet(node, 0, (val % 2 != 0));
}
/*
* mytype is an extensive example of simple_c_type capabilities.
*
* It will take options at node open, keep context and handle all
* events.
*
* It stores an integer and a boolean, initially set through options
* and then modified via input ports, then from time to time (every
* 500ms) it will create a string with both values and send on its
* output port.
*
*/
#define MYTYPE_OPTIONS_SUB_API 0x1234
int someint;
bool somebool;
};
struct sol_timeout *timer;
int someint;
bool somebool;
};
static bool
on_timeout(void *data)
{
struct sol_flow_node *node = data;
uint16_t port_idx;
char buf[256];
printf("mytype tick... send packet. ctx=%p someint=%d, somebool=%d\n",
ctx, ctx->someint, ctx->somebool);
snprintf(buf, sizeof(buf), "%d/%s",
ctx->someint,
ctx->somebool ? "true" : "false");
/* this is to demo the discovery from name, but one could/should use the
* port index for efficiency matters.
*/
port_idx = sol_flow_simple_c_type_get_port_out_index(mytype, "STRING");
sol_flow_send_string_packet(node, port_idx, buf);
return true;
}
static int
mytype_func(struct sol_flow_node *node, const struct sol_flow_simple_c_type_event *ev, void *data)
{
struct mytype_context *ctx = data;
switch (ev->type) {
case SOL_FLOW_SIMPLE_C_TYPE_EVENT_TYPE_OPEN: {
if (ev->options
#endif
) {
struct mytype_options *opt = (struct mytype_options *)ev->options;
ctx->someint = opt->someint;
ctx->somebool = opt->somebool;
}
/* every 500ms send out a string representing our someint + somebool */
ctx->timer = sol_timeout_add(500, on_timeout, node);
if (!ctx->timer)
return -ENOMEM;
printf("simple_c_type opened ctx=%p, someint=%d, somebool=%d\n",
ctx, ctx->someint, ctx->somebool);
return 0;
}
case SOL_FLOW_SIMPLE_C_TYPE_EVENT_TYPE_CLOSE: {
printf("simple_c_type closed ctx=%p\n", ctx);
return 0;
}
case SOL_FLOW_SIMPLE_C_TYPE_EVENT_TYPE_PROCESS_PORT_IN: {
/* this is to show the port names, ideally one would keep the
* indexes and use them here, doing integer comparisons
* instead of strcmp()
*/
if (strcmp(ev->port_name, "IRANGE") == 0) {
int32_t val;
printf("simple_c_type updated integer from %d to %d\n",
ctx->someint, val);
ctx->someint = val;
return 0;
}
} else if (strcmp(ev->port_name, "BOOLEAN") == 0) {
bool val;
if (sol_flow_packet_get_bool(ev->packet, &val) == 0) {
printf("simple_c_type updated boolean from %d to %d\n",
ctx->somebool, val);
ctx->somebool = val;
return 0;
}
}
printf("simple_c_type port '%s' got unexpected data!\n", ev->port_name);
return -EINVAL;
}
case SOL_FLOW_SIMPLE_C_TYPE_EVENT_TYPE_CONNECT_PORT_IN:
printf("simple_c_type port IN '%s' id=%d conn=%d connected ctx=%p\n",
ev->port_name, ev->port, ev->conn_id, ctx);
return 0;
case SOL_FLOW_SIMPLE_C_TYPE_EVENT_TYPE_DISCONNECT_PORT_IN:
printf("simple_c_type port IN '%s' id=%d conn=%d disconnected ctx=%p\n",
ev->port_name, ev->port, ev->conn_id, ctx);
return 0;
case SOL_FLOW_SIMPLE_C_TYPE_EVENT_TYPE_CONNECT_PORT_OUT:
printf("simple_c_type port OUT '%s' id=%d conn=%d connected ctx=%p\n",
ev->port_name, ev->port, ev->conn_id, ctx);
return 0;
case SOL_FLOW_SIMPLE_C_TYPE_EVENT_TYPE_DISCONNECT_PORT_OUT:
printf("simple_c_type port OUT '%s' id=%d conn=%d disconnected ctx=%p\n",
ev->port_name, ev->port, ev->conn_id, ctx);
return 0;
}
return -EINVAL;
}
static void
startup(void)
{
/* you can give your simple_c_type custom arguments, just give it
* the struct and remember to fill its "base" with the API fields.
* the 'api_version' is checked by sol-flow calls, while sub_api
* is checked at mytype_func when handling the
* SOL_FLOW_SIMPLE_C_TYPE_EVENT_TYPE_OPEN.
*/
struct mytype_options mystuff_opts = {
.base = {
#ifndef SOL_NO_API_VERSION
#endif
},
.someint = 12,
.somebool = true,
};
/* declare 'isodd' without private data and with ports:
* input: IN (index: 0)
* output: OUT (index: 0)
*/
NULL);
/* declare mytype with 'struct mytype_context' private data and with ports:
* input: IRANGE (index: 0), BOOLEAN (index: 1)
* output: STRING (index: 0, as input and output have separate arrays)
*/
"mytype", sizeof(struct mytype_context), sizeof(struct mytype_options),
NULL);
/* for types declared as builtin or external modules, add by type name */
"timer", NULL);
"boolean/toggle", NULL);
"int/accumulator", NULL);
"console", NULL);
"console", NULL);
"console", NULL);
/* use our types as we'd use any custom type: given its handle */
sol_flow_builder_add_node(builder, "isodd", isoddtype, NULL);
sol_flow_builder_add_node(builder, "mystuff", mytype, &mystuff_opts.base);
/* setup connections */
sol_flow_builder_connect(builder, "timer", "OUT", -1,
"booltoggle", "IN", -1);
sol_flow_builder_connect(builder, "timer", "OUT", -1,
"intacc", "INC", -1);
/* intacc OUT -> IN isodd OUT -> IN console_isodd */
sol_flow_builder_connect(builder, "intacc", "OUT", -1,
"isodd", "IN", -1);
sol_flow_builder_connect(builder, "isodd", "OUT", -1,
"console_isodd", "IN", -1);
/* booltoggle OUT -> BOOLEAN mystuff
* intacc OUT -> IRANGE mystuff
* mystuff STRING -> IN console_mystuff
*/
sol_flow_builder_connect(builder, "booltoggle", "OUT", -1,
"mystuff", "BOOLEAN", -1);
sol_flow_builder_connect(builder, "intacc", "OUT", -1,
"mystuff", "IRANGE", -1);
sol_flow_builder_connect(builder, "mystuff", "STRING", -1,
"console_mystuff", "IN", -1);
/* also print out values from boolean toggle and integer
* accumulator so we can double check the results.
*/
sol_flow_builder_connect(builder, "booltoggle", "OUT", -1,
"debug", "IN", -1);
sol_flow_builder_connect(builder, "intacc", "OUT", -1,
"debug", "IN", -1);
/* this creates a static flow using the low-level API that will
* actually run the flow. Note that its memory is bound to
* builder, then keep builder alive.
*/
/* create and run the flow */
flow = sol_flow_node_new(NULL, "simple_c_type", flow_node_type, NULL);
}
static void
shutdown(void)
{
/* stop the flow, disconnect ports and close children nodes */
/* delete types */
sol_flow_node_type_del(flow_node_type);
/* delete the builder */
}