Commit a9cd4e73 authored by Daan Vreeken's avatar Daan Vreeken
Browse files

Add a new block called 'oneshot'.

When its 'reset' input is active, the output will always be off (=false).
When the 'set' input is active, the output will be turned on.
Once the 'set' input becomes inactive, the output will remain on for 'period'
seconds and then turn off.
A parameter called 'force' allows the block to be forced into the 'set' or
'reset' states.

	new file:   block/block_oneshot.c
parent a149913a
/*
* Copyright (c) 2015,
* Daan Vreeken <Daan @ Vitsch . nl> - Vitsch Electronics
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS `AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <controller/controller_block.h>
#include <controller/controller_time.h>
#include <log/log.h>
/*
inputs outputs
-----------------------------
| |
---| set out |----
---| reset |
| |
-----------------------------
params:
o period (seconds, double)
o force (true/false, integer)
When the 'reset' input is active, the output will always be off (=false).
When the 'set' input is active, the output will be turned on.
Once the 'set' input becomes inactive, the output will remain on for
'period' seconds and then turn off.
The above can be overridden with the 'force' parameter. At the moment
'force' is set to 'true', a 'set' event is generated.
At the moment 'force' is set to 'false', a 'reset' event is generated.
*/
struct controller_block_private {
// inputs
bool *set, *reset;
// outputs
bool out;
// internal variables
uint32_t period;
uint32_t ticks_left;
};
#define OUTPUT(name) (priv->name)
#define INPUT(name) (*priv->name)
#define DEBUG
static void calculate(struct controller_block *block)
{
struct controller_block_private *priv;
priv = block->private;
if (INPUT(reset) == true) {
OUTPUT(out) = false;
return;
}
if (INPUT(set) == true) {
OUTPUT(out) = true;
priv->ticks_left = priv->period;
} else {
if ((priv->ticks_left) && (--priv->ticks_left == 0))
OUTPUT(out) = false;
}
}
static struct controller_block_interm_list interms[] = {
{ "set", CONTROLLER_BLOCK_TERM_BOOL,
offsetof(struct controller_block_private, set) },
{ "reset", CONTROLLER_BLOCK_TERM_BOOL,
offsetof(struct controller_block_private, reset) },
{ NULL },
};
static struct controller_block_outterm_list outterms[] = {
{ "out", CONTROLLER_BLOCK_TERM_BOOL,
offsetof(struct controller_block_private, out) },
{ NULL },
};
static int set_period(struct controller_block *block, double period)
{
struct controller_block_private *priv;
priv = block->private;
if (period <= 0.0) {
log_send(LOG_T_ERROR, "%s: 'period' must be > 0.0 sec.",
block->name);
return -1;
}
// Calculate how many samples are in one 'period'.
priv->period = ceil(period *
controller_time_frequency_get(block->time));
#ifdef DEBUG
log_send(LOG_T_DEBUG, "%s: period=%d samples", block->name,
priv->period);
#endif
// Limit the output on time to the new setting.
if (priv->period > priv->ticks_left)
priv->ticks_left = priv->period;
return 0;
}
static int param_set_period(struct controller_block *block, char *param,
int argc, va_list val)
{
float period;
period = va_arg(val, double);
return set_period(block, period);
}
static int param_set_force(struct controller_block *block, char *param,
int argc, va_list val)
{
struct controller_block_private *priv;
int e;
priv = block->private;
e = va_arg(val, int);
if (e == true) {
// 'set'
OUTPUT(out) = true;
priv->ticks_left = priv->period;
log_send(LOG_T_DEBUG, "%s: forced 'set' event", block->name);
} else {
// 'reset'
OUTPUT(out) = false;
priv->ticks_left = 0;
log_send(LOG_T_DEBUG, "%s: forced 'reset' event",
block->name);
}
return 0;
}
static struct controller_block_param_list params[] = {
{ "period", false, param_set_period, .args = { "double", NULL } },
{ "force", false, param_set_force, .args = { "int", NULL } },
{ NULL },
};
static struct controller_block * block_oneshot_create(char *name,
int argc, va_list val)
{
struct controller_block *block;
struct controller_block_private *priv;
double period_s;
int ret;
block = controller_block_alloc("oneshot", name,
sizeof(struct controller_block_private));
if (block == NULL)
return NULL;
priv = block->private;
// initial state
OUTPUT(out) = false;
priv->ticks_left = 0;
if (argc == 0) {
set_period(block, 1.0);
} else {
period_s = va_arg(val, double);
ret = set_period(block, period_s);
if (ret != 0)
goto err_block;
}
if (controller_block_interm_list_init(block, interms))
goto err_block;
if (controller_block_outterm_list_init(block, outterms))
goto err_block;
if (controller_block_param_list_add(block, params))
goto err_block;
block->calculate = calculate;
if (controller_block_add(block))
goto err_block;
return block;
err_block:
controller_block_free(block);
return NULL;
}
BLOCK_CREATE(oneshot) = {
.create = block_oneshot_create,
.args = { "", "double", NULL },
};
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment