#include "rtapi.h"
#include "rtapi_app.h"
#include "hal.h"
#include "streamer.h"
#include "rtapi_errno.h"
#include "rtapi_string.h"
MODULE_AUTHOR("John Kasunich");
MODULE_DESCRIPTION("Realtime File Streamer HAL");
MODULE_LICENSE("GPL");
static char *cfg[MAX_STREAMERS];
RTAPI_MP_ARRAY_STRING(cfg,MAX_STREAMERS,"config string");
static int depth[MAX_STREAMERS];
RTAPI_MP_ARRAY_INT(depth,MAX_STREAMERS,"fifo depth");
typedef struct {
hal_stream_t fifo;
hal_s32_t *curr_depth;
hal_bit_t *empty;
hal_bit_t *enable;
hal_s32_t *underruns;
hal_bit_t *clock;
hal_s32_t *clock_mode;
int myclockedge;
pin_data_t pins[HAL_STREAM_MAX_PINS];
} streamer_t;
static int comp_id;
static int nstreamers;
static streamer_t *streams;
static int init_streamer(int num, streamer_t *stream);
static void update(void *arg, long period);
int rtapi_app_main(void)
{
int n, retval;
comp_id = hal_init("streamer");
if (comp_id < 0) {
rtapi_print_msg(RTAPI_MSG_ERR, "STREAMER: ERROR: hal_init() failed\n");
return -EINVAL;
}
streams = hal_malloc(MAX_STREAMERS * sizeof(streamer_t));
for ( n = 0 ; n < MAX_STREAMERS ; n++ ) {
if (( cfg[n] == NULL ) || ( *cfg == '\0' ) || ( depth[n] <= 0 )) {
break;
}
retval = hal_stream_create(&streams[n].fifo, comp_id, STREAMER_SHMEM_KEY+n, depth[n], cfg[n]);
if(retval < 0) {
goto fail;
}
nstreamers++;
retval = init_streamer(n, &streams[n]);
}
if ( n == 0 ) {
rtapi_print_msg(RTAPI_MSG_ERR,
"STREAMER: ERROR: no channels specified\n");
retval = -EINVAL;
goto fail;
}
hal_ready(comp_id);
return 0;
fail:
for(n=0; n<nstreamers; n++) hal_stream_destroy(&streams[n].fifo);
hal_exit(comp_id);
return retval;
}
void rtapi_app_exit(void)
{
int i;
for(i=0; i<nstreamers; i++) hal_stream_destroy(&streams[i].fifo);
hal_exit(comp_id);
}
static void update(void *arg, long period)
{
streamer_t *str;
pin_data_t *pptr;
int n, doclk;
str = arg;
int myclockedge =
str->myclockedge=((str->myclockedge<<1) | (*(str->clock) & 1)) & 3;
doclk=0;
if ( *(str->enable) ) {
doclk=1;
switch (*str->clock_mode) {
case 0:
break;
case 1:
if ( myclockedge!=2) {
doclk=0;
}
break;
case 2:
if ( myclockedge!=1) {
doclk=0;
}
break;
case 3:
if ((myclockedge==0) | ( myclockedge==3)) {
doclk=0;
}
break;
default:
break;
}
}
pptr = str->pins;
int depth = hal_stream_depth(&str->fifo);
*(str->curr_depth) = depth;
*(str->empty) = depth == 0;
if(!doclk)
return;
if(depth == 0) {
(*str->underruns)++;
return;
}
union hal_stream_data data[HAL_STREAM_MAX_PINS];
if(hal_stream_read(&str->fifo, data, NULL) < 0)
{
(*str->underruns)++;
return;
}
union hal_stream_data *dptr = data;
int num_pins = hal_stream_element_count(&str->fifo);
for ( n = 0 ; n < num_pins ; n++ ) {
switch ( hal_stream_element_type(&str->fifo, n) ) {
case HAL_FLOAT:
*(pptr->hfloat) = dptr->f;
break;
case HAL_BIT:
if ( dptr->b ) {
*(pptr->hbit) = 1;
} else {
*(pptr->hbit) = 0;
}
break;
case HAL_U32:
*(pptr->hu32) = dptr->u;
break;
case HAL_S32:
*(pptr->hs32) = dptr->s;
break;
default:
break;
}
dptr++;
pptr++;
}
}
static int init_streamer(int num, streamer_t *str)
{
int retval, n, usefp;
pin_data_t *pptr;
char buf[HAL_NAME_LEN + 1];
retval = hal_pin_bit_newf(HAL_OUT, &(str->empty), comp_id,
"streamer.%d.empty", num);
if (retval != 0 ) {
rtapi_print_msg(RTAPI_MSG_ERR,
"STREAMER: ERROR: 'empty' pin export failed\n");
return -EIO;
}
retval = hal_pin_bit_newf(HAL_IN, &(str->enable), comp_id,
"streamer.%d.enable", num);
if (retval != 0 ) {
rtapi_print_msg(RTAPI_MSG_ERR,
"STREAMER: ERROR: 'enable' pin export failed\n");
return -EIO;
}
retval = hal_pin_s32_newf(HAL_OUT, &(str->curr_depth), comp_id,
"streamer.%d.curr-depth", num);
if (retval != 0 ) {
rtapi_print_msg(RTAPI_MSG_ERR,
"STREAMER: ERROR: 'curr_depth' pin export failed\n");
return -EIO;
}
retval = hal_pin_s32_newf(HAL_IO, &(str->underruns), comp_id,
"streamer.%d.underruns", num);
if (retval != 0 ) {
rtapi_print_msg(RTAPI_MSG_ERR,
"STREAMER: ERROR: 'underruns' pin export failed\n");
return -EIO;
}
retval = hal_pin_bit_newf(HAL_IN, &(str->clock), comp_id,
"streamer.%d.clock", num);
if (retval != 0 ) {
rtapi_print_msg(RTAPI_MSG_ERR,
"STREAMER: ERROR: 'clock' pin export failed\n");
return -EIO;
}
retval = hal_pin_s32_newf(HAL_IN, &(str->clock_mode), comp_id,
"streamer.%d.clock-mode", num);
if (retval != 0 ) {
rtapi_print_msg(RTAPI_MSG_ERR,
"STREAMER: ERROR: 'clock_mode' pin export failed\n");
return -EIO;
}
*(str->empty) = 1;
*(str->enable) = 1;
*(str->curr_depth) = 0;
*(str->underruns) = 0;
*(str->clock_mode) = 0;
pptr = str->pins;
usefp = 0;
for ( n = 0 ; n < hal_stream_element_count(&str->fifo); n++ ) {
rtapi_snprintf(buf, sizeof(buf), "streamer.%d.pin.%d", num, n);
retval = hal_pin_new(buf, hal_stream_element_type(&str->fifo, n), HAL_OUT, (void **)pptr, comp_id );
if (retval != 0 ) {
rtapi_print_msg(RTAPI_MSG_ERR,
"STREAMER: ERROR: pin '%s' export failed\n", buf);
return -EIO;
}
switch ( hal_stream_element_type(&str->fifo, n) ) {
case HAL_FLOAT:
*(pptr->hfloat) = 0.0;
usefp = 1;
break;
case HAL_BIT:
*(pptr->hbit) = 0;
break;
case HAL_U32:
*(pptr->hu32) = 0;
break;
case HAL_S32:
*(pptr->hs32) = 0;
break;
default:
break;
}
pptr++;
}
rtapi_snprintf(buf, sizeof(buf), "streamer.%d", num);
retval = hal_export_funct(buf, update, str, usefp, 0, comp_id);
if (retval != 0) {
rtapi_print_msg(RTAPI_MSG_ERR,
"STREAMER: ERROR: function export failed\n");
return retval;
}
return 0;
}