diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3624768 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +__pycache__ +out +tacapp.tar.gz +Sources +tacapp +worryingFiles +cc.tar.gz diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3624768 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +__pycache__ +out +tacapp.tar.gz +Sources +tacapp +worryingFiles +cc.tar.gz diff --git a/errors.json b/errors.json new file mode 100644 index 0000000..5ec898a --- /dev/null +++ b/errors.json @@ -0,0 +1,4 @@ +{ + "missing_blocks": [], + "multiple_definitions": [] +} \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3624768 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +__pycache__ +out +tacapp.tar.gz +Sources +tacapp +worryingFiles +cc.tar.gz diff --git a/errors.json b/errors.json new file mode 100644 index 0000000..5ec898a --- /dev/null +++ b/errors.json @@ -0,0 +1,4 @@ +{ + "missing_blocks": [], + "multiple_definitions": [] +} \ No newline at end of file diff --git a/hardcodedFiles/tacReadRmnBlock.c b/hardcodedFiles/tacReadRmnBlock.c new file mode 100644 index 0000000..8acbcfa --- /dev/null +++ b/hardcodedFiles/tacReadRmnBlock.c @@ -0,0 +1,568 @@ +/******************************************************************************* +* E.S.O. - VLT project +* +* "@(#) $Id: tacReadRmnBlock.c 305476 2018-01-19 08:56:18Z rfrahm $" +* +* who when what +* ------- -------- ---------------------------------------------- +* gzins 2010-07-27 ported to VLTSW2010 and VxWorks 6.4 +* swehner 2008-10-10 creation +*/ + +/************************************************************************ +* NAME +* tacReadRmnBlock - Implemements the standard functions for the +* tacReadRmn block and tacReadRfm block. +* tacReadRmnBlock - Reads from 1rst generation reflective memory network +* tacReadRfmBlock - Reads from 2nd generation reflective memory network + +* Parameters: +* field - token names for the RMN fields to read (up to 10) +* Inputs: 0 +* Outputs: 1 +* output - 1..10 depending on number of field parameters +* +* +* +* FILES +* +* ENVIRONMENT +* TAC +* +* RETURN VALUES +* +* CAUTIONS +* +* EXAMPLES +* TAC.BLOCK9.TYPE ReadRmn +* TAC.BLOCK9.NAME ReadRmn +* +* SEE ALSO +* +* BUGS +* +*------------------------------------------------------------------------ +*/ + +#define _POSIX_SOURCE 1 +#include "vltPort.h" + +ATTRIBUTE_UNUSED static const char *rcsId="@(#) $Id: tacReadRmnBlock.c 305476 2018-01-19 08:56:18Z rfrahm $"; + +/* + * System Headers + */ + +#include /* taskSpawn, taskDelay, ... */ +#include /* printf ... */ +#include /* malloc ... */ +#include /* malloc ... */ +#include +#include + +/* + * Local Headers + */ + +#include "tacStdBlock.h" +#include "tacRmnBlock.h" +#include "rmassPublic.h" +#include "rmassPrivate.h" + +/* + * Compilation directives + */ + +/* + * Constants + */ + +#define tacREAD_RMN_EXPECTED_PARAM 1 +#define tacREAD_RMN_DEFAULT_INPUT_NUMBER 0 +#define tacREAD_RMN_DEFAULT_OUTPUT_NUMBER tacMAX_DATA_NUMBER + +#define tacREAD_RMN_FIELD_STRING_LEN 256 +#define tacSTRLEN sizeof(double) + +/* + * Types + */ + +/* + * Local function declaration + */ + +/* + * Global variables + */ + +/* + * Function definition + */ + + +STATUS tacReadRmnBlockCheckParameter (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the ADDBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = NULL; + + pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + /* field string is built from block params */ + if ( tacRmnBlockCheckParameter ( pSelf, parameter, 0, error) != OK ) + { + return ERROR; + } + + /* useful information on the screen */ + printf ("ReadRmn %s: [%s]\n", pSelf->name, pSelfParam->fieldString); + + return OK; +} + +STATUS tacReadRfmBlockCheckParameter (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the ADDBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = NULL; + + pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + /* field string is built from block params */ + if ( tacRmnBlockCheckParameter ( pSelf, parameter, 0, error) != OK ) + { + return ERROR; + } + + /* useful information on the screen */ + printf ("ReadRfm %s: [%s]\n", pSelf->name, pSelfParam->fieldString); + + return OK; +} + +/* + * Constructor Hooks - Called when a block of this type is instanciated (CONFIG or ADDBLCK commands) + */ + +STATUS tacReadRmBlockConstructor (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the ADDBLCK command */ + vltLOGICAL isRmn, + tacERROR* error) /* Error structure - not a stack */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = NULL; + + /* Check that the expected number of parameters has been received */ + if (parameter->number < tacREAD_RMN_EXPECTED_PARAM) + { + char errorParam[40]; + + sprintf(errorParam, "Expected at least %d, received %d", tacREAD_RMN_EXPECTED_PARAM, parameter->number); + tacRTC_ERR(tacERR_PARAM_NUMBER, errorParam); + return ERROR; + } + + /* Allocate and initialize block-specific arrays */ + if (tacStdBlockAllocateArrays(pSelf, 0, tacREAD_RMN_DEFAULT_INPUT_NUMBER, tacREAD_RMN_DEFAULT_OUTPUT_NUMBER, error) == ERROR) + { + return ERROR; + } + + if (tacStdBlockAllocateArrayBySize(pSelf, tacSTDBLOCK_PARAM_ARRAY, sizeof(tacRMN_LOCAL_PARAMETER), error) == ERROR) + { + tacStdBlockReleaseArray(pSelf, tacSTDBLOCK_INPUT_ARRAY, error); + tacStdBlockReleaseArray(pSelf, tacSTDBLOCK_OUTPUT_ARRAY, error); + return ERROR; + } + + if ( isRmn ) + { + if ( tacReadRmnBlockCheckParameter (pSelf, parameter, error) == ERROR) + { + return ERROR; + } + } + else + { + if ( tacReadRfmBlockCheckParameter (pSelf, parameter, error) == ERROR) + { + return ERROR; + } + } + + pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + pSelfParam->handleValid = rmassACCESS_BLOCKED; + + /* Attach to RMN */ + if ( rmassReadAttach (&pSelfParam->handle, + pSelfParam->fieldString, + &pSelfParam->val[0], + &pSelfParam->val[1], + &pSelfParam->val[2], + &pSelfParam->val[3], + &pSelfParam->val[4], + &pSelfParam->val[5], + &pSelfParam->val[6], + &pSelfParam->val[7], + &pSelfParam->val[8], + &pSelfParam->val[9]) != SUCCESS ) + { + char errorParam[40]; + + sprintf(errorParam, "Attach to RMN failed."); + tacRTC_ERR(tacERR_INTERNAL, errorParam); + return ERROR; + } + + pSelfParam->handleValid = rmassACCESS_FREE; + + return OK; +} + +STATUS tacReadRmnBlockConstructor (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the ADDBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + if ( tacReadRmBlockConstructor (pSelf, parameter, ccsTRUE, error ) == ERROR ) + { + return ERROR; + } + return OK; +} + +STATUS tacReadRfmBlockConstructor (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the ADDBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + if ( tacReadRmBlockConstructor (pSelf, parameter, ccsFALSE, error ) == ERROR ) + { + return ERROR; + } + return OK; +} + + + +/* + * Destructor Hooks - Called when the block is removed from the algorithm (DELBLCK or new CONFIG commands) + */ + +void tacReadRmnBlockDestructor (tacSTDBLOCK* pSelf) /* Reference to the block instance */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = NULL; + pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + pSelfParam->handleValid = rmassACCESS_BLOCKED; + /* wait until semaphore is acknowledged by realtime algo + * or just procede if realtime is not active */ + while ((*pSelf->shared).active && pSelfParam->handleValid != rmassACCESS_BLOCK_ACKN) + { + taskDelay(1); + } + + rmassDetach (&pSelfParam->handle); + + return; +} + +/* + * Change parameters Hooks - Called when modifying the block parameters (MODBLCK command) + */ + +STATUS tacReadRmnBlockSetParameter (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the MODBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + if ( tacReadRmnBlockCheckParameter (pSelf, parameter, error) == ERROR) + { + return ERROR; + } + + pSelfParam->handleValid = rmassACCESS_BLOCKED; + /* wait until semaphore is acknowledged by realtime algo + * or just procede if realtime is not active */ + while ((*pSelf->shared).active && pSelfParam->handleValid != rmassACCESS_BLOCK_ACKN) + { + taskDelay(1); + } + + /* detach RMN handle */ + if ( rmassDetach (&pSelfParam->handle) != SUCCESS ) + { + char errorParam[40]; + + sprintf(errorParam, "rmassDetach returned error."); + tacRTC_ERR(tacERR_INTERNAL, errorParam); + return ERROR; + } + + if ( rmassReadAttach (&pSelfParam->handle, + pSelfParam->fieldString, + &pSelfParam->val[0], + &pSelfParam->val[1], + &pSelfParam->val[2], + &pSelfParam->val[3], + &pSelfParam->val[4], + &pSelfParam->val[5], + &pSelfParam->val[6], + &pSelfParam->val[7], + &pSelfParam->val[8], + &pSelfParam->val[9]) != SUCCESS ) + { + char errorParam[40]; + + sprintf(errorParam, "Attach to RMN failed."); + tacRTC_ERR(tacERR_INTERNAL, errorParam); + return ERROR; + } + + pSelfParam->handleValid = rmassACCESS_FREE; + + return OK; +} + +STATUS tacReadRfmBlockSetParameter (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the MODBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + if ( tacReadRfmBlockCheckParameter (pSelf, parameter, error) == ERROR) + { + return ERROR; + } + + pSelfParam->handleValid = rmassACCESS_BLOCKED; + /* wait until semaphore is acknowledged by realtime algo + * or just procede if realtime is not active */ + while ((*pSelf->shared).active && pSelfParam->handleValid != rmassACCESS_BLOCK_ACKN) + { + taskDelay(1); + } + + /* detach RMN handle */ + if ( rmassDetach (&pSelfParam->handle) != SUCCESS ) + { + char errorParam[40]; + + sprintf(errorParam, "rmassDetach returned error."); + tacRTC_ERR(tacERR_INTERNAL, errorParam); + return ERROR; + } + + if ( rmassReadAttach (&pSelfParam->handle, + pSelfParam->fieldString, + &pSelfParam->val[0], + &pSelfParam->val[1], + &pSelfParam->val[2], + &pSelfParam->val[3], + &pSelfParam->val[4], + &pSelfParam->val[5], + &pSelfParam->val[6], + &pSelfParam->val[7], + &pSelfParam->val[8], + &pSelfParam->val[9]) != SUCCESS ) + { + char errorParam[40]; + + sprintf(errorParam, "Attach to RFM failed."); + tacRTC_ERR(tacERR_INTERNAL, errorParam); + return ERROR; + } + + pSelfParam->handleValid = rmassACCESS_FREE; + + return OK; +} + +/* + * Algorithm Hooks - Called at each time the TAC algorithm is evaluated (ONLINE state) + */ + +void tacReadRmnBlockAlgorithm (tacSTDBLOCK* pSelf) /* Reference to the block instance */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + int i; + + if ( pSelfParam->handleValid == rmassACCESS_BLOCKED ) + { + pSelfParam->handleValid = rmassACCESS_BLOCK_ACKN; + } + + if ( pSelfParam->handleValid == rmassACCESS_FREE ) + { + /* actual RMN read operation */ + rmassReadAccessRmn (&pSelfParam->handle); + + /* Write to outputs */ + for (i=0; i < pSelfParam->numFields; i++) + { + switch (pSelfParam->type[i]) + { + case rmassTIMESEC: + case rmassUINT32: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).ui); + break; + case rmassTIMEUSEC: + case rmassINT32: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).i); + break; + case rmassFLOAT: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).f); + break; + default: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).d); + break; + } + } + + /* provide zero values at unsatisfied outputs + * I consider this a good thing to do since the block + * is always configured */ + for (i=pSelfParam->numFields; i < tacREAD_RMN_DEFAULT_OUTPUT_NUMBER; i++) + { + tacStdBlockSetOutput(pSelf, i, 0.0); + } + } +} + +void tacReadRfmBlockAlgorithm (tacSTDBLOCK* pSelf) /* Reference to the block instance */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + int i; + + if ( pSelfParam->handleValid == rmassACCESS_BLOCKED ) + { + pSelfParam->handleValid = rmassACCESS_BLOCK_ACKN; + } + + if ( pSelfParam->handleValid == rmassACCESS_FREE ) + { + /* actual RMN read operation */ + rmassReadAccessRfm (&pSelfParam->handle); + + /* Write to outputs */ + for (i=0; i < pSelfParam->numFields; i++) + { + switch (pSelfParam->type[i]) + { + case rmassTIMESEC: + case rmassUINT32: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).ui); + break; + case rmassTIMEUSEC: + case rmassINT32: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).i); + break; + case rmassFLOAT: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).f); + break; + default: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).d); + break; + } + } + + /* provide zero values at unsatisfied outputs + * I consider this a good thing to do since the block + * is always configured */ + for (i=pSelfParam->numFields; i < tacREAD_RMN_DEFAULT_OUTPUT_NUMBER; i++) + { + tacStdBlockSetOutput(pSelf, i, 0.0); + } + } +} + +/* + * Show Hooks - Called when the tacRtcTaskShow routine is executed + */ + +void tacReadRmnBlockShow (tacSTDBLOCK* pSelf) /* Reference to the block instance */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + /* Print parameter values */ + printf(" Attached: %s\n", pSelfParam->fieldString); + + return; +} + + +/***************************************************/ +/* The following code is common to all block types */ +/* Do not modify without any good reasons */ +/***************************************************/ + +/* + * Installation function + */ + +tacSTDBLOCK_TYPE tacReadRmnTypeInfo = { + "ReadRmn", + &tacReadRmnBlockConstructor, + &tacRmBlockGetParameter, + &tacReadRmnBlockAlgorithm, + &tacReadRmnBlockSetParameter, + NULL, + NULL, + &tacReadRmnBlockDestructor, + &tacReadRmnBlockShow +}; + +tacSTDBLOCK_TYPE tacReadRfmTypeInfo = { + "ReadRfm", + &tacReadRfmBlockConstructor, + &tacRmBlockGetParameter, + &tacReadRfmBlockAlgorithm, + &tacReadRmnBlockSetParameter, + NULL, + NULL, + &tacReadRmnBlockDestructor, + &tacReadRmnBlockShow +}; + +STATUS tacReadRmnBlockInitAll (void) +{ + /***************************************************/ + /* The following code is common to all block types */ + /* Do not modify without any good reasons */ + /***************************************************/ + + /* Install ReadRmn1g Block Hooks */ + tacStdBlockInstallNewType(&tacReadRmnTypeInfo); + + /*****************************/ + /* End of common code region */ + /*****************************/ + + /* Perform other library initialization operations */ + + return OK; +} + +STATUS tacReadRfmBlockInitAll (void) +{ + /***************************************************/ + /* The following code is common to all block types */ + /* Do not modify without any good reasons */ + /***************************************************/ + + /* Install ReadRmn1g Block Hooks */ + tacStdBlockInstallNewType(&tacReadRfmTypeInfo); + + /*****************************/ + /* End of common code region */ + /*****************************/ + + /* Perform other library initialization operations */ + + return OK; +} + +/*___oOo___*/ + + + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3624768 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +__pycache__ +out +tacapp.tar.gz +Sources +tacapp +worryingFiles +cc.tar.gz diff --git a/errors.json b/errors.json new file mode 100644 index 0000000..5ec898a --- /dev/null +++ b/errors.json @@ -0,0 +1,4 @@ +{ + "missing_blocks": [], + "multiple_definitions": [] +} \ No newline at end of file diff --git a/hardcodedFiles/tacReadRmnBlock.c b/hardcodedFiles/tacReadRmnBlock.c new file mode 100644 index 0000000..8acbcfa --- /dev/null +++ b/hardcodedFiles/tacReadRmnBlock.c @@ -0,0 +1,568 @@ +/******************************************************************************* +* E.S.O. - VLT project +* +* "@(#) $Id: tacReadRmnBlock.c 305476 2018-01-19 08:56:18Z rfrahm $" +* +* who when what +* ------- -------- ---------------------------------------------- +* gzins 2010-07-27 ported to VLTSW2010 and VxWorks 6.4 +* swehner 2008-10-10 creation +*/ + +/************************************************************************ +* NAME +* tacReadRmnBlock - Implemements the standard functions for the +* tacReadRmn block and tacReadRfm block. +* tacReadRmnBlock - Reads from 1rst generation reflective memory network +* tacReadRfmBlock - Reads from 2nd generation reflective memory network + +* Parameters: +* field - token names for the RMN fields to read (up to 10) +* Inputs: 0 +* Outputs: 1 +* output - 1..10 depending on number of field parameters +* +* +* +* FILES +* +* ENVIRONMENT +* TAC +* +* RETURN VALUES +* +* CAUTIONS +* +* EXAMPLES +* TAC.BLOCK9.TYPE ReadRmn +* TAC.BLOCK9.NAME ReadRmn +* +* SEE ALSO +* +* BUGS +* +*------------------------------------------------------------------------ +*/ + +#define _POSIX_SOURCE 1 +#include "vltPort.h" + +ATTRIBUTE_UNUSED static const char *rcsId="@(#) $Id: tacReadRmnBlock.c 305476 2018-01-19 08:56:18Z rfrahm $"; + +/* + * System Headers + */ + +#include /* taskSpawn, taskDelay, ... */ +#include /* printf ... */ +#include /* malloc ... */ +#include /* malloc ... */ +#include +#include + +/* + * Local Headers + */ + +#include "tacStdBlock.h" +#include "tacRmnBlock.h" +#include "rmassPublic.h" +#include "rmassPrivate.h" + +/* + * Compilation directives + */ + +/* + * Constants + */ + +#define tacREAD_RMN_EXPECTED_PARAM 1 +#define tacREAD_RMN_DEFAULT_INPUT_NUMBER 0 +#define tacREAD_RMN_DEFAULT_OUTPUT_NUMBER tacMAX_DATA_NUMBER + +#define tacREAD_RMN_FIELD_STRING_LEN 256 +#define tacSTRLEN sizeof(double) + +/* + * Types + */ + +/* + * Local function declaration + */ + +/* + * Global variables + */ + +/* + * Function definition + */ + + +STATUS tacReadRmnBlockCheckParameter (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the ADDBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = NULL; + + pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + /* field string is built from block params */ + if ( tacRmnBlockCheckParameter ( pSelf, parameter, 0, error) != OK ) + { + return ERROR; + } + + /* useful information on the screen */ + printf ("ReadRmn %s: [%s]\n", pSelf->name, pSelfParam->fieldString); + + return OK; +} + +STATUS tacReadRfmBlockCheckParameter (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the ADDBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = NULL; + + pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + /* field string is built from block params */ + if ( tacRmnBlockCheckParameter ( pSelf, parameter, 0, error) != OK ) + { + return ERROR; + } + + /* useful information on the screen */ + printf ("ReadRfm %s: [%s]\n", pSelf->name, pSelfParam->fieldString); + + return OK; +} + +/* + * Constructor Hooks - Called when a block of this type is instanciated (CONFIG or ADDBLCK commands) + */ + +STATUS tacReadRmBlockConstructor (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the ADDBLCK command */ + vltLOGICAL isRmn, + tacERROR* error) /* Error structure - not a stack */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = NULL; + + /* Check that the expected number of parameters has been received */ + if (parameter->number < tacREAD_RMN_EXPECTED_PARAM) + { + char errorParam[40]; + + sprintf(errorParam, "Expected at least %d, received %d", tacREAD_RMN_EXPECTED_PARAM, parameter->number); + tacRTC_ERR(tacERR_PARAM_NUMBER, errorParam); + return ERROR; + } + + /* Allocate and initialize block-specific arrays */ + if (tacStdBlockAllocateArrays(pSelf, 0, tacREAD_RMN_DEFAULT_INPUT_NUMBER, tacREAD_RMN_DEFAULT_OUTPUT_NUMBER, error) == ERROR) + { + return ERROR; + } + + if (tacStdBlockAllocateArrayBySize(pSelf, tacSTDBLOCK_PARAM_ARRAY, sizeof(tacRMN_LOCAL_PARAMETER), error) == ERROR) + { + tacStdBlockReleaseArray(pSelf, tacSTDBLOCK_INPUT_ARRAY, error); + tacStdBlockReleaseArray(pSelf, tacSTDBLOCK_OUTPUT_ARRAY, error); + return ERROR; + } + + if ( isRmn ) + { + if ( tacReadRmnBlockCheckParameter (pSelf, parameter, error) == ERROR) + { + return ERROR; + } + } + else + { + if ( tacReadRfmBlockCheckParameter (pSelf, parameter, error) == ERROR) + { + return ERROR; + } + } + + pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + pSelfParam->handleValid = rmassACCESS_BLOCKED; + + /* Attach to RMN */ + if ( rmassReadAttach (&pSelfParam->handle, + pSelfParam->fieldString, + &pSelfParam->val[0], + &pSelfParam->val[1], + &pSelfParam->val[2], + &pSelfParam->val[3], + &pSelfParam->val[4], + &pSelfParam->val[5], + &pSelfParam->val[6], + &pSelfParam->val[7], + &pSelfParam->val[8], + &pSelfParam->val[9]) != SUCCESS ) + { + char errorParam[40]; + + sprintf(errorParam, "Attach to RMN failed."); + tacRTC_ERR(tacERR_INTERNAL, errorParam); + return ERROR; + } + + pSelfParam->handleValid = rmassACCESS_FREE; + + return OK; +} + +STATUS tacReadRmnBlockConstructor (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the ADDBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + if ( tacReadRmBlockConstructor (pSelf, parameter, ccsTRUE, error ) == ERROR ) + { + return ERROR; + } + return OK; +} + +STATUS tacReadRfmBlockConstructor (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the ADDBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + if ( tacReadRmBlockConstructor (pSelf, parameter, ccsFALSE, error ) == ERROR ) + { + return ERROR; + } + return OK; +} + + + +/* + * Destructor Hooks - Called when the block is removed from the algorithm (DELBLCK or new CONFIG commands) + */ + +void tacReadRmnBlockDestructor (tacSTDBLOCK* pSelf) /* Reference to the block instance */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = NULL; + pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + pSelfParam->handleValid = rmassACCESS_BLOCKED; + /* wait until semaphore is acknowledged by realtime algo + * or just procede if realtime is not active */ + while ((*pSelf->shared).active && pSelfParam->handleValid != rmassACCESS_BLOCK_ACKN) + { + taskDelay(1); + } + + rmassDetach (&pSelfParam->handle); + + return; +} + +/* + * Change parameters Hooks - Called when modifying the block parameters (MODBLCK command) + */ + +STATUS tacReadRmnBlockSetParameter (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the MODBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + if ( tacReadRmnBlockCheckParameter (pSelf, parameter, error) == ERROR) + { + return ERROR; + } + + pSelfParam->handleValid = rmassACCESS_BLOCKED; + /* wait until semaphore is acknowledged by realtime algo + * or just procede if realtime is not active */ + while ((*pSelf->shared).active && pSelfParam->handleValid != rmassACCESS_BLOCK_ACKN) + { + taskDelay(1); + } + + /* detach RMN handle */ + if ( rmassDetach (&pSelfParam->handle) != SUCCESS ) + { + char errorParam[40]; + + sprintf(errorParam, "rmassDetach returned error."); + tacRTC_ERR(tacERR_INTERNAL, errorParam); + return ERROR; + } + + if ( rmassReadAttach (&pSelfParam->handle, + pSelfParam->fieldString, + &pSelfParam->val[0], + &pSelfParam->val[1], + &pSelfParam->val[2], + &pSelfParam->val[3], + &pSelfParam->val[4], + &pSelfParam->val[5], + &pSelfParam->val[6], + &pSelfParam->val[7], + &pSelfParam->val[8], + &pSelfParam->val[9]) != SUCCESS ) + { + char errorParam[40]; + + sprintf(errorParam, "Attach to RMN failed."); + tacRTC_ERR(tacERR_INTERNAL, errorParam); + return ERROR; + } + + pSelfParam->handleValid = rmassACCESS_FREE; + + return OK; +} + +STATUS tacReadRfmBlockSetParameter (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the MODBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + if ( tacReadRfmBlockCheckParameter (pSelf, parameter, error) == ERROR) + { + return ERROR; + } + + pSelfParam->handleValid = rmassACCESS_BLOCKED; + /* wait until semaphore is acknowledged by realtime algo + * or just procede if realtime is not active */ + while ((*pSelf->shared).active && pSelfParam->handleValid != rmassACCESS_BLOCK_ACKN) + { + taskDelay(1); + } + + /* detach RMN handle */ + if ( rmassDetach (&pSelfParam->handle) != SUCCESS ) + { + char errorParam[40]; + + sprintf(errorParam, "rmassDetach returned error."); + tacRTC_ERR(tacERR_INTERNAL, errorParam); + return ERROR; + } + + if ( rmassReadAttach (&pSelfParam->handle, + pSelfParam->fieldString, + &pSelfParam->val[0], + &pSelfParam->val[1], + &pSelfParam->val[2], + &pSelfParam->val[3], + &pSelfParam->val[4], + &pSelfParam->val[5], + &pSelfParam->val[6], + &pSelfParam->val[7], + &pSelfParam->val[8], + &pSelfParam->val[9]) != SUCCESS ) + { + char errorParam[40]; + + sprintf(errorParam, "Attach to RFM failed."); + tacRTC_ERR(tacERR_INTERNAL, errorParam); + return ERROR; + } + + pSelfParam->handleValid = rmassACCESS_FREE; + + return OK; +} + +/* + * Algorithm Hooks - Called at each time the TAC algorithm is evaluated (ONLINE state) + */ + +void tacReadRmnBlockAlgorithm (tacSTDBLOCK* pSelf) /* Reference to the block instance */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + int i; + + if ( pSelfParam->handleValid == rmassACCESS_BLOCKED ) + { + pSelfParam->handleValid = rmassACCESS_BLOCK_ACKN; + } + + if ( pSelfParam->handleValid == rmassACCESS_FREE ) + { + /* actual RMN read operation */ + rmassReadAccessRmn (&pSelfParam->handle); + + /* Write to outputs */ + for (i=0; i < pSelfParam->numFields; i++) + { + switch (pSelfParam->type[i]) + { + case rmassTIMESEC: + case rmassUINT32: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).ui); + break; + case rmassTIMEUSEC: + case rmassINT32: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).i); + break; + case rmassFLOAT: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).f); + break; + default: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).d); + break; + } + } + + /* provide zero values at unsatisfied outputs + * I consider this a good thing to do since the block + * is always configured */ + for (i=pSelfParam->numFields; i < tacREAD_RMN_DEFAULT_OUTPUT_NUMBER; i++) + { + tacStdBlockSetOutput(pSelf, i, 0.0); + } + } +} + +void tacReadRfmBlockAlgorithm (tacSTDBLOCK* pSelf) /* Reference to the block instance */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + int i; + + if ( pSelfParam->handleValid == rmassACCESS_BLOCKED ) + { + pSelfParam->handleValid = rmassACCESS_BLOCK_ACKN; + } + + if ( pSelfParam->handleValid == rmassACCESS_FREE ) + { + /* actual RMN read operation */ + rmassReadAccessRfm (&pSelfParam->handle); + + /* Write to outputs */ + for (i=0; i < pSelfParam->numFields; i++) + { + switch (pSelfParam->type[i]) + { + case rmassTIMESEC: + case rmassUINT32: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).ui); + break; + case rmassTIMEUSEC: + case rmassINT32: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).i); + break; + case rmassFLOAT: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).f); + break; + default: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).d); + break; + } + } + + /* provide zero values at unsatisfied outputs + * I consider this a good thing to do since the block + * is always configured */ + for (i=pSelfParam->numFields; i < tacREAD_RMN_DEFAULT_OUTPUT_NUMBER; i++) + { + tacStdBlockSetOutput(pSelf, i, 0.0); + } + } +} + +/* + * Show Hooks - Called when the tacRtcTaskShow routine is executed + */ + +void tacReadRmnBlockShow (tacSTDBLOCK* pSelf) /* Reference to the block instance */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + /* Print parameter values */ + printf(" Attached: %s\n", pSelfParam->fieldString); + + return; +} + + +/***************************************************/ +/* The following code is common to all block types */ +/* Do not modify without any good reasons */ +/***************************************************/ + +/* + * Installation function + */ + +tacSTDBLOCK_TYPE tacReadRmnTypeInfo = { + "ReadRmn", + &tacReadRmnBlockConstructor, + &tacRmBlockGetParameter, + &tacReadRmnBlockAlgorithm, + &tacReadRmnBlockSetParameter, + NULL, + NULL, + &tacReadRmnBlockDestructor, + &tacReadRmnBlockShow +}; + +tacSTDBLOCK_TYPE tacReadRfmTypeInfo = { + "ReadRfm", + &tacReadRfmBlockConstructor, + &tacRmBlockGetParameter, + &tacReadRfmBlockAlgorithm, + &tacReadRmnBlockSetParameter, + NULL, + NULL, + &tacReadRmnBlockDestructor, + &tacReadRmnBlockShow +}; + +STATUS tacReadRmnBlockInitAll (void) +{ + /***************************************************/ + /* The following code is common to all block types */ + /* Do not modify without any good reasons */ + /***************************************************/ + + /* Install ReadRmn1g Block Hooks */ + tacStdBlockInstallNewType(&tacReadRmnTypeInfo); + + /*****************************/ + /* End of common code region */ + /*****************************/ + + /* Perform other library initialization operations */ + + return OK; +} + +STATUS tacReadRfmBlockInitAll (void) +{ + /***************************************************/ + /* The following code is common to all block types */ + /* Do not modify without any good reasons */ + /***************************************************/ + + /* Install ReadRmn1g Block Hooks */ + tacStdBlockInstallNewType(&tacReadRfmTypeInfo); + + /*****************************/ + /* End of common code region */ + /*****************************/ + + /* Perform other library initialization operations */ + + return OK; +} + +/*___oOo___*/ + + + diff --git a/hardcodedFiles/tacSinkBlock.c b/hardcodedFiles/tacSinkBlock.c new file mode 100644 index 0000000..df39833 --- /dev/null +++ b/hardcodedFiles/tacSinkBlock.c @@ -0,0 +1,1256 @@ +/******************************************************************************* +* E.S.O. - VLT project +* +* "@(#) $Id: tacSinkBlock.c 339094 2021-02-10 03:10:02Z jgil $" +* +* who when what +* ------- -------- ---------------------------------------------- +* rdembet 06/08/20 New MonitorState block with no data averaging +* swehner 28/11/09 SPR20090234 Correction in rate adjustment in reset hook +* swehner 27/11/09 Fixed message queue handling +* swehner 10/10/09 New block FastProbe for unlimited rec frequency +* swehner 22/09/09 PPRS 32341 Replaced specialized tacSINK_SHMSG stack +* with standard vxWorks message queue. +* bbauvir 21/09/04 VLTSW20040113 - One sample might be lost +* bbauvir 29/03/04 Monitor block averages over the reporting period +* bbauvir 29/12/02 Probe to the SampTask +* bbauvir 26/12/02 MsgQ access through DPC mechanism +* bbauvir 14/07/02 New MsgQ of TAC version 1.22 +* bbauvir 21/03/01 Created +*/ + +/************************************************************************ +* NAME +* tacSinkBlock - Standard data monitoring blocks +* +* SYNOPSIS +* lcubootAutoCdBoot 1,"tacsink.boot" +* < tacsink.boot +* +* DESCRIPTION +* Block type: Display +* Parameters: +* Inputs: 1 +* Outputs: none +* +* This function block samples the value of its input signal at the +* specified and issues a message containing the time +* and the value of the input on the vxWorks terminal. +* It does not allow modification of the parameter at runtime. +* +* Block type: Monitor +* Parameters: +* +* Inputs: 10max +* Outputs: none +* +* This function block samples the value of its input signals at the +* specified (0.0 to send a message at the system sampling +* period) and issues a message containing the time and the value of +* the inputs on the shared memory. This message is intercepted by the +* background task running on the master CPU. The monitored values are +* written into the online database. The number of inputs of the block +* is specified by parameter. +* This block does not allow modification of the parameters at runtime. +* +* Block type: MonitorState +* Parameters: +* +* Inputs: 10max +* Outputs: none +* +* Same as Monitor block but without the averaging of received data, +* see VLTSW-14260 JIRA ticket. +* +* Block type: Probe +* Parameters: +* +* Inputs: 10max +* Outputs: none +* +* Block type: FastProbe +* Parameters: +* +* Inputs: 10max +* Outputs: none +* +* This function block samples the value of its input signals at the +* specified (0.0 to send a message at the system sampling +* period) and issues a message containing the time and the value of +* the inputs on the shared memory. This message is intercepted by the +* background task running on the master CPU. The number of inputs of +* the block is specified by parameter. +* This message is passed to an external application callback if +* provided. +* This block does not allow modification of the parameters at runtime. +* The normal Probe block has a limited sampling frequency of not more +* than 2kHz. The reason is in particular the bottleneck between master +* and slave CPU which all samples have to pass through a mechanism of +* VME bus shared memory. On one-CPU-systems this limitation does not +* apply so you are free to choose faster sampling. You may of course +* hit other limitations (processor speed, network traffic etc.) +* +* FILES +* +* ENVIRONMENT +* TAC +* +* RETURN VALUES +* +* CAUTIONS +* All these blocks compute an decimation value to use to trigger the +* sampling of the input signals, from the system sampling period. +* They should be created after any synchronization block. +* +* In order to cope with system performances, a minimum +* is defined for each block. The minimum applied periods are 0.1 (10Hz), +* 0.01 (100Hz) and 0.5e-3 (2kHz) for the 'Display', 'Monitor' and +* 'Probe' blocks respectively. +* +* EXAMPLES +* # 5 signals @ 2Hz (monitored in the database) +* TAC.BLOCK9.TYPE Monitor +* TAC.BLOCK9.NAME Monitor +* TAC.BLOCK9.PARAM 0.5, 5 +* +* # 5 signals @ the RT algorithm sampling period (0.0) +* TAC.BLOCK10.TYPE Probe +* TAC.BLOCK10.NAME Probe +* TAC.BLOCK10.PARAM 0.0, 5 +* +* SEE ALSO +* tacServerInstallDataCallback, tacServerRemoveDataCallback +* +* BUGS +* +*------------------------------------------------------------------------ +*/ + +#define _POSIX_SOURCE 1 +#include "vltPort.h" + + +/* + * System Headers + */ + +#include +#include +#include /* logMsg ... */ +#include /* printf ... */ +#include /* malloc ... */ +#include /* memcpy ... */ +#include + +/* + * Local Headers + */ + +#include "tacStdBlock.h" +#include "tacShMsgQ.h" + +/* + * Compilation directives + */ + +/* + * Constants + */ + +#define tacSINK_DEFAULT_EXPECTED_PARAM 2 + +#define tacSINK_DEFAULT_INPUT_NUMBER tacMAX_DATA_NUMBER /* Up to 10 input channels */ +#define tacSINK_DEFAULT_OUTPUT_NUMBER tacMAX_DATA_NUMBER + +#define tacSINK_ONE_EXPECTED_PARAM 1 +#define tacSINK_ONE_INPUT_NUMBER 1 + +#define tacSINK_DISPLAY_MIN_SAMPLING_PERIOD .1 /* 10Hz */ +#define tacSINK_MONITOR_MIN_SAMPLING_PERIOD .01 /* 100Hz */ +#define tacSINK_PROBE_MIN_SAMPLING_PERIOD .5e-3 /* 2kHz */ + +#define tacSINK_DISPLAY_LOG_STRING_SIZE 128 + +#define tacSINK_MONITOR_DEFAULT_DB_POINT "tac:data:monitor" +#define tacSINK_MONITOR_MAX_DB_ADDR_SIZE 64 + +#define tacSINK_MONITOR_QUEUE_SIZE 6 +#define tacSINK_PROBE_QUEUE_SIZE 6 + + +typedef enum { + tacSINK_SAMPLING_PERIOD = 0, + tacSINK_INPUT_NUMBER, + tacSINK_MONITOR_DB_POINT, +}tacSINK_SCOPE_PARAM_INDEX; + +/* + * Types + */ + +typedef struct { + unsigned short rate; + unsigned short counter; + unsigned short inputNb; + unsigned int lost; + double rateParam; + char* dbPoint; + MSG_Q_ID msgq; + tacSHMSG shmMsg; +}tacSINK_SCOPE_LOCAL_PARAMETER; + +/* + * Function declaration + */ + +extern STATUS tacDpcPushRequest(tacVOIDFCTPTR pFunct, void* parameter); + +/* + * Local function declaration + */ + +/* + * Note: Routines called from within the algorithm must be declared with + * static __inline__ + */ + +STATUS tacSinkSendMonitorMessage(MSG_Q_ID * msgqvoid); +STATUS tacSinkSendMonitorStateMessage(MSG_Q_ID * msgqvoid); +STATUS tacSinkSendProbeMessage(MSG_Q_ID * msgq); +STATUS tacSinkDeleteMessageQueue(MSG_Q_ID * msgq); +STATUS tacSinkCommonBlockConstructor(tacSTDBLOCK* pSelf, tacERROR* error); + +/* + * Global variables + */ + +char logStr[tacSINK_DISPLAY_LOG_STRING_SIZE]; /* Logging string used for Display */ + + +/* + * Function definition + */ + +/* + * Constructor Hooks + */ + +STATUS tacSinkDisplayBlockConstructor (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = NULL; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = NULL; + + /* Check that the expected number of parameters has been received */ + if (parameter->number < tacSINK_ONE_EXPECTED_PARAM) + { + char errorParam[40]; + + sprintf(errorParam, "Expected %d, received %d", tacSINK_ONE_EXPECTED_PARAM, parameter->number); + tacRTC_ERR(tacERR_PARAM_NUMBER, errorParam); + return ERROR; + } + + /* Check that the parameters are valid */ + pRealParam = (double*) parameter->buffer; + + /* Passed parameter is the sampling period of the block */ + if (pRealParam[tacSINK_SAMPLING_PERIOD] < (*pSelf->shared).samplingPeriod) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = (*pSelf->shared).samplingPeriod; + } + + if (pRealParam[tacSINK_SAMPLING_PERIOD] < tacSINK_DISPLAY_MIN_SAMPLING_PERIOD) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = tacSINK_DISPLAY_MIN_SAMPLING_PERIOD; + } + + /* Call common constructor */ + if (tacSinkCommonBlockConstructor(pSelf, error) != OK) + { + return ERROR; + } + + /* Store parameters */ + pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; /* We will only store short integers */ + + /* + * Compute the rate at which data has to be processed - divide and take + * the integer part of the result + */ + + pSelfParam->rate = (unsigned short) (pRealParam[tacSINK_SAMPLING_PERIOD] / (*pSelf->shared).samplingPeriod); + pSelfParam->counter = 0; /* Decimation counter */ + + /* + * Perform other block initialization operations + */ + + return OK; +} + +STATUS tacSinkMonitorBlockConstructor (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = NULL; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = NULL; + unsigned short arrayIndex = 0; + + /* Check that the expected number of parameters has been received */ + if (parameter->number < tacSINK_DEFAULT_EXPECTED_PARAM) + { + char errorParam[40]; + + sprintf(errorParam, "Expected %d, received %d", tacSINK_DEFAULT_EXPECTED_PARAM, parameter->number); + tacRTC_ERR(tacERR_PARAM_NUMBER, errorParam); + return ERROR; + } + + /* Check that the parameters are valid */ + pRealParam = (double*) parameter->buffer; + + /* Passed parameter is the sampling period of the block */ + if (pRealParam[tacSINK_SAMPLING_PERIOD] < (*pSelf->shared).samplingPeriod) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = (*pSelf->shared).samplingPeriod; + } + + if (pRealParam[tacSINK_SAMPLING_PERIOD] < tacSINK_MONITOR_MIN_SAMPLING_PERIOD) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = tacSINK_MONITOR_MIN_SAMPLING_PERIOD; + } + + /* Number of inputs is minimum 1 up to tacMSG_MAX_DATA_NUMBER */ + if ((pRealParam[tacSINK_INPUT_NUMBER] < 1) || + (pRealParam[tacSINK_INPUT_NUMBER] > tacMAX_DATA_NUMBER)) + { + tacRTC_ERR(tacERR_PARAM_INVALID, ""); + return ERROR; + } + + /* Call common constructor */ + if (tacSinkCommonBlockConstructor(pSelf, error) != OK) + { + return ERROR; + } + + /* Store parameters */ + pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* + * Compute the rate at which data has to be processed - divide and take + * the integer part of the result + */ + + pSelfParam->rate = (unsigned short) (pRealParam[tacSINK_SAMPLING_PERIOD] / (*pSelf->shared).samplingPeriod); + pSelfParam->counter = 0; /* Decimation counter */ + pSelfParam->inputNb = (unsigned short) pRealParam[tacSINK_INPUT_NUMBER]; + + /* Optional parameter is an application-specific DB point */ + if (parameter->number == tacSINK_DEFAULT_EXPECTED_PARAM + 1) + { + printf("tacSinkMonitorBlockConstructor - DB point %s\n",(char*) &(pRealParam[tacSINK_MONITOR_DB_POINT])); + pSelfParam->dbPoint = (char*) malloc(tacSINK_MONITOR_MAX_DB_ADDR_SIZE); + strcpy(pSelfParam->dbPoint, (char*) &(pRealParam[tacSINK_MONITOR_DB_POINT])); + } + else + { + printf("tacSinkMonitorBlockConstructor - Default DB point\n"); + pSelfParam->dbPoint = NULL; + } + + /* Specify the number of input signals to attach to become resolved */ + tacStdBlockSetInputNumber(pSelf, pSelfParam->inputNb); + + /* + * Perform other block initialization operations + */ + + /* Create the block internal message queue which tosses the messages out of the + * interrupt context. They are buffered in the queue until the DPC tasks + * picks them up and sends them over the shared memory message queue. + * Sorry for that double-queuing, that's because of the M-S architecture */ + + pSelfParam->msgq = msgQCreate(tacSINK_MONITOR_QUEUE_SIZE, sizeof(tacSHMSG), 0); + if ( pSelfParam->msgq == NULL ) + { + char errorParam[40]; + + sprintf(errorParam, "Could not create probe block message queue"); + tacRTC_ERR(tacERR_MALLOC, errorParam); + return ERROR; + } + + /* will count if a message can't be pushed in the queue */ + pSelfParam->lost = 0; + + /* Warn the background task that a new probe block has been created */ + pSelfParam->shmMsg.type = tacSHMSG_ADD_MONITOR; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + + if (pSelfParam->dbPoint == NULL) + { + strcpy((char*) &(pSelfParam->shmMsg.msgBody.monitor.data), tacSINK_MONITOR_DEFAULT_DB_POINT); + } + else + { + strcpy((char*) &(pSelfParam->shmMsg.msgBody.monitor.data), *((char**) &(pSelfParam->dbPoint))); + } + + printf("tacSinkMonitorBlockConstructor - Attach to %s\n",(char*) &(pSelfParam->shmMsg.msgBody.monitor.data)); + + /* Send message */ + tacShMsgQSendBgInfo(&(pSelfParam->shmMsg)); + + /* Initialize the message parameters */ + pSelfParam->shmMsg.type = tacSHMSG_MONITOR_DATA; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + pSelfParam->shmMsg.msgBody.monitor.data.number = pSelfParam->inputNb; + + /* The output port is used to average the inputs over the reporting period */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pSelf->output[arrayIndex] = 0.0; + } + + return OK; +} + +STATUS tacSinkMonitorStateBlockConstructor (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = NULL; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = NULL; + unsigned short arrayIndex = 0; + + /* Check that the expected number of parameters has been received */ + if (parameter->number < tacSINK_DEFAULT_EXPECTED_PARAM) + { + char errorParam[40]; + + sprintf(errorParam, "Expected %d, received %d", tacSINK_DEFAULT_EXPECTED_PARAM, parameter->number); + tacRTC_ERR(tacERR_PARAM_NUMBER, errorParam); + return ERROR; + } + + /* Check that the parameters are valid */ + pRealParam = (double*) parameter->buffer; + + /* Passed parameter is the sampling period of the block */ + if (pRealParam[tacSINK_SAMPLING_PERIOD] < (*pSelf->shared).samplingPeriod) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = (*pSelf->shared).samplingPeriod; + } + + if (pRealParam[tacSINK_SAMPLING_PERIOD] < tacSINK_MONITOR_MIN_SAMPLING_PERIOD) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = tacSINK_MONITOR_MIN_SAMPLING_PERIOD; + } + + /* Number of inputs is minimum 1 up to tacMSG_MAX_DATA_NUMBER */ + if ((pRealParam[tacSINK_INPUT_NUMBER] < 1) || + (pRealParam[tacSINK_INPUT_NUMBER] > tacMAX_DATA_NUMBER)) + { + tacRTC_ERR(tacERR_PARAM_INVALID, ""); + return ERROR; + } + + /* Call common constructor */ + if (tacSinkCommonBlockConstructor(pSelf, error) != OK) + { + return ERROR; + } + + /* Store parameters */ + pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* + * Compute the rate at which data has to be processed - divide and take + * the integer part of the result + */ + + pSelfParam->rate = (unsigned short) (pRealParam[tacSINK_SAMPLING_PERIOD] / (*pSelf->shared).samplingPeriod); + pSelfParam->counter = 0; /* Decimation counter */ + pSelfParam->inputNb = (unsigned short) pRealParam[tacSINK_INPUT_NUMBER]; + + /* Optional parameter is an application-specific DB point */ + if (parameter->number == tacSINK_DEFAULT_EXPECTED_PARAM + 1) + { + printf("tacSinkMonitorStateBlockConstructor - DB point %s\n",(char*) &(pRealParam[tacSINK_MONITOR_DB_POINT])); + pSelfParam->dbPoint = (char*) malloc(tacSINK_MONITOR_MAX_DB_ADDR_SIZE); + strcpy(pSelfParam->dbPoint, (char*) &(pRealParam[tacSINK_MONITOR_DB_POINT])); + } + else + { + printf("tacSinkMonitorStateBlockConstructor - Default DB point\n"); + pSelfParam->dbPoint = NULL; + } + + /* Specify the number of input signals to attach to become resolved */ + tacStdBlockSetInputNumber(pSelf, pSelfParam->inputNb); + + /* + * Perform other block initialization operations + */ + + /* Create the block internal message queue which tosses the messages out of the + * interrupt context. They are buffered in the queue until the DPC tasks + * picks them up and sends them over the shared memory message queue. + * Sorry for that double-queuing, that's because of the M-S architecture */ + + pSelfParam->msgq = msgQCreate(tacSINK_MONITOR_QUEUE_SIZE, sizeof(tacSHMSG), 0); + if ( pSelfParam->msgq == NULL ) + { + char errorParam[40]; + + sprintf(errorParam, "Could not create probe block message queue"); + tacRTC_ERR(tacERR_MALLOC, errorParam); + return ERROR; + } + + /* will count if a message can't be pushed in the queue */ + pSelfParam->lost = 0; + + /* Warn the background task that a new probe block has been created */ + pSelfParam->shmMsg.type = tacSHMSG_ADD_MONITOR; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + + if (pSelfParam->dbPoint == NULL) + { + strcpy((char*) &(pSelfParam->shmMsg.msgBody.monitor.data), tacSINK_MONITOR_DEFAULT_DB_POINT); + } + else + { + strcpy((char*) &(pSelfParam->shmMsg.msgBody.monitor.data), *((char**) &(pSelfParam->dbPoint))); + } + + printf("tacSinkMonitorStateBlockConstructor - Attach to %s\n",(char*) &(pSelfParam->shmMsg.msgBody.monitor.data)); + + /* Send message */ + tacShMsgQSendBgInfo(&(pSelfParam->shmMsg)); + + /* Initialize the message parameters */ + pSelfParam->shmMsg.type = tacSHMSG_MONITOR_DATA; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + pSelfParam->shmMsg.msgBody.monitor.data.number = pSelfParam->inputNb; + + /* Init output port which won't be used to average the inputs over the reporting period */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pSelf->output[arrayIndex] = 0.0; + } + + return OK; +} + +STATUS tacSinkProbeBlockCommonConstructor (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + double minPeriod, + tacERROR* error) +{ + double* pRealParam = NULL; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = NULL; + + /* Check that the expected number of parameters has been received */ + if (parameter->number < tacSINK_DEFAULT_EXPECTED_PARAM) + { + char errorParam[40]; + + sprintf(errorParam, "Expected %d, received %d", tacSINK_DEFAULT_EXPECTED_PARAM, parameter->number); + tacRTC_ERR(tacERR_PARAM_NUMBER, errorParam); + return ERROR; + } + + /* Check that the parameters are valid */ + pRealParam = (double*) parameter->buffer; + + /* Passed parameter is the sampling period of the block */ + if (pRealParam[tacSINK_SAMPLING_PERIOD] < (*pSelf->shared).samplingPeriod) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = (*pSelf->shared).samplingPeriod; + } + + if (pRealParam[tacSINK_SAMPLING_PERIOD] < minPeriod) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = minPeriod; + } + + /* Number of inputs is minimum 1 up to tacMSG_MAX_DATA_NUMBER */ + if ((pRealParam[tacSINK_INPUT_NUMBER] < 1) || + (pRealParam[tacSINK_INPUT_NUMBER] > tacMAX_DATA_NUMBER)) + { + tacRTC_ERR(tacERR_PARAM_INVALID, ""); + return ERROR; + } + + /* Call common constructor */ + if (tacSinkCommonBlockConstructor(pSelf, error) != OK) + { + return ERROR; + } + + /* Store parameters */ + pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* + * Compute the rate at which data has to be processed - divide and take + * the integer part of the result + */ + + pSelfParam->rateParam = pRealParam[tacSINK_SAMPLING_PERIOD]; + pSelfParam->rate = (unsigned short) (pRealParam[tacSINK_SAMPLING_PERIOD] / (*pSelf->shared).samplingPeriod); + pSelfParam->counter = 0; /* Decimation counter */ + pSelfParam->inputNb = (unsigned short) pRealParam[tacSINK_INPUT_NUMBER]; + + /* Specify the number of input signals to attach to become resolved */ + tacStdBlockSetInputNumber(pSelf, pSelfParam->inputNb); + + /* + * Perform other block initialization operations + */ + + /* Create the block internal message queue which gets the messages out of the + * interrupt context. They are buffered in the queue until the DPC tasks + * picks them up and sends them over the shared memory message queue. + * Sorry for that double-queuing, that's because of the M-S architecture */ + + /* There is only one message queue for all probe blocks! */ + pSelfParam->msgq = msgQCreate(tacSINK_PROBE_QUEUE_SIZE, sizeof(tacSHMSG), 0); + if ( pSelfParam->msgq == NULL ) + { + char errorParam[40]; + + sprintf(errorParam, "Could not create probe block message queue"); + tacRTC_ERR(tacERR_MALLOC, errorParam); + return ERROR; + } + + /* will count if a message can't be pushed in the queue */ + pSelfParam->lost = 0; + + /* Warn the background task that a new probe block has been created */ + pSelfParam->shmMsg.type = tacSHMSG_ADD_PROBE; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + + /* Send message */ + tacShMsgQSendDataSample(&pSelfParam->shmMsg); + + /* Initialize the message parameters */ + pSelfParam->shmMsg.type = tacSHMSG_TRANSFER_DATA; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + pSelfParam->shmMsg.msgBody.monitor.data.number = pSelfParam->inputNb; + + return OK; +} + +/* Probe block has a max. sampling frequency of 2kHz */ +STATUS tacSinkProbeBlockConstructor (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + return tacSinkProbeBlockCommonConstructor (pSelf, parameter, tacSINK_PROBE_MIN_SAMPLING_PERIOD, error); +} + +/* Fast probe is the same as probe but not does have the + * limitation on the max. recording frequency */ +STATUS tacSinkFastProbeBlockConstructor (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + return tacSinkProbeBlockCommonConstructor (pSelf, parameter, 0.0, error); +} + +void tacSinkProbeBlockReset (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = + (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* + * Re-Compute the rate at which data has to be processed + */ + if (pSelfParam->rateParam < (*pSelf->shared).samplingPeriod ) + { + pSelfParam->rate = 1; + } + else + { + pSelfParam->rate = (unsigned short) + (pSelfParam->rateParam / (*pSelf->shared).samplingPeriod); + } + + return; +} + +/* + * Report parameters Hooks + */ + +STATUS tacSinkDisplayBlockGetParameter (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = (double*) parameter->buffer; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Send back the expected number of parameters */ + parameter->number = tacSINK_ONE_EXPECTED_PARAM; + + /* Report current parameters */ + pRealParam[tacSINK_SAMPLING_PERIOD] = (double) (pSelfParam->rate * (*pSelf->shared).samplingPeriod); + + return OK; +} + +STATUS tacSinkMonitorBlockGetParameter (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = (double*) parameter->buffer; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Send back the expected number of parameters */ + parameter->number = tacSINK_DEFAULT_EXPECTED_PARAM; + + /* Report current parameters */ + pRealParam[tacSINK_SAMPLING_PERIOD] = (double) (pSelfParam->rate * (*pSelf->shared).samplingPeriod); + pRealParam[tacSINK_INPUT_NUMBER] = (double) pSelfParam->inputNb; + + if (*((char**) &(pSelfParam->dbPoint)) != NULL) + { + parameter->number += 1; + parameter->type[tacSINK_MONITOR_DB_POINT] = tacPARAM_STRING; + strcpy((char*) &(pRealParam[tacSINK_MONITOR_DB_POINT]), *((char**) &(pSelfParam->dbPoint))); + } + + return OK; +} + +STATUS tacSinkMonitorStateBlockGetParameter (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = (double*) parameter->buffer; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Send back the expected number of parameters */ + parameter->number = tacSINK_DEFAULT_EXPECTED_PARAM; + + /* Report current parameters */ + pRealParam[tacSINK_SAMPLING_PERIOD] = (double) (pSelfParam->rate * (*pSelf->shared).samplingPeriod); + pRealParam[tacSINK_INPUT_NUMBER] = (double) pSelfParam->inputNb; + + if (*((char**) &(pSelfParam->dbPoint)) != NULL) + { + parameter->number += 1; + parameter->type[tacSINK_MONITOR_DB_POINT] = tacPARAM_STRING; + strcpy((char*) &(pRealParam[tacSINK_MONITOR_DB_POINT]), *((char**) &(pSelfParam->dbPoint))); + } + + return OK; +} + +STATUS tacSinkProbeBlockGetParameter (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = (double*) parameter->buffer; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Send back the expected number of parameters */ + parameter->number = tacSINK_DEFAULT_EXPECTED_PARAM; + + /* Report current parameters */ + pRealParam[tacSINK_SAMPLING_PERIOD] = (double) (pSelfParam->rate * (*pSelf->shared).samplingPeriod); + pRealParam[tacSINK_INPUT_NUMBER] = (double) pSelfParam->inputNb; + + return OK; +} + +/* + * Change parameters Hooks + */ + +/* + * Algorithm Hooks + */ + +void tacSinkDisplayBlockAlgorithm (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + if ((pSelfParam->counter % pSelfParam->rate) == 0) /* It's time to process data */ + { + sprintf(logStr,"Name: %s Time: %ld.%6ld Value: %g\n", + pSelf->name, + (*pSelf->shared).currentTime.seconds, + (*pSelf->shared).currentTime.microsec, + tacStdBlockGetInput(pSelf,0)); + + tacDpcPushRequest((tacVOIDFCTPTR) &printf, logStr); + + pSelfParam->counter = 0; + } + + pSelfParam->counter++; +} + +void tacSinkMonitorBlockAlgorithm (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + unsigned short arrayIndex = 0; + + /* The output port is used to average the inputs over the reporting period */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pSelf->output[arrayIndex] += tacStdBlockGetInput(pSelf,arrayIndex); + } + + if ((pSelfParam->counter % pSelfParam->rate) == 0) /* It's time to process data */ + { + tacDATA* pData = &(pSelfParam->shmMsg.msgBody.monitor.data); /* We are only interested in message body */ + + /* pData->number = pSelfParam->inputNb; */ + pData->timeStamp = (*pSelf->shared).currentTime; + + /* pData points to the body of the Message */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pData->buffer[arrayIndex] = pSelf->output[arrayIndex] / pSelfParam->rate; + } + + /* Push message into probe block's message que to get the + * data out of the interrupt comtext. */ + if ( msgQSend (pSelfParam->msgq, (char*) &(pSelfParam->shmMsg), sizeof(tacSHMSG), NO_WAIT, 0) != OK ) + { + (pSelfParam->lost)++; + } + + /* Defer procedure call */ + tacDpcPushRequest((tacVOIDFCTPTR) &tacSinkSendMonitorMessage, &pSelfParam->msgq); + + pSelfParam->counter = 0; + + /* The output port is used to average the inputs over the reporting period */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pSelf->output[arrayIndex] = 0.0; + } + } + + pSelfParam->counter++; +} + +void tacSinkMonitorStateBlockAlgorithm (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + unsigned short arrayIndex = 0; + + if ((pSelfParam->counter % pSelfParam->rate) == 0) /* It's time to process data */ + { + tacDATA* pData = &(pSelfParam->shmMsg.msgBody.monitor.data); /* We are only interested in message body */ + + /* pData->number = pSelfParam->inputNb; */ + pData->timeStamp = (*pSelf->shared).currentTime; + + /* pData points to the body of the Message */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pData->buffer[arrayIndex] = tacStdBlockGetInput(pSelf,arrayIndex); + } + + /* Push message into probe block's message que to get the + * data out of the interrupt comtext. */ + if ( msgQSend (pSelfParam->msgq, (char*) &(pSelfParam->shmMsg), sizeof(tacSHMSG), NO_WAIT, 0) != OK ) + { + (pSelfParam->lost)++; + } + + /* Defer procedure call */ + tacDpcPushRequest((tacVOIDFCTPTR) &tacSinkSendMonitorMessage, &pSelfParam->msgq); + + pSelfParam->counter = 0; + } + + pSelfParam->counter++; +} + +void tacSinkProbeBlockAlgorithm (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + unsigned short arrayIndex = 0; + + if ((pSelfParam->counter % pSelfParam->rate) == 0) /* It's time to process data */ + { + tacDATA* pData = &(pSelfParam->shmMsg.msgBody.monitor.data); /* We are only interested in message body */ + + pData->timeStamp = (*pSelf->shared).currentTime; + + /* pData points to the body of the Message */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pData->buffer[arrayIndex] = tacStdBlockGetInput(pSelf,arrayIndex); + } + + /* Push message into probe block's message que to get the + * data out of the interrupt comtext. */ + if ( msgQSend (pSelfParam->msgq, (char*) &(pSelfParam->shmMsg), sizeof(tacSHMSG), NO_WAIT, 0) != OK ) + { + (pSelfParam->lost)++; + } + + /* Defer procedure call: + * tacSinkSendProbeMessage is called outside the interrupt routine + * and will take care to pick up the message from the probe block's + * message queue and send it over the shared memory message queue */ + tacDpcPushRequest((tacVOIDFCTPTR) &tacSinkSendProbeMessage, &pSelfParam->msgq); + + pSelfParam->counter = 0; + } + + pSelfParam->counter++; +} + +/* + * Reset Hooks + */ + +/* + * Stop Hooks + */ + +/* + * Destructor Hooks + */ + +/* + * Note: This destructor is used mainly to send a MONITOR message containing + * 0.0 in order to reset the database array (otherwise going from an + * algorithm with 4 monitored data to one with 3 monitored data leaves + * the 4th value equal to the last ...) + */ + +void tacSinkMonitorBlockDestructor (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + tacDATA* pData = &(pSelfParam->shmMsg.msgBody.monitor.data); + unsigned short arrayIndex = 0; + + /* Reset DB values */ + pSelfParam->shmMsg.type = tacSHMSG_MONITOR_DATA; + pData = &(pSelfParam->shmMsg.msgBody.monitor.data); + + pData->number = pSelfParam->inputNb; + + /* pData points to the body of the Message */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pData->buffer[arrayIndex] = 0.0; + } + + /* Send message */ + tacShMsgQSendBgInfo(&pSelfParam->shmMsg); + + pSelfParam->shmMsg.type = tacSHMSG_REMOVE_MONITOR; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + + /* Send message */ + tacShMsgQSendBgInfo(&pSelfParam->shmMsg); + + free(pSelfParam->dbPoint); + + /* delete internal message queue. Do this as deferred procedure call + * to make sure it is only called when all messages have been send + * (through the same deferred call mechanism) */ + tacDpcPushRequest((tacVOIDFCTPTR) tacSinkDeleteMessageQueue, &(pSelfParam->msgq)); + + return; +} + +void tacSinkMonitorStateBlockDestructor (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + tacDATA* pData = &(pSelfParam->shmMsg.msgBody.monitor.data); + unsigned short arrayIndex = 0; + + /* Reset DB values */ + pSelfParam->shmMsg.type = tacSHMSG_MONITOR_DATA; + pData = &(pSelfParam->shmMsg.msgBody.monitor.data); + + pData->number = pSelfParam->inputNb; + + /* pData points to the body of the Message */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pData->buffer[arrayIndex] = 0.0; + } + + /* Send message */ + tacShMsgQSendBgInfo(&pSelfParam->shmMsg); + + pSelfParam->shmMsg.type = tacSHMSG_REMOVE_MONITOR; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + + /* Send message */ + tacShMsgQSendBgInfo(&pSelfParam->shmMsg); + + free(pSelfParam->dbPoint); + + /* delete internal message queue. Do this as deferred procedure call + * to make sure it is only called when all messages have been send + * (through the same deferred call mechanism) */ + tacDpcPushRequest((tacVOIDFCTPTR) tacSinkDeleteMessageQueue, &(pSelfParam->msgq)); + + return; +} + +void tacSinkProbeBlockDestructor (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + pSelfParam->shmMsg.type = tacSHMSG_REMOVE_PROBE; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + + /* Send message */ + tacShMsgQSendDataSample(&pSelfParam->shmMsg); + + /* delete internal message queue. Do this as deferred procedure call + * to make sure it is only called when all messages have been send + * (through the same deferred call mechanism) */ + tacDpcPushRequest((tacVOIDFCTPTR) tacSinkDeleteMessageQueue, &(pSelfParam->msgq)); + + return; +} + +/* + * Show Hooks + */ + +void tacSinkDisplayBlockShow (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Print parameter values */ + printf(" Update rate: %d\n",pSelfParam->rate); + + return; +} + +void tacSinkMonitorBlockShow (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Print parameter values */ + printf(" Update rate: %d\n",pSelfParam->rate); + printf(" Number of input signals: %d\n",pSelfParam->inputNb); + printf(" Queued samples: %d\n", msgQNumMsgs(pSelfParam->msgq)); + printf(" Lost samples: %d\n",pSelfParam->lost); + + if (pSelfParam->dbPoint != NULL) + { + printf(" DB Point: %s\n", pSelfParam->dbPoint); + } + + return; +} + +void tacSinkMonitorStateBlockShow (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Print parameter values */ + printf(" Using MonitorState block, not averaging received data\n"); + printf(" Update rate: %d\n",pSelfParam->rate); + printf(" Number of input signals: %d\n",pSelfParam->inputNb); + printf(" Queued samples: %d\n", msgQNumMsgs(pSelfParam->msgq)); + printf(" Lost samples: %d\n",pSelfParam->lost); + + if (pSelfParam->dbPoint != NULL) + { + printf(" DB Point: %s\n", pSelfParam->dbPoint); + } + + return; +} + +void tacSinkProbeBlockShow (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Print parameter values */ + printf(" Update rate: %d\n",pSelfParam->rate); + printf(" Update rate param (sec): %f\n",pSelfParam->rateParam); + printf(" Number of input signals: %d\n",pSelfParam->inputNb); + printf(" Queued samples: %d\n", msgQNumMsgs(pSelfParam->msgq)); + printf(" Lost samples: %d\n",pSelfParam->lost); + + return; +} + +/* + * Installation function + */ + +tacSTDBLOCK_TYPE tacSinkDisplayTypeInfo = { + "Display", + &tacSinkDisplayBlockConstructor, + &tacSinkDisplayBlockGetParameter, + &tacSinkDisplayBlockAlgorithm, + NULL, + NULL, + NULL, + NULL, + &tacSinkDisplayBlockShow, +}; + +tacSTDBLOCK_TYPE tacSinkMonitorTypeInfo = { + "Monitor", + &tacSinkMonitorBlockConstructor, + &tacSinkMonitorBlockGetParameter, + &tacSinkMonitorBlockAlgorithm, + NULL, + NULL, + NULL, + &tacSinkMonitorBlockDestructor, + &tacSinkMonitorBlockShow, +}; + +tacSTDBLOCK_TYPE tacSinkMonitorStateTypeInfo = { + "MonitorState", + &tacSinkMonitorStateBlockConstructor, + &tacSinkMonitorStateBlockGetParameter, + &tacSinkMonitorStateBlockAlgorithm, + NULL, + NULL, + NULL, + &tacSinkMonitorStateBlockDestructor, + &tacSinkMonitorStateBlockShow, +}; + +/* Probe with a maximal sampling rate of 2kHz */ +tacSTDBLOCK_TYPE tacSinkProbeTypeInfo = { + "Probe", + &tacSinkProbeBlockConstructor, + &tacSinkProbeBlockGetParameter, + &tacSinkProbeBlockAlgorithm, + NULL, + &tacSinkProbeBlockReset, + NULL, + &tacSinkProbeBlockDestructor, + &tacSinkProbeBlockShow, +}; + +/* Fast probe is the same as probe but not does have the + * limitation on the max. recording frequency */ +tacSTDBLOCK_TYPE tacSinkFastProbeTypeInfo = { + "FastProbe", + &tacSinkFastProbeBlockConstructor, + &tacSinkProbeBlockGetParameter, + &tacSinkProbeBlockAlgorithm, + NULL, + &tacSinkProbeBlockReset, + NULL, + &tacSinkProbeBlockDestructor, + &tacSinkProbeBlockShow, +}; + +STATUS tacSinkBlockInitAll (void) +{ + /* Install Sink Block Hooks */ + tacStdBlockInstallNewType(&tacSinkDisplayTypeInfo); + tacStdBlockInstallNewType(&tacSinkMonitorTypeInfo); + tacStdBlockInstallNewType(&tacSinkMonitorStateTypeInfo); + tacStdBlockInstallNewType(&tacSinkProbeTypeInfo); + tacStdBlockInstallNewType(&tacSinkFastProbeTypeInfo); + + /* + * Perform other library initialization operations + */ + + return OK; +} + +/* + * Local functions + */ + +/* + * Note: Routines called from within the algorithm must be declared with + * static __inline__ + */ + +STATUS tacSinkCommonBlockConstructor (tacSTDBLOCK* pSelf, + tacERROR* error) +{ + /* Allocate specific arrays (pointers are initialized to NULL by StdBlock) */ + if (tacStdBlockAllocateArrays(pSelf, 0, tacSINK_DEFAULT_INPUT_NUMBER, + tacSINK_DEFAULT_OUTPUT_NUMBER, error) == ERROR) + { + return ERROR; + } + + if (tacStdBlockAllocateArrayBySize(pSelf, tacSTDBLOCK_PARAM_ARRAY, + sizeof(tacSINK_SCOPE_LOCAL_PARAMETER), error) == ERROR) + { + tacStdBlockReleaseArray(pSelf, tacSTDBLOCK_INPUT_ARRAY, error); + tacStdBlockReleaseArray(pSelf, tacSTDBLOCK_OUTPUT_ARRAY, error); + return ERROR; + } + + /* Specify the number of input signals to attach to become resolved */ + tacStdBlockSetInputNumber(pSelf, tacSINK_ONE_INPUT_NUMBER); /* Required */ + + return OK; +} + +STATUS tacSinkSendMonitorMessage(MSG_Q_ID * msgq) +{ + /* Send message using provided function (different for Monitor and Probe blocks) */ + /* Send message using provided function (different for Monitor and Probe blocks) */ + tacSHMSG msg; + + if ( msgQReceive(*msgq, (char*) &msg, sizeof(tacSHMSG), NO_WAIT) == sizeof(tacSHMSG) ) + { + tacShMsgQSendBgInfo (&msg); + } + + return OK; +} + +STATUS tacSinkSendProbeMessage(MSG_Q_ID * msgq) +{ + /* Send message using provided function (different for Monitor and Probe blocks) */ + tacSHMSG msg; + + if ( msgq == NULL ) + { + return ERROR; + } + + if ( msgQReceive(*msgq, (char*) &msg, sizeof(tacSHMSG), NO_WAIT) == sizeof(tacSHMSG) ) + { + tacShMsgQSendDataSample (&msg); + } + return OK; +} + +STATUS tacSinkDeleteMessageQueue (MSG_Q_ID * msgq) +{ + /* Is called when block is destroyed and removes the internal message queue */ + STATUS status; + + status = msgQDelete (*msgq); + *msgq = NULL; + return status; +} + + +/*___oOo___*/ + + + + + + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3624768 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +__pycache__ +out +tacapp.tar.gz +Sources +tacapp +worryingFiles +cc.tar.gz diff --git a/errors.json b/errors.json new file mode 100644 index 0000000..5ec898a --- /dev/null +++ b/errors.json @@ -0,0 +1,4 @@ +{ + "missing_blocks": [], + "multiple_definitions": [] +} \ No newline at end of file diff --git a/hardcodedFiles/tacReadRmnBlock.c b/hardcodedFiles/tacReadRmnBlock.c new file mode 100644 index 0000000..8acbcfa --- /dev/null +++ b/hardcodedFiles/tacReadRmnBlock.c @@ -0,0 +1,568 @@ +/******************************************************************************* +* E.S.O. - VLT project +* +* "@(#) $Id: tacReadRmnBlock.c 305476 2018-01-19 08:56:18Z rfrahm $" +* +* who when what +* ------- -------- ---------------------------------------------- +* gzins 2010-07-27 ported to VLTSW2010 and VxWorks 6.4 +* swehner 2008-10-10 creation +*/ + +/************************************************************************ +* NAME +* tacReadRmnBlock - Implemements the standard functions for the +* tacReadRmn block and tacReadRfm block. +* tacReadRmnBlock - Reads from 1rst generation reflective memory network +* tacReadRfmBlock - Reads from 2nd generation reflective memory network + +* Parameters: +* field - token names for the RMN fields to read (up to 10) +* Inputs: 0 +* Outputs: 1 +* output - 1..10 depending on number of field parameters +* +* +* +* FILES +* +* ENVIRONMENT +* TAC +* +* RETURN VALUES +* +* CAUTIONS +* +* EXAMPLES +* TAC.BLOCK9.TYPE ReadRmn +* TAC.BLOCK9.NAME ReadRmn +* +* SEE ALSO +* +* BUGS +* +*------------------------------------------------------------------------ +*/ + +#define _POSIX_SOURCE 1 +#include "vltPort.h" + +ATTRIBUTE_UNUSED static const char *rcsId="@(#) $Id: tacReadRmnBlock.c 305476 2018-01-19 08:56:18Z rfrahm $"; + +/* + * System Headers + */ + +#include /* taskSpawn, taskDelay, ... */ +#include /* printf ... */ +#include /* malloc ... */ +#include /* malloc ... */ +#include +#include + +/* + * Local Headers + */ + +#include "tacStdBlock.h" +#include "tacRmnBlock.h" +#include "rmassPublic.h" +#include "rmassPrivate.h" + +/* + * Compilation directives + */ + +/* + * Constants + */ + +#define tacREAD_RMN_EXPECTED_PARAM 1 +#define tacREAD_RMN_DEFAULT_INPUT_NUMBER 0 +#define tacREAD_RMN_DEFAULT_OUTPUT_NUMBER tacMAX_DATA_NUMBER + +#define tacREAD_RMN_FIELD_STRING_LEN 256 +#define tacSTRLEN sizeof(double) + +/* + * Types + */ + +/* + * Local function declaration + */ + +/* + * Global variables + */ + +/* + * Function definition + */ + + +STATUS tacReadRmnBlockCheckParameter (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the ADDBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = NULL; + + pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + /* field string is built from block params */ + if ( tacRmnBlockCheckParameter ( pSelf, parameter, 0, error) != OK ) + { + return ERROR; + } + + /* useful information on the screen */ + printf ("ReadRmn %s: [%s]\n", pSelf->name, pSelfParam->fieldString); + + return OK; +} + +STATUS tacReadRfmBlockCheckParameter (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the ADDBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = NULL; + + pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + /* field string is built from block params */ + if ( tacRmnBlockCheckParameter ( pSelf, parameter, 0, error) != OK ) + { + return ERROR; + } + + /* useful information on the screen */ + printf ("ReadRfm %s: [%s]\n", pSelf->name, pSelfParam->fieldString); + + return OK; +} + +/* + * Constructor Hooks - Called when a block of this type is instanciated (CONFIG or ADDBLCK commands) + */ + +STATUS tacReadRmBlockConstructor (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the ADDBLCK command */ + vltLOGICAL isRmn, + tacERROR* error) /* Error structure - not a stack */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = NULL; + + /* Check that the expected number of parameters has been received */ + if (parameter->number < tacREAD_RMN_EXPECTED_PARAM) + { + char errorParam[40]; + + sprintf(errorParam, "Expected at least %d, received %d", tacREAD_RMN_EXPECTED_PARAM, parameter->number); + tacRTC_ERR(tacERR_PARAM_NUMBER, errorParam); + return ERROR; + } + + /* Allocate and initialize block-specific arrays */ + if (tacStdBlockAllocateArrays(pSelf, 0, tacREAD_RMN_DEFAULT_INPUT_NUMBER, tacREAD_RMN_DEFAULT_OUTPUT_NUMBER, error) == ERROR) + { + return ERROR; + } + + if (tacStdBlockAllocateArrayBySize(pSelf, tacSTDBLOCK_PARAM_ARRAY, sizeof(tacRMN_LOCAL_PARAMETER), error) == ERROR) + { + tacStdBlockReleaseArray(pSelf, tacSTDBLOCK_INPUT_ARRAY, error); + tacStdBlockReleaseArray(pSelf, tacSTDBLOCK_OUTPUT_ARRAY, error); + return ERROR; + } + + if ( isRmn ) + { + if ( tacReadRmnBlockCheckParameter (pSelf, parameter, error) == ERROR) + { + return ERROR; + } + } + else + { + if ( tacReadRfmBlockCheckParameter (pSelf, parameter, error) == ERROR) + { + return ERROR; + } + } + + pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + pSelfParam->handleValid = rmassACCESS_BLOCKED; + + /* Attach to RMN */ + if ( rmassReadAttach (&pSelfParam->handle, + pSelfParam->fieldString, + &pSelfParam->val[0], + &pSelfParam->val[1], + &pSelfParam->val[2], + &pSelfParam->val[3], + &pSelfParam->val[4], + &pSelfParam->val[5], + &pSelfParam->val[6], + &pSelfParam->val[7], + &pSelfParam->val[8], + &pSelfParam->val[9]) != SUCCESS ) + { + char errorParam[40]; + + sprintf(errorParam, "Attach to RMN failed."); + tacRTC_ERR(tacERR_INTERNAL, errorParam); + return ERROR; + } + + pSelfParam->handleValid = rmassACCESS_FREE; + + return OK; +} + +STATUS tacReadRmnBlockConstructor (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the ADDBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + if ( tacReadRmBlockConstructor (pSelf, parameter, ccsTRUE, error ) == ERROR ) + { + return ERROR; + } + return OK; +} + +STATUS tacReadRfmBlockConstructor (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the ADDBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + if ( tacReadRmBlockConstructor (pSelf, parameter, ccsFALSE, error ) == ERROR ) + { + return ERROR; + } + return OK; +} + + + +/* + * Destructor Hooks - Called when the block is removed from the algorithm (DELBLCK or new CONFIG commands) + */ + +void tacReadRmnBlockDestructor (tacSTDBLOCK* pSelf) /* Reference to the block instance */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = NULL; + pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + pSelfParam->handleValid = rmassACCESS_BLOCKED; + /* wait until semaphore is acknowledged by realtime algo + * or just procede if realtime is not active */ + while ((*pSelf->shared).active && pSelfParam->handleValid != rmassACCESS_BLOCK_ACKN) + { + taskDelay(1); + } + + rmassDetach (&pSelfParam->handle); + + return; +} + +/* + * Change parameters Hooks - Called when modifying the block parameters (MODBLCK command) + */ + +STATUS tacReadRmnBlockSetParameter (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the MODBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + if ( tacReadRmnBlockCheckParameter (pSelf, parameter, error) == ERROR) + { + return ERROR; + } + + pSelfParam->handleValid = rmassACCESS_BLOCKED; + /* wait until semaphore is acknowledged by realtime algo + * or just procede if realtime is not active */ + while ((*pSelf->shared).active && pSelfParam->handleValid != rmassACCESS_BLOCK_ACKN) + { + taskDelay(1); + } + + /* detach RMN handle */ + if ( rmassDetach (&pSelfParam->handle) != SUCCESS ) + { + char errorParam[40]; + + sprintf(errorParam, "rmassDetach returned error."); + tacRTC_ERR(tacERR_INTERNAL, errorParam); + return ERROR; + } + + if ( rmassReadAttach (&pSelfParam->handle, + pSelfParam->fieldString, + &pSelfParam->val[0], + &pSelfParam->val[1], + &pSelfParam->val[2], + &pSelfParam->val[3], + &pSelfParam->val[4], + &pSelfParam->val[5], + &pSelfParam->val[6], + &pSelfParam->val[7], + &pSelfParam->val[8], + &pSelfParam->val[9]) != SUCCESS ) + { + char errorParam[40]; + + sprintf(errorParam, "Attach to RMN failed."); + tacRTC_ERR(tacERR_INTERNAL, errorParam); + return ERROR; + } + + pSelfParam->handleValid = rmassACCESS_FREE; + + return OK; +} + +STATUS tacReadRfmBlockSetParameter (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the MODBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + if ( tacReadRfmBlockCheckParameter (pSelf, parameter, error) == ERROR) + { + return ERROR; + } + + pSelfParam->handleValid = rmassACCESS_BLOCKED; + /* wait until semaphore is acknowledged by realtime algo + * or just procede if realtime is not active */ + while ((*pSelf->shared).active && pSelfParam->handleValid != rmassACCESS_BLOCK_ACKN) + { + taskDelay(1); + } + + /* detach RMN handle */ + if ( rmassDetach (&pSelfParam->handle) != SUCCESS ) + { + char errorParam[40]; + + sprintf(errorParam, "rmassDetach returned error."); + tacRTC_ERR(tacERR_INTERNAL, errorParam); + return ERROR; + } + + if ( rmassReadAttach (&pSelfParam->handle, + pSelfParam->fieldString, + &pSelfParam->val[0], + &pSelfParam->val[1], + &pSelfParam->val[2], + &pSelfParam->val[3], + &pSelfParam->val[4], + &pSelfParam->val[5], + &pSelfParam->val[6], + &pSelfParam->val[7], + &pSelfParam->val[8], + &pSelfParam->val[9]) != SUCCESS ) + { + char errorParam[40]; + + sprintf(errorParam, "Attach to RFM failed."); + tacRTC_ERR(tacERR_INTERNAL, errorParam); + return ERROR; + } + + pSelfParam->handleValid = rmassACCESS_FREE; + + return OK; +} + +/* + * Algorithm Hooks - Called at each time the TAC algorithm is evaluated (ONLINE state) + */ + +void tacReadRmnBlockAlgorithm (tacSTDBLOCK* pSelf) /* Reference to the block instance */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + int i; + + if ( pSelfParam->handleValid == rmassACCESS_BLOCKED ) + { + pSelfParam->handleValid = rmassACCESS_BLOCK_ACKN; + } + + if ( pSelfParam->handleValid == rmassACCESS_FREE ) + { + /* actual RMN read operation */ + rmassReadAccessRmn (&pSelfParam->handle); + + /* Write to outputs */ + for (i=0; i < pSelfParam->numFields; i++) + { + switch (pSelfParam->type[i]) + { + case rmassTIMESEC: + case rmassUINT32: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).ui); + break; + case rmassTIMEUSEC: + case rmassINT32: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).i); + break; + case rmassFLOAT: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).f); + break; + default: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).d); + break; + } + } + + /* provide zero values at unsatisfied outputs + * I consider this a good thing to do since the block + * is always configured */ + for (i=pSelfParam->numFields; i < tacREAD_RMN_DEFAULT_OUTPUT_NUMBER; i++) + { + tacStdBlockSetOutput(pSelf, i, 0.0); + } + } +} + +void tacReadRfmBlockAlgorithm (tacSTDBLOCK* pSelf) /* Reference to the block instance */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + int i; + + if ( pSelfParam->handleValid == rmassACCESS_BLOCKED ) + { + pSelfParam->handleValid = rmassACCESS_BLOCK_ACKN; + } + + if ( pSelfParam->handleValid == rmassACCESS_FREE ) + { + /* actual RMN read operation */ + rmassReadAccessRfm (&pSelfParam->handle); + + /* Write to outputs */ + for (i=0; i < pSelfParam->numFields; i++) + { + switch (pSelfParam->type[i]) + { + case rmassTIMESEC: + case rmassUINT32: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).ui); + break; + case rmassTIMEUSEC: + case rmassINT32: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).i); + break; + case rmassFLOAT: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).f); + break; + default: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).d); + break; + } + } + + /* provide zero values at unsatisfied outputs + * I consider this a good thing to do since the block + * is always configured */ + for (i=pSelfParam->numFields; i < tacREAD_RMN_DEFAULT_OUTPUT_NUMBER; i++) + { + tacStdBlockSetOutput(pSelf, i, 0.0); + } + } +} + +/* + * Show Hooks - Called when the tacRtcTaskShow routine is executed + */ + +void tacReadRmnBlockShow (tacSTDBLOCK* pSelf) /* Reference to the block instance */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + /* Print parameter values */ + printf(" Attached: %s\n", pSelfParam->fieldString); + + return; +} + + +/***************************************************/ +/* The following code is common to all block types */ +/* Do not modify without any good reasons */ +/***************************************************/ + +/* + * Installation function + */ + +tacSTDBLOCK_TYPE tacReadRmnTypeInfo = { + "ReadRmn", + &tacReadRmnBlockConstructor, + &tacRmBlockGetParameter, + &tacReadRmnBlockAlgorithm, + &tacReadRmnBlockSetParameter, + NULL, + NULL, + &tacReadRmnBlockDestructor, + &tacReadRmnBlockShow +}; + +tacSTDBLOCK_TYPE tacReadRfmTypeInfo = { + "ReadRfm", + &tacReadRfmBlockConstructor, + &tacRmBlockGetParameter, + &tacReadRfmBlockAlgorithm, + &tacReadRmnBlockSetParameter, + NULL, + NULL, + &tacReadRmnBlockDestructor, + &tacReadRmnBlockShow +}; + +STATUS tacReadRmnBlockInitAll (void) +{ + /***************************************************/ + /* The following code is common to all block types */ + /* Do not modify without any good reasons */ + /***************************************************/ + + /* Install ReadRmn1g Block Hooks */ + tacStdBlockInstallNewType(&tacReadRmnTypeInfo); + + /*****************************/ + /* End of common code region */ + /*****************************/ + + /* Perform other library initialization operations */ + + return OK; +} + +STATUS tacReadRfmBlockInitAll (void) +{ + /***************************************************/ + /* The following code is common to all block types */ + /* Do not modify without any good reasons */ + /***************************************************/ + + /* Install ReadRmn1g Block Hooks */ + tacStdBlockInstallNewType(&tacReadRfmTypeInfo); + + /*****************************/ + /* End of common code region */ + /*****************************/ + + /* Perform other library initialization operations */ + + return OK; +} + +/*___oOo___*/ + + + diff --git a/hardcodedFiles/tacSinkBlock.c b/hardcodedFiles/tacSinkBlock.c new file mode 100644 index 0000000..df39833 --- /dev/null +++ b/hardcodedFiles/tacSinkBlock.c @@ -0,0 +1,1256 @@ +/******************************************************************************* +* E.S.O. - VLT project +* +* "@(#) $Id: tacSinkBlock.c 339094 2021-02-10 03:10:02Z jgil $" +* +* who when what +* ------- -------- ---------------------------------------------- +* rdembet 06/08/20 New MonitorState block with no data averaging +* swehner 28/11/09 SPR20090234 Correction in rate adjustment in reset hook +* swehner 27/11/09 Fixed message queue handling +* swehner 10/10/09 New block FastProbe for unlimited rec frequency +* swehner 22/09/09 PPRS 32341 Replaced specialized tacSINK_SHMSG stack +* with standard vxWorks message queue. +* bbauvir 21/09/04 VLTSW20040113 - One sample might be lost +* bbauvir 29/03/04 Monitor block averages over the reporting period +* bbauvir 29/12/02 Probe to the SampTask +* bbauvir 26/12/02 MsgQ access through DPC mechanism +* bbauvir 14/07/02 New MsgQ of TAC version 1.22 +* bbauvir 21/03/01 Created +*/ + +/************************************************************************ +* NAME +* tacSinkBlock - Standard data monitoring blocks +* +* SYNOPSIS +* lcubootAutoCdBoot 1,"tacsink.boot" +* < tacsink.boot +* +* DESCRIPTION +* Block type: Display +* Parameters: +* Inputs: 1 +* Outputs: none +* +* This function block samples the value of its input signal at the +* specified and issues a message containing the time +* and the value of the input on the vxWorks terminal. +* It does not allow modification of the parameter at runtime. +* +* Block type: Monitor +* Parameters: +* +* Inputs: 10max +* Outputs: none +* +* This function block samples the value of its input signals at the +* specified (0.0 to send a message at the system sampling +* period) and issues a message containing the time and the value of +* the inputs on the shared memory. This message is intercepted by the +* background task running on the master CPU. The monitored values are +* written into the online database. The number of inputs of the block +* is specified by parameter. +* This block does not allow modification of the parameters at runtime. +* +* Block type: MonitorState +* Parameters: +* +* Inputs: 10max +* Outputs: none +* +* Same as Monitor block but without the averaging of received data, +* see VLTSW-14260 JIRA ticket. +* +* Block type: Probe +* Parameters: +* +* Inputs: 10max +* Outputs: none +* +* Block type: FastProbe +* Parameters: +* +* Inputs: 10max +* Outputs: none +* +* This function block samples the value of its input signals at the +* specified (0.0 to send a message at the system sampling +* period) and issues a message containing the time and the value of +* the inputs on the shared memory. This message is intercepted by the +* background task running on the master CPU. The number of inputs of +* the block is specified by parameter. +* This message is passed to an external application callback if +* provided. +* This block does not allow modification of the parameters at runtime. +* The normal Probe block has a limited sampling frequency of not more +* than 2kHz. The reason is in particular the bottleneck between master +* and slave CPU which all samples have to pass through a mechanism of +* VME bus shared memory. On one-CPU-systems this limitation does not +* apply so you are free to choose faster sampling. You may of course +* hit other limitations (processor speed, network traffic etc.) +* +* FILES +* +* ENVIRONMENT +* TAC +* +* RETURN VALUES +* +* CAUTIONS +* All these blocks compute an decimation value to use to trigger the +* sampling of the input signals, from the system sampling period. +* They should be created after any synchronization block. +* +* In order to cope with system performances, a minimum +* is defined for each block. The minimum applied periods are 0.1 (10Hz), +* 0.01 (100Hz) and 0.5e-3 (2kHz) for the 'Display', 'Monitor' and +* 'Probe' blocks respectively. +* +* EXAMPLES +* # 5 signals @ 2Hz (monitored in the database) +* TAC.BLOCK9.TYPE Monitor +* TAC.BLOCK9.NAME Monitor +* TAC.BLOCK9.PARAM 0.5, 5 +* +* # 5 signals @ the RT algorithm sampling period (0.0) +* TAC.BLOCK10.TYPE Probe +* TAC.BLOCK10.NAME Probe +* TAC.BLOCK10.PARAM 0.0, 5 +* +* SEE ALSO +* tacServerInstallDataCallback, tacServerRemoveDataCallback +* +* BUGS +* +*------------------------------------------------------------------------ +*/ + +#define _POSIX_SOURCE 1 +#include "vltPort.h" + + +/* + * System Headers + */ + +#include +#include +#include /* logMsg ... */ +#include /* printf ... */ +#include /* malloc ... */ +#include /* memcpy ... */ +#include + +/* + * Local Headers + */ + +#include "tacStdBlock.h" +#include "tacShMsgQ.h" + +/* + * Compilation directives + */ + +/* + * Constants + */ + +#define tacSINK_DEFAULT_EXPECTED_PARAM 2 + +#define tacSINK_DEFAULT_INPUT_NUMBER tacMAX_DATA_NUMBER /* Up to 10 input channels */ +#define tacSINK_DEFAULT_OUTPUT_NUMBER tacMAX_DATA_NUMBER + +#define tacSINK_ONE_EXPECTED_PARAM 1 +#define tacSINK_ONE_INPUT_NUMBER 1 + +#define tacSINK_DISPLAY_MIN_SAMPLING_PERIOD .1 /* 10Hz */ +#define tacSINK_MONITOR_MIN_SAMPLING_PERIOD .01 /* 100Hz */ +#define tacSINK_PROBE_MIN_SAMPLING_PERIOD .5e-3 /* 2kHz */ + +#define tacSINK_DISPLAY_LOG_STRING_SIZE 128 + +#define tacSINK_MONITOR_DEFAULT_DB_POINT "tac:data:monitor" +#define tacSINK_MONITOR_MAX_DB_ADDR_SIZE 64 + +#define tacSINK_MONITOR_QUEUE_SIZE 6 +#define tacSINK_PROBE_QUEUE_SIZE 6 + + +typedef enum { + tacSINK_SAMPLING_PERIOD = 0, + tacSINK_INPUT_NUMBER, + tacSINK_MONITOR_DB_POINT, +}tacSINK_SCOPE_PARAM_INDEX; + +/* + * Types + */ + +typedef struct { + unsigned short rate; + unsigned short counter; + unsigned short inputNb; + unsigned int lost; + double rateParam; + char* dbPoint; + MSG_Q_ID msgq; + tacSHMSG shmMsg; +}tacSINK_SCOPE_LOCAL_PARAMETER; + +/* + * Function declaration + */ + +extern STATUS tacDpcPushRequest(tacVOIDFCTPTR pFunct, void* parameter); + +/* + * Local function declaration + */ + +/* + * Note: Routines called from within the algorithm must be declared with + * static __inline__ + */ + +STATUS tacSinkSendMonitorMessage(MSG_Q_ID * msgqvoid); +STATUS tacSinkSendMonitorStateMessage(MSG_Q_ID * msgqvoid); +STATUS tacSinkSendProbeMessage(MSG_Q_ID * msgq); +STATUS tacSinkDeleteMessageQueue(MSG_Q_ID * msgq); +STATUS tacSinkCommonBlockConstructor(tacSTDBLOCK* pSelf, tacERROR* error); + +/* + * Global variables + */ + +char logStr[tacSINK_DISPLAY_LOG_STRING_SIZE]; /* Logging string used for Display */ + + +/* + * Function definition + */ + +/* + * Constructor Hooks + */ + +STATUS tacSinkDisplayBlockConstructor (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = NULL; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = NULL; + + /* Check that the expected number of parameters has been received */ + if (parameter->number < tacSINK_ONE_EXPECTED_PARAM) + { + char errorParam[40]; + + sprintf(errorParam, "Expected %d, received %d", tacSINK_ONE_EXPECTED_PARAM, parameter->number); + tacRTC_ERR(tacERR_PARAM_NUMBER, errorParam); + return ERROR; + } + + /* Check that the parameters are valid */ + pRealParam = (double*) parameter->buffer; + + /* Passed parameter is the sampling period of the block */ + if (pRealParam[tacSINK_SAMPLING_PERIOD] < (*pSelf->shared).samplingPeriod) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = (*pSelf->shared).samplingPeriod; + } + + if (pRealParam[tacSINK_SAMPLING_PERIOD] < tacSINK_DISPLAY_MIN_SAMPLING_PERIOD) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = tacSINK_DISPLAY_MIN_SAMPLING_PERIOD; + } + + /* Call common constructor */ + if (tacSinkCommonBlockConstructor(pSelf, error) != OK) + { + return ERROR; + } + + /* Store parameters */ + pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; /* We will only store short integers */ + + /* + * Compute the rate at which data has to be processed - divide and take + * the integer part of the result + */ + + pSelfParam->rate = (unsigned short) (pRealParam[tacSINK_SAMPLING_PERIOD] / (*pSelf->shared).samplingPeriod); + pSelfParam->counter = 0; /* Decimation counter */ + + /* + * Perform other block initialization operations + */ + + return OK; +} + +STATUS tacSinkMonitorBlockConstructor (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = NULL; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = NULL; + unsigned short arrayIndex = 0; + + /* Check that the expected number of parameters has been received */ + if (parameter->number < tacSINK_DEFAULT_EXPECTED_PARAM) + { + char errorParam[40]; + + sprintf(errorParam, "Expected %d, received %d", tacSINK_DEFAULT_EXPECTED_PARAM, parameter->number); + tacRTC_ERR(tacERR_PARAM_NUMBER, errorParam); + return ERROR; + } + + /* Check that the parameters are valid */ + pRealParam = (double*) parameter->buffer; + + /* Passed parameter is the sampling period of the block */ + if (pRealParam[tacSINK_SAMPLING_PERIOD] < (*pSelf->shared).samplingPeriod) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = (*pSelf->shared).samplingPeriod; + } + + if (pRealParam[tacSINK_SAMPLING_PERIOD] < tacSINK_MONITOR_MIN_SAMPLING_PERIOD) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = tacSINK_MONITOR_MIN_SAMPLING_PERIOD; + } + + /* Number of inputs is minimum 1 up to tacMSG_MAX_DATA_NUMBER */ + if ((pRealParam[tacSINK_INPUT_NUMBER] < 1) || + (pRealParam[tacSINK_INPUT_NUMBER] > tacMAX_DATA_NUMBER)) + { + tacRTC_ERR(tacERR_PARAM_INVALID, ""); + return ERROR; + } + + /* Call common constructor */ + if (tacSinkCommonBlockConstructor(pSelf, error) != OK) + { + return ERROR; + } + + /* Store parameters */ + pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* + * Compute the rate at which data has to be processed - divide and take + * the integer part of the result + */ + + pSelfParam->rate = (unsigned short) (pRealParam[tacSINK_SAMPLING_PERIOD] / (*pSelf->shared).samplingPeriod); + pSelfParam->counter = 0; /* Decimation counter */ + pSelfParam->inputNb = (unsigned short) pRealParam[tacSINK_INPUT_NUMBER]; + + /* Optional parameter is an application-specific DB point */ + if (parameter->number == tacSINK_DEFAULT_EXPECTED_PARAM + 1) + { + printf("tacSinkMonitorBlockConstructor - DB point %s\n",(char*) &(pRealParam[tacSINK_MONITOR_DB_POINT])); + pSelfParam->dbPoint = (char*) malloc(tacSINK_MONITOR_MAX_DB_ADDR_SIZE); + strcpy(pSelfParam->dbPoint, (char*) &(pRealParam[tacSINK_MONITOR_DB_POINT])); + } + else + { + printf("tacSinkMonitorBlockConstructor - Default DB point\n"); + pSelfParam->dbPoint = NULL; + } + + /* Specify the number of input signals to attach to become resolved */ + tacStdBlockSetInputNumber(pSelf, pSelfParam->inputNb); + + /* + * Perform other block initialization operations + */ + + /* Create the block internal message queue which tosses the messages out of the + * interrupt context. They are buffered in the queue until the DPC tasks + * picks them up and sends them over the shared memory message queue. + * Sorry for that double-queuing, that's because of the M-S architecture */ + + pSelfParam->msgq = msgQCreate(tacSINK_MONITOR_QUEUE_SIZE, sizeof(tacSHMSG), 0); + if ( pSelfParam->msgq == NULL ) + { + char errorParam[40]; + + sprintf(errorParam, "Could not create probe block message queue"); + tacRTC_ERR(tacERR_MALLOC, errorParam); + return ERROR; + } + + /* will count if a message can't be pushed in the queue */ + pSelfParam->lost = 0; + + /* Warn the background task that a new probe block has been created */ + pSelfParam->shmMsg.type = tacSHMSG_ADD_MONITOR; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + + if (pSelfParam->dbPoint == NULL) + { + strcpy((char*) &(pSelfParam->shmMsg.msgBody.monitor.data), tacSINK_MONITOR_DEFAULT_DB_POINT); + } + else + { + strcpy((char*) &(pSelfParam->shmMsg.msgBody.monitor.data), *((char**) &(pSelfParam->dbPoint))); + } + + printf("tacSinkMonitorBlockConstructor - Attach to %s\n",(char*) &(pSelfParam->shmMsg.msgBody.monitor.data)); + + /* Send message */ + tacShMsgQSendBgInfo(&(pSelfParam->shmMsg)); + + /* Initialize the message parameters */ + pSelfParam->shmMsg.type = tacSHMSG_MONITOR_DATA; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + pSelfParam->shmMsg.msgBody.monitor.data.number = pSelfParam->inputNb; + + /* The output port is used to average the inputs over the reporting period */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pSelf->output[arrayIndex] = 0.0; + } + + return OK; +} + +STATUS tacSinkMonitorStateBlockConstructor (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = NULL; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = NULL; + unsigned short arrayIndex = 0; + + /* Check that the expected number of parameters has been received */ + if (parameter->number < tacSINK_DEFAULT_EXPECTED_PARAM) + { + char errorParam[40]; + + sprintf(errorParam, "Expected %d, received %d", tacSINK_DEFAULT_EXPECTED_PARAM, parameter->number); + tacRTC_ERR(tacERR_PARAM_NUMBER, errorParam); + return ERROR; + } + + /* Check that the parameters are valid */ + pRealParam = (double*) parameter->buffer; + + /* Passed parameter is the sampling period of the block */ + if (pRealParam[tacSINK_SAMPLING_PERIOD] < (*pSelf->shared).samplingPeriod) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = (*pSelf->shared).samplingPeriod; + } + + if (pRealParam[tacSINK_SAMPLING_PERIOD] < tacSINK_MONITOR_MIN_SAMPLING_PERIOD) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = tacSINK_MONITOR_MIN_SAMPLING_PERIOD; + } + + /* Number of inputs is minimum 1 up to tacMSG_MAX_DATA_NUMBER */ + if ((pRealParam[tacSINK_INPUT_NUMBER] < 1) || + (pRealParam[tacSINK_INPUT_NUMBER] > tacMAX_DATA_NUMBER)) + { + tacRTC_ERR(tacERR_PARAM_INVALID, ""); + return ERROR; + } + + /* Call common constructor */ + if (tacSinkCommonBlockConstructor(pSelf, error) != OK) + { + return ERROR; + } + + /* Store parameters */ + pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* + * Compute the rate at which data has to be processed - divide and take + * the integer part of the result + */ + + pSelfParam->rate = (unsigned short) (pRealParam[tacSINK_SAMPLING_PERIOD] / (*pSelf->shared).samplingPeriod); + pSelfParam->counter = 0; /* Decimation counter */ + pSelfParam->inputNb = (unsigned short) pRealParam[tacSINK_INPUT_NUMBER]; + + /* Optional parameter is an application-specific DB point */ + if (parameter->number == tacSINK_DEFAULT_EXPECTED_PARAM + 1) + { + printf("tacSinkMonitorStateBlockConstructor - DB point %s\n",(char*) &(pRealParam[tacSINK_MONITOR_DB_POINT])); + pSelfParam->dbPoint = (char*) malloc(tacSINK_MONITOR_MAX_DB_ADDR_SIZE); + strcpy(pSelfParam->dbPoint, (char*) &(pRealParam[tacSINK_MONITOR_DB_POINT])); + } + else + { + printf("tacSinkMonitorStateBlockConstructor - Default DB point\n"); + pSelfParam->dbPoint = NULL; + } + + /* Specify the number of input signals to attach to become resolved */ + tacStdBlockSetInputNumber(pSelf, pSelfParam->inputNb); + + /* + * Perform other block initialization operations + */ + + /* Create the block internal message queue which tosses the messages out of the + * interrupt context. They are buffered in the queue until the DPC tasks + * picks them up and sends them over the shared memory message queue. + * Sorry for that double-queuing, that's because of the M-S architecture */ + + pSelfParam->msgq = msgQCreate(tacSINK_MONITOR_QUEUE_SIZE, sizeof(tacSHMSG), 0); + if ( pSelfParam->msgq == NULL ) + { + char errorParam[40]; + + sprintf(errorParam, "Could not create probe block message queue"); + tacRTC_ERR(tacERR_MALLOC, errorParam); + return ERROR; + } + + /* will count if a message can't be pushed in the queue */ + pSelfParam->lost = 0; + + /* Warn the background task that a new probe block has been created */ + pSelfParam->shmMsg.type = tacSHMSG_ADD_MONITOR; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + + if (pSelfParam->dbPoint == NULL) + { + strcpy((char*) &(pSelfParam->shmMsg.msgBody.monitor.data), tacSINK_MONITOR_DEFAULT_DB_POINT); + } + else + { + strcpy((char*) &(pSelfParam->shmMsg.msgBody.monitor.data), *((char**) &(pSelfParam->dbPoint))); + } + + printf("tacSinkMonitorStateBlockConstructor - Attach to %s\n",(char*) &(pSelfParam->shmMsg.msgBody.monitor.data)); + + /* Send message */ + tacShMsgQSendBgInfo(&(pSelfParam->shmMsg)); + + /* Initialize the message parameters */ + pSelfParam->shmMsg.type = tacSHMSG_MONITOR_DATA; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + pSelfParam->shmMsg.msgBody.monitor.data.number = pSelfParam->inputNb; + + /* Init output port which won't be used to average the inputs over the reporting period */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pSelf->output[arrayIndex] = 0.0; + } + + return OK; +} + +STATUS tacSinkProbeBlockCommonConstructor (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + double minPeriod, + tacERROR* error) +{ + double* pRealParam = NULL; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = NULL; + + /* Check that the expected number of parameters has been received */ + if (parameter->number < tacSINK_DEFAULT_EXPECTED_PARAM) + { + char errorParam[40]; + + sprintf(errorParam, "Expected %d, received %d", tacSINK_DEFAULT_EXPECTED_PARAM, parameter->number); + tacRTC_ERR(tacERR_PARAM_NUMBER, errorParam); + return ERROR; + } + + /* Check that the parameters are valid */ + pRealParam = (double*) parameter->buffer; + + /* Passed parameter is the sampling period of the block */ + if (pRealParam[tacSINK_SAMPLING_PERIOD] < (*pSelf->shared).samplingPeriod) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = (*pSelf->shared).samplingPeriod; + } + + if (pRealParam[tacSINK_SAMPLING_PERIOD] < minPeriod) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = minPeriod; + } + + /* Number of inputs is minimum 1 up to tacMSG_MAX_DATA_NUMBER */ + if ((pRealParam[tacSINK_INPUT_NUMBER] < 1) || + (pRealParam[tacSINK_INPUT_NUMBER] > tacMAX_DATA_NUMBER)) + { + tacRTC_ERR(tacERR_PARAM_INVALID, ""); + return ERROR; + } + + /* Call common constructor */ + if (tacSinkCommonBlockConstructor(pSelf, error) != OK) + { + return ERROR; + } + + /* Store parameters */ + pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* + * Compute the rate at which data has to be processed - divide and take + * the integer part of the result + */ + + pSelfParam->rateParam = pRealParam[tacSINK_SAMPLING_PERIOD]; + pSelfParam->rate = (unsigned short) (pRealParam[tacSINK_SAMPLING_PERIOD] / (*pSelf->shared).samplingPeriod); + pSelfParam->counter = 0; /* Decimation counter */ + pSelfParam->inputNb = (unsigned short) pRealParam[tacSINK_INPUT_NUMBER]; + + /* Specify the number of input signals to attach to become resolved */ + tacStdBlockSetInputNumber(pSelf, pSelfParam->inputNb); + + /* + * Perform other block initialization operations + */ + + /* Create the block internal message queue which gets the messages out of the + * interrupt context. They are buffered in the queue until the DPC tasks + * picks them up and sends them over the shared memory message queue. + * Sorry for that double-queuing, that's because of the M-S architecture */ + + /* There is only one message queue for all probe blocks! */ + pSelfParam->msgq = msgQCreate(tacSINK_PROBE_QUEUE_SIZE, sizeof(tacSHMSG), 0); + if ( pSelfParam->msgq == NULL ) + { + char errorParam[40]; + + sprintf(errorParam, "Could not create probe block message queue"); + tacRTC_ERR(tacERR_MALLOC, errorParam); + return ERROR; + } + + /* will count if a message can't be pushed in the queue */ + pSelfParam->lost = 0; + + /* Warn the background task that a new probe block has been created */ + pSelfParam->shmMsg.type = tacSHMSG_ADD_PROBE; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + + /* Send message */ + tacShMsgQSendDataSample(&pSelfParam->shmMsg); + + /* Initialize the message parameters */ + pSelfParam->shmMsg.type = tacSHMSG_TRANSFER_DATA; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + pSelfParam->shmMsg.msgBody.monitor.data.number = pSelfParam->inputNb; + + return OK; +} + +/* Probe block has a max. sampling frequency of 2kHz */ +STATUS tacSinkProbeBlockConstructor (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + return tacSinkProbeBlockCommonConstructor (pSelf, parameter, tacSINK_PROBE_MIN_SAMPLING_PERIOD, error); +} + +/* Fast probe is the same as probe but not does have the + * limitation on the max. recording frequency */ +STATUS tacSinkFastProbeBlockConstructor (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + return tacSinkProbeBlockCommonConstructor (pSelf, parameter, 0.0, error); +} + +void tacSinkProbeBlockReset (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = + (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* + * Re-Compute the rate at which data has to be processed + */ + if (pSelfParam->rateParam < (*pSelf->shared).samplingPeriod ) + { + pSelfParam->rate = 1; + } + else + { + pSelfParam->rate = (unsigned short) + (pSelfParam->rateParam / (*pSelf->shared).samplingPeriod); + } + + return; +} + +/* + * Report parameters Hooks + */ + +STATUS tacSinkDisplayBlockGetParameter (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = (double*) parameter->buffer; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Send back the expected number of parameters */ + parameter->number = tacSINK_ONE_EXPECTED_PARAM; + + /* Report current parameters */ + pRealParam[tacSINK_SAMPLING_PERIOD] = (double) (pSelfParam->rate * (*pSelf->shared).samplingPeriod); + + return OK; +} + +STATUS tacSinkMonitorBlockGetParameter (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = (double*) parameter->buffer; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Send back the expected number of parameters */ + parameter->number = tacSINK_DEFAULT_EXPECTED_PARAM; + + /* Report current parameters */ + pRealParam[tacSINK_SAMPLING_PERIOD] = (double) (pSelfParam->rate * (*pSelf->shared).samplingPeriod); + pRealParam[tacSINK_INPUT_NUMBER] = (double) pSelfParam->inputNb; + + if (*((char**) &(pSelfParam->dbPoint)) != NULL) + { + parameter->number += 1; + parameter->type[tacSINK_MONITOR_DB_POINT] = tacPARAM_STRING; + strcpy((char*) &(pRealParam[tacSINK_MONITOR_DB_POINT]), *((char**) &(pSelfParam->dbPoint))); + } + + return OK; +} + +STATUS tacSinkMonitorStateBlockGetParameter (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = (double*) parameter->buffer; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Send back the expected number of parameters */ + parameter->number = tacSINK_DEFAULT_EXPECTED_PARAM; + + /* Report current parameters */ + pRealParam[tacSINK_SAMPLING_PERIOD] = (double) (pSelfParam->rate * (*pSelf->shared).samplingPeriod); + pRealParam[tacSINK_INPUT_NUMBER] = (double) pSelfParam->inputNb; + + if (*((char**) &(pSelfParam->dbPoint)) != NULL) + { + parameter->number += 1; + parameter->type[tacSINK_MONITOR_DB_POINT] = tacPARAM_STRING; + strcpy((char*) &(pRealParam[tacSINK_MONITOR_DB_POINT]), *((char**) &(pSelfParam->dbPoint))); + } + + return OK; +} + +STATUS tacSinkProbeBlockGetParameter (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = (double*) parameter->buffer; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Send back the expected number of parameters */ + parameter->number = tacSINK_DEFAULT_EXPECTED_PARAM; + + /* Report current parameters */ + pRealParam[tacSINK_SAMPLING_PERIOD] = (double) (pSelfParam->rate * (*pSelf->shared).samplingPeriod); + pRealParam[tacSINK_INPUT_NUMBER] = (double) pSelfParam->inputNb; + + return OK; +} + +/* + * Change parameters Hooks + */ + +/* + * Algorithm Hooks + */ + +void tacSinkDisplayBlockAlgorithm (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + if ((pSelfParam->counter % pSelfParam->rate) == 0) /* It's time to process data */ + { + sprintf(logStr,"Name: %s Time: %ld.%6ld Value: %g\n", + pSelf->name, + (*pSelf->shared).currentTime.seconds, + (*pSelf->shared).currentTime.microsec, + tacStdBlockGetInput(pSelf,0)); + + tacDpcPushRequest((tacVOIDFCTPTR) &printf, logStr); + + pSelfParam->counter = 0; + } + + pSelfParam->counter++; +} + +void tacSinkMonitorBlockAlgorithm (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + unsigned short arrayIndex = 0; + + /* The output port is used to average the inputs over the reporting period */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pSelf->output[arrayIndex] += tacStdBlockGetInput(pSelf,arrayIndex); + } + + if ((pSelfParam->counter % pSelfParam->rate) == 0) /* It's time to process data */ + { + tacDATA* pData = &(pSelfParam->shmMsg.msgBody.monitor.data); /* We are only interested in message body */ + + /* pData->number = pSelfParam->inputNb; */ + pData->timeStamp = (*pSelf->shared).currentTime; + + /* pData points to the body of the Message */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pData->buffer[arrayIndex] = pSelf->output[arrayIndex] / pSelfParam->rate; + } + + /* Push message into probe block's message que to get the + * data out of the interrupt comtext. */ + if ( msgQSend (pSelfParam->msgq, (char*) &(pSelfParam->shmMsg), sizeof(tacSHMSG), NO_WAIT, 0) != OK ) + { + (pSelfParam->lost)++; + } + + /* Defer procedure call */ + tacDpcPushRequest((tacVOIDFCTPTR) &tacSinkSendMonitorMessage, &pSelfParam->msgq); + + pSelfParam->counter = 0; + + /* The output port is used to average the inputs over the reporting period */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pSelf->output[arrayIndex] = 0.0; + } + } + + pSelfParam->counter++; +} + +void tacSinkMonitorStateBlockAlgorithm (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + unsigned short arrayIndex = 0; + + if ((pSelfParam->counter % pSelfParam->rate) == 0) /* It's time to process data */ + { + tacDATA* pData = &(pSelfParam->shmMsg.msgBody.monitor.data); /* We are only interested in message body */ + + /* pData->number = pSelfParam->inputNb; */ + pData->timeStamp = (*pSelf->shared).currentTime; + + /* pData points to the body of the Message */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pData->buffer[arrayIndex] = tacStdBlockGetInput(pSelf,arrayIndex); + } + + /* Push message into probe block's message que to get the + * data out of the interrupt comtext. */ + if ( msgQSend (pSelfParam->msgq, (char*) &(pSelfParam->shmMsg), sizeof(tacSHMSG), NO_WAIT, 0) != OK ) + { + (pSelfParam->lost)++; + } + + /* Defer procedure call */ + tacDpcPushRequest((tacVOIDFCTPTR) &tacSinkSendMonitorMessage, &pSelfParam->msgq); + + pSelfParam->counter = 0; + } + + pSelfParam->counter++; +} + +void tacSinkProbeBlockAlgorithm (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + unsigned short arrayIndex = 0; + + if ((pSelfParam->counter % pSelfParam->rate) == 0) /* It's time to process data */ + { + tacDATA* pData = &(pSelfParam->shmMsg.msgBody.monitor.data); /* We are only interested in message body */ + + pData->timeStamp = (*pSelf->shared).currentTime; + + /* pData points to the body of the Message */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pData->buffer[arrayIndex] = tacStdBlockGetInput(pSelf,arrayIndex); + } + + /* Push message into probe block's message que to get the + * data out of the interrupt comtext. */ + if ( msgQSend (pSelfParam->msgq, (char*) &(pSelfParam->shmMsg), sizeof(tacSHMSG), NO_WAIT, 0) != OK ) + { + (pSelfParam->lost)++; + } + + /* Defer procedure call: + * tacSinkSendProbeMessage is called outside the interrupt routine + * and will take care to pick up the message from the probe block's + * message queue and send it over the shared memory message queue */ + tacDpcPushRequest((tacVOIDFCTPTR) &tacSinkSendProbeMessage, &pSelfParam->msgq); + + pSelfParam->counter = 0; + } + + pSelfParam->counter++; +} + +/* + * Reset Hooks + */ + +/* + * Stop Hooks + */ + +/* + * Destructor Hooks + */ + +/* + * Note: This destructor is used mainly to send a MONITOR message containing + * 0.0 in order to reset the database array (otherwise going from an + * algorithm with 4 monitored data to one with 3 monitored data leaves + * the 4th value equal to the last ...) + */ + +void tacSinkMonitorBlockDestructor (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + tacDATA* pData = &(pSelfParam->shmMsg.msgBody.monitor.data); + unsigned short arrayIndex = 0; + + /* Reset DB values */ + pSelfParam->shmMsg.type = tacSHMSG_MONITOR_DATA; + pData = &(pSelfParam->shmMsg.msgBody.monitor.data); + + pData->number = pSelfParam->inputNb; + + /* pData points to the body of the Message */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pData->buffer[arrayIndex] = 0.0; + } + + /* Send message */ + tacShMsgQSendBgInfo(&pSelfParam->shmMsg); + + pSelfParam->shmMsg.type = tacSHMSG_REMOVE_MONITOR; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + + /* Send message */ + tacShMsgQSendBgInfo(&pSelfParam->shmMsg); + + free(pSelfParam->dbPoint); + + /* delete internal message queue. Do this as deferred procedure call + * to make sure it is only called when all messages have been send + * (through the same deferred call mechanism) */ + tacDpcPushRequest((tacVOIDFCTPTR) tacSinkDeleteMessageQueue, &(pSelfParam->msgq)); + + return; +} + +void tacSinkMonitorStateBlockDestructor (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + tacDATA* pData = &(pSelfParam->shmMsg.msgBody.monitor.data); + unsigned short arrayIndex = 0; + + /* Reset DB values */ + pSelfParam->shmMsg.type = tacSHMSG_MONITOR_DATA; + pData = &(pSelfParam->shmMsg.msgBody.monitor.data); + + pData->number = pSelfParam->inputNb; + + /* pData points to the body of the Message */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pData->buffer[arrayIndex] = 0.0; + } + + /* Send message */ + tacShMsgQSendBgInfo(&pSelfParam->shmMsg); + + pSelfParam->shmMsg.type = tacSHMSG_REMOVE_MONITOR; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + + /* Send message */ + tacShMsgQSendBgInfo(&pSelfParam->shmMsg); + + free(pSelfParam->dbPoint); + + /* delete internal message queue. Do this as deferred procedure call + * to make sure it is only called when all messages have been send + * (through the same deferred call mechanism) */ + tacDpcPushRequest((tacVOIDFCTPTR) tacSinkDeleteMessageQueue, &(pSelfParam->msgq)); + + return; +} + +void tacSinkProbeBlockDestructor (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + pSelfParam->shmMsg.type = tacSHMSG_REMOVE_PROBE; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + + /* Send message */ + tacShMsgQSendDataSample(&pSelfParam->shmMsg); + + /* delete internal message queue. Do this as deferred procedure call + * to make sure it is only called when all messages have been send + * (through the same deferred call mechanism) */ + tacDpcPushRequest((tacVOIDFCTPTR) tacSinkDeleteMessageQueue, &(pSelfParam->msgq)); + + return; +} + +/* + * Show Hooks + */ + +void tacSinkDisplayBlockShow (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Print parameter values */ + printf(" Update rate: %d\n",pSelfParam->rate); + + return; +} + +void tacSinkMonitorBlockShow (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Print parameter values */ + printf(" Update rate: %d\n",pSelfParam->rate); + printf(" Number of input signals: %d\n",pSelfParam->inputNb); + printf(" Queued samples: %d\n", msgQNumMsgs(pSelfParam->msgq)); + printf(" Lost samples: %d\n",pSelfParam->lost); + + if (pSelfParam->dbPoint != NULL) + { + printf(" DB Point: %s\n", pSelfParam->dbPoint); + } + + return; +} + +void tacSinkMonitorStateBlockShow (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Print parameter values */ + printf(" Using MonitorState block, not averaging received data\n"); + printf(" Update rate: %d\n",pSelfParam->rate); + printf(" Number of input signals: %d\n",pSelfParam->inputNb); + printf(" Queued samples: %d\n", msgQNumMsgs(pSelfParam->msgq)); + printf(" Lost samples: %d\n",pSelfParam->lost); + + if (pSelfParam->dbPoint != NULL) + { + printf(" DB Point: %s\n", pSelfParam->dbPoint); + } + + return; +} + +void tacSinkProbeBlockShow (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Print parameter values */ + printf(" Update rate: %d\n",pSelfParam->rate); + printf(" Update rate param (sec): %f\n",pSelfParam->rateParam); + printf(" Number of input signals: %d\n",pSelfParam->inputNb); + printf(" Queued samples: %d\n", msgQNumMsgs(pSelfParam->msgq)); + printf(" Lost samples: %d\n",pSelfParam->lost); + + return; +} + +/* + * Installation function + */ + +tacSTDBLOCK_TYPE tacSinkDisplayTypeInfo = { + "Display", + &tacSinkDisplayBlockConstructor, + &tacSinkDisplayBlockGetParameter, + &tacSinkDisplayBlockAlgorithm, + NULL, + NULL, + NULL, + NULL, + &tacSinkDisplayBlockShow, +}; + +tacSTDBLOCK_TYPE tacSinkMonitorTypeInfo = { + "Monitor", + &tacSinkMonitorBlockConstructor, + &tacSinkMonitorBlockGetParameter, + &tacSinkMonitorBlockAlgorithm, + NULL, + NULL, + NULL, + &tacSinkMonitorBlockDestructor, + &tacSinkMonitorBlockShow, +}; + +tacSTDBLOCK_TYPE tacSinkMonitorStateTypeInfo = { + "MonitorState", + &tacSinkMonitorStateBlockConstructor, + &tacSinkMonitorStateBlockGetParameter, + &tacSinkMonitorStateBlockAlgorithm, + NULL, + NULL, + NULL, + &tacSinkMonitorStateBlockDestructor, + &tacSinkMonitorStateBlockShow, +}; + +/* Probe with a maximal sampling rate of 2kHz */ +tacSTDBLOCK_TYPE tacSinkProbeTypeInfo = { + "Probe", + &tacSinkProbeBlockConstructor, + &tacSinkProbeBlockGetParameter, + &tacSinkProbeBlockAlgorithm, + NULL, + &tacSinkProbeBlockReset, + NULL, + &tacSinkProbeBlockDestructor, + &tacSinkProbeBlockShow, +}; + +/* Fast probe is the same as probe but not does have the + * limitation on the max. recording frequency */ +tacSTDBLOCK_TYPE tacSinkFastProbeTypeInfo = { + "FastProbe", + &tacSinkFastProbeBlockConstructor, + &tacSinkProbeBlockGetParameter, + &tacSinkProbeBlockAlgorithm, + NULL, + &tacSinkProbeBlockReset, + NULL, + &tacSinkProbeBlockDestructor, + &tacSinkProbeBlockShow, +}; + +STATUS tacSinkBlockInitAll (void) +{ + /* Install Sink Block Hooks */ + tacStdBlockInstallNewType(&tacSinkDisplayTypeInfo); + tacStdBlockInstallNewType(&tacSinkMonitorTypeInfo); + tacStdBlockInstallNewType(&tacSinkMonitorStateTypeInfo); + tacStdBlockInstallNewType(&tacSinkProbeTypeInfo); + tacStdBlockInstallNewType(&tacSinkFastProbeTypeInfo); + + /* + * Perform other library initialization operations + */ + + return OK; +} + +/* + * Local functions + */ + +/* + * Note: Routines called from within the algorithm must be declared with + * static __inline__ + */ + +STATUS tacSinkCommonBlockConstructor (tacSTDBLOCK* pSelf, + tacERROR* error) +{ + /* Allocate specific arrays (pointers are initialized to NULL by StdBlock) */ + if (tacStdBlockAllocateArrays(pSelf, 0, tacSINK_DEFAULT_INPUT_NUMBER, + tacSINK_DEFAULT_OUTPUT_NUMBER, error) == ERROR) + { + return ERROR; + } + + if (tacStdBlockAllocateArrayBySize(pSelf, tacSTDBLOCK_PARAM_ARRAY, + sizeof(tacSINK_SCOPE_LOCAL_PARAMETER), error) == ERROR) + { + tacStdBlockReleaseArray(pSelf, tacSTDBLOCK_INPUT_ARRAY, error); + tacStdBlockReleaseArray(pSelf, tacSTDBLOCK_OUTPUT_ARRAY, error); + return ERROR; + } + + /* Specify the number of input signals to attach to become resolved */ + tacStdBlockSetInputNumber(pSelf, tacSINK_ONE_INPUT_NUMBER); /* Required */ + + return OK; +} + +STATUS tacSinkSendMonitorMessage(MSG_Q_ID * msgq) +{ + /* Send message using provided function (different for Monitor and Probe blocks) */ + /* Send message using provided function (different for Monitor and Probe blocks) */ + tacSHMSG msg; + + if ( msgQReceive(*msgq, (char*) &msg, sizeof(tacSHMSG), NO_WAIT) == sizeof(tacSHMSG) ) + { + tacShMsgQSendBgInfo (&msg); + } + + return OK; +} + +STATUS tacSinkSendProbeMessage(MSG_Q_ID * msgq) +{ + /* Send message using provided function (different for Monitor and Probe blocks) */ + tacSHMSG msg; + + if ( msgq == NULL ) + { + return ERROR; + } + + if ( msgQReceive(*msgq, (char*) &msg, sizeof(tacSHMSG), NO_WAIT) == sizeof(tacSHMSG) ) + { + tacShMsgQSendDataSample (&msg); + } + return OK; +} + +STATUS tacSinkDeleteMessageQueue (MSG_Q_ID * msgq) +{ + /* Is called when block is destroyed and removes the internal message queue */ + STATUS status; + + status = msgQDelete (*msgq); + *msgq = NULL; + return status; +} + + +/*___oOo___*/ + + + + + + diff --git a/src/arguments.py b/src/arguments.py new file mode 100644 index 0000000..94e4cea --- /dev/null +++ b/src/arguments.py @@ -0,0 +1,26 @@ +import getopt + +def exitUsage(): + print("usage: %s <.tasrc file> -i -o " % sys.argv[0]) + sys.exit(1) + +def readArguments(args): + sourceDirectories = [] + outputFile = "" + try: + options, _ = getopt.getopt(args, "hi:o:") + except getopt.GetoptError: + exitUsage() + for option, arg in options: + if option == "-h": + exitUsage() + elif option == "-o": + outputFile = arg + elif option == "-i": + sourceDirectories.append(arg) + if outputFile == "": + exitUsage() + if len(sourceDirectories) == 0: + print("WARNING: no source directories specified!") + return outputFile, sourceDirectories + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3624768 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +__pycache__ +out +tacapp.tar.gz +Sources +tacapp +worryingFiles +cc.tar.gz diff --git a/errors.json b/errors.json new file mode 100644 index 0000000..5ec898a --- /dev/null +++ b/errors.json @@ -0,0 +1,4 @@ +{ + "missing_blocks": [], + "multiple_definitions": [] +} \ No newline at end of file diff --git a/hardcodedFiles/tacReadRmnBlock.c b/hardcodedFiles/tacReadRmnBlock.c new file mode 100644 index 0000000..8acbcfa --- /dev/null +++ b/hardcodedFiles/tacReadRmnBlock.c @@ -0,0 +1,568 @@ +/******************************************************************************* +* E.S.O. - VLT project +* +* "@(#) $Id: tacReadRmnBlock.c 305476 2018-01-19 08:56:18Z rfrahm $" +* +* who when what +* ------- -------- ---------------------------------------------- +* gzins 2010-07-27 ported to VLTSW2010 and VxWorks 6.4 +* swehner 2008-10-10 creation +*/ + +/************************************************************************ +* NAME +* tacReadRmnBlock - Implemements the standard functions for the +* tacReadRmn block and tacReadRfm block. +* tacReadRmnBlock - Reads from 1rst generation reflective memory network +* tacReadRfmBlock - Reads from 2nd generation reflective memory network + +* Parameters: +* field - token names for the RMN fields to read (up to 10) +* Inputs: 0 +* Outputs: 1 +* output - 1..10 depending on number of field parameters +* +* +* +* FILES +* +* ENVIRONMENT +* TAC +* +* RETURN VALUES +* +* CAUTIONS +* +* EXAMPLES +* TAC.BLOCK9.TYPE ReadRmn +* TAC.BLOCK9.NAME ReadRmn +* +* SEE ALSO +* +* BUGS +* +*------------------------------------------------------------------------ +*/ + +#define _POSIX_SOURCE 1 +#include "vltPort.h" + +ATTRIBUTE_UNUSED static const char *rcsId="@(#) $Id: tacReadRmnBlock.c 305476 2018-01-19 08:56:18Z rfrahm $"; + +/* + * System Headers + */ + +#include /* taskSpawn, taskDelay, ... */ +#include /* printf ... */ +#include /* malloc ... */ +#include /* malloc ... */ +#include +#include + +/* + * Local Headers + */ + +#include "tacStdBlock.h" +#include "tacRmnBlock.h" +#include "rmassPublic.h" +#include "rmassPrivate.h" + +/* + * Compilation directives + */ + +/* + * Constants + */ + +#define tacREAD_RMN_EXPECTED_PARAM 1 +#define tacREAD_RMN_DEFAULT_INPUT_NUMBER 0 +#define tacREAD_RMN_DEFAULT_OUTPUT_NUMBER tacMAX_DATA_NUMBER + +#define tacREAD_RMN_FIELD_STRING_LEN 256 +#define tacSTRLEN sizeof(double) + +/* + * Types + */ + +/* + * Local function declaration + */ + +/* + * Global variables + */ + +/* + * Function definition + */ + + +STATUS tacReadRmnBlockCheckParameter (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the ADDBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = NULL; + + pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + /* field string is built from block params */ + if ( tacRmnBlockCheckParameter ( pSelf, parameter, 0, error) != OK ) + { + return ERROR; + } + + /* useful information on the screen */ + printf ("ReadRmn %s: [%s]\n", pSelf->name, pSelfParam->fieldString); + + return OK; +} + +STATUS tacReadRfmBlockCheckParameter (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the ADDBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = NULL; + + pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + /* field string is built from block params */ + if ( tacRmnBlockCheckParameter ( pSelf, parameter, 0, error) != OK ) + { + return ERROR; + } + + /* useful information on the screen */ + printf ("ReadRfm %s: [%s]\n", pSelf->name, pSelfParam->fieldString); + + return OK; +} + +/* + * Constructor Hooks - Called when a block of this type is instanciated (CONFIG or ADDBLCK commands) + */ + +STATUS tacReadRmBlockConstructor (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the ADDBLCK command */ + vltLOGICAL isRmn, + tacERROR* error) /* Error structure - not a stack */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = NULL; + + /* Check that the expected number of parameters has been received */ + if (parameter->number < tacREAD_RMN_EXPECTED_PARAM) + { + char errorParam[40]; + + sprintf(errorParam, "Expected at least %d, received %d", tacREAD_RMN_EXPECTED_PARAM, parameter->number); + tacRTC_ERR(tacERR_PARAM_NUMBER, errorParam); + return ERROR; + } + + /* Allocate and initialize block-specific arrays */ + if (tacStdBlockAllocateArrays(pSelf, 0, tacREAD_RMN_DEFAULT_INPUT_NUMBER, tacREAD_RMN_DEFAULT_OUTPUT_NUMBER, error) == ERROR) + { + return ERROR; + } + + if (tacStdBlockAllocateArrayBySize(pSelf, tacSTDBLOCK_PARAM_ARRAY, sizeof(tacRMN_LOCAL_PARAMETER), error) == ERROR) + { + tacStdBlockReleaseArray(pSelf, tacSTDBLOCK_INPUT_ARRAY, error); + tacStdBlockReleaseArray(pSelf, tacSTDBLOCK_OUTPUT_ARRAY, error); + return ERROR; + } + + if ( isRmn ) + { + if ( tacReadRmnBlockCheckParameter (pSelf, parameter, error) == ERROR) + { + return ERROR; + } + } + else + { + if ( tacReadRfmBlockCheckParameter (pSelf, parameter, error) == ERROR) + { + return ERROR; + } + } + + pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + pSelfParam->handleValid = rmassACCESS_BLOCKED; + + /* Attach to RMN */ + if ( rmassReadAttach (&pSelfParam->handle, + pSelfParam->fieldString, + &pSelfParam->val[0], + &pSelfParam->val[1], + &pSelfParam->val[2], + &pSelfParam->val[3], + &pSelfParam->val[4], + &pSelfParam->val[5], + &pSelfParam->val[6], + &pSelfParam->val[7], + &pSelfParam->val[8], + &pSelfParam->val[9]) != SUCCESS ) + { + char errorParam[40]; + + sprintf(errorParam, "Attach to RMN failed."); + tacRTC_ERR(tacERR_INTERNAL, errorParam); + return ERROR; + } + + pSelfParam->handleValid = rmassACCESS_FREE; + + return OK; +} + +STATUS tacReadRmnBlockConstructor (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the ADDBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + if ( tacReadRmBlockConstructor (pSelf, parameter, ccsTRUE, error ) == ERROR ) + { + return ERROR; + } + return OK; +} + +STATUS tacReadRfmBlockConstructor (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the ADDBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + if ( tacReadRmBlockConstructor (pSelf, parameter, ccsFALSE, error ) == ERROR ) + { + return ERROR; + } + return OK; +} + + + +/* + * Destructor Hooks - Called when the block is removed from the algorithm (DELBLCK or new CONFIG commands) + */ + +void tacReadRmnBlockDestructor (tacSTDBLOCK* pSelf) /* Reference to the block instance */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = NULL; + pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + pSelfParam->handleValid = rmassACCESS_BLOCKED; + /* wait until semaphore is acknowledged by realtime algo + * or just procede if realtime is not active */ + while ((*pSelf->shared).active && pSelfParam->handleValid != rmassACCESS_BLOCK_ACKN) + { + taskDelay(1); + } + + rmassDetach (&pSelfParam->handle); + + return; +} + +/* + * Change parameters Hooks - Called when modifying the block parameters (MODBLCK command) + */ + +STATUS tacReadRmnBlockSetParameter (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the MODBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + if ( tacReadRmnBlockCheckParameter (pSelf, parameter, error) == ERROR) + { + return ERROR; + } + + pSelfParam->handleValid = rmassACCESS_BLOCKED; + /* wait until semaphore is acknowledged by realtime algo + * or just procede if realtime is not active */ + while ((*pSelf->shared).active && pSelfParam->handleValid != rmassACCESS_BLOCK_ACKN) + { + taskDelay(1); + } + + /* detach RMN handle */ + if ( rmassDetach (&pSelfParam->handle) != SUCCESS ) + { + char errorParam[40]; + + sprintf(errorParam, "rmassDetach returned error."); + tacRTC_ERR(tacERR_INTERNAL, errorParam); + return ERROR; + } + + if ( rmassReadAttach (&pSelfParam->handle, + pSelfParam->fieldString, + &pSelfParam->val[0], + &pSelfParam->val[1], + &pSelfParam->val[2], + &pSelfParam->val[3], + &pSelfParam->val[4], + &pSelfParam->val[5], + &pSelfParam->val[6], + &pSelfParam->val[7], + &pSelfParam->val[8], + &pSelfParam->val[9]) != SUCCESS ) + { + char errorParam[40]; + + sprintf(errorParam, "Attach to RMN failed."); + tacRTC_ERR(tacERR_INTERNAL, errorParam); + return ERROR; + } + + pSelfParam->handleValid = rmassACCESS_FREE; + + return OK; +} + +STATUS tacReadRfmBlockSetParameter (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the MODBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + if ( tacReadRfmBlockCheckParameter (pSelf, parameter, error) == ERROR) + { + return ERROR; + } + + pSelfParam->handleValid = rmassACCESS_BLOCKED; + /* wait until semaphore is acknowledged by realtime algo + * or just procede if realtime is not active */ + while ((*pSelf->shared).active && pSelfParam->handleValid != rmassACCESS_BLOCK_ACKN) + { + taskDelay(1); + } + + /* detach RMN handle */ + if ( rmassDetach (&pSelfParam->handle) != SUCCESS ) + { + char errorParam[40]; + + sprintf(errorParam, "rmassDetach returned error."); + tacRTC_ERR(tacERR_INTERNAL, errorParam); + return ERROR; + } + + if ( rmassReadAttach (&pSelfParam->handle, + pSelfParam->fieldString, + &pSelfParam->val[0], + &pSelfParam->val[1], + &pSelfParam->val[2], + &pSelfParam->val[3], + &pSelfParam->val[4], + &pSelfParam->val[5], + &pSelfParam->val[6], + &pSelfParam->val[7], + &pSelfParam->val[8], + &pSelfParam->val[9]) != SUCCESS ) + { + char errorParam[40]; + + sprintf(errorParam, "Attach to RFM failed."); + tacRTC_ERR(tacERR_INTERNAL, errorParam); + return ERROR; + } + + pSelfParam->handleValid = rmassACCESS_FREE; + + return OK; +} + +/* + * Algorithm Hooks - Called at each time the TAC algorithm is evaluated (ONLINE state) + */ + +void tacReadRmnBlockAlgorithm (tacSTDBLOCK* pSelf) /* Reference to the block instance */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + int i; + + if ( pSelfParam->handleValid == rmassACCESS_BLOCKED ) + { + pSelfParam->handleValid = rmassACCESS_BLOCK_ACKN; + } + + if ( pSelfParam->handleValid == rmassACCESS_FREE ) + { + /* actual RMN read operation */ + rmassReadAccessRmn (&pSelfParam->handle); + + /* Write to outputs */ + for (i=0; i < pSelfParam->numFields; i++) + { + switch (pSelfParam->type[i]) + { + case rmassTIMESEC: + case rmassUINT32: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).ui); + break; + case rmassTIMEUSEC: + case rmassINT32: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).i); + break; + case rmassFLOAT: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).f); + break; + default: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).d); + break; + } + } + + /* provide zero values at unsatisfied outputs + * I consider this a good thing to do since the block + * is always configured */ + for (i=pSelfParam->numFields; i < tacREAD_RMN_DEFAULT_OUTPUT_NUMBER; i++) + { + tacStdBlockSetOutput(pSelf, i, 0.0); + } + } +} + +void tacReadRfmBlockAlgorithm (tacSTDBLOCK* pSelf) /* Reference to the block instance */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + int i; + + if ( pSelfParam->handleValid == rmassACCESS_BLOCKED ) + { + pSelfParam->handleValid = rmassACCESS_BLOCK_ACKN; + } + + if ( pSelfParam->handleValid == rmassACCESS_FREE ) + { + /* actual RMN read operation */ + rmassReadAccessRfm (&pSelfParam->handle); + + /* Write to outputs */ + for (i=0; i < pSelfParam->numFields; i++) + { + switch (pSelfParam->type[i]) + { + case rmassTIMESEC: + case rmassUINT32: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).ui); + break; + case rmassTIMEUSEC: + case rmassINT32: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).i); + break; + case rmassFLOAT: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).f); + break; + default: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).d); + break; + } + } + + /* provide zero values at unsatisfied outputs + * I consider this a good thing to do since the block + * is always configured */ + for (i=pSelfParam->numFields; i < tacREAD_RMN_DEFAULT_OUTPUT_NUMBER; i++) + { + tacStdBlockSetOutput(pSelf, i, 0.0); + } + } +} + +/* + * Show Hooks - Called when the tacRtcTaskShow routine is executed + */ + +void tacReadRmnBlockShow (tacSTDBLOCK* pSelf) /* Reference to the block instance */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + /* Print parameter values */ + printf(" Attached: %s\n", pSelfParam->fieldString); + + return; +} + + +/***************************************************/ +/* The following code is common to all block types */ +/* Do not modify without any good reasons */ +/***************************************************/ + +/* + * Installation function + */ + +tacSTDBLOCK_TYPE tacReadRmnTypeInfo = { + "ReadRmn", + &tacReadRmnBlockConstructor, + &tacRmBlockGetParameter, + &tacReadRmnBlockAlgorithm, + &tacReadRmnBlockSetParameter, + NULL, + NULL, + &tacReadRmnBlockDestructor, + &tacReadRmnBlockShow +}; + +tacSTDBLOCK_TYPE tacReadRfmTypeInfo = { + "ReadRfm", + &tacReadRfmBlockConstructor, + &tacRmBlockGetParameter, + &tacReadRfmBlockAlgorithm, + &tacReadRmnBlockSetParameter, + NULL, + NULL, + &tacReadRmnBlockDestructor, + &tacReadRmnBlockShow +}; + +STATUS tacReadRmnBlockInitAll (void) +{ + /***************************************************/ + /* The following code is common to all block types */ + /* Do not modify without any good reasons */ + /***************************************************/ + + /* Install ReadRmn1g Block Hooks */ + tacStdBlockInstallNewType(&tacReadRmnTypeInfo); + + /*****************************/ + /* End of common code region */ + /*****************************/ + + /* Perform other library initialization operations */ + + return OK; +} + +STATUS tacReadRfmBlockInitAll (void) +{ + /***************************************************/ + /* The following code is common to all block types */ + /* Do not modify without any good reasons */ + /***************************************************/ + + /* Install ReadRmn1g Block Hooks */ + tacStdBlockInstallNewType(&tacReadRfmTypeInfo); + + /*****************************/ + /* End of common code region */ + /*****************************/ + + /* Perform other library initialization operations */ + + return OK; +} + +/*___oOo___*/ + + + diff --git a/hardcodedFiles/tacSinkBlock.c b/hardcodedFiles/tacSinkBlock.c new file mode 100644 index 0000000..df39833 --- /dev/null +++ b/hardcodedFiles/tacSinkBlock.c @@ -0,0 +1,1256 @@ +/******************************************************************************* +* E.S.O. - VLT project +* +* "@(#) $Id: tacSinkBlock.c 339094 2021-02-10 03:10:02Z jgil $" +* +* who when what +* ------- -------- ---------------------------------------------- +* rdembet 06/08/20 New MonitorState block with no data averaging +* swehner 28/11/09 SPR20090234 Correction in rate adjustment in reset hook +* swehner 27/11/09 Fixed message queue handling +* swehner 10/10/09 New block FastProbe for unlimited rec frequency +* swehner 22/09/09 PPRS 32341 Replaced specialized tacSINK_SHMSG stack +* with standard vxWorks message queue. +* bbauvir 21/09/04 VLTSW20040113 - One sample might be lost +* bbauvir 29/03/04 Monitor block averages over the reporting period +* bbauvir 29/12/02 Probe to the SampTask +* bbauvir 26/12/02 MsgQ access through DPC mechanism +* bbauvir 14/07/02 New MsgQ of TAC version 1.22 +* bbauvir 21/03/01 Created +*/ + +/************************************************************************ +* NAME +* tacSinkBlock - Standard data monitoring blocks +* +* SYNOPSIS +* lcubootAutoCdBoot 1,"tacsink.boot" +* < tacsink.boot +* +* DESCRIPTION +* Block type: Display +* Parameters: +* Inputs: 1 +* Outputs: none +* +* This function block samples the value of its input signal at the +* specified and issues a message containing the time +* and the value of the input on the vxWorks terminal. +* It does not allow modification of the parameter at runtime. +* +* Block type: Monitor +* Parameters: +* +* Inputs: 10max +* Outputs: none +* +* This function block samples the value of its input signals at the +* specified (0.0 to send a message at the system sampling +* period) and issues a message containing the time and the value of +* the inputs on the shared memory. This message is intercepted by the +* background task running on the master CPU. The monitored values are +* written into the online database. The number of inputs of the block +* is specified by parameter. +* This block does not allow modification of the parameters at runtime. +* +* Block type: MonitorState +* Parameters: +* +* Inputs: 10max +* Outputs: none +* +* Same as Monitor block but without the averaging of received data, +* see VLTSW-14260 JIRA ticket. +* +* Block type: Probe +* Parameters: +* +* Inputs: 10max +* Outputs: none +* +* Block type: FastProbe +* Parameters: +* +* Inputs: 10max +* Outputs: none +* +* This function block samples the value of its input signals at the +* specified (0.0 to send a message at the system sampling +* period) and issues a message containing the time and the value of +* the inputs on the shared memory. This message is intercepted by the +* background task running on the master CPU. The number of inputs of +* the block is specified by parameter. +* This message is passed to an external application callback if +* provided. +* This block does not allow modification of the parameters at runtime. +* The normal Probe block has a limited sampling frequency of not more +* than 2kHz. The reason is in particular the bottleneck between master +* and slave CPU which all samples have to pass through a mechanism of +* VME bus shared memory. On one-CPU-systems this limitation does not +* apply so you are free to choose faster sampling. You may of course +* hit other limitations (processor speed, network traffic etc.) +* +* FILES +* +* ENVIRONMENT +* TAC +* +* RETURN VALUES +* +* CAUTIONS +* All these blocks compute an decimation value to use to trigger the +* sampling of the input signals, from the system sampling period. +* They should be created after any synchronization block. +* +* In order to cope with system performances, a minimum +* is defined for each block. The minimum applied periods are 0.1 (10Hz), +* 0.01 (100Hz) and 0.5e-3 (2kHz) for the 'Display', 'Monitor' and +* 'Probe' blocks respectively. +* +* EXAMPLES +* # 5 signals @ 2Hz (monitored in the database) +* TAC.BLOCK9.TYPE Monitor +* TAC.BLOCK9.NAME Monitor +* TAC.BLOCK9.PARAM 0.5, 5 +* +* # 5 signals @ the RT algorithm sampling period (0.0) +* TAC.BLOCK10.TYPE Probe +* TAC.BLOCK10.NAME Probe +* TAC.BLOCK10.PARAM 0.0, 5 +* +* SEE ALSO +* tacServerInstallDataCallback, tacServerRemoveDataCallback +* +* BUGS +* +*------------------------------------------------------------------------ +*/ + +#define _POSIX_SOURCE 1 +#include "vltPort.h" + + +/* + * System Headers + */ + +#include +#include +#include /* logMsg ... */ +#include /* printf ... */ +#include /* malloc ... */ +#include /* memcpy ... */ +#include + +/* + * Local Headers + */ + +#include "tacStdBlock.h" +#include "tacShMsgQ.h" + +/* + * Compilation directives + */ + +/* + * Constants + */ + +#define tacSINK_DEFAULT_EXPECTED_PARAM 2 + +#define tacSINK_DEFAULT_INPUT_NUMBER tacMAX_DATA_NUMBER /* Up to 10 input channels */ +#define tacSINK_DEFAULT_OUTPUT_NUMBER tacMAX_DATA_NUMBER + +#define tacSINK_ONE_EXPECTED_PARAM 1 +#define tacSINK_ONE_INPUT_NUMBER 1 + +#define tacSINK_DISPLAY_MIN_SAMPLING_PERIOD .1 /* 10Hz */ +#define tacSINK_MONITOR_MIN_SAMPLING_PERIOD .01 /* 100Hz */ +#define tacSINK_PROBE_MIN_SAMPLING_PERIOD .5e-3 /* 2kHz */ + +#define tacSINK_DISPLAY_LOG_STRING_SIZE 128 + +#define tacSINK_MONITOR_DEFAULT_DB_POINT "tac:data:monitor" +#define tacSINK_MONITOR_MAX_DB_ADDR_SIZE 64 + +#define tacSINK_MONITOR_QUEUE_SIZE 6 +#define tacSINK_PROBE_QUEUE_SIZE 6 + + +typedef enum { + tacSINK_SAMPLING_PERIOD = 0, + tacSINK_INPUT_NUMBER, + tacSINK_MONITOR_DB_POINT, +}tacSINK_SCOPE_PARAM_INDEX; + +/* + * Types + */ + +typedef struct { + unsigned short rate; + unsigned short counter; + unsigned short inputNb; + unsigned int lost; + double rateParam; + char* dbPoint; + MSG_Q_ID msgq; + tacSHMSG shmMsg; +}tacSINK_SCOPE_LOCAL_PARAMETER; + +/* + * Function declaration + */ + +extern STATUS tacDpcPushRequest(tacVOIDFCTPTR pFunct, void* parameter); + +/* + * Local function declaration + */ + +/* + * Note: Routines called from within the algorithm must be declared with + * static __inline__ + */ + +STATUS tacSinkSendMonitorMessage(MSG_Q_ID * msgqvoid); +STATUS tacSinkSendMonitorStateMessage(MSG_Q_ID * msgqvoid); +STATUS tacSinkSendProbeMessage(MSG_Q_ID * msgq); +STATUS tacSinkDeleteMessageQueue(MSG_Q_ID * msgq); +STATUS tacSinkCommonBlockConstructor(tacSTDBLOCK* pSelf, tacERROR* error); + +/* + * Global variables + */ + +char logStr[tacSINK_DISPLAY_LOG_STRING_SIZE]; /* Logging string used for Display */ + + +/* + * Function definition + */ + +/* + * Constructor Hooks + */ + +STATUS tacSinkDisplayBlockConstructor (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = NULL; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = NULL; + + /* Check that the expected number of parameters has been received */ + if (parameter->number < tacSINK_ONE_EXPECTED_PARAM) + { + char errorParam[40]; + + sprintf(errorParam, "Expected %d, received %d", tacSINK_ONE_EXPECTED_PARAM, parameter->number); + tacRTC_ERR(tacERR_PARAM_NUMBER, errorParam); + return ERROR; + } + + /* Check that the parameters are valid */ + pRealParam = (double*) parameter->buffer; + + /* Passed parameter is the sampling period of the block */ + if (pRealParam[tacSINK_SAMPLING_PERIOD] < (*pSelf->shared).samplingPeriod) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = (*pSelf->shared).samplingPeriod; + } + + if (pRealParam[tacSINK_SAMPLING_PERIOD] < tacSINK_DISPLAY_MIN_SAMPLING_PERIOD) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = tacSINK_DISPLAY_MIN_SAMPLING_PERIOD; + } + + /* Call common constructor */ + if (tacSinkCommonBlockConstructor(pSelf, error) != OK) + { + return ERROR; + } + + /* Store parameters */ + pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; /* We will only store short integers */ + + /* + * Compute the rate at which data has to be processed - divide and take + * the integer part of the result + */ + + pSelfParam->rate = (unsigned short) (pRealParam[tacSINK_SAMPLING_PERIOD] / (*pSelf->shared).samplingPeriod); + pSelfParam->counter = 0; /* Decimation counter */ + + /* + * Perform other block initialization operations + */ + + return OK; +} + +STATUS tacSinkMonitorBlockConstructor (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = NULL; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = NULL; + unsigned short arrayIndex = 0; + + /* Check that the expected number of parameters has been received */ + if (parameter->number < tacSINK_DEFAULT_EXPECTED_PARAM) + { + char errorParam[40]; + + sprintf(errorParam, "Expected %d, received %d", tacSINK_DEFAULT_EXPECTED_PARAM, parameter->number); + tacRTC_ERR(tacERR_PARAM_NUMBER, errorParam); + return ERROR; + } + + /* Check that the parameters are valid */ + pRealParam = (double*) parameter->buffer; + + /* Passed parameter is the sampling period of the block */ + if (pRealParam[tacSINK_SAMPLING_PERIOD] < (*pSelf->shared).samplingPeriod) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = (*pSelf->shared).samplingPeriod; + } + + if (pRealParam[tacSINK_SAMPLING_PERIOD] < tacSINK_MONITOR_MIN_SAMPLING_PERIOD) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = tacSINK_MONITOR_MIN_SAMPLING_PERIOD; + } + + /* Number of inputs is minimum 1 up to tacMSG_MAX_DATA_NUMBER */ + if ((pRealParam[tacSINK_INPUT_NUMBER] < 1) || + (pRealParam[tacSINK_INPUT_NUMBER] > tacMAX_DATA_NUMBER)) + { + tacRTC_ERR(tacERR_PARAM_INVALID, ""); + return ERROR; + } + + /* Call common constructor */ + if (tacSinkCommonBlockConstructor(pSelf, error) != OK) + { + return ERROR; + } + + /* Store parameters */ + pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* + * Compute the rate at which data has to be processed - divide and take + * the integer part of the result + */ + + pSelfParam->rate = (unsigned short) (pRealParam[tacSINK_SAMPLING_PERIOD] / (*pSelf->shared).samplingPeriod); + pSelfParam->counter = 0; /* Decimation counter */ + pSelfParam->inputNb = (unsigned short) pRealParam[tacSINK_INPUT_NUMBER]; + + /* Optional parameter is an application-specific DB point */ + if (parameter->number == tacSINK_DEFAULT_EXPECTED_PARAM + 1) + { + printf("tacSinkMonitorBlockConstructor - DB point %s\n",(char*) &(pRealParam[tacSINK_MONITOR_DB_POINT])); + pSelfParam->dbPoint = (char*) malloc(tacSINK_MONITOR_MAX_DB_ADDR_SIZE); + strcpy(pSelfParam->dbPoint, (char*) &(pRealParam[tacSINK_MONITOR_DB_POINT])); + } + else + { + printf("tacSinkMonitorBlockConstructor - Default DB point\n"); + pSelfParam->dbPoint = NULL; + } + + /* Specify the number of input signals to attach to become resolved */ + tacStdBlockSetInputNumber(pSelf, pSelfParam->inputNb); + + /* + * Perform other block initialization operations + */ + + /* Create the block internal message queue which tosses the messages out of the + * interrupt context. They are buffered in the queue until the DPC tasks + * picks them up and sends them over the shared memory message queue. + * Sorry for that double-queuing, that's because of the M-S architecture */ + + pSelfParam->msgq = msgQCreate(tacSINK_MONITOR_QUEUE_SIZE, sizeof(tacSHMSG), 0); + if ( pSelfParam->msgq == NULL ) + { + char errorParam[40]; + + sprintf(errorParam, "Could not create probe block message queue"); + tacRTC_ERR(tacERR_MALLOC, errorParam); + return ERROR; + } + + /* will count if a message can't be pushed in the queue */ + pSelfParam->lost = 0; + + /* Warn the background task that a new probe block has been created */ + pSelfParam->shmMsg.type = tacSHMSG_ADD_MONITOR; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + + if (pSelfParam->dbPoint == NULL) + { + strcpy((char*) &(pSelfParam->shmMsg.msgBody.monitor.data), tacSINK_MONITOR_DEFAULT_DB_POINT); + } + else + { + strcpy((char*) &(pSelfParam->shmMsg.msgBody.monitor.data), *((char**) &(pSelfParam->dbPoint))); + } + + printf("tacSinkMonitorBlockConstructor - Attach to %s\n",(char*) &(pSelfParam->shmMsg.msgBody.monitor.data)); + + /* Send message */ + tacShMsgQSendBgInfo(&(pSelfParam->shmMsg)); + + /* Initialize the message parameters */ + pSelfParam->shmMsg.type = tacSHMSG_MONITOR_DATA; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + pSelfParam->shmMsg.msgBody.monitor.data.number = pSelfParam->inputNb; + + /* The output port is used to average the inputs over the reporting period */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pSelf->output[arrayIndex] = 0.0; + } + + return OK; +} + +STATUS tacSinkMonitorStateBlockConstructor (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = NULL; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = NULL; + unsigned short arrayIndex = 0; + + /* Check that the expected number of parameters has been received */ + if (parameter->number < tacSINK_DEFAULT_EXPECTED_PARAM) + { + char errorParam[40]; + + sprintf(errorParam, "Expected %d, received %d", tacSINK_DEFAULT_EXPECTED_PARAM, parameter->number); + tacRTC_ERR(tacERR_PARAM_NUMBER, errorParam); + return ERROR; + } + + /* Check that the parameters are valid */ + pRealParam = (double*) parameter->buffer; + + /* Passed parameter is the sampling period of the block */ + if (pRealParam[tacSINK_SAMPLING_PERIOD] < (*pSelf->shared).samplingPeriod) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = (*pSelf->shared).samplingPeriod; + } + + if (pRealParam[tacSINK_SAMPLING_PERIOD] < tacSINK_MONITOR_MIN_SAMPLING_PERIOD) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = tacSINK_MONITOR_MIN_SAMPLING_PERIOD; + } + + /* Number of inputs is minimum 1 up to tacMSG_MAX_DATA_NUMBER */ + if ((pRealParam[tacSINK_INPUT_NUMBER] < 1) || + (pRealParam[tacSINK_INPUT_NUMBER] > tacMAX_DATA_NUMBER)) + { + tacRTC_ERR(tacERR_PARAM_INVALID, ""); + return ERROR; + } + + /* Call common constructor */ + if (tacSinkCommonBlockConstructor(pSelf, error) != OK) + { + return ERROR; + } + + /* Store parameters */ + pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* + * Compute the rate at which data has to be processed - divide and take + * the integer part of the result + */ + + pSelfParam->rate = (unsigned short) (pRealParam[tacSINK_SAMPLING_PERIOD] / (*pSelf->shared).samplingPeriod); + pSelfParam->counter = 0; /* Decimation counter */ + pSelfParam->inputNb = (unsigned short) pRealParam[tacSINK_INPUT_NUMBER]; + + /* Optional parameter is an application-specific DB point */ + if (parameter->number == tacSINK_DEFAULT_EXPECTED_PARAM + 1) + { + printf("tacSinkMonitorStateBlockConstructor - DB point %s\n",(char*) &(pRealParam[tacSINK_MONITOR_DB_POINT])); + pSelfParam->dbPoint = (char*) malloc(tacSINK_MONITOR_MAX_DB_ADDR_SIZE); + strcpy(pSelfParam->dbPoint, (char*) &(pRealParam[tacSINK_MONITOR_DB_POINT])); + } + else + { + printf("tacSinkMonitorStateBlockConstructor - Default DB point\n"); + pSelfParam->dbPoint = NULL; + } + + /* Specify the number of input signals to attach to become resolved */ + tacStdBlockSetInputNumber(pSelf, pSelfParam->inputNb); + + /* + * Perform other block initialization operations + */ + + /* Create the block internal message queue which tosses the messages out of the + * interrupt context. They are buffered in the queue until the DPC tasks + * picks them up and sends them over the shared memory message queue. + * Sorry for that double-queuing, that's because of the M-S architecture */ + + pSelfParam->msgq = msgQCreate(tacSINK_MONITOR_QUEUE_SIZE, sizeof(tacSHMSG), 0); + if ( pSelfParam->msgq == NULL ) + { + char errorParam[40]; + + sprintf(errorParam, "Could not create probe block message queue"); + tacRTC_ERR(tacERR_MALLOC, errorParam); + return ERROR; + } + + /* will count if a message can't be pushed in the queue */ + pSelfParam->lost = 0; + + /* Warn the background task that a new probe block has been created */ + pSelfParam->shmMsg.type = tacSHMSG_ADD_MONITOR; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + + if (pSelfParam->dbPoint == NULL) + { + strcpy((char*) &(pSelfParam->shmMsg.msgBody.monitor.data), tacSINK_MONITOR_DEFAULT_DB_POINT); + } + else + { + strcpy((char*) &(pSelfParam->shmMsg.msgBody.monitor.data), *((char**) &(pSelfParam->dbPoint))); + } + + printf("tacSinkMonitorStateBlockConstructor - Attach to %s\n",(char*) &(pSelfParam->shmMsg.msgBody.monitor.data)); + + /* Send message */ + tacShMsgQSendBgInfo(&(pSelfParam->shmMsg)); + + /* Initialize the message parameters */ + pSelfParam->shmMsg.type = tacSHMSG_MONITOR_DATA; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + pSelfParam->shmMsg.msgBody.monitor.data.number = pSelfParam->inputNb; + + /* Init output port which won't be used to average the inputs over the reporting period */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pSelf->output[arrayIndex] = 0.0; + } + + return OK; +} + +STATUS tacSinkProbeBlockCommonConstructor (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + double minPeriod, + tacERROR* error) +{ + double* pRealParam = NULL; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = NULL; + + /* Check that the expected number of parameters has been received */ + if (parameter->number < tacSINK_DEFAULT_EXPECTED_PARAM) + { + char errorParam[40]; + + sprintf(errorParam, "Expected %d, received %d", tacSINK_DEFAULT_EXPECTED_PARAM, parameter->number); + tacRTC_ERR(tacERR_PARAM_NUMBER, errorParam); + return ERROR; + } + + /* Check that the parameters are valid */ + pRealParam = (double*) parameter->buffer; + + /* Passed parameter is the sampling period of the block */ + if (pRealParam[tacSINK_SAMPLING_PERIOD] < (*pSelf->shared).samplingPeriod) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = (*pSelf->shared).samplingPeriod; + } + + if (pRealParam[tacSINK_SAMPLING_PERIOD] < minPeriod) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = minPeriod; + } + + /* Number of inputs is minimum 1 up to tacMSG_MAX_DATA_NUMBER */ + if ((pRealParam[tacSINK_INPUT_NUMBER] < 1) || + (pRealParam[tacSINK_INPUT_NUMBER] > tacMAX_DATA_NUMBER)) + { + tacRTC_ERR(tacERR_PARAM_INVALID, ""); + return ERROR; + } + + /* Call common constructor */ + if (tacSinkCommonBlockConstructor(pSelf, error) != OK) + { + return ERROR; + } + + /* Store parameters */ + pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* + * Compute the rate at which data has to be processed - divide and take + * the integer part of the result + */ + + pSelfParam->rateParam = pRealParam[tacSINK_SAMPLING_PERIOD]; + pSelfParam->rate = (unsigned short) (pRealParam[tacSINK_SAMPLING_PERIOD] / (*pSelf->shared).samplingPeriod); + pSelfParam->counter = 0; /* Decimation counter */ + pSelfParam->inputNb = (unsigned short) pRealParam[tacSINK_INPUT_NUMBER]; + + /* Specify the number of input signals to attach to become resolved */ + tacStdBlockSetInputNumber(pSelf, pSelfParam->inputNb); + + /* + * Perform other block initialization operations + */ + + /* Create the block internal message queue which gets the messages out of the + * interrupt context. They are buffered in the queue until the DPC tasks + * picks them up and sends them over the shared memory message queue. + * Sorry for that double-queuing, that's because of the M-S architecture */ + + /* There is only one message queue for all probe blocks! */ + pSelfParam->msgq = msgQCreate(tacSINK_PROBE_QUEUE_SIZE, sizeof(tacSHMSG), 0); + if ( pSelfParam->msgq == NULL ) + { + char errorParam[40]; + + sprintf(errorParam, "Could not create probe block message queue"); + tacRTC_ERR(tacERR_MALLOC, errorParam); + return ERROR; + } + + /* will count if a message can't be pushed in the queue */ + pSelfParam->lost = 0; + + /* Warn the background task that a new probe block has been created */ + pSelfParam->shmMsg.type = tacSHMSG_ADD_PROBE; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + + /* Send message */ + tacShMsgQSendDataSample(&pSelfParam->shmMsg); + + /* Initialize the message parameters */ + pSelfParam->shmMsg.type = tacSHMSG_TRANSFER_DATA; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + pSelfParam->shmMsg.msgBody.monitor.data.number = pSelfParam->inputNb; + + return OK; +} + +/* Probe block has a max. sampling frequency of 2kHz */ +STATUS tacSinkProbeBlockConstructor (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + return tacSinkProbeBlockCommonConstructor (pSelf, parameter, tacSINK_PROBE_MIN_SAMPLING_PERIOD, error); +} + +/* Fast probe is the same as probe but not does have the + * limitation on the max. recording frequency */ +STATUS tacSinkFastProbeBlockConstructor (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + return tacSinkProbeBlockCommonConstructor (pSelf, parameter, 0.0, error); +} + +void tacSinkProbeBlockReset (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = + (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* + * Re-Compute the rate at which data has to be processed + */ + if (pSelfParam->rateParam < (*pSelf->shared).samplingPeriod ) + { + pSelfParam->rate = 1; + } + else + { + pSelfParam->rate = (unsigned short) + (pSelfParam->rateParam / (*pSelf->shared).samplingPeriod); + } + + return; +} + +/* + * Report parameters Hooks + */ + +STATUS tacSinkDisplayBlockGetParameter (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = (double*) parameter->buffer; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Send back the expected number of parameters */ + parameter->number = tacSINK_ONE_EXPECTED_PARAM; + + /* Report current parameters */ + pRealParam[tacSINK_SAMPLING_PERIOD] = (double) (pSelfParam->rate * (*pSelf->shared).samplingPeriod); + + return OK; +} + +STATUS tacSinkMonitorBlockGetParameter (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = (double*) parameter->buffer; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Send back the expected number of parameters */ + parameter->number = tacSINK_DEFAULT_EXPECTED_PARAM; + + /* Report current parameters */ + pRealParam[tacSINK_SAMPLING_PERIOD] = (double) (pSelfParam->rate * (*pSelf->shared).samplingPeriod); + pRealParam[tacSINK_INPUT_NUMBER] = (double) pSelfParam->inputNb; + + if (*((char**) &(pSelfParam->dbPoint)) != NULL) + { + parameter->number += 1; + parameter->type[tacSINK_MONITOR_DB_POINT] = tacPARAM_STRING; + strcpy((char*) &(pRealParam[tacSINK_MONITOR_DB_POINT]), *((char**) &(pSelfParam->dbPoint))); + } + + return OK; +} + +STATUS tacSinkMonitorStateBlockGetParameter (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = (double*) parameter->buffer; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Send back the expected number of parameters */ + parameter->number = tacSINK_DEFAULT_EXPECTED_PARAM; + + /* Report current parameters */ + pRealParam[tacSINK_SAMPLING_PERIOD] = (double) (pSelfParam->rate * (*pSelf->shared).samplingPeriod); + pRealParam[tacSINK_INPUT_NUMBER] = (double) pSelfParam->inputNb; + + if (*((char**) &(pSelfParam->dbPoint)) != NULL) + { + parameter->number += 1; + parameter->type[tacSINK_MONITOR_DB_POINT] = tacPARAM_STRING; + strcpy((char*) &(pRealParam[tacSINK_MONITOR_DB_POINT]), *((char**) &(pSelfParam->dbPoint))); + } + + return OK; +} + +STATUS tacSinkProbeBlockGetParameter (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = (double*) parameter->buffer; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Send back the expected number of parameters */ + parameter->number = tacSINK_DEFAULT_EXPECTED_PARAM; + + /* Report current parameters */ + pRealParam[tacSINK_SAMPLING_PERIOD] = (double) (pSelfParam->rate * (*pSelf->shared).samplingPeriod); + pRealParam[tacSINK_INPUT_NUMBER] = (double) pSelfParam->inputNb; + + return OK; +} + +/* + * Change parameters Hooks + */ + +/* + * Algorithm Hooks + */ + +void tacSinkDisplayBlockAlgorithm (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + if ((pSelfParam->counter % pSelfParam->rate) == 0) /* It's time to process data */ + { + sprintf(logStr,"Name: %s Time: %ld.%6ld Value: %g\n", + pSelf->name, + (*pSelf->shared).currentTime.seconds, + (*pSelf->shared).currentTime.microsec, + tacStdBlockGetInput(pSelf,0)); + + tacDpcPushRequest((tacVOIDFCTPTR) &printf, logStr); + + pSelfParam->counter = 0; + } + + pSelfParam->counter++; +} + +void tacSinkMonitorBlockAlgorithm (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + unsigned short arrayIndex = 0; + + /* The output port is used to average the inputs over the reporting period */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pSelf->output[arrayIndex] += tacStdBlockGetInput(pSelf,arrayIndex); + } + + if ((pSelfParam->counter % pSelfParam->rate) == 0) /* It's time to process data */ + { + tacDATA* pData = &(pSelfParam->shmMsg.msgBody.monitor.data); /* We are only interested in message body */ + + /* pData->number = pSelfParam->inputNb; */ + pData->timeStamp = (*pSelf->shared).currentTime; + + /* pData points to the body of the Message */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pData->buffer[arrayIndex] = pSelf->output[arrayIndex] / pSelfParam->rate; + } + + /* Push message into probe block's message que to get the + * data out of the interrupt comtext. */ + if ( msgQSend (pSelfParam->msgq, (char*) &(pSelfParam->shmMsg), sizeof(tacSHMSG), NO_WAIT, 0) != OK ) + { + (pSelfParam->lost)++; + } + + /* Defer procedure call */ + tacDpcPushRequest((tacVOIDFCTPTR) &tacSinkSendMonitorMessage, &pSelfParam->msgq); + + pSelfParam->counter = 0; + + /* The output port is used to average the inputs over the reporting period */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pSelf->output[arrayIndex] = 0.0; + } + } + + pSelfParam->counter++; +} + +void tacSinkMonitorStateBlockAlgorithm (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + unsigned short arrayIndex = 0; + + if ((pSelfParam->counter % pSelfParam->rate) == 0) /* It's time to process data */ + { + tacDATA* pData = &(pSelfParam->shmMsg.msgBody.monitor.data); /* We are only interested in message body */ + + /* pData->number = pSelfParam->inputNb; */ + pData->timeStamp = (*pSelf->shared).currentTime; + + /* pData points to the body of the Message */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pData->buffer[arrayIndex] = tacStdBlockGetInput(pSelf,arrayIndex); + } + + /* Push message into probe block's message que to get the + * data out of the interrupt comtext. */ + if ( msgQSend (pSelfParam->msgq, (char*) &(pSelfParam->shmMsg), sizeof(tacSHMSG), NO_WAIT, 0) != OK ) + { + (pSelfParam->lost)++; + } + + /* Defer procedure call */ + tacDpcPushRequest((tacVOIDFCTPTR) &tacSinkSendMonitorMessage, &pSelfParam->msgq); + + pSelfParam->counter = 0; + } + + pSelfParam->counter++; +} + +void tacSinkProbeBlockAlgorithm (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + unsigned short arrayIndex = 0; + + if ((pSelfParam->counter % pSelfParam->rate) == 0) /* It's time to process data */ + { + tacDATA* pData = &(pSelfParam->shmMsg.msgBody.monitor.data); /* We are only interested in message body */ + + pData->timeStamp = (*pSelf->shared).currentTime; + + /* pData points to the body of the Message */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pData->buffer[arrayIndex] = tacStdBlockGetInput(pSelf,arrayIndex); + } + + /* Push message into probe block's message que to get the + * data out of the interrupt comtext. */ + if ( msgQSend (pSelfParam->msgq, (char*) &(pSelfParam->shmMsg), sizeof(tacSHMSG), NO_WAIT, 0) != OK ) + { + (pSelfParam->lost)++; + } + + /* Defer procedure call: + * tacSinkSendProbeMessage is called outside the interrupt routine + * and will take care to pick up the message from the probe block's + * message queue and send it over the shared memory message queue */ + tacDpcPushRequest((tacVOIDFCTPTR) &tacSinkSendProbeMessage, &pSelfParam->msgq); + + pSelfParam->counter = 0; + } + + pSelfParam->counter++; +} + +/* + * Reset Hooks + */ + +/* + * Stop Hooks + */ + +/* + * Destructor Hooks + */ + +/* + * Note: This destructor is used mainly to send a MONITOR message containing + * 0.0 in order to reset the database array (otherwise going from an + * algorithm with 4 monitored data to one with 3 monitored data leaves + * the 4th value equal to the last ...) + */ + +void tacSinkMonitorBlockDestructor (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + tacDATA* pData = &(pSelfParam->shmMsg.msgBody.monitor.data); + unsigned short arrayIndex = 0; + + /* Reset DB values */ + pSelfParam->shmMsg.type = tacSHMSG_MONITOR_DATA; + pData = &(pSelfParam->shmMsg.msgBody.monitor.data); + + pData->number = pSelfParam->inputNb; + + /* pData points to the body of the Message */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pData->buffer[arrayIndex] = 0.0; + } + + /* Send message */ + tacShMsgQSendBgInfo(&pSelfParam->shmMsg); + + pSelfParam->shmMsg.type = tacSHMSG_REMOVE_MONITOR; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + + /* Send message */ + tacShMsgQSendBgInfo(&pSelfParam->shmMsg); + + free(pSelfParam->dbPoint); + + /* delete internal message queue. Do this as deferred procedure call + * to make sure it is only called when all messages have been send + * (through the same deferred call mechanism) */ + tacDpcPushRequest((tacVOIDFCTPTR) tacSinkDeleteMessageQueue, &(pSelfParam->msgq)); + + return; +} + +void tacSinkMonitorStateBlockDestructor (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + tacDATA* pData = &(pSelfParam->shmMsg.msgBody.monitor.data); + unsigned short arrayIndex = 0; + + /* Reset DB values */ + pSelfParam->shmMsg.type = tacSHMSG_MONITOR_DATA; + pData = &(pSelfParam->shmMsg.msgBody.monitor.data); + + pData->number = pSelfParam->inputNb; + + /* pData points to the body of the Message */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pData->buffer[arrayIndex] = 0.0; + } + + /* Send message */ + tacShMsgQSendBgInfo(&pSelfParam->shmMsg); + + pSelfParam->shmMsg.type = tacSHMSG_REMOVE_MONITOR; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + + /* Send message */ + tacShMsgQSendBgInfo(&pSelfParam->shmMsg); + + free(pSelfParam->dbPoint); + + /* delete internal message queue. Do this as deferred procedure call + * to make sure it is only called when all messages have been send + * (through the same deferred call mechanism) */ + tacDpcPushRequest((tacVOIDFCTPTR) tacSinkDeleteMessageQueue, &(pSelfParam->msgq)); + + return; +} + +void tacSinkProbeBlockDestructor (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + pSelfParam->shmMsg.type = tacSHMSG_REMOVE_PROBE; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + + /* Send message */ + tacShMsgQSendDataSample(&pSelfParam->shmMsg); + + /* delete internal message queue. Do this as deferred procedure call + * to make sure it is only called when all messages have been send + * (through the same deferred call mechanism) */ + tacDpcPushRequest((tacVOIDFCTPTR) tacSinkDeleteMessageQueue, &(pSelfParam->msgq)); + + return; +} + +/* + * Show Hooks + */ + +void tacSinkDisplayBlockShow (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Print parameter values */ + printf(" Update rate: %d\n",pSelfParam->rate); + + return; +} + +void tacSinkMonitorBlockShow (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Print parameter values */ + printf(" Update rate: %d\n",pSelfParam->rate); + printf(" Number of input signals: %d\n",pSelfParam->inputNb); + printf(" Queued samples: %d\n", msgQNumMsgs(pSelfParam->msgq)); + printf(" Lost samples: %d\n",pSelfParam->lost); + + if (pSelfParam->dbPoint != NULL) + { + printf(" DB Point: %s\n", pSelfParam->dbPoint); + } + + return; +} + +void tacSinkMonitorStateBlockShow (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Print parameter values */ + printf(" Using MonitorState block, not averaging received data\n"); + printf(" Update rate: %d\n",pSelfParam->rate); + printf(" Number of input signals: %d\n",pSelfParam->inputNb); + printf(" Queued samples: %d\n", msgQNumMsgs(pSelfParam->msgq)); + printf(" Lost samples: %d\n",pSelfParam->lost); + + if (pSelfParam->dbPoint != NULL) + { + printf(" DB Point: %s\n", pSelfParam->dbPoint); + } + + return; +} + +void tacSinkProbeBlockShow (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Print parameter values */ + printf(" Update rate: %d\n",pSelfParam->rate); + printf(" Update rate param (sec): %f\n",pSelfParam->rateParam); + printf(" Number of input signals: %d\n",pSelfParam->inputNb); + printf(" Queued samples: %d\n", msgQNumMsgs(pSelfParam->msgq)); + printf(" Lost samples: %d\n",pSelfParam->lost); + + return; +} + +/* + * Installation function + */ + +tacSTDBLOCK_TYPE tacSinkDisplayTypeInfo = { + "Display", + &tacSinkDisplayBlockConstructor, + &tacSinkDisplayBlockGetParameter, + &tacSinkDisplayBlockAlgorithm, + NULL, + NULL, + NULL, + NULL, + &tacSinkDisplayBlockShow, +}; + +tacSTDBLOCK_TYPE tacSinkMonitorTypeInfo = { + "Monitor", + &tacSinkMonitorBlockConstructor, + &tacSinkMonitorBlockGetParameter, + &tacSinkMonitorBlockAlgorithm, + NULL, + NULL, + NULL, + &tacSinkMonitorBlockDestructor, + &tacSinkMonitorBlockShow, +}; + +tacSTDBLOCK_TYPE tacSinkMonitorStateTypeInfo = { + "MonitorState", + &tacSinkMonitorStateBlockConstructor, + &tacSinkMonitorStateBlockGetParameter, + &tacSinkMonitorStateBlockAlgorithm, + NULL, + NULL, + NULL, + &tacSinkMonitorStateBlockDestructor, + &tacSinkMonitorStateBlockShow, +}; + +/* Probe with a maximal sampling rate of 2kHz */ +tacSTDBLOCK_TYPE tacSinkProbeTypeInfo = { + "Probe", + &tacSinkProbeBlockConstructor, + &tacSinkProbeBlockGetParameter, + &tacSinkProbeBlockAlgorithm, + NULL, + &tacSinkProbeBlockReset, + NULL, + &tacSinkProbeBlockDestructor, + &tacSinkProbeBlockShow, +}; + +/* Fast probe is the same as probe but not does have the + * limitation on the max. recording frequency */ +tacSTDBLOCK_TYPE tacSinkFastProbeTypeInfo = { + "FastProbe", + &tacSinkFastProbeBlockConstructor, + &tacSinkProbeBlockGetParameter, + &tacSinkProbeBlockAlgorithm, + NULL, + &tacSinkProbeBlockReset, + NULL, + &tacSinkProbeBlockDestructor, + &tacSinkProbeBlockShow, +}; + +STATUS tacSinkBlockInitAll (void) +{ + /* Install Sink Block Hooks */ + tacStdBlockInstallNewType(&tacSinkDisplayTypeInfo); + tacStdBlockInstallNewType(&tacSinkMonitorTypeInfo); + tacStdBlockInstallNewType(&tacSinkMonitorStateTypeInfo); + tacStdBlockInstallNewType(&tacSinkProbeTypeInfo); + tacStdBlockInstallNewType(&tacSinkFastProbeTypeInfo); + + /* + * Perform other library initialization operations + */ + + return OK; +} + +/* + * Local functions + */ + +/* + * Note: Routines called from within the algorithm must be declared with + * static __inline__ + */ + +STATUS tacSinkCommonBlockConstructor (tacSTDBLOCK* pSelf, + tacERROR* error) +{ + /* Allocate specific arrays (pointers are initialized to NULL by StdBlock) */ + if (tacStdBlockAllocateArrays(pSelf, 0, tacSINK_DEFAULT_INPUT_NUMBER, + tacSINK_DEFAULT_OUTPUT_NUMBER, error) == ERROR) + { + return ERROR; + } + + if (tacStdBlockAllocateArrayBySize(pSelf, tacSTDBLOCK_PARAM_ARRAY, + sizeof(tacSINK_SCOPE_LOCAL_PARAMETER), error) == ERROR) + { + tacStdBlockReleaseArray(pSelf, tacSTDBLOCK_INPUT_ARRAY, error); + tacStdBlockReleaseArray(pSelf, tacSTDBLOCK_OUTPUT_ARRAY, error); + return ERROR; + } + + /* Specify the number of input signals to attach to become resolved */ + tacStdBlockSetInputNumber(pSelf, tacSINK_ONE_INPUT_NUMBER); /* Required */ + + return OK; +} + +STATUS tacSinkSendMonitorMessage(MSG_Q_ID * msgq) +{ + /* Send message using provided function (different for Monitor and Probe blocks) */ + /* Send message using provided function (different for Monitor and Probe blocks) */ + tacSHMSG msg; + + if ( msgQReceive(*msgq, (char*) &msg, sizeof(tacSHMSG), NO_WAIT) == sizeof(tacSHMSG) ) + { + tacShMsgQSendBgInfo (&msg); + } + + return OK; +} + +STATUS tacSinkSendProbeMessage(MSG_Q_ID * msgq) +{ + /* Send message using provided function (different for Monitor and Probe blocks) */ + tacSHMSG msg; + + if ( msgq == NULL ) + { + return ERROR; + } + + if ( msgQReceive(*msgq, (char*) &msg, sizeof(tacSHMSG), NO_WAIT) == sizeof(tacSHMSG) ) + { + tacShMsgQSendDataSample (&msg); + } + return OK; +} + +STATUS tacSinkDeleteMessageQueue (MSG_Q_ID * msgq) +{ + /* Is called when block is destroyed and removes the internal message queue */ + STATUS status; + + status = msgQDelete (*msgq); + *msgq = NULL; + return status; +} + + +/*___oOo___*/ + + + + + + diff --git a/src/arguments.py b/src/arguments.py new file mode 100644 index 0000000..94e4cea --- /dev/null +++ b/src/arguments.py @@ -0,0 +1,26 @@ +import getopt + +def exitUsage(): + print("usage: %s <.tasrc file> -i -o " % sys.argv[0]) + sys.exit(1) + +def readArguments(args): + sourceDirectories = [] + outputFile = "" + try: + options, _ = getopt.getopt(args, "hi:o:") + except getopt.GetoptError: + exitUsage() + for option, arg in options: + if option == "-h": + exitUsage() + elif option == "-o": + outputFile = arg + elif option == "-i": + sourceDirectories.append(arg) + if outputFile == "": + exitUsage() + if len(sourceDirectories) == 0: + print("WARNING: no source directories specified!") + return outputFile, sourceDirectories + diff --git a/src/converter.py b/src/converter.py new file mode 100755 index 0000000..3e44058 --- /dev/null +++ b/src/converter.py @@ -0,0 +1,18 @@ +#!/usr/bin/python3 + +import sys + +import arguments +from tacsrc.tac import readTAC +import grc +import portNaming + +if __name__ == "__main__": + if len(sys.argv) == 1: + params.exitUsage() + inputFile = sys.argv[1] + outputFile, sourceDirectories = arguments.readArguments(sys.argv[2:]) + blocks, connections, blockTypes = readTAC(inputFile) + portNaming.resolvePortNames(blockTypes, sourceDirectories) + grc.write(outputFile, blocks, connections) + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3624768 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +__pycache__ +out +tacapp.tar.gz +Sources +tacapp +worryingFiles +cc.tar.gz diff --git a/errors.json b/errors.json new file mode 100644 index 0000000..5ec898a --- /dev/null +++ b/errors.json @@ -0,0 +1,4 @@ +{ + "missing_blocks": [], + "multiple_definitions": [] +} \ No newline at end of file diff --git a/hardcodedFiles/tacReadRmnBlock.c b/hardcodedFiles/tacReadRmnBlock.c new file mode 100644 index 0000000..8acbcfa --- /dev/null +++ b/hardcodedFiles/tacReadRmnBlock.c @@ -0,0 +1,568 @@ +/******************************************************************************* +* E.S.O. - VLT project +* +* "@(#) $Id: tacReadRmnBlock.c 305476 2018-01-19 08:56:18Z rfrahm $" +* +* who when what +* ------- -------- ---------------------------------------------- +* gzins 2010-07-27 ported to VLTSW2010 and VxWorks 6.4 +* swehner 2008-10-10 creation +*/ + +/************************************************************************ +* NAME +* tacReadRmnBlock - Implemements the standard functions for the +* tacReadRmn block and tacReadRfm block. +* tacReadRmnBlock - Reads from 1rst generation reflective memory network +* tacReadRfmBlock - Reads from 2nd generation reflective memory network + +* Parameters: +* field - token names for the RMN fields to read (up to 10) +* Inputs: 0 +* Outputs: 1 +* output - 1..10 depending on number of field parameters +* +* +* +* FILES +* +* ENVIRONMENT +* TAC +* +* RETURN VALUES +* +* CAUTIONS +* +* EXAMPLES +* TAC.BLOCK9.TYPE ReadRmn +* TAC.BLOCK9.NAME ReadRmn +* +* SEE ALSO +* +* BUGS +* +*------------------------------------------------------------------------ +*/ + +#define _POSIX_SOURCE 1 +#include "vltPort.h" + +ATTRIBUTE_UNUSED static const char *rcsId="@(#) $Id: tacReadRmnBlock.c 305476 2018-01-19 08:56:18Z rfrahm $"; + +/* + * System Headers + */ + +#include /* taskSpawn, taskDelay, ... */ +#include /* printf ... */ +#include /* malloc ... */ +#include /* malloc ... */ +#include +#include + +/* + * Local Headers + */ + +#include "tacStdBlock.h" +#include "tacRmnBlock.h" +#include "rmassPublic.h" +#include "rmassPrivate.h" + +/* + * Compilation directives + */ + +/* + * Constants + */ + +#define tacREAD_RMN_EXPECTED_PARAM 1 +#define tacREAD_RMN_DEFAULT_INPUT_NUMBER 0 +#define tacREAD_RMN_DEFAULT_OUTPUT_NUMBER tacMAX_DATA_NUMBER + +#define tacREAD_RMN_FIELD_STRING_LEN 256 +#define tacSTRLEN sizeof(double) + +/* + * Types + */ + +/* + * Local function declaration + */ + +/* + * Global variables + */ + +/* + * Function definition + */ + + +STATUS tacReadRmnBlockCheckParameter (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the ADDBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = NULL; + + pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + /* field string is built from block params */ + if ( tacRmnBlockCheckParameter ( pSelf, parameter, 0, error) != OK ) + { + return ERROR; + } + + /* useful information on the screen */ + printf ("ReadRmn %s: [%s]\n", pSelf->name, pSelfParam->fieldString); + + return OK; +} + +STATUS tacReadRfmBlockCheckParameter (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the ADDBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = NULL; + + pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + /* field string is built from block params */ + if ( tacRmnBlockCheckParameter ( pSelf, parameter, 0, error) != OK ) + { + return ERROR; + } + + /* useful information on the screen */ + printf ("ReadRfm %s: [%s]\n", pSelf->name, pSelfParam->fieldString); + + return OK; +} + +/* + * Constructor Hooks - Called when a block of this type is instanciated (CONFIG or ADDBLCK commands) + */ + +STATUS tacReadRmBlockConstructor (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the ADDBLCK command */ + vltLOGICAL isRmn, + tacERROR* error) /* Error structure - not a stack */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = NULL; + + /* Check that the expected number of parameters has been received */ + if (parameter->number < tacREAD_RMN_EXPECTED_PARAM) + { + char errorParam[40]; + + sprintf(errorParam, "Expected at least %d, received %d", tacREAD_RMN_EXPECTED_PARAM, parameter->number); + tacRTC_ERR(tacERR_PARAM_NUMBER, errorParam); + return ERROR; + } + + /* Allocate and initialize block-specific arrays */ + if (tacStdBlockAllocateArrays(pSelf, 0, tacREAD_RMN_DEFAULT_INPUT_NUMBER, tacREAD_RMN_DEFAULT_OUTPUT_NUMBER, error) == ERROR) + { + return ERROR; + } + + if (tacStdBlockAllocateArrayBySize(pSelf, tacSTDBLOCK_PARAM_ARRAY, sizeof(tacRMN_LOCAL_PARAMETER), error) == ERROR) + { + tacStdBlockReleaseArray(pSelf, tacSTDBLOCK_INPUT_ARRAY, error); + tacStdBlockReleaseArray(pSelf, tacSTDBLOCK_OUTPUT_ARRAY, error); + return ERROR; + } + + if ( isRmn ) + { + if ( tacReadRmnBlockCheckParameter (pSelf, parameter, error) == ERROR) + { + return ERROR; + } + } + else + { + if ( tacReadRfmBlockCheckParameter (pSelf, parameter, error) == ERROR) + { + return ERROR; + } + } + + pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + pSelfParam->handleValid = rmassACCESS_BLOCKED; + + /* Attach to RMN */ + if ( rmassReadAttach (&pSelfParam->handle, + pSelfParam->fieldString, + &pSelfParam->val[0], + &pSelfParam->val[1], + &pSelfParam->val[2], + &pSelfParam->val[3], + &pSelfParam->val[4], + &pSelfParam->val[5], + &pSelfParam->val[6], + &pSelfParam->val[7], + &pSelfParam->val[8], + &pSelfParam->val[9]) != SUCCESS ) + { + char errorParam[40]; + + sprintf(errorParam, "Attach to RMN failed."); + tacRTC_ERR(tacERR_INTERNAL, errorParam); + return ERROR; + } + + pSelfParam->handleValid = rmassACCESS_FREE; + + return OK; +} + +STATUS tacReadRmnBlockConstructor (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the ADDBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + if ( tacReadRmBlockConstructor (pSelf, parameter, ccsTRUE, error ) == ERROR ) + { + return ERROR; + } + return OK; +} + +STATUS tacReadRfmBlockConstructor (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the ADDBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + if ( tacReadRmBlockConstructor (pSelf, parameter, ccsFALSE, error ) == ERROR ) + { + return ERROR; + } + return OK; +} + + + +/* + * Destructor Hooks - Called when the block is removed from the algorithm (DELBLCK or new CONFIG commands) + */ + +void tacReadRmnBlockDestructor (tacSTDBLOCK* pSelf) /* Reference to the block instance */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = NULL; + pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + pSelfParam->handleValid = rmassACCESS_BLOCKED; + /* wait until semaphore is acknowledged by realtime algo + * or just procede if realtime is not active */ + while ((*pSelf->shared).active && pSelfParam->handleValid != rmassACCESS_BLOCK_ACKN) + { + taskDelay(1); + } + + rmassDetach (&pSelfParam->handle); + + return; +} + +/* + * Change parameters Hooks - Called when modifying the block parameters (MODBLCK command) + */ + +STATUS tacReadRmnBlockSetParameter (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the MODBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + if ( tacReadRmnBlockCheckParameter (pSelf, parameter, error) == ERROR) + { + return ERROR; + } + + pSelfParam->handleValid = rmassACCESS_BLOCKED; + /* wait until semaphore is acknowledged by realtime algo + * or just procede if realtime is not active */ + while ((*pSelf->shared).active && pSelfParam->handleValid != rmassACCESS_BLOCK_ACKN) + { + taskDelay(1); + } + + /* detach RMN handle */ + if ( rmassDetach (&pSelfParam->handle) != SUCCESS ) + { + char errorParam[40]; + + sprintf(errorParam, "rmassDetach returned error."); + tacRTC_ERR(tacERR_INTERNAL, errorParam); + return ERROR; + } + + if ( rmassReadAttach (&pSelfParam->handle, + pSelfParam->fieldString, + &pSelfParam->val[0], + &pSelfParam->val[1], + &pSelfParam->val[2], + &pSelfParam->val[3], + &pSelfParam->val[4], + &pSelfParam->val[5], + &pSelfParam->val[6], + &pSelfParam->val[7], + &pSelfParam->val[8], + &pSelfParam->val[9]) != SUCCESS ) + { + char errorParam[40]; + + sprintf(errorParam, "Attach to RMN failed."); + tacRTC_ERR(tacERR_INTERNAL, errorParam); + return ERROR; + } + + pSelfParam->handleValid = rmassACCESS_FREE; + + return OK; +} + +STATUS tacReadRfmBlockSetParameter (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the MODBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + if ( tacReadRfmBlockCheckParameter (pSelf, parameter, error) == ERROR) + { + return ERROR; + } + + pSelfParam->handleValid = rmassACCESS_BLOCKED; + /* wait until semaphore is acknowledged by realtime algo + * or just procede if realtime is not active */ + while ((*pSelf->shared).active && pSelfParam->handleValid != rmassACCESS_BLOCK_ACKN) + { + taskDelay(1); + } + + /* detach RMN handle */ + if ( rmassDetach (&pSelfParam->handle) != SUCCESS ) + { + char errorParam[40]; + + sprintf(errorParam, "rmassDetach returned error."); + tacRTC_ERR(tacERR_INTERNAL, errorParam); + return ERROR; + } + + if ( rmassReadAttach (&pSelfParam->handle, + pSelfParam->fieldString, + &pSelfParam->val[0], + &pSelfParam->val[1], + &pSelfParam->val[2], + &pSelfParam->val[3], + &pSelfParam->val[4], + &pSelfParam->val[5], + &pSelfParam->val[6], + &pSelfParam->val[7], + &pSelfParam->val[8], + &pSelfParam->val[9]) != SUCCESS ) + { + char errorParam[40]; + + sprintf(errorParam, "Attach to RFM failed."); + tacRTC_ERR(tacERR_INTERNAL, errorParam); + return ERROR; + } + + pSelfParam->handleValid = rmassACCESS_FREE; + + return OK; +} + +/* + * Algorithm Hooks - Called at each time the TAC algorithm is evaluated (ONLINE state) + */ + +void tacReadRmnBlockAlgorithm (tacSTDBLOCK* pSelf) /* Reference to the block instance */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + int i; + + if ( pSelfParam->handleValid == rmassACCESS_BLOCKED ) + { + pSelfParam->handleValid = rmassACCESS_BLOCK_ACKN; + } + + if ( pSelfParam->handleValid == rmassACCESS_FREE ) + { + /* actual RMN read operation */ + rmassReadAccessRmn (&pSelfParam->handle); + + /* Write to outputs */ + for (i=0; i < pSelfParam->numFields; i++) + { + switch (pSelfParam->type[i]) + { + case rmassTIMESEC: + case rmassUINT32: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).ui); + break; + case rmassTIMEUSEC: + case rmassINT32: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).i); + break; + case rmassFLOAT: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).f); + break; + default: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).d); + break; + } + } + + /* provide zero values at unsatisfied outputs + * I consider this a good thing to do since the block + * is always configured */ + for (i=pSelfParam->numFields; i < tacREAD_RMN_DEFAULT_OUTPUT_NUMBER; i++) + { + tacStdBlockSetOutput(pSelf, i, 0.0); + } + } +} + +void tacReadRfmBlockAlgorithm (tacSTDBLOCK* pSelf) /* Reference to the block instance */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + int i; + + if ( pSelfParam->handleValid == rmassACCESS_BLOCKED ) + { + pSelfParam->handleValid = rmassACCESS_BLOCK_ACKN; + } + + if ( pSelfParam->handleValid == rmassACCESS_FREE ) + { + /* actual RMN read operation */ + rmassReadAccessRfm (&pSelfParam->handle); + + /* Write to outputs */ + for (i=0; i < pSelfParam->numFields; i++) + { + switch (pSelfParam->type[i]) + { + case rmassTIMESEC: + case rmassUINT32: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).ui); + break; + case rmassTIMEUSEC: + case rmassINT32: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).i); + break; + case rmassFLOAT: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).f); + break; + default: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).d); + break; + } + } + + /* provide zero values at unsatisfied outputs + * I consider this a good thing to do since the block + * is always configured */ + for (i=pSelfParam->numFields; i < tacREAD_RMN_DEFAULT_OUTPUT_NUMBER; i++) + { + tacStdBlockSetOutput(pSelf, i, 0.0); + } + } +} + +/* + * Show Hooks - Called when the tacRtcTaskShow routine is executed + */ + +void tacReadRmnBlockShow (tacSTDBLOCK* pSelf) /* Reference to the block instance */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + /* Print parameter values */ + printf(" Attached: %s\n", pSelfParam->fieldString); + + return; +} + + +/***************************************************/ +/* The following code is common to all block types */ +/* Do not modify without any good reasons */ +/***************************************************/ + +/* + * Installation function + */ + +tacSTDBLOCK_TYPE tacReadRmnTypeInfo = { + "ReadRmn", + &tacReadRmnBlockConstructor, + &tacRmBlockGetParameter, + &tacReadRmnBlockAlgorithm, + &tacReadRmnBlockSetParameter, + NULL, + NULL, + &tacReadRmnBlockDestructor, + &tacReadRmnBlockShow +}; + +tacSTDBLOCK_TYPE tacReadRfmTypeInfo = { + "ReadRfm", + &tacReadRfmBlockConstructor, + &tacRmBlockGetParameter, + &tacReadRfmBlockAlgorithm, + &tacReadRmnBlockSetParameter, + NULL, + NULL, + &tacReadRmnBlockDestructor, + &tacReadRmnBlockShow +}; + +STATUS tacReadRmnBlockInitAll (void) +{ + /***************************************************/ + /* The following code is common to all block types */ + /* Do not modify without any good reasons */ + /***************************************************/ + + /* Install ReadRmn1g Block Hooks */ + tacStdBlockInstallNewType(&tacReadRmnTypeInfo); + + /*****************************/ + /* End of common code region */ + /*****************************/ + + /* Perform other library initialization operations */ + + return OK; +} + +STATUS tacReadRfmBlockInitAll (void) +{ + /***************************************************/ + /* The following code is common to all block types */ + /* Do not modify without any good reasons */ + /***************************************************/ + + /* Install ReadRmn1g Block Hooks */ + tacStdBlockInstallNewType(&tacReadRfmTypeInfo); + + /*****************************/ + /* End of common code region */ + /*****************************/ + + /* Perform other library initialization operations */ + + return OK; +} + +/*___oOo___*/ + + + diff --git a/hardcodedFiles/tacSinkBlock.c b/hardcodedFiles/tacSinkBlock.c new file mode 100644 index 0000000..df39833 --- /dev/null +++ b/hardcodedFiles/tacSinkBlock.c @@ -0,0 +1,1256 @@ +/******************************************************************************* +* E.S.O. - VLT project +* +* "@(#) $Id: tacSinkBlock.c 339094 2021-02-10 03:10:02Z jgil $" +* +* who when what +* ------- -------- ---------------------------------------------- +* rdembet 06/08/20 New MonitorState block with no data averaging +* swehner 28/11/09 SPR20090234 Correction in rate adjustment in reset hook +* swehner 27/11/09 Fixed message queue handling +* swehner 10/10/09 New block FastProbe for unlimited rec frequency +* swehner 22/09/09 PPRS 32341 Replaced specialized tacSINK_SHMSG stack +* with standard vxWorks message queue. +* bbauvir 21/09/04 VLTSW20040113 - One sample might be lost +* bbauvir 29/03/04 Monitor block averages over the reporting period +* bbauvir 29/12/02 Probe to the SampTask +* bbauvir 26/12/02 MsgQ access through DPC mechanism +* bbauvir 14/07/02 New MsgQ of TAC version 1.22 +* bbauvir 21/03/01 Created +*/ + +/************************************************************************ +* NAME +* tacSinkBlock - Standard data monitoring blocks +* +* SYNOPSIS +* lcubootAutoCdBoot 1,"tacsink.boot" +* < tacsink.boot +* +* DESCRIPTION +* Block type: Display +* Parameters: +* Inputs: 1 +* Outputs: none +* +* This function block samples the value of its input signal at the +* specified and issues a message containing the time +* and the value of the input on the vxWorks terminal. +* It does not allow modification of the parameter at runtime. +* +* Block type: Monitor +* Parameters: +* +* Inputs: 10max +* Outputs: none +* +* This function block samples the value of its input signals at the +* specified (0.0 to send a message at the system sampling +* period) and issues a message containing the time and the value of +* the inputs on the shared memory. This message is intercepted by the +* background task running on the master CPU. The monitored values are +* written into the online database. The number of inputs of the block +* is specified by parameter. +* This block does not allow modification of the parameters at runtime. +* +* Block type: MonitorState +* Parameters: +* +* Inputs: 10max +* Outputs: none +* +* Same as Monitor block but without the averaging of received data, +* see VLTSW-14260 JIRA ticket. +* +* Block type: Probe +* Parameters: +* +* Inputs: 10max +* Outputs: none +* +* Block type: FastProbe +* Parameters: +* +* Inputs: 10max +* Outputs: none +* +* This function block samples the value of its input signals at the +* specified (0.0 to send a message at the system sampling +* period) and issues a message containing the time and the value of +* the inputs on the shared memory. This message is intercepted by the +* background task running on the master CPU. The number of inputs of +* the block is specified by parameter. +* This message is passed to an external application callback if +* provided. +* This block does not allow modification of the parameters at runtime. +* The normal Probe block has a limited sampling frequency of not more +* than 2kHz. The reason is in particular the bottleneck between master +* and slave CPU which all samples have to pass through a mechanism of +* VME bus shared memory. On one-CPU-systems this limitation does not +* apply so you are free to choose faster sampling. You may of course +* hit other limitations (processor speed, network traffic etc.) +* +* FILES +* +* ENVIRONMENT +* TAC +* +* RETURN VALUES +* +* CAUTIONS +* All these blocks compute an decimation value to use to trigger the +* sampling of the input signals, from the system sampling period. +* They should be created after any synchronization block. +* +* In order to cope with system performances, a minimum +* is defined for each block. The minimum applied periods are 0.1 (10Hz), +* 0.01 (100Hz) and 0.5e-3 (2kHz) for the 'Display', 'Monitor' and +* 'Probe' blocks respectively. +* +* EXAMPLES +* # 5 signals @ 2Hz (monitored in the database) +* TAC.BLOCK9.TYPE Monitor +* TAC.BLOCK9.NAME Monitor +* TAC.BLOCK9.PARAM 0.5, 5 +* +* # 5 signals @ the RT algorithm sampling period (0.0) +* TAC.BLOCK10.TYPE Probe +* TAC.BLOCK10.NAME Probe +* TAC.BLOCK10.PARAM 0.0, 5 +* +* SEE ALSO +* tacServerInstallDataCallback, tacServerRemoveDataCallback +* +* BUGS +* +*------------------------------------------------------------------------ +*/ + +#define _POSIX_SOURCE 1 +#include "vltPort.h" + + +/* + * System Headers + */ + +#include +#include +#include /* logMsg ... */ +#include /* printf ... */ +#include /* malloc ... */ +#include /* memcpy ... */ +#include + +/* + * Local Headers + */ + +#include "tacStdBlock.h" +#include "tacShMsgQ.h" + +/* + * Compilation directives + */ + +/* + * Constants + */ + +#define tacSINK_DEFAULT_EXPECTED_PARAM 2 + +#define tacSINK_DEFAULT_INPUT_NUMBER tacMAX_DATA_NUMBER /* Up to 10 input channels */ +#define tacSINK_DEFAULT_OUTPUT_NUMBER tacMAX_DATA_NUMBER + +#define tacSINK_ONE_EXPECTED_PARAM 1 +#define tacSINK_ONE_INPUT_NUMBER 1 + +#define tacSINK_DISPLAY_MIN_SAMPLING_PERIOD .1 /* 10Hz */ +#define tacSINK_MONITOR_MIN_SAMPLING_PERIOD .01 /* 100Hz */ +#define tacSINK_PROBE_MIN_SAMPLING_PERIOD .5e-3 /* 2kHz */ + +#define tacSINK_DISPLAY_LOG_STRING_SIZE 128 + +#define tacSINK_MONITOR_DEFAULT_DB_POINT "tac:data:monitor" +#define tacSINK_MONITOR_MAX_DB_ADDR_SIZE 64 + +#define tacSINK_MONITOR_QUEUE_SIZE 6 +#define tacSINK_PROBE_QUEUE_SIZE 6 + + +typedef enum { + tacSINK_SAMPLING_PERIOD = 0, + tacSINK_INPUT_NUMBER, + tacSINK_MONITOR_DB_POINT, +}tacSINK_SCOPE_PARAM_INDEX; + +/* + * Types + */ + +typedef struct { + unsigned short rate; + unsigned short counter; + unsigned short inputNb; + unsigned int lost; + double rateParam; + char* dbPoint; + MSG_Q_ID msgq; + tacSHMSG shmMsg; +}tacSINK_SCOPE_LOCAL_PARAMETER; + +/* + * Function declaration + */ + +extern STATUS tacDpcPushRequest(tacVOIDFCTPTR pFunct, void* parameter); + +/* + * Local function declaration + */ + +/* + * Note: Routines called from within the algorithm must be declared with + * static __inline__ + */ + +STATUS tacSinkSendMonitorMessage(MSG_Q_ID * msgqvoid); +STATUS tacSinkSendMonitorStateMessage(MSG_Q_ID * msgqvoid); +STATUS tacSinkSendProbeMessage(MSG_Q_ID * msgq); +STATUS tacSinkDeleteMessageQueue(MSG_Q_ID * msgq); +STATUS tacSinkCommonBlockConstructor(tacSTDBLOCK* pSelf, tacERROR* error); + +/* + * Global variables + */ + +char logStr[tacSINK_DISPLAY_LOG_STRING_SIZE]; /* Logging string used for Display */ + + +/* + * Function definition + */ + +/* + * Constructor Hooks + */ + +STATUS tacSinkDisplayBlockConstructor (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = NULL; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = NULL; + + /* Check that the expected number of parameters has been received */ + if (parameter->number < tacSINK_ONE_EXPECTED_PARAM) + { + char errorParam[40]; + + sprintf(errorParam, "Expected %d, received %d", tacSINK_ONE_EXPECTED_PARAM, parameter->number); + tacRTC_ERR(tacERR_PARAM_NUMBER, errorParam); + return ERROR; + } + + /* Check that the parameters are valid */ + pRealParam = (double*) parameter->buffer; + + /* Passed parameter is the sampling period of the block */ + if (pRealParam[tacSINK_SAMPLING_PERIOD] < (*pSelf->shared).samplingPeriod) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = (*pSelf->shared).samplingPeriod; + } + + if (pRealParam[tacSINK_SAMPLING_PERIOD] < tacSINK_DISPLAY_MIN_SAMPLING_PERIOD) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = tacSINK_DISPLAY_MIN_SAMPLING_PERIOD; + } + + /* Call common constructor */ + if (tacSinkCommonBlockConstructor(pSelf, error) != OK) + { + return ERROR; + } + + /* Store parameters */ + pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; /* We will only store short integers */ + + /* + * Compute the rate at which data has to be processed - divide and take + * the integer part of the result + */ + + pSelfParam->rate = (unsigned short) (pRealParam[tacSINK_SAMPLING_PERIOD] / (*pSelf->shared).samplingPeriod); + pSelfParam->counter = 0; /* Decimation counter */ + + /* + * Perform other block initialization operations + */ + + return OK; +} + +STATUS tacSinkMonitorBlockConstructor (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = NULL; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = NULL; + unsigned short arrayIndex = 0; + + /* Check that the expected number of parameters has been received */ + if (parameter->number < tacSINK_DEFAULT_EXPECTED_PARAM) + { + char errorParam[40]; + + sprintf(errorParam, "Expected %d, received %d", tacSINK_DEFAULT_EXPECTED_PARAM, parameter->number); + tacRTC_ERR(tacERR_PARAM_NUMBER, errorParam); + return ERROR; + } + + /* Check that the parameters are valid */ + pRealParam = (double*) parameter->buffer; + + /* Passed parameter is the sampling period of the block */ + if (pRealParam[tacSINK_SAMPLING_PERIOD] < (*pSelf->shared).samplingPeriod) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = (*pSelf->shared).samplingPeriod; + } + + if (pRealParam[tacSINK_SAMPLING_PERIOD] < tacSINK_MONITOR_MIN_SAMPLING_PERIOD) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = tacSINK_MONITOR_MIN_SAMPLING_PERIOD; + } + + /* Number of inputs is minimum 1 up to tacMSG_MAX_DATA_NUMBER */ + if ((pRealParam[tacSINK_INPUT_NUMBER] < 1) || + (pRealParam[tacSINK_INPUT_NUMBER] > tacMAX_DATA_NUMBER)) + { + tacRTC_ERR(tacERR_PARAM_INVALID, ""); + return ERROR; + } + + /* Call common constructor */ + if (tacSinkCommonBlockConstructor(pSelf, error) != OK) + { + return ERROR; + } + + /* Store parameters */ + pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* + * Compute the rate at which data has to be processed - divide and take + * the integer part of the result + */ + + pSelfParam->rate = (unsigned short) (pRealParam[tacSINK_SAMPLING_PERIOD] / (*pSelf->shared).samplingPeriod); + pSelfParam->counter = 0; /* Decimation counter */ + pSelfParam->inputNb = (unsigned short) pRealParam[tacSINK_INPUT_NUMBER]; + + /* Optional parameter is an application-specific DB point */ + if (parameter->number == tacSINK_DEFAULT_EXPECTED_PARAM + 1) + { + printf("tacSinkMonitorBlockConstructor - DB point %s\n",(char*) &(pRealParam[tacSINK_MONITOR_DB_POINT])); + pSelfParam->dbPoint = (char*) malloc(tacSINK_MONITOR_MAX_DB_ADDR_SIZE); + strcpy(pSelfParam->dbPoint, (char*) &(pRealParam[tacSINK_MONITOR_DB_POINT])); + } + else + { + printf("tacSinkMonitorBlockConstructor - Default DB point\n"); + pSelfParam->dbPoint = NULL; + } + + /* Specify the number of input signals to attach to become resolved */ + tacStdBlockSetInputNumber(pSelf, pSelfParam->inputNb); + + /* + * Perform other block initialization operations + */ + + /* Create the block internal message queue which tosses the messages out of the + * interrupt context. They are buffered in the queue until the DPC tasks + * picks them up and sends them over the shared memory message queue. + * Sorry for that double-queuing, that's because of the M-S architecture */ + + pSelfParam->msgq = msgQCreate(tacSINK_MONITOR_QUEUE_SIZE, sizeof(tacSHMSG), 0); + if ( pSelfParam->msgq == NULL ) + { + char errorParam[40]; + + sprintf(errorParam, "Could not create probe block message queue"); + tacRTC_ERR(tacERR_MALLOC, errorParam); + return ERROR; + } + + /* will count if a message can't be pushed in the queue */ + pSelfParam->lost = 0; + + /* Warn the background task that a new probe block has been created */ + pSelfParam->shmMsg.type = tacSHMSG_ADD_MONITOR; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + + if (pSelfParam->dbPoint == NULL) + { + strcpy((char*) &(pSelfParam->shmMsg.msgBody.monitor.data), tacSINK_MONITOR_DEFAULT_DB_POINT); + } + else + { + strcpy((char*) &(pSelfParam->shmMsg.msgBody.monitor.data), *((char**) &(pSelfParam->dbPoint))); + } + + printf("tacSinkMonitorBlockConstructor - Attach to %s\n",(char*) &(pSelfParam->shmMsg.msgBody.monitor.data)); + + /* Send message */ + tacShMsgQSendBgInfo(&(pSelfParam->shmMsg)); + + /* Initialize the message parameters */ + pSelfParam->shmMsg.type = tacSHMSG_MONITOR_DATA; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + pSelfParam->shmMsg.msgBody.monitor.data.number = pSelfParam->inputNb; + + /* The output port is used to average the inputs over the reporting period */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pSelf->output[arrayIndex] = 0.0; + } + + return OK; +} + +STATUS tacSinkMonitorStateBlockConstructor (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = NULL; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = NULL; + unsigned short arrayIndex = 0; + + /* Check that the expected number of parameters has been received */ + if (parameter->number < tacSINK_DEFAULT_EXPECTED_PARAM) + { + char errorParam[40]; + + sprintf(errorParam, "Expected %d, received %d", tacSINK_DEFAULT_EXPECTED_PARAM, parameter->number); + tacRTC_ERR(tacERR_PARAM_NUMBER, errorParam); + return ERROR; + } + + /* Check that the parameters are valid */ + pRealParam = (double*) parameter->buffer; + + /* Passed parameter is the sampling period of the block */ + if (pRealParam[tacSINK_SAMPLING_PERIOD] < (*pSelf->shared).samplingPeriod) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = (*pSelf->shared).samplingPeriod; + } + + if (pRealParam[tacSINK_SAMPLING_PERIOD] < tacSINK_MONITOR_MIN_SAMPLING_PERIOD) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = tacSINK_MONITOR_MIN_SAMPLING_PERIOD; + } + + /* Number of inputs is minimum 1 up to tacMSG_MAX_DATA_NUMBER */ + if ((pRealParam[tacSINK_INPUT_NUMBER] < 1) || + (pRealParam[tacSINK_INPUT_NUMBER] > tacMAX_DATA_NUMBER)) + { + tacRTC_ERR(tacERR_PARAM_INVALID, ""); + return ERROR; + } + + /* Call common constructor */ + if (tacSinkCommonBlockConstructor(pSelf, error) != OK) + { + return ERROR; + } + + /* Store parameters */ + pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* + * Compute the rate at which data has to be processed - divide and take + * the integer part of the result + */ + + pSelfParam->rate = (unsigned short) (pRealParam[tacSINK_SAMPLING_PERIOD] / (*pSelf->shared).samplingPeriod); + pSelfParam->counter = 0; /* Decimation counter */ + pSelfParam->inputNb = (unsigned short) pRealParam[tacSINK_INPUT_NUMBER]; + + /* Optional parameter is an application-specific DB point */ + if (parameter->number == tacSINK_DEFAULT_EXPECTED_PARAM + 1) + { + printf("tacSinkMonitorStateBlockConstructor - DB point %s\n",(char*) &(pRealParam[tacSINK_MONITOR_DB_POINT])); + pSelfParam->dbPoint = (char*) malloc(tacSINK_MONITOR_MAX_DB_ADDR_SIZE); + strcpy(pSelfParam->dbPoint, (char*) &(pRealParam[tacSINK_MONITOR_DB_POINT])); + } + else + { + printf("tacSinkMonitorStateBlockConstructor - Default DB point\n"); + pSelfParam->dbPoint = NULL; + } + + /* Specify the number of input signals to attach to become resolved */ + tacStdBlockSetInputNumber(pSelf, pSelfParam->inputNb); + + /* + * Perform other block initialization operations + */ + + /* Create the block internal message queue which tosses the messages out of the + * interrupt context. They are buffered in the queue until the DPC tasks + * picks them up and sends them over the shared memory message queue. + * Sorry for that double-queuing, that's because of the M-S architecture */ + + pSelfParam->msgq = msgQCreate(tacSINK_MONITOR_QUEUE_SIZE, sizeof(tacSHMSG), 0); + if ( pSelfParam->msgq == NULL ) + { + char errorParam[40]; + + sprintf(errorParam, "Could not create probe block message queue"); + tacRTC_ERR(tacERR_MALLOC, errorParam); + return ERROR; + } + + /* will count if a message can't be pushed in the queue */ + pSelfParam->lost = 0; + + /* Warn the background task that a new probe block has been created */ + pSelfParam->shmMsg.type = tacSHMSG_ADD_MONITOR; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + + if (pSelfParam->dbPoint == NULL) + { + strcpy((char*) &(pSelfParam->shmMsg.msgBody.monitor.data), tacSINK_MONITOR_DEFAULT_DB_POINT); + } + else + { + strcpy((char*) &(pSelfParam->shmMsg.msgBody.monitor.data), *((char**) &(pSelfParam->dbPoint))); + } + + printf("tacSinkMonitorStateBlockConstructor - Attach to %s\n",(char*) &(pSelfParam->shmMsg.msgBody.monitor.data)); + + /* Send message */ + tacShMsgQSendBgInfo(&(pSelfParam->shmMsg)); + + /* Initialize the message parameters */ + pSelfParam->shmMsg.type = tacSHMSG_MONITOR_DATA; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + pSelfParam->shmMsg.msgBody.monitor.data.number = pSelfParam->inputNb; + + /* Init output port which won't be used to average the inputs over the reporting period */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pSelf->output[arrayIndex] = 0.0; + } + + return OK; +} + +STATUS tacSinkProbeBlockCommonConstructor (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + double minPeriod, + tacERROR* error) +{ + double* pRealParam = NULL; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = NULL; + + /* Check that the expected number of parameters has been received */ + if (parameter->number < tacSINK_DEFAULT_EXPECTED_PARAM) + { + char errorParam[40]; + + sprintf(errorParam, "Expected %d, received %d", tacSINK_DEFAULT_EXPECTED_PARAM, parameter->number); + tacRTC_ERR(tacERR_PARAM_NUMBER, errorParam); + return ERROR; + } + + /* Check that the parameters are valid */ + pRealParam = (double*) parameter->buffer; + + /* Passed parameter is the sampling period of the block */ + if (pRealParam[tacSINK_SAMPLING_PERIOD] < (*pSelf->shared).samplingPeriod) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = (*pSelf->shared).samplingPeriod; + } + + if (pRealParam[tacSINK_SAMPLING_PERIOD] < minPeriod) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = minPeriod; + } + + /* Number of inputs is minimum 1 up to tacMSG_MAX_DATA_NUMBER */ + if ((pRealParam[tacSINK_INPUT_NUMBER] < 1) || + (pRealParam[tacSINK_INPUT_NUMBER] > tacMAX_DATA_NUMBER)) + { + tacRTC_ERR(tacERR_PARAM_INVALID, ""); + return ERROR; + } + + /* Call common constructor */ + if (tacSinkCommonBlockConstructor(pSelf, error) != OK) + { + return ERROR; + } + + /* Store parameters */ + pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* + * Compute the rate at which data has to be processed - divide and take + * the integer part of the result + */ + + pSelfParam->rateParam = pRealParam[tacSINK_SAMPLING_PERIOD]; + pSelfParam->rate = (unsigned short) (pRealParam[tacSINK_SAMPLING_PERIOD] / (*pSelf->shared).samplingPeriod); + pSelfParam->counter = 0; /* Decimation counter */ + pSelfParam->inputNb = (unsigned short) pRealParam[tacSINK_INPUT_NUMBER]; + + /* Specify the number of input signals to attach to become resolved */ + tacStdBlockSetInputNumber(pSelf, pSelfParam->inputNb); + + /* + * Perform other block initialization operations + */ + + /* Create the block internal message queue which gets the messages out of the + * interrupt context. They are buffered in the queue until the DPC tasks + * picks them up and sends them over the shared memory message queue. + * Sorry for that double-queuing, that's because of the M-S architecture */ + + /* There is only one message queue for all probe blocks! */ + pSelfParam->msgq = msgQCreate(tacSINK_PROBE_QUEUE_SIZE, sizeof(tacSHMSG), 0); + if ( pSelfParam->msgq == NULL ) + { + char errorParam[40]; + + sprintf(errorParam, "Could not create probe block message queue"); + tacRTC_ERR(tacERR_MALLOC, errorParam); + return ERROR; + } + + /* will count if a message can't be pushed in the queue */ + pSelfParam->lost = 0; + + /* Warn the background task that a new probe block has been created */ + pSelfParam->shmMsg.type = tacSHMSG_ADD_PROBE; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + + /* Send message */ + tacShMsgQSendDataSample(&pSelfParam->shmMsg); + + /* Initialize the message parameters */ + pSelfParam->shmMsg.type = tacSHMSG_TRANSFER_DATA; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + pSelfParam->shmMsg.msgBody.monitor.data.number = pSelfParam->inputNb; + + return OK; +} + +/* Probe block has a max. sampling frequency of 2kHz */ +STATUS tacSinkProbeBlockConstructor (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + return tacSinkProbeBlockCommonConstructor (pSelf, parameter, tacSINK_PROBE_MIN_SAMPLING_PERIOD, error); +} + +/* Fast probe is the same as probe but not does have the + * limitation on the max. recording frequency */ +STATUS tacSinkFastProbeBlockConstructor (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + return tacSinkProbeBlockCommonConstructor (pSelf, parameter, 0.0, error); +} + +void tacSinkProbeBlockReset (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = + (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* + * Re-Compute the rate at which data has to be processed + */ + if (pSelfParam->rateParam < (*pSelf->shared).samplingPeriod ) + { + pSelfParam->rate = 1; + } + else + { + pSelfParam->rate = (unsigned short) + (pSelfParam->rateParam / (*pSelf->shared).samplingPeriod); + } + + return; +} + +/* + * Report parameters Hooks + */ + +STATUS tacSinkDisplayBlockGetParameter (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = (double*) parameter->buffer; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Send back the expected number of parameters */ + parameter->number = tacSINK_ONE_EXPECTED_PARAM; + + /* Report current parameters */ + pRealParam[tacSINK_SAMPLING_PERIOD] = (double) (pSelfParam->rate * (*pSelf->shared).samplingPeriod); + + return OK; +} + +STATUS tacSinkMonitorBlockGetParameter (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = (double*) parameter->buffer; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Send back the expected number of parameters */ + parameter->number = tacSINK_DEFAULT_EXPECTED_PARAM; + + /* Report current parameters */ + pRealParam[tacSINK_SAMPLING_PERIOD] = (double) (pSelfParam->rate * (*pSelf->shared).samplingPeriod); + pRealParam[tacSINK_INPUT_NUMBER] = (double) pSelfParam->inputNb; + + if (*((char**) &(pSelfParam->dbPoint)) != NULL) + { + parameter->number += 1; + parameter->type[tacSINK_MONITOR_DB_POINT] = tacPARAM_STRING; + strcpy((char*) &(pRealParam[tacSINK_MONITOR_DB_POINT]), *((char**) &(pSelfParam->dbPoint))); + } + + return OK; +} + +STATUS tacSinkMonitorStateBlockGetParameter (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = (double*) parameter->buffer; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Send back the expected number of parameters */ + parameter->number = tacSINK_DEFAULT_EXPECTED_PARAM; + + /* Report current parameters */ + pRealParam[tacSINK_SAMPLING_PERIOD] = (double) (pSelfParam->rate * (*pSelf->shared).samplingPeriod); + pRealParam[tacSINK_INPUT_NUMBER] = (double) pSelfParam->inputNb; + + if (*((char**) &(pSelfParam->dbPoint)) != NULL) + { + parameter->number += 1; + parameter->type[tacSINK_MONITOR_DB_POINT] = tacPARAM_STRING; + strcpy((char*) &(pRealParam[tacSINK_MONITOR_DB_POINT]), *((char**) &(pSelfParam->dbPoint))); + } + + return OK; +} + +STATUS tacSinkProbeBlockGetParameter (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = (double*) parameter->buffer; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Send back the expected number of parameters */ + parameter->number = tacSINK_DEFAULT_EXPECTED_PARAM; + + /* Report current parameters */ + pRealParam[tacSINK_SAMPLING_PERIOD] = (double) (pSelfParam->rate * (*pSelf->shared).samplingPeriod); + pRealParam[tacSINK_INPUT_NUMBER] = (double) pSelfParam->inputNb; + + return OK; +} + +/* + * Change parameters Hooks + */ + +/* + * Algorithm Hooks + */ + +void tacSinkDisplayBlockAlgorithm (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + if ((pSelfParam->counter % pSelfParam->rate) == 0) /* It's time to process data */ + { + sprintf(logStr,"Name: %s Time: %ld.%6ld Value: %g\n", + pSelf->name, + (*pSelf->shared).currentTime.seconds, + (*pSelf->shared).currentTime.microsec, + tacStdBlockGetInput(pSelf,0)); + + tacDpcPushRequest((tacVOIDFCTPTR) &printf, logStr); + + pSelfParam->counter = 0; + } + + pSelfParam->counter++; +} + +void tacSinkMonitorBlockAlgorithm (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + unsigned short arrayIndex = 0; + + /* The output port is used to average the inputs over the reporting period */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pSelf->output[arrayIndex] += tacStdBlockGetInput(pSelf,arrayIndex); + } + + if ((pSelfParam->counter % pSelfParam->rate) == 0) /* It's time to process data */ + { + tacDATA* pData = &(pSelfParam->shmMsg.msgBody.monitor.data); /* We are only interested in message body */ + + /* pData->number = pSelfParam->inputNb; */ + pData->timeStamp = (*pSelf->shared).currentTime; + + /* pData points to the body of the Message */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pData->buffer[arrayIndex] = pSelf->output[arrayIndex] / pSelfParam->rate; + } + + /* Push message into probe block's message que to get the + * data out of the interrupt comtext. */ + if ( msgQSend (pSelfParam->msgq, (char*) &(pSelfParam->shmMsg), sizeof(tacSHMSG), NO_WAIT, 0) != OK ) + { + (pSelfParam->lost)++; + } + + /* Defer procedure call */ + tacDpcPushRequest((tacVOIDFCTPTR) &tacSinkSendMonitorMessage, &pSelfParam->msgq); + + pSelfParam->counter = 0; + + /* The output port is used to average the inputs over the reporting period */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pSelf->output[arrayIndex] = 0.0; + } + } + + pSelfParam->counter++; +} + +void tacSinkMonitorStateBlockAlgorithm (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + unsigned short arrayIndex = 0; + + if ((pSelfParam->counter % pSelfParam->rate) == 0) /* It's time to process data */ + { + tacDATA* pData = &(pSelfParam->shmMsg.msgBody.monitor.data); /* We are only interested in message body */ + + /* pData->number = pSelfParam->inputNb; */ + pData->timeStamp = (*pSelf->shared).currentTime; + + /* pData points to the body of the Message */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pData->buffer[arrayIndex] = tacStdBlockGetInput(pSelf,arrayIndex); + } + + /* Push message into probe block's message que to get the + * data out of the interrupt comtext. */ + if ( msgQSend (pSelfParam->msgq, (char*) &(pSelfParam->shmMsg), sizeof(tacSHMSG), NO_WAIT, 0) != OK ) + { + (pSelfParam->lost)++; + } + + /* Defer procedure call */ + tacDpcPushRequest((tacVOIDFCTPTR) &tacSinkSendMonitorMessage, &pSelfParam->msgq); + + pSelfParam->counter = 0; + } + + pSelfParam->counter++; +} + +void tacSinkProbeBlockAlgorithm (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + unsigned short arrayIndex = 0; + + if ((pSelfParam->counter % pSelfParam->rate) == 0) /* It's time to process data */ + { + tacDATA* pData = &(pSelfParam->shmMsg.msgBody.monitor.data); /* We are only interested in message body */ + + pData->timeStamp = (*pSelf->shared).currentTime; + + /* pData points to the body of the Message */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pData->buffer[arrayIndex] = tacStdBlockGetInput(pSelf,arrayIndex); + } + + /* Push message into probe block's message que to get the + * data out of the interrupt comtext. */ + if ( msgQSend (pSelfParam->msgq, (char*) &(pSelfParam->shmMsg), sizeof(tacSHMSG), NO_WAIT, 0) != OK ) + { + (pSelfParam->lost)++; + } + + /* Defer procedure call: + * tacSinkSendProbeMessage is called outside the interrupt routine + * and will take care to pick up the message from the probe block's + * message queue and send it over the shared memory message queue */ + tacDpcPushRequest((tacVOIDFCTPTR) &tacSinkSendProbeMessage, &pSelfParam->msgq); + + pSelfParam->counter = 0; + } + + pSelfParam->counter++; +} + +/* + * Reset Hooks + */ + +/* + * Stop Hooks + */ + +/* + * Destructor Hooks + */ + +/* + * Note: This destructor is used mainly to send a MONITOR message containing + * 0.0 in order to reset the database array (otherwise going from an + * algorithm with 4 monitored data to one with 3 monitored data leaves + * the 4th value equal to the last ...) + */ + +void tacSinkMonitorBlockDestructor (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + tacDATA* pData = &(pSelfParam->shmMsg.msgBody.monitor.data); + unsigned short arrayIndex = 0; + + /* Reset DB values */ + pSelfParam->shmMsg.type = tacSHMSG_MONITOR_DATA; + pData = &(pSelfParam->shmMsg.msgBody.monitor.data); + + pData->number = pSelfParam->inputNb; + + /* pData points to the body of the Message */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pData->buffer[arrayIndex] = 0.0; + } + + /* Send message */ + tacShMsgQSendBgInfo(&pSelfParam->shmMsg); + + pSelfParam->shmMsg.type = tacSHMSG_REMOVE_MONITOR; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + + /* Send message */ + tacShMsgQSendBgInfo(&pSelfParam->shmMsg); + + free(pSelfParam->dbPoint); + + /* delete internal message queue. Do this as deferred procedure call + * to make sure it is only called when all messages have been send + * (through the same deferred call mechanism) */ + tacDpcPushRequest((tacVOIDFCTPTR) tacSinkDeleteMessageQueue, &(pSelfParam->msgq)); + + return; +} + +void tacSinkMonitorStateBlockDestructor (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + tacDATA* pData = &(pSelfParam->shmMsg.msgBody.monitor.data); + unsigned short arrayIndex = 0; + + /* Reset DB values */ + pSelfParam->shmMsg.type = tacSHMSG_MONITOR_DATA; + pData = &(pSelfParam->shmMsg.msgBody.monitor.data); + + pData->number = pSelfParam->inputNb; + + /* pData points to the body of the Message */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pData->buffer[arrayIndex] = 0.0; + } + + /* Send message */ + tacShMsgQSendBgInfo(&pSelfParam->shmMsg); + + pSelfParam->shmMsg.type = tacSHMSG_REMOVE_MONITOR; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + + /* Send message */ + tacShMsgQSendBgInfo(&pSelfParam->shmMsg); + + free(pSelfParam->dbPoint); + + /* delete internal message queue. Do this as deferred procedure call + * to make sure it is only called when all messages have been send + * (through the same deferred call mechanism) */ + tacDpcPushRequest((tacVOIDFCTPTR) tacSinkDeleteMessageQueue, &(pSelfParam->msgq)); + + return; +} + +void tacSinkProbeBlockDestructor (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + pSelfParam->shmMsg.type = tacSHMSG_REMOVE_PROBE; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + + /* Send message */ + tacShMsgQSendDataSample(&pSelfParam->shmMsg); + + /* delete internal message queue. Do this as deferred procedure call + * to make sure it is only called when all messages have been send + * (through the same deferred call mechanism) */ + tacDpcPushRequest((tacVOIDFCTPTR) tacSinkDeleteMessageQueue, &(pSelfParam->msgq)); + + return; +} + +/* + * Show Hooks + */ + +void tacSinkDisplayBlockShow (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Print parameter values */ + printf(" Update rate: %d\n",pSelfParam->rate); + + return; +} + +void tacSinkMonitorBlockShow (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Print parameter values */ + printf(" Update rate: %d\n",pSelfParam->rate); + printf(" Number of input signals: %d\n",pSelfParam->inputNb); + printf(" Queued samples: %d\n", msgQNumMsgs(pSelfParam->msgq)); + printf(" Lost samples: %d\n",pSelfParam->lost); + + if (pSelfParam->dbPoint != NULL) + { + printf(" DB Point: %s\n", pSelfParam->dbPoint); + } + + return; +} + +void tacSinkMonitorStateBlockShow (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Print parameter values */ + printf(" Using MonitorState block, not averaging received data\n"); + printf(" Update rate: %d\n",pSelfParam->rate); + printf(" Number of input signals: %d\n",pSelfParam->inputNb); + printf(" Queued samples: %d\n", msgQNumMsgs(pSelfParam->msgq)); + printf(" Lost samples: %d\n",pSelfParam->lost); + + if (pSelfParam->dbPoint != NULL) + { + printf(" DB Point: %s\n", pSelfParam->dbPoint); + } + + return; +} + +void tacSinkProbeBlockShow (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Print parameter values */ + printf(" Update rate: %d\n",pSelfParam->rate); + printf(" Update rate param (sec): %f\n",pSelfParam->rateParam); + printf(" Number of input signals: %d\n",pSelfParam->inputNb); + printf(" Queued samples: %d\n", msgQNumMsgs(pSelfParam->msgq)); + printf(" Lost samples: %d\n",pSelfParam->lost); + + return; +} + +/* + * Installation function + */ + +tacSTDBLOCK_TYPE tacSinkDisplayTypeInfo = { + "Display", + &tacSinkDisplayBlockConstructor, + &tacSinkDisplayBlockGetParameter, + &tacSinkDisplayBlockAlgorithm, + NULL, + NULL, + NULL, + NULL, + &tacSinkDisplayBlockShow, +}; + +tacSTDBLOCK_TYPE tacSinkMonitorTypeInfo = { + "Monitor", + &tacSinkMonitorBlockConstructor, + &tacSinkMonitorBlockGetParameter, + &tacSinkMonitorBlockAlgorithm, + NULL, + NULL, + NULL, + &tacSinkMonitorBlockDestructor, + &tacSinkMonitorBlockShow, +}; + +tacSTDBLOCK_TYPE tacSinkMonitorStateTypeInfo = { + "MonitorState", + &tacSinkMonitorStateBlockConstructor, + &tacSinkMonitorStateBlockGetParameter, + &tacSinkMonitorStateBlockAlgorithm, + NULL, + NULL, + NULL, + &tacSinkMonitorStateBlockDestructor, + &tacSinkMonitorStateBlockShow, +}; + +/* Probe with a maximal sampling rate of 2kHz */ +tacSTDBLOCK_TYPE tacSinkProbeTypeInfo = { + "Probe", + &tacSinkProbeBlockConstructor, + &tacSinkProbeBlockGetParameter, + &tacSinkProbeBlockAlgorithm, + NULL, + &tacSinkProbeBlockReset, + NULL, + &tacSinkProbeBlockDestructor, + &tacSinkProbeBlockShow, +}; + +/* Fast probe is the same as probe but not does have the + * limitation on the max. recording frequency */ +tacSTDBLOCK_TYPE tacSinkFastProbeTypeInfo = { + "FastProbe", + &tacSinkFastProbeBlockConstructor, + &tacSinkProbeBlockGetParameter, + &tacSinkProbeBlockAlgorithm, + NULL, + &tacSinkProbeBlockReset, + NULL, + &tacSinkProbeBlockDestructor, + &tacSinkProbeBlockShow, +}; + +STATUS tacSinkBlockInitAll (void) +{ + /* Install Sink Block Hooks */ + tacStdBlockInstallNewType(&tacSinkDisplayTypeInfo); + tacStdBlockInstallNewType(&tacSinkMonitorTypeInfo); + tacStdBlockInstallNewType(&tacSinkMonitorStateTypeInfo); + tacStdBlockInstallNewType(&tacSinkProbeTypeInfo); + tacStdBlockInstallNewType(&tacSinkFastProbeTypeInfo); + + /* + * Perform other library initialization operations + */ + + return OK; +} + +/* + * Local functions + */ + +/* + * Note: Routines called from within the algorithm must be declared with + * static __inline__ + */ + +STATUS tacSinkCommonBlockConstructor (tacSTDBLOCK* pSelf, + tacERROR* error) +{ + /* Allocate specific arrays (pointers are initialized to NULL by StdBlock) */ + if (tacStdBlockAllocateArrays(pSelf, 0, tacSINK_DEFAULT_INPUT_NUMBER, + tacSINK_DEFAULT_OUTPUT_NUMBER, error) == ERROR) + { + return ERROR; + } + + if (tacStdBlockAllocateArrayBySize(pSelf, tacSTDBLOCK_PARAM_ARRAY, + sizeof(tacSINK_SCOPE_LOCAL_PARAMETER), error) == ERROR) + { + tacStdBlockReleaseArray(pSelf, tacSTDBLOCK_INPUT_ARRAY, error); + tacStdBlockReleaseArray(pSelf, tacSTDBLOCK_OUTPUT_ARRAY, error); + return ERROR; + } + + /* Specify the number of input signals to attach to become resolved */ + tacStdBlockSetInputNumber(pSelf, tacSINK_ONE_INPUT_NUMBER); /* Required */ + + return OK; +} + +STATUS tacSinkSendMonitorMessage(MSG_Q_ID * msgq) +{ + /* Send message using provided function (different for Monitor and Probe blocks) */ + /* Send message using provided function (different for Monitor and Probe blocks) */ + tacSHMSG msg; + + if ( msgQReceive(*msgq, (char*) &msg, sizeof(tacSHMSG), NO_WAIT) == sizeof(tacSHMSG) ) + { + tacShMsgQSendBgInfo (&msg); + } + + return OK; +} + +STATUS tacSinkSendProbeMessage(MSG_Q_ID * msgq) +{ + /* Send message using provided function (different for Monitor and Probe blocks) */ + tacSHMSG msg; + + if ( msgq == NULL ) + { + return ERROR; + } + + if ( msgQReceive(*msgq, (char*) &msg, sizeof(tacSHMSG), NO_WAIT) == sizeof(tacSHMSG) ) + { + tacShMsgQSendDataSample (&msg); + } + return OK; +} + +STATUS tacSinkDeleteMessageQueue (MSG_Q_ID * msgq) +{ + /* Is called when block is destroyed and removes the internal message queue */ + STATUS status; + + status = msgQDelete (*msgq); + *msgq = NULL; + return status; +} + + +/*___oOo___*/ + + + + + + diff --git a/src/arguments.py b/src/arguments.py new file mode 100644 index 0000000..94e4cea --- /dev/null +++ b/src/arguments.py @@ -0,0 +1,26 @@ +import getopt + +def exitUsage(): + print("usage: %s <.tasrc file> -i -o " % sys.argv[0]) + sys.exit(1) + +def readArguments(args): + sourceDirectories = [] + outputFile = "" + try: + options, _ = getopt.getopt(args, "hi:o:") + except getopt.GetoptError: + exitUsage() + for option, arg in options: + if option == "-h": + exitUsage() + elif option == "-o": + outputFile = arg + elif option == "-i": + sourceDirectories.append(arg) + if outputFile == "": + exitUsage() + if len(sourceDirectories) == 0: + print("WARNING: no source directories specified!") + return outputFile, sourceDirectories + diff --git a/src/converter.py b/src/converter.py new file mode 100755 index 0000000..3e44058 --- /dev/null +++ b/src/converter.py @@ -0,0 +1,18 @@ +#!/usr/bin/python3 + +import sys + +import arguments +from tacsrc.tac import readTAC +import grc +import portNaming + +if __name__ == "__main__": + if len(sys.argv) == 1: + params.exitUsage() + inputFile = sys.argv[1] + outputFile, sourceDirectories = arguments.readArguments(sys.argv[2:]) + blocks, connections, blockTypes = readTAC(inputFile) + portNaming.resolvePortNames(blockTypes, sourceDirectories) + grc.write(outputFile, blocks, connections) + diff --git a/src/defaultBlockTypes.py b/src/defaultBlockTypes.py new file mode 100644 index 0000000..a7c7a7a --- /dev/null +++ b/src/defaultBlockTypes.py @@ -0,0 +1,74 @@ +from tacsrc.blockType import BlockType + +class VariablePorts: + def __init__(self, ioDescriptionName, sizeFunction): + self.ioDescriptionName = ioDescriptionName + self.sizeFunction = sizeFunction + + def mapName(self, position, name, index): + return + + def getRealPort(self, originalPort): + return 0 + + def ensureLength(self, length): + return + + def getIODescription(self, block): + return "\\\\n0:%s[%s]" % (self.ioDescriptionName, self.sizeFunction(block)) + + def getRealCount(self): + return 1 + +def inParameters(block): + return block.parameters[1] + +def parameterSize(block): + return len(block.parameters) + +monitor = BlockType("Monitor") +monitor.inputs = VariablePorts("input", inParameters) + +monitorState = BlockType("MonitorState") +monitorState.inputs = VariablePorts("input", inParameters) + +probe = BlockType("Probe") +probe.inputs = VariablePorts("input", inParameters) + +readRfm = BlockType("ReadRfm") +readRfm.outputs = VariablePorts("output", parameterSize) + +rms = BlockType("RMS") +rms.inputs.mapName(0, "input", 0) +rms.outputs.mapName(0, "output", 0) + +constant = BlockType("Constant") +constant.outputs.mapName(0, "CONST", 0) + +manual = BlockType("ManualSwitch") +manual.inputs.mapName(0, "input", 0) +manual.outputs.mapName(0, "output", 0) + +noise = BlockType("NormalNoise") +noise.outputs.mapName(0, "output", 0) + +writeRMNNoTim = BlockType("WriteRmNoTim") +writeRMNNoTim.inputs = VariablePorts("input", parameterSize) + +defaultBlockTypes = { + "Monitor": monitor, + "MonitorState": monitorState, + "Probe": probe, + "ReadRfm": readRfm, + "TIM": BlockType("TIM"), + "WAIT_RFM_INTERRUPT": BlockType("WAIT_RFM_INTERRUPT"), + "RMS": rms, + "Constant": constant, + "ManualSwitch": manual, + "NormalNoise": noise, + "WriteRmNoTim": writeRMNNoTim +} + +def addDefaultBlockTypes(blockTypes): + for key in defaultBlockTypes: + blockTypes[key] = defaultBlockTypes[key] diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3624768 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +__pycache__ +out +tacapp.tar.gz +Sources +tacapp +worryingFiles +cc.tar.gz diff --git a/errors.json b/errors.json new file mode 100644 index 0000000..5ec898a --- /dev/null +++ b/errors.json @@ -0,0 +1,4 @@ +{ + "missing_blocks": [], + "multiple_definitions": [] +} \ No newline at end of file diff --git a/hardcodedFiles/tacReadRmnBlock.c b/hardcodedFiles/tacReadRmnBlock.c new file mode 100644 index 0000000..8acbcfa --- /dev/null +++ b/hardcodedFiles/tacReadRmnBlock.c @@ -0,0 +1,568 @@ +/******************************************************************************* +* E.S.O. - VLT project +* +* "@(#) $Id: tacReadRmnBlock.c 305476 2018-01-19 08:56:18Z rfrahm $" +* +* who when what +* ------- -------- ---------------------------------------------- +* gzins 2010-07-27 ported to VLTSW2010 and VxWorks 6.4 +* swehner 2008-10-10 creation +*/ + +/************************************************************************ +* NAME +* tacReadRmnBlock - Implemements the standard functions for the +* tacReadRmn block and tacReadRfm block. +* tacReadRmnBlock - Reads from 1rst generation reflective memory network +* tacReadRfmBlock - Reads from 2nd generation reflective memory network + +* Parameters: +* field - token names for the RMN fields to read (up to 10) +* Inputs: 0 +* Outputs: 1 +* output - 1..10 depending on number of field parameters +* +* +* +* FILES +* +* ENVIRONMENT +* TAC +* +* RETURN VALUES +* +* CAUTIONS +* +* EXAMPLES +* TAC.BLOCK9.TYPE ReadRmn +* TAC.BLOCK9.NAME ReadRmn +* +* SEE ALSO +* +* BUGS +* +*------------------------------------------------------------------------ +*/ + +#define _POSIX_SOURCE 1 +#include "vltPort.h" + +ATTRIBUTE_UNUSED static const char *rcsId="@(#) $Id: tacReadRmnBlock.c 305476 2018-01-19 08:56:18Z rfrahm $"; + +/* + * System Headers + */ + +#include /* taskSpawn, taskDelay, ... */ +#include /* printf ... */ +#include /* malloc ... */ +#include /* malloc ... */ +#include +#include + +/* + * Local Headers + */ + +#include "tacStdBlock.h" +#include "tacRmnBlock.h" +#include "rmassPublic.h" +#include "rmassPrivate.h" + +/* + * Compilation directives + */ + +/* + * Constants + */ + +#define tacREAD_RMN_EXPECTED_PARAM 1 +#define tacREAD_RMN_DEFAULT_INPUT_NUMBER 0 +#define tacREAD_RMN_DEFAULT_OUTPUT_NUMBER tacMAX_DATA_NUMBER + +#define tacREAD_RMN_FIELD_STRING_LEN 256 +#define tacSTRLEN sizeof(double) + +/* + * Types + */ + +/* + * Local function declaration + */ + +/* + * Global variables + */ + +/* + * Function definition + */ + + +STATUS tacReadRmnBlockCheckParameter (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the ADDBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = NULL; + + pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + /* field string is built from block params */ + if ( tacRmnBlockCheckParameter ( pSelf, parameter, 0, error) != OK ) + { + return ERROR; + } + + /* useful information on the screen */ + printf ("ReadRmn %s: [%s]\n", pSelf->name, pSelfParam->fieldString); + + return OK; +} + +STATUS tacReadRfmBlockCheckParameter (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the ADDBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = NULL; + + pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + /* field string is built from block params */ + if ( tacRmnBlockCheckParameter ( pSelf, parameter, 0, error) != OK ) + { + return ERROR; + } + + /* useful information on the screen */ + printf ("ReadRfm %s: [%s]\n", pSelf->name, pSelfParam->fieldString); + + return OK; +} + +/* + * Constructor Hooks - Called when a block of this type is instanciated (CONFIG or ADDBLCK commands) + */ + +STATUS tacReadRmBlockConstructor (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the ADDBLCK command */ + vltLOGICAL isRmn, + tacERROR* error) /* Error structure - not a stack */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = NULL; + + /* Check that the expected number of parameters has been received */ + if (parameter->number < tacREAD_RMN_EXPECTED_PARAM) + { + char errorParam[40]; + + sprintf(errorParam, "Expected at least %d, received %d", tacREAD_RMN_EXPECTED_PARAM, parameter->number); + tacRTC_ERR(tacERR_PARAM_NUMBER, errorParam); + return ERROR; + } + + /* Allocate and initialize block-specific arrays */ + if (tacStdBlockAllocateArrays(pSelf, 0, tacREAD_RMN_DEFAULT_INPUT_NUMBER, tacREAD_RMN_DEFAULT_OUTPUT_NUMBER, error) == ERROR) + { + return ERROR; + } + + if (tacStdBlockAllocateArrayBySize(pSelf, tacSTDBLOCK_PARAM_ARRAY, sizeof(tacRMN_LOCAL_PARAMETER), error) == ERROR) + { + tacStdBlockReleaseArray(pSelf, tacSTDBLOCK_INPUT_ARRAY, error); + tacStdBlockReleaseArray(pSelf, tacSTDBLOCK_OUTPUT_ARRAY, error); + return ERROR; + } + + if ( isRmn ) + { + if ( tacReadRmnBlockCheckParameter (pSelf, parameter, error) == ERROR) + { + return ERROR; + } + } + else + { + if ( tacReadRfmBlockCheckParameter (pSelf, parameter, error) == ERROR) + { + return ERROR; + } + } + + pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + pSelfParam->handleValid = rmassACCESS_BLOCKED; + + /* Attach to RMN */ + if ( rmassReadAttach (&pSelfParam->handle, + pSelfParam->fieldString, + &pSelfParam->val[0], + &pSelfParam->val[1], + &pSelfParam->val[2], + &pSelfParam->val[3], + &pSelfParam->val[4], + &pSelfParam->val[5], + &pSelfParam->val[6], + &pSelfParam->val[7], + &pSelfParam->val[8], + &pSelfParam->val[9]) != SUCCESS ) + { + char errorParam[40]; + + sprintf(errorParam, "Attach to RMN failed."); + tacRTC_ERR(tacERR_INTERNAL, errorParam); + return ERROR; + } + + pSelfParam->handleValid = rmassACCESS_FREE; + + return OK; +} + +STATUS tacReadRmnBlockConstructor (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the ADDBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + if ( tacReadRmBlockConstructor (pSelf, parameter, ccsTRUE, error ) == ERROR ) + { + return ERROR; + } + return OK; +} + +STATUS tacReadRfmBlockConstructor (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the ADDBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + if ( tacReadRmBlockConstructor (pSelf, parameter, ccsFALSE, error ) == ERROR ) + { + return ERROR; + } + return OK; +} + + + +/* + * Destructor Hooks - Called when the block is removed from the algorithm (DELBLCK or new CONFIG commands) + */ + +void tacReadRmnBlockDestructor (tacSTDBLOCK* pSelf) /* Reference to the block instance */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = NULL; + pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + pSelfParam->handleValid = rmassACCESS_BLOCKED; + /* wait until semaphore is acknowledged by realtime algo + * or just procede if realtime is not active */ + while ((*pSelf->shared).active && pSelfParam->handleValid != rmassACCESS_BLOCK_ACKN) + { + taskDelay(1); + } + + rmassDetach (&pSelfParam->handle); + + return; +} + +/* + * Change parameters Hooks - Called when modifying the block parameters (MODBLCK command) + */ + +STATUS tacReadRmnBlockSetParameter (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the MODBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + if ( tacReadRmnBlockCheckParameter (pSelf, parameter, error) == ERROR) + { + return ERROR; + } + + pSelfParam->handleValid = rmassACCESS_BLOCKED; + /* wait until semaphore is acknowledged by realtime algo + * or just procede if realtime is not active */ + while ((*pSelf->shared).active && pSelfParam->handleValid != rmassACCESS_BLOCK_ACKN) + { + taskDelay(1); + } + + /* detach RMN handle */ + if ( rmassDetach (&pSelfParam->handle) != SUCCESS ) + { + char errorParam[40]; + + sprintf(errorParam, "rmassDetach returned error."); + tacRTC_ERR(tacERR_INTERNAL, errorParam); + return ERROR; + } + + if ( rmassReadAttach (&pSelfParam->handle, + pSelfParam->fieldString, + &pSelfParam->val[0], + &pSelfParam->val[1], + &pSelfParam->val[2], + &pSelfParam->val[3], + &pSelfParam->val[4], + &pSelfParam->val[5], + &pSelfParam->val[6], + &pSelfParam->val[7], + &pSelfParam->val[8], + &pSelfParam->val[9]) != SUCCESS ) + { + char errorParam[40]; + + sprintf(errorParam, "Attach to RMN failed."); + tacRTC_ERR(tacERR_INTERNAL, errorParam); + return ERROR; + } + + pSelfParam->handleValid = rmassACCESS_FREE; + + return OK; +} + +STATUS tacReadRfmBlockSetParameter (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the MODBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + if ( tacReadRfmBlockCheckParameter (pSelf, parameter, error) == ERROR) + { + return ERROR; + } + + pSelfParam->handleValid = rmassACCESS_BLOCKED; + /* wait until semaphore is acknowledged by realtime algo + * or just procede if realtime is not active */ + while ((*pSelf->shared).active && pSelfParam->handleValid != rmassACCESS_BLOCK_ACKN) + { + taskDelay(1); + } + + /* detach RMN handle */ + if ( rmassDetach (&pSelfParam->handle) != SUCCESS ) + { + char errorParam[40]; + + sprintf(errorParam, "rmassDetach returned error."); + tacRTC_ERR(tacERR_INTERNAL, errorParam); + return ERROR; + } + + if ( rmassReadAttach (&pSelfParam->handle, + pSelfParam->fieldString, + &pSelfParam->val[0], + &pSelfParam->val[1], + &pSelfParam->val[2], + &pSelfParam->val[3], + &pSelfParam->val[4], + &pSelfParam->val[5], + &pSelfParam->val[6], + &pSelfParam->val[7], + &pSelfParam->val[8], + &pSelfParam->val[9]) != SUCCESS ) + { + char errorParam[40]; + + sprintf(errorParam, "Attach to RFM failed."); + tacRTC_ERR(tacERR_INTERNAL, errorParam); + return ERROR; + } + + pSelfParam->handleValid = rmassACCESS_FREE; + + return OK; +} + +/* + * Algorithm Hooks - Called at each time the TAC algorithm is evaluated (ONLINE state) + */ + +void tacReadRmnBlockAlgorithm (tacSTDBLOCK* pSelf) /* Reference to the block instance */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + int i; + + if ( pSelfParam->handleValid == rmassACCESS_BLOCKED ) + { + pSelfParam->handleValid = rmassACCESS_BLOCK_ACKN; + } + + if ( pSelfParam->handleValid == rmassACCESS_FREE ) + { + /* actual RMN read operation */ + rmassReadAccessRmn (&pSelfParam->handle); + + /* Write to outputs */ + for (i=0; i < pSelfParam->numFields; i++) + { + switch (pSelfParam->type[i]) + { + case rmassTIMESEC: + case rmassUINT32: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).ui); + break; + case rmassTIMEUSEC: + case rmassINT32: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).i); + break; + case rmassFLOAT: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).f); + break; + default: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).d); + break; + } + } + + /* provide zero values at unsatisfied outputs + * I consider this a good thing to do since the block + * is always configured */ + for (i=pSelfParam->numFields; i < tacREAD_RMN_DEFAULT_OUTPUT_NUMBER; i++) + { + tacStdBlockSetOutput(pSelf, i, 0.0); + } + } +} + +void tacReadRfmBlockAlgorithm (tacSTDBLOCK* pSelf) /* Reference to the block instance */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + int i; + + if ( pSelfParam->handleValid == rmassACCESS_BLOCKED ) + { + pSelfParam->handleValid = rmassACCESS_BLOCK_ACKN; + } + + if ( pSelfParam->handleValid == rmassACCESS_FREE ) + { + /* actual RMN read operation */ + rmassReadAccessRfm (&pSelfParam->handle); + + /* Write to outputs */ + for (i=0; i < pSelfParam->numFields; i++) + { + switch (pSelfParam->type[i]) + { + case rmassTIMESEC: + case rmassUINT32: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).ui); + break; + case rmassTIMEUSEC: + case rmassINT32: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).i); + break; + case rmassFLOAT: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).f); + break; + default: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).d); + break; + } + } + + /* provide zero values at unsatisfied outputs + * I consider this a good thing to do since the block + * is always configured */ + for (i=pSelfParam->numFields; i < tacREAD_RMN_DEFAULT_OUTPUT_NUMBER; i++) + { + tacStdBlockSetOutput(pSelf, i, 0.0); + } + } +} + +/* + * Show Hooks - Called when the tacRtcTaskShow routine is executed + */ + +void tacReadRmnBlockShow (tacSTDBLOCK* pSelf) /* Reference to the block instance */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + /* Print parameter values */ + printf(" Attached: %s\n", pSelfParam->fieldString); + + return; +} + + +/***************************************************/ +/* The following code is common to all block types */ +/* Do not modify without any good reasons */ +/***************************************************/ + +/* + * Installation function + */ + +tacSTDBLOCK_TYPE tacReadRmnTypeInfo = { + "ReadRmn", + &tacReadRmnBlockConstructor, + &tacRmBlockGetParameter, + &tacReadRmnBlockAlgorithm, + &tacReadRmnBlockSetParameter, + NULL, + NULL, + &tacReadRmnBlockDestructor, + &tacReadRmnBlockShow +}; + +tacSTDBLOCK_TYPE tacReadRfmTypeInfo = { + "ReadRfm", + &tacReadRfmBlockConstructor, + &tacRmBlockGetParameter, + &tacReadRfmBlockAlgorithm, + &tacReadRmnBlockSetParameter, + NULL, + NULL, + &tacReadRmnBlockDestructor, + &tacReadRmnBlockShow +}; + +STATUS tacReadRmnBlockInitAll (void) +{ + /***************************************************/ + /* The following code is common to all block types */ + /* Do not modify without any good reasons */ + /***************************************************/ + + /* Install ReadRmn1g Block Hooks */ + tacStdBlockInstallNewType(&tacReadRmnTypeInfo); + + /*****************************/ + /* End of common code region */ + /*****************************/ + + /* Perform other library initialization operations */ + + return OK; +} + +STATUS tacReadRfmBlockInitAll (void) +{ + /***************************************************/ + /* The following code is common to all block types */ + /* Do not modify without any good reasons */ + /***************************************************/ + + /* Install ReadRmn1g Block Hooks */ + tacStdBlockInstallNewType(&tacReadRfmTypeInfo); + + /*****************************/ + /* End of common code region */ + /*****************************/ + + /* Perform other library initialization operations */ + + return OK; +} + +/*___oOo___*/ + + + diff --git a/hardcodedFiles/tacSinkBlock.c b/hardcodedFiles/tacSinkBlock.c new file mode 100644 index 0000000..df39833 --- /dev/null +++ b/hardcodedFiles/tacSinkBlock.c @@ -0,0 +1,1256 @@ +/******************************************************************************* +* E.S.O. - VLT project +* +* "@(#) $Id: tacSinkBlock.c 339094 2021-02-10 03:10:02Z jgil $" +* +* who when what +* ------- -------- ---------------------------------------------- +* rdembet 06/08/20 New MonitorState block with no data averaging +* swehner 28/11/09 SPR20090234 Correction in rate adjustment in reset hook +* swehner 27/11/09 Fixed message queue handling +* swehner 10/10/09 New block FastProbe for unlimited rec frequency +* swehner 22/09/09 PPRS 32341 Replaced specialized tacSINK_SHMSG stack +* with standard vxWorks message queue. +* bbauvir 21/09/04 VLTSW20040113 - One sample might be lost +* bbauvir 29/03/04 Monitor block averages over the reporting period +* bbauvir 29/12/02 Probe to the SampTask +* bbauvir 26/12/02 MsgQ access through DPC mechanism +* bbauvir 14/07/02 New MsgQ of TAC version 1.22 +* bbauvir 21/03/01 Created +*/ + +/************************************************************************ +* NAME +* tacSinkBlock - Standard data monitoring blocks +* +* SYNOPSIS +* lcubootAutoCdBoot 1,"tacsink.boot" +* < tacsink.boot +* +* DESCRIPTION +* Block type: Display +* Parameters: +* Inputs: 1 +* Outputs: none +* +* This function block samples the value of its input signal at the +* specified and issues a message containing the time +* and the value of the input on the vxWorks terminal. +* It does not allow modification of the parameter at runtime. +* +* Block type: Monitor +* Parameters: +* +* Inputs: 10max +* Outputs: none +* +* This function block samples the value of its input signals at the +* specified (0.0 to send a message at the system sampling +* period) and issues a message containing the time and the value of +* the inputs on the shared memory. This message is intercepted by the +* background task running on the master CPU. The monitored values are +* written into the online database. The number of inputs of the block +* is specified by parameter. +* This block does not allow modification of the parameters at runtime. +* +* Block type: MonitorState +* Parameters: +* +* Inputs: 10max +* Outputs: none +* +* Same as Monitor block but without the averaging of received data, +* see VLTSW-14260 JIRA ticket. +* +* Block type: Probe +* Parameters: +* +* Inputs: 10max +* Outputs: none +* +* Block type: FastProbe +* Parameters: +* +* Inputs: 10max +* Outputs: none +* +* This function block samples the value of its input signals at the +* specified (0.0 to send a message at the system sampling +* period) and issues a message containing the time and the value of +* the inputs on the shared memory. This message is intercepted by the +* background task running on the master CPU. The number of inputs of +* the block is specified by parameter. +* This message is passed to an external application callback if +* provided. +* This block does not allow modification of the parameters at runtime. +* The normal Probe block has a limited sampling frequency of not more +* than 2kHz. The reason is in particular the bottleneck between master +* and slave CPU which all samples have to pass through a mechanism of +* VME bus shared memory. On one-CPU-systems this limitation does not +* apply so you are free to choose faster sampling. You may of course +* hit other limitations (processor speed, network traffic etc.) +* +* FILES +* +* ENVIRONMENT +* TAC +* +* RETURN VALUES +* +* CAUTIONS +* All these blocks compute an decimation value to use to trigger the +* sampling of the input signals, from the system sampling period. +* They should be created after any synchronization block. +* +* In order to cope with system performances, a minimum +* is defined for each block. The minimum applied periods are 0.1 (10Hz), +* 0.01 (100Hz) and 0.5e-3 (2kHz) for the 'Display', 'Monitor' and +* 'Probe' blocks respectively. +* +* EXAMPLES +* # 5 signals @ 2Hz (monitored in the database) +* TAC.BLOCK9.TYPE Monitor +* TAC.BLOCK9.NAME Monitor +* TAC.BLOCK9.PARAM 0.5, 5 +* +* # 5 signals @ the RT algorithm sampling period (0.0) +* TAC.BLOCK10.TYPE Probe +* TAC.BLOCK10.NAME Probe +* TAC.BLOCK10.PARAM 0.0, 5 +* +* SEE ALSO +* tacServerInstallDataCallback, tacServerRemoveDataCallback +* +* BUGS +* +*------------------------------------------------------------------------ +*/ + +#define _POSIX_SOURCE 1 +#include "vltPort.h" + + +/* + * System Headers + */ + +#include +#include +#include /* logMsg ... */ +#include /* printf ... */ +#include /* malloc ... */ +#include /* memcpy ... */ +#include + +/* + * Local Headers + */ + +#include "tacStdBlock.h" +#include "tacShMsgQ.h" + +/* + * Compilation directives + */ + +/* + * Constants + */ + +#define tacSINK_DEFAULT_EXPECTED_PARAM 2 + +#define tacSINK_DEFAULT_INPUT_NUMBER tacMAX_DATA_NUMBER /* Up to 10 input channels */ +#define tacSINK_DEFAULT_OUTPUT_NUMBER tacMAX_DATA_NUMBER + +#define tacSINK_ONE_EXPECTED_PARAM 1 +#define tacSINK_ONE_INPUT_NUMBER 1 + +#define tacSINK_DISPLAY_MIN_SAMPLING_PERIOD .1 /* 10Hz */ +#define tacSINK_MONITOR_MIN_SAMPLING_PERIOD .01 /* 100Hz */ +#define tacSINK_PROBE_MIN_SAMPLING_PERIOD .5e-3 /* 2kHz */ + +#define tacSINK_DISPLAY_LOG_STRING_SIZE 128 + +#define tacSINK_MONITOR_DEFAULT_DB_POINT "tac:data:monitor" +#define tacSINK_MONITOR_MAX_DB_ADDR_SIZE 64 + +#define tacSINK_MONITOR_QUEUE_SIZE 6 +#define tacSINK_PROBE_QUEUE_SIZE 6 + + +typedef enum { + tacSINK_SAMPLING_PERIOD = 0, + tacSINK_INPUT_NUMBER, + tacSINK_MONITOR_DB_POINT, +}tacSINK_SCOPE_PARAM_INDEX; + +/* + * Types + */ + +typedef struct { + unsigned short rate; + unsigned short counter; + unsigned short inputNb; + unsigned int lost; + double rateParam; + char* dbPoint; + MSG_Q_ID msgq; + tacSHMSG shmMsg; +}tacSINK_SCOPE_LOCAL_PARAMETER; + +/* + * Function declaration + */ + +extern STATUS tacDpcPushRequest(tacVOIDFCTPTR pFunct, void* parameter); + +/* + * Local function declaration + */ + +/* + * Note: Routines called from within the algorithm must be declared with + * static __inline__ + */ + +STATUS tacSinkSendMonitorMessage(MSG_Q_ID * msgqvoid); +STATUS tacSinkSendMonitorStateMessage(MSG_Q_ID * msgqvoid); +STATUS tacSinkSendProbeMessage(MSG_Q_ID * msgq); +STATUS tacSinkDeleteMessageQueue(MSG_Q_ID * msgq); +STATUS tacSinkCommonBlockConstructor(tacSTDBLOCK* pSelf, tacERROR* error); + +/* + * Global variables + */ + +char logStr[tacSINK_DISPLAY_LOG_STRING_SIZE]; /* Logging string used for Display */ + + +/* + * Function definition + */ + +/* + * Constructor Hooks + */ + +STATUS tacSinkDisplayBlockConstructor (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = NULL; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = NULL; + + /* Check that the expected number of parameters has been received */ + if (parameter->number < tacSINK_ONE_EXPECTED_PARAM) + { + char errorParam[40]; + + sprintf(errorParam, "Expected %d, received %d", tacSINK_ONE_EXPECTED_PARAM, parameter->number); + tacRTC_ERR(tacERR_PARAM_NUMBER, errorParam); + return ERROR; + } + + /* Check that the parameters are valid */ + pRealParam = (double*) parameter->buffer; + + /* Passed parameter is the sampling period of the block */ + if (pRealParam[tacSINK_SAMPLING_PERIOD] < (*pSelf->shared).samplingPeriod) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = (*pSelf->shared).samplingPeriod; + } + + if (pRealParam[tacSINK_SAMPLING_PERIOD] < tacSINK_DISPLAY_MIN_SAMPLING_PERIOD) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = tacSINK_DISPLAY_MIN_SAMPLING_PERIOD; + } + + /* Call common constructor */ + if (tacSinkCommonBlockConstructor(pSelf, error) != OK) + { + return ERROR; + } + + /* Store parameters */ + pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; /* We will only store short integers */ + + /* + * Compute the rate at which data has to be processed - divide and take + * the integer part of the result + */ + + pSelfParam->rate = (unsigned short) (pRealParam[tacSINK_SAMPLING_PERIOD] / (*pSelf->shared).samplingPeriod); + pSelfParam->counter = 0; /* Decimation counter */ + + /* + * Perform other block initialization operations + */ + + return OK; +} + +STATUS tacSinkMonitorBlockConstructor (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = NULL; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = NULL; + unsigned short arrayIndex = 0; + + /* Check that the expected number of parameters has been received */ + if (parameter->number < tacSINK_DEFAULT_EXPECTED_PARAM) + { + char errorParam[40]; + + sprintf(errorParam, "Expected %d, received %d", tacSINK_DEFAULT_EXPECTED_PARAM, parameter->number); + tacRTC_ERR(tacERR_PARAM_NUMBER, errorParam); + return ERROR; + } + + /* Check that the parameters are valid */ + pRealParam = (double*) parameter->buffer; + + /* Passed parameter is the sampling period of the block */ + if (pRealParam[tacSINK_SAMPLING_PERIOD] < (*pSelf->shared).samplingPeriod) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = (*pSelf->shared).samplingPeriod; + } + + if (pRealParam[tacSINK_SAMPLING_PERIOD] < tacSINK_MONITOR_MIN_SAMPLING_PERIOD) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = tacSINK_MONITOR_MIN_SAMPLING_PERIOD; + } + + /* Number of inputs is minimum 1 up to tacMSG_MAX_DATA_NUMBER */ + if ((pRealParam[tacSINK_INPUT_NUMBER] < 1) || + (pRealParam[tacSINK_INPUT_NUMBER] > tacMAX_DATA_NUMBER)) + { + tacRTC_ERR(tacERR_PARAM_INVALID, ""); + return ERROR; + } + + /* Call common constructor */ + if (tacSinkCommonBlockConstructor(pSelf, error) != OK) + { + return ERROR; + } + + /* Store parameters */ + pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* + * Compute the rate at which data has to be processed - divide and take + * the integer part of the result + */ + + pSelfParam->rate = (unsigned short) (pRealParam[tacSINK_SAMPLING_PERIOD] / (*pSelf->shared).samplingPeriod); + pSelfParam->counter = 0; /* Decimation counter */ + pSelfParam->inputNb = (unsigned short) pRealParam[tacSINK_INPUT_NUMBER]; + + /* Optional parameter is an application-specific DB point */ + if (parameter->number == tacSINK_DEFAULT_EXPECTED_PARAM + 1) + { + printf("tacSinkMonitorBlockConstructor - DB point %s\n",(char*) &(pRealParam[tacSINK_MONITOR_DB_POINT])); + pSelfParam->dbPoint = (char*) malloc(tacSINK_MONITOR_MAX_DB_ADDR_SIZE); + strcpy(pSelfParam->dbPoint, (char*) &(pRealParam[tacSINK_MONITOR_DB_POINT])); + } + else + { + printf("tacSinkMonitorBlockConstructor - Default DB point\n"); + pSelfParam->dbPoint = NULL; + } + + /* Specify the number of input signals to attach to become resolved */ + tacStdBlockSetInputNumber(pSelf, pSelfParam->inputNb); + + /* + * Perform other block initialization operations + */ + + /* Create the block internal message queue which tosses the messages out of the + * interrupt context. They are buffered in the queue until the DPC tasks + * picks them up and sends them over the shared memory message queue. + * Sorry for that double-queuing, that's because of the M-S architecture */ + + pSelfParam->msgq = msgQCreate(tacSINK_MONITOR_QUEUE_SIZE, sizeof(tacSHMSG), 0); + if ( pSelfParam->msgq == NULL ) + { + char errorParam[40]; + + sprintf(errorParam, "Could not create probe block message queue"); + tacRTC_ERR(tacERR_MALLOC, errorParam); + return ERROR; + } + + /* will count if a message can't be pushed in the queue */ + pSelfParam->lost = 0; + + /* Warn the background task that a new probe block has been created */ + pSelfParam->shmMsg.type = tacSHMSG_ADD_MONITOR; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + + if (pSelfParam->dbPoint == NULL) + { + strcpy((char*) &(pSelfParam->shmMsg.msgBody.monitor.data), tacSINK_MONITOR_DEFAULT_DB_POINT); + } + else + { + strcpy((char*) &(pSelfParam->shmMsg.msgBody.monitor.data), *((char**) &(pSelfParam->dbPoint))); + } + + printf("tacSinkMonitorBlockConstructor - Attach to %s\n",(char*) &(pSelfParam->shmMsg.msgBody.monitor.data)); + + /* Send message */ + tacShMsgQSendBgInfo(&(pSelfParam->shmMsg)); + + /* Initialize the message parameters */ + pSelfParam->shmMsg.type = tacSHMSG_MONITOR_DATA; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + pSelfParam->shmMsg.msgBody.monitor.data.number = pSelfParam->inputNb; + + /* The output port is used to average the inputs over the reporting period */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pSelf->output[arrayIndex] = 0.0; + } + + return OK; +} + +STATUS tacSinkMonitorStateBlockConstructor (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = NULL; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = NULL; + unsigned short arrayIndex = 0; + + /* Check that the expected number of parameters has been received */ + if (parameter->number < tacSINK_DEFAULT_EXPECTED_PARAM) + { + char errorParam[40]; + + sprintf(errorParam, "Expected %d, received %d", tacSINK_DEFAULT_EXPECTED_PARAM, parameter->number); + tacRTC_ERR(tacERR_PARAM_NUMBER, errorParam); + return ERROR; + } + + /* Check that the parameters are valid */ + pRealParam = (double*) parameter->buffer; + + /* Passed parameter is the sampling period of the block */ + if (pRealParam[tacSINK_SAMPLING_PERIOD] < (*pSelf->shared).samplingPeriod) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = (*pSelf->shared).samplingPeriod; + } + + if (pRealParam[tacSINK_SAMPLING_PERIOD] < tacSINK_MONITOR_MIN_SAMPLING_PERIOD) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = tacSINK_MONITOR_MIN_SAMPLING_PERIOD; + } + + /* Number of inputs is minimum 1 up to tacMSG_MAX_DATA_NUMBER */ + if ((pRealParam[tacSINK_INPUT_NUMBER] < 1) || + (pRealParam[tacSINK_INPUT_NUMBER] > tacMAX_DATA_NUMBER)) + { + tacRTC_ERR(tacERR_PARAM_INVALID, ""); + return ERROR; + } + + /* Call common constructor */ + if (tacSinkCommonBlockConstructor(pSelf, error) != OK) + { + return ERROR; + } + + /* Store parameters */ + pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* + * Compute the rate at which data has to be processed - divide and take + * the integer part of the result + */ + + pSelfParam->rate = (unsigned short) (pRealParam[tacSINK_SAMPLING_PERIOD] / (*pSelf->shared).samplingPeriod); + pSelfParam->counter = 0; /* Decimation counter */ + pSelfParam->inputNb = (unsigned short) pRealParam[tacSINK_INPUT_NUMBER]; + + /* Optional parameter is an application-specific DB point */ + if (parameter->number == tacSINK_DEFAULT_EXPECTED_PARAM + 1) + { + printf("tacSinkMonitorStateBlockConstructor - DB point %s\n",(char*) &(pRealParam[tacSINK_MONITOR_DB_POINT])); + pSelfParam->dbPoint = (char*) malloc(tacSINK_MONITOR_MAX_DB_ADDR_SIZE); + strcpy(pSelfParam->dbPoint, (char*) &(pRealParam[tacSINK_MONITOR_DB_POINT])); + } + else + { + printf("tacSinkMonitorStateBlockConstructor - Default DB point\n"); + pSelfParam->dbPoint = NULL; + } + + /* Specify the number of input signals to attach to become resolved */ + tacStdBlockSetInputNumber(pSelf, pSelfParam->inputNb); + + /* + * Perform other block initialization operations + */ + + /* Create the block internal message queue which tosses the messages out of the + * interrupt context. They are buffered in the queue until the DPC tasks + * picks them up and sends them over the shared memory message queue. + * Sorry for that double-queuing, that's because of the M-S architecture */ + + pSelfParam->msgq = msgQCreate(tacSINK_MONITOR_QUEUE_SIZE, sizeof(tacSHMSG), 0); + if ( pSelfParam->msgq == NULL ) + { + char errorParam[40]; + + sprintf(errorParam, "Could not create probe block message queue"); + tacRTC_ERR(tacERR_MALLOC, errorParam); + return ERROR; + } + + /* will count if a message can't be pushed in the queue */ + pSelfParam->lost = 0; + + /* Warn the background task that a new probe block has been created */ + pSelfParam->shmMsg.type = tacSHMSG_ADD_MONITOR; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + + if (pSelfParam->dbPoint == NULL) + { + strcpy((char*) &(pSelfParam->shmMsg.msgBody.monitor.data), tacSINK_MONITOR_DEFAULT_DB_POINT); + } + else + { + strcpy((char*) &(pSelfParam->shmMsg.msgBody.monitor.data), *((char**) &(pSelfParam->dbPoint))); + } + + printf("tacSinkMonitorStateBlockConstructor - Attach to %s\n",(char*) &(pSelfParam->shmMsg.msgBody.monitor.data)); + + /* Send message */ + tacShMsgQSendBgInfo(&(pSelfParam->shmMsg)); + + /* Initialize the message parameters */ + pSelfParam->shmMsg.type = tacSHMSG_MONITOR_DATA; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + pSelfParam->shmMsg.msgBody.monitor.data.number = pSelfParam->inputNb; + + /* Init output port which won't be used to average the inputs over the reporting period */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pSelf->output[arrayIndex] = 0.0; + } + + return OK; +} + +STATUS tacSinkProbeBlockCommonConstructor (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + double minPeriod, + tacERROR* error) +{ + double* pRealParam = NULL; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = NULL; + + /* Check that the expected number of parameters has been received */ + if (parameter->number < tacSINK_DEFAULT_EXPECTED_PARAM) + { + char errorParam[40]; + + sprintf(errorParam, "Expected %d, received %d", tacSINK_DEFAULT_EXPECTED_PARAM, parameter->number); + tacRTC_ERR(tacERR_PARAM_NUMBER, errorParam); + return ERROR; + } + + /* Check that the parameters are valid */ + pRealParam = (double*) parameter->buffer; + + /* Passed parameter is the sampling period of the block */ + if (pRealParam[tacSINK_SAMPLING_PERIOD] < (*pSelf->shared).samplingPeriod) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = (*pSelf->shared).samplingPeriod; + } + + if (pRealParam[tacSINK_SAMPLING_PERIOD] < minPeriod) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = minPeriod; + } + + /* Number of inputs is minimum 1 up to tacMSG_MAX_DATA_NUMBER */ + if ((pRealParam[tacSINK_INPUT_NUMBER] < 1) || + (pRealParam[tacSINK_INPUT_NUMBER] > tacMAX_DATA_NUMBER)) + { + tacRTC_ERR(tacERR_PARAM_INVALID, ""); + return ERROR; + } + + /* Call common constructor */ + if (tacSinkCommonBlockConstructor(pSelf, error) != OK) + { + return ERROR; + } + + /* Store parameters */ + pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* + * Compute the rate at which data has to be processed - divide and take + * the integer part of the result + */ + + pSelfParam->rateParam = pRealParam[tacSINK_SAMPLING_PERIOD]; + pSelfParam->rate = (unsigned short) (pRealParam[tacSINK_SAMPLING_PERIOD] / (*pSelf->shared).samplingPeriod); + pSelfParam->counter = 0; /* Decimation counter */ + pSelfParam->inputNb = (unsigned short) pRealParam[tacSINK_INPUT_NUMBER]; + + /* Specify the number of input signals to attach to become resolved */ + tacStdBlockSetInputNumber(pSelf, pSelfParam->inputNb); + + /* + * Perform other block initialization operations + */ + + /* Create the block internal message queue which gets the messages out of the + * interrupt context. They are buffered in the queue until the DPC tasks + * picks them up and sends them over the shared memory message queue. + * Sorry for that double-queuing, that's because of the M-S architecture */ + + /* There is only one message queue for all probe blocks! */ + pSelfParam->msgq = msgQCreate(tacSINK_PROBE_QUEUE_SIZE, sizeof(tacSHMSG), 0); + if ( pSelfParam->msgq == NULL ) + { + char errorParam[40]; + + sprintf(errorParam, "Could not create probe block message queue"); + tacRTC_ERR(tacERR_MALLOC, errorParam); + return ERROR; + } + + /* will count if a message can't be pushed in the queue */ + pSelfParam->lost = 0; + + /* Warn the background task that a new probe block has been created */ + pSelfParam->shmMsg.type = tacSHMSG_ADD_PROBE; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + + /* Send message */ + tacShMsgQSendDataSample(&pSelfParam->shmMsg); + + /* Initialize the message parameters */ + pSelfParam->shmMsg.type = tacSHMSG_TRANSFER_DATA; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + pSelfParam->shmMsg.msgBody.monitor.data.number = pSelfParam->inputNb; + + return OK; +} + +/* Probe block has a max. sampling frequency of 2kHz */ +STATUS tacSinkProbeBlockConstructor (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + return tacSinkProbeBlockCommonConstructor (pSelf, parameter, tacSINK_PROBE_MIN_SAMPLING_PERIOD, error); +} + +/* Fast probe is the same as probe but not does have the + * limitation on the max. recording frequency */ +STATUS tacSinkFastProbeBlockConstructor (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + return tacSinkProbeBlockCommonConstructor (pSelf, parameter, 0.0, error); +} + +void tacSinkProbeBlockReset (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = + (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* + * Re-Compute the rate at which data has to be processed + */ + if (pSelfParam->rateParam < (*pSelf->shared).samplingPeriod ) + { + pSelfParam->rate = 1; + } + else + { + pSelfParam->rate = (unsigned short) + (pSelfParam->rateParam / (*pSelf->shared).samplingPeriod); + } + + return; +} + +/* + * Report parameters Hooks + */ + +STATUS tacSinkDisplayBlockGetParameter (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = (double*) parameter->buffer; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Send back the expected number of parameters */ + parameter->number = tacSINK_ONE_EXPECTED_PARAM; + + /* Report current parameters */ + pRealParam[tacSINK_SAMPLING_PERIOD] = (double) (pSelfParam->rate * (*pSelf->shared).samplingPeriod); + + return OK; +} + +STATUS tacSinkMonitorBlockGetParameter (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = (double*) parameter->buffer; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Send back the expected number of parameters */ + parameter->number = tacSINK_DEFAULT_EXPECTED_PARAM; + + /* Report current parameters */ + pRealParam[tacSINK_SAMPLING_PERIOD] = (double) (pSelfParam->rate * (*pSelf->shared).samplingPeriod); + pRealParam[tacSINK_INPUT_NUMBER] = (double) pSelfParam->inputNb; + + if (*((char**) &(pSelfParam->dbPoint)) != NULL) + { + parameter->number += 1; + parameter->type[tacSINK_MONITOR_DB_POINT] = tacPARAM_STRING; + strcpy((char*) &(pRealParam[tacSINK_MONITOR_DB_POINT]), *((char**) &(pSelfParam->dbPoint))); + } + + return OK; +} + +STATUS tacSinkMonitorStateBlockGetParameter (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = (double*) parameter->buffer; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Send back the expected number of parameters */ + parameter->number = tacSINK_DEFAULT_EXPECTED_PARAM; + + /* Report current parameters */ + pRealParam[tacSINK_SAMPLING_PERIOD] = (double) (pSelfParam->rate * (*pSelf->shared).samplingPeriod); + pRealParam[tacSINK_INPUT_NUMBER] = (double) pSelfParam->inputNb; + + if (*((char**) &(pSelfParam->dbPoint)) != NULL) + { + parameter->number += 1; + parameter->type[tacSINK_MONITOR_DB_POINT] = tacPARAM_STRING; + strcpy((char*) &(pRealParam[tacSINK_MONITOR_DB_POINT]), *((char**) &(pSelfParam->dbPoint))); + } + + return OK; +} + +STATUS tacSinkProbeBlockGetParameter (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = (double*) parameter->buffer; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Send back the expected number of parameters */ + parameter->number = tacSINK_DEFAULT_EXPECTED_PARAM; + + /* Report current parameters */ + pRealParam[tacSINK_SAMPLING_PERIOD] = (double) (pSelfParam->rate * (*pSelf->shared).samplingPeriod); + pRealParam[tacSINK_INPUT_NUMBER] = (double) pSelfParam->inputNb; + + return OK; +} + +/* + * Change parameters Hooks + */ + +/* + * Algorithm Hooks + */ + +void tacSinkDisplayBlockAlgorithm (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + if ((pSelfParam->counter % pSelfParam->rate) == 0) /* It's time to process data */ + { + sprintf(logStr,"Name: %s Time: %ld.%6ld Value: %g\n", + pSelf->name, + (*pSelf->shared).currentTime.seconds, + (*pSelf->shared).currentTime.microsec, + tacStdBlockGetInput(pSelf,0)); + + tacDpcPushRequest((tacVOIDFCTPTR) &printf, logStr); + + pSelfParam->counter = 0; + } + + pSelfParam->counter++; +} + +void tacSinkMonitorBlockAlgorithm (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + unsigned short arrayIndex = 0; + + /* The output port is used to average the inputs over the reporting period */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pSelf->output[arrayIndex] += tacStdBlockGetInput(pSelf,arrayIndex); + } + + if ((pSelfParam->counter % pSelfParam->rate) == 0) /* It's time to process data */ + { + tacDATA* pData = &(pSelfParam->shmMsg.msgBody.monitor.data); /* We are only interested in message body */ + + /* pData->number = pSelfParam->inputNb; */ + pData->timeStamp = (*pSelf->shared).currentTime; + + /* pData points to the body of the Message */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pData->buffer[arrayIndex] = pSelf->output[arrayIndex] / pSelfParam->rate; + } + + /* Push message into probe block's message que to get the + * data out of the interrupt comtext. */ + if ( msgQSend (pSelfParam->msgq, (char*) &(pSelfParam->shmMsg), sizeof(tacSHMSG), NO_WAIT, 0) != OK ) + { + (pSelfParam->lost)++; + } + + /* Defer procedure call */ + tacDpcPushRequest((tacVOIDFCTPTR) &tacSinkSendMonitorMessage, &pSelfParam->msgq); + + pSelfParam->counter = 0; + + /* The output port is used to average the inputs over the reporting period */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pSelf->output[arrayIndex] = 0.0; + } + } + + pSelfParam->counter++; +} + +void tacSinkMonitorStateBlockAlgorithm (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + unsigned short arrayIndex = 0; + + if ((pSelfParam->counter % pSelfParam->rate) == 0) /* It's time to process data */ + { + tacDATA* pData = &(pSelfParam->shmMsg.msgBody.monitor.data); /* We are only interested in message body */ + + /* pData->number = pSelfParam->inputNb; */ + pData->timeStamp = (*pSelf->shared).currentTime; + + /* pData points to the body of the Message */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pData->buffer[arrayIndex] = tacStdBlockGetInput(pSelf,arrayIndex); + } + + /* Push message into probe block's message que to get the + * data out of the interrupt comtext. */ + if ( msgQSend (pSelfParam->msgq, (char*) &(pSelfParam->shmMsg), sizeof(tacSHMSG), NO_WAIT, 0) != OK ) + { + (pSelfParam->lost)++; + } + + /* Defer procedure call */ + tacDpcPushRequest((tacVOIDFCTPTR) &tacSinkSendMonitorMessage, &pSelfParam->msgq); + + pSelfParam->counter = 0; + } + + pSelfParam->counter++; +} + +void tacSinkProbeBlockAlgorithm (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + unsigned short arrayIndex = 0; + + if ((pSelfParam->counter % pSelfParam->rate) == 0) /* It's time to process data */ + { + tacDATA* pData = &(pSelfParam->shmMsg.msgBody.monitor.data); /* We are only interested in message body */ + + pData->timeStamp = (*pSelf->shared).currentTime; + + /* pData points to the body of the Message */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pData->buffer[arrayIndex] = tacStdBlockGetInput(pSelf,arrayIndex); + } + + /* Push message into probe block's message que to get the + * data out of the interrupt comtext. */ + if ( msgQSend (pSelfParam->msgq, (char*) &(pSelfParam->shmMsg), sizeof(tacSHMSG), NO_WAIT, 0) != OK ) + { + (pSelfParam->lost)++; + } + + /* Defer procedure call: + * tacSinkSendProbeMessage is called outside the interrupt routine + * and will take care to pick up the message from the probe block's + * message queue and send it over the shared memory message queue */ + tacDpcPushRequest((tacVOIDFCTPTR) &tacSinkSendProbeMessage, &pSelfParam->msgq); + + pSelfParam->counter = 0; + } + + pSelfParam->counter++; +} + +/* + * Reset Hooks + */ + +/* + * Stop Hooks + */ + +/* + * Destructor Hooks + */ + +/* + * Note: This destructor is used mainly to send a MONITOR message containing + * 0.0 in order to reset the database array (otherwise going from an + * algorithm with 4 monitored data to one with 3 monitored data leaves + * the 4th value equal to the last ...) + */ + +void tacSinkMonitorBlockDestructor (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + tacDATA* pData = &(pSelfParam->shmMsg.msgBody.monitor.data); + unsigned short arrayIndex = 0; + + /* Reset DB values */ + pSelfParam->shmMsg.type = tacSHMSG_MONITOR_DATA; + pData = &(pSelfParam->shmMsg.msgBody.monitor.data); + + pData->number = pSelfParam->inputNb; + + /* pData points to the body of the Message */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pData->buffer[arrayIndex] = 0.0; + } + + /* Send message */ + tacShMsgQSendBgInfo(&pSelfParam->shmMsg); + + pSelfParam->shmMsg.type = tacSHMSG_REMOVE_MONITOR; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + + /* Send message */ + tacShMsgQSendBgInfo(&pSelfParam->shmMsg); + + free(pSelfParam->dbPoint); + + /* delete internal message queue. Do this as deferred procedure call + * to make sure it is only called when all messages have been send + * (through the same deferred call mechanism) */ + tacDpcPushRequest((tacVOIDFCTPTR) tacSinkDeleteMessageQueue, &(pSelfParam->msgq)); + + return; +} + +void tacSinkMonitorStateBlockDestructor (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + tacDATA* pData = &(pSelfParam->shmMsg.msgBody.monitor.data); + unsigned short arrayIndex = 0; + + /* Reset DB values */ + pSelfParam->shmMsg.type = tacSHMSG_MONITOR_DATA; + pData = &(pSelfParam->shmMsg.msgBody.monitor.data); + + pData->number = pSelfParam->inputNb; + + /* pData points to the body of the Message */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pData->buffer[arrayIndex] = 0.0; + } + + /* Send message */ + tacShMsgQSendBgInfo(&pSelfParam->shmMsg); + + pSelfParam->shmMsg.type = tacSHMSG_REMOVE_MONITOR; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + + /* Send message */ + tacShMsgQSendBgInfo(&pSelfParam->shmMsg); + + free(pSelfParam->dbPoint); + + /* delete internal message queue. Do this as deferred procedure call + * to make sure it is only called when all messages have been send + * (through the same deferred call mechanism) */ + tacDpcPushRequest((tacVOIDFCTPTR) tacSinkDeleteMessageQueue, &(pSelfParam->msgq)); + + return; +} + +void tacSinkProbeBlockDestructor (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + pSelfParam->shmMsg.type = tacSHMSG_REMOVE_PROBE; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + + /* Send message */ + tacShMsgQSendDataSample(&pSelfParam->shmMsg); + + /* delete internal message queue. Do this as deferred procedure call + * to make sure it is only called when all messages have been send + * (through the same deferred call mechanism) */ + tacDpcPushRequest((tacVOIDFCTPTR) tacSinkDeleteMessageQueue, &(pSelfParam->msgq)); + + return; +} + +/* + * Show Hooks + */ + +void tacSinkDisplayBlockShow (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Print parameter values */ + printf(" Update rate: %d\n",pSelfParam->rate); + + return; +} + +void tacSinkMonitorBlockShow (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Print parameter values */ + printf(" Update rate: %d\n",pSelfParam->rate); + printf(" Number of input signals: %d\n",pSelfParam->inputNb); + printf(" Queued samples: %d\n", msgQNumMsgs(pSelfParam->msgq)); + printf(" Lost samples: %d\n",pSelfParam->lost); + + if (pSelfParam->dbPoint != NULL) + { + printf(" DB Point: %s\n", pSelfParam->dbPoint); + } + + return; +} + +void tacSinkMonitorStateBlockShow (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Print parameter values */ + printf(" Using MonitorState block, not averaging received data\n"); + printf(" Update rate: %d\n",pSelfParam->rate); + printf(" Number of input signals: %d\n",pSelfParam->inputNb); + printf(" Queued samples: %d\n", msgQNumMsgs(pSelfParam->msgq)); + printf(" Lost samples: %d\n",pSelfParam->lost); + + if (pSelfParam->dbPoint != NULL) + { + printf(" DB Point: %s\n", pSelfParam->dbPoint); + } + + return; +} + +void tacSinkProbeBlockShow (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Print parameter values */ + printf(" Update rate: %d\n",pSelfParam->rate); + printf(" Update rate param (sec): %f\n",pSelfParam->rateParam); + printf(" Number of input signals: %d\n",pSelfParam->inputNb); + printf(" Queued samples: %d\n", msgQNumMsgs(pSelfParam->msgq)); + printf(" Lost samples: %d\n",pSelfParam->lost); + + return; +} + +/* + * Installation function + */ + +tacSTDBLOCK_TYPE tacSinkDisplayTypeInfo = { + "Display", + &tacSinkDisplayBlockConstructor, + &tacSinkDisplayBlockGetParameter, + &tacSinkDisplayBlockAlgorithm, + NULL, + NULL, + NULL, + NULL, + &tacSinkDisplayBlockShow, +}; + +tacSTDBLOCK_TYPE tacSinkMonitorTypeInfo = { + "Monitor", + &tacSinkMonitorBlockConstructor, + &tacSinkMonitorBlockGetParameter, + &tacSinkMonitorBlockAlgorithm, + NULL, + NULL, + NULL, + &tacSinkMonitorBlockDestructor, + &tacSinkMonitorBlockShow, +}; + +tacSTDBLOCK_TYPE tacSinkMonitorStateTypeInfo = { + "MonitorState", + &tacSinkMonitorStateBlockConstructor, + &tacSinkMonitorStateBlockGetParameter, + &tacSinkMonitorStateBlockAlgorithm, + NULL, + NULL, + NULL, + &tacSinkMonitorStateBlockDestructor, + &tacSinkMonitorStateBlockShow, +}; + +/* Probe with a maximal sampling rate of 2kHz */ +tacSTDBLOCK_TYPE tacSinkProbeTypeInfo = { + "Probe", + &tacSinkProbeBlockConstructor, + &tacSinkProbeBlockGetParameter, + &tacSinkProbeBlockAlgorithm, + NULL, + &tacSinkProbeBlockReset, + NULL, + &tacSinkProbeBlockDestructor, + &tacSinkProbeBlockShow, +}; + +/* Fast probe is the same as probe but not does have the + * limitation on the max. recording frequency */ +tacSTDBLOCK_TYPE tacSinkFastProbeTypeInfo = { + "FastProbe", + &tacSinkFastProbeBlockConstructor, + &tacSinkProbeBlockGetParameter, + &tacSinkProbeBlockAlgorithm, + NULL, + &tacSinkProbeBlockReset, + NULL, + &tacSinkProbeBlockDestructor, + &tacSinkProbeBlockShow, +}; + +STATUS tacSinkBlockInitAll (void) +{ + /* Install Sink Block Hooks */ + tacStdBlockInstallNewType(&tacSinkDisplayTypeInfo); + tacStdBlockInstallNewType(&tacSinkMonitorTypeInfo); + tacStdBlockInstallNewType(&tacSinkMonitorStateTypeInfo); + tacStdBlockInstallNewType(&tacSinkProbeTypeInfo); + tacStdBlockInstallNewType(&tacSinkFastProbeTypeInfo); + + /* + * Perform other library initialization operations + */ + + return OK; +} + +/* + * Local functions + */ + +/* + * Note: Routines called from within the algorithm must be declared with + * static __inline__ + */ + +STATUS tacSinkCommonBlockConstructor (tacSTDBLOCK* pSelf, + tacERROR* error) +{ + /* Allocate specific arrays (pointers are initialized to NULL by StdBlock) */ + if (tacStdBlockAllocateArrays(pSelf, 0, tacSINK_DEFAULT_INPUT_NUMBER, + tacSINK_DEFAULT_OUTPUT_NUMBER, error) == ERROR) + { + return ERROR; + } + + if (tacStdBlockAllocateArrayBySize(pSelf, tacSTDBLOCK_PARAM_ARRAY, + sizeof(tacSINK_SCOPE_LOCAL_PARAMETER), error) == ERROR) + { + tacStdBlockReleaseArray(pSelf, tacSTDBLOCK_INPUT_ARRAY, error); + tacStdBlockReleaseArray(pSelf, tacSTDBLOCK_OUTPUT_ARRAY, error); + return ERROR; + } + + /* Specify the number of input signals to attach to become resolved */ + tacStdBlockSetInputNumber(pSelf, tacSINK_ONE_INPUT_NUMBER); /* Required */ + + return OK; +} + +STATUS tacSinkSendMonitorMessage(MSG_Q_ID * msgq) +{ + /* Send message using provided function (different for Monitor and Probe blocks) */ + /* Send message using provided function (different for Monitor and Probe blocks) */ + tacSHMSG msg; + + if ( msgQReceive(*msgq, (char*) &msg, sizeof(tacSHMSG), NO_WAIT) == sizeof(tacSHMSG) ) + { + tacShMsgQSendBgInfo (&msg); + } + + return OK; +} + +STATUS tacSinkSendProbeMessage(MSG_Q_ID * msgq) +{ + /* Send message using provided function (different for Monitor and Probe blocks) */ + tacSHMSG msg; + + if ( msgq == NULL ) + { + return ERROR; + } + + if ( msgQReceive(*msgq, (char*) &msg, sizeof(tacSHMSG), NO_WAIT) == sizeof(tacSHMSG) ) + { + tacShMsgQSendDataSample (&msg); + } + return OK; +} + +STATUS tacSinkDeleteMessageQueue (MSG_Q_ID * msgq) +{ + /* Is called when block is destroyed and removes the internal message queue */ + STATUS status; + + status = msgQDelete (*msgq); + *msgq = NULL; + return status; +} + + +/*___oOo___*/ + + + + + + diff --git a/src/arguments.py b/src/arguments.py new file mode 100644 index 0000000..94e4cea --- /dev/null +++ b/src/arguments.py @@ -0,0 +1,26 @@ +import getopt + +def exitUsage(): + print("usage: %s <.tasrc file> -i -o " % sys.argv[0]) + sys.exit(1) + +def readArguments(args): + sourceDirectories = [] + outputFile = "" + try: + options, _ = getopt.getopt(args, "hi:o:") + except getopt.GetoptError: + exitUsage() + for option, arg in options: + if option == "-h": + exitUsage() + elif option == "-o": + outputFile = arg + elif option == "-i": + sourceDirectories.append(arg) + if outputFile == "": + exitUsage() + if len(sourceDirectories) == 0: + print("WARNING: no source directories specified!") + return outputFile, sourceDirectories + diff --git a/src/converter.py b/src/converter.py new file mode 100755 index 0000000..3e44058 --- /dev/null +++ b/src/converter.py @@ -0,0 +1,18 @@ +#!/usr/bin/python3 + +import sys + +import arguments +from tacsrc.tac import readTAC +import grc +import portNaming + +if __name__ == "__main__": + if len(sys.argv) == 1: + params.exitUsage() + inputFile = sys.argv[1] + outputFile, sourceDirectories = arguments.readArguments(sys.argv[2:]) + blocks, connections, blockTypes = readTAC(inputFile) + portNaming.resolvePortNames(blockTypes, sourceDirectories) + grc.write(outputFile, blocks, connections) + diff --git a/src/defaultBlockTypes.py b/src/defaultBlockTypes.py new file mode 100644 index 0000000..a7c7a7a --- /dev/null +++ b/src/defaultBlockTypes.py @@ -0,0 +1,74 @@ +from tacsrc.blockType import BlockType + +class VariablePorts: + def __init__(self, ioDescriptionName, sizeFunction): + self.ioDescriptionName = ioDescriptionName + self.sizeFunction = sizeFunction + + def mapName(self, position, name, index): + return + + def getRealPort(self, originalPort): + return 0 + + def ensureLength(self, length): + return + + def getIODescription(self, block): + return "\\\\n0:%s[%s]" % (self.ioDescriptionName, self.sizeFunction(block)) + + def getRealCount(self): + return 1 + +def inParameters(block): + return block.parameters[1] + +def parameterSize(block): + return len(block.parameters) + +monitor = BlockType("Monitor") +monitor.inputs = VariablePorts("input", inParameters) + +monitorState = BlockType("MonitorState") +monitorState.inputs = VariablePorts("input", inParameters) + +probe = BlockType("Probe") +probe.inputs = VariablePorts("input", inParameters) + +readRfm = BlockType("ReadRfm") +readRfm.outputs = VariablePorts("output", parameterSize) + +rms = BlockType("RMS") +rms.inputs.mapName(0, "input", 0) +rms.outputs.mapName(0, "output", 0) + +constant = BlockType("Constant") +constant.outputs.mapName(0, "CONST", 0) + +manual = BlockType("ManualSwitch") +manual.inputs.mapName(0, "input", 0) +manual.outputs.mapName(0, "output", 0) + +noise = BlockType("NormalNoise") +noise.outputs.mapName(0, "output", 0) + +writeRMNNoTim = BlockType("WriteRmNoTim") +writeRMNNoTim.inputs = VariablePorts("input", parameterSize) + +defaultBlockTypes = { + "Monitor": monitor, + "MonitorState": monitorState, + "Probe": probe, + "ReadRfm": readRfm, + "TIM": BlockType("TIM"), + "WAIT_RFM_INTERRUPT": BlockType("WAIT_RFM_INTERRUPT"), + "RMS": rms, + "Constant": constant, + "ManualSwitch": manual, + "NormalNoise": noise, + "WriteRmNoTim": writeRMNNoTim +} + +def addDefaultBlockTypes(blockTypes): + for key in defaultBlockTypes: + blockTypes[key] = defaultBlockTypes[key] diff --git a/src/grc.py b/src/grc.py new file mode 100644 index 0000000..ed02659 --- /dev/null +++ b/src/grc.py @@ -0,0 +1,94 @@ +GRC_TEMPLATE = ''' +options: + parameters: + title: 'TASRC to GRC converter output' + states: + coordinate: [-100, -100] + +blocks: +%s + +connections: +%s + +metadata: + file_format: 1 +''' + +BLOCK_TEMPLATE = ''' +- name: %s + id: epy_block + parameters: + _source_code: "from gnuradio import gr\\nimport numpy as np\\nclass BLOCK(gr.sync_block):\\n def __init__(self):\\n gr.sync_block.__init__(self,name='%s:%s%s',in_sig=%s,out_sig=%s)\\n def work(self, input_items, output_items):\\n return len(output_items[0])" + states: + coordinate: [%s, %s] +''' + +LINK_TEMPLATE = "- [%s, '%s', %s, '%s']\n" + +def getLongestDependencyRow(blocks, blockDependencies): + currentMax = 0 + for block in blocks: + current = getLongestDependencyRow(blockDependencies[block], blockDependencies) + 1 + if current > currentMax: + currentMax = current + return currentMax + +def getPosition(block, blockDependencies, reverseBlockDependencies, depths): + position = getLongestDependencyRow(blockDependencies[block], blockDependencies) + depths += [0] * (position+1 - len(depths)) + y = depths[position] + depths[position] += 50 # base offset + depths[position] += max( + (3+block.blockType.inputs.getRealCount()+block.blockType.outputs.getRealCount()) * 15, + max(block.blockType.inputs.getRealCount(), block.blockType.outputs.getRealCount()) * 30) + return position * 300, y + +def getBlockDependencies(blocks, links): + blockDependencies = {} + for block in blocks: + blockDependencies[block] = [] + for link in links: + if link.toBlock == block: + blockDependencies[block].append(link.fromBlock) + reverseBlockDependencies = {} + for block in blockDependencies: + for dependency in blockDependencies[block]: + if not dependency in reverseBlockDependencies: + reverseBlockDependencies[dependency] = [] + reverseBlockDependencies[dependency].append(block) + return blockDependencies, reverseBlockDependencies + +def getBlocksContent(blocks, links): + blockDependencies, reverseBlockDependencies = getBlockDependencies(blocks, links) + depths = [] + blocksContent = "" + for block in blocks: + description = block.blockType.getIODescription(block) + inputs = "[%s]" % ", ".join(["np.int8"] * block.blockType.inputs.getRealCount()) + outputs = "[%s]" % ", ".join(["np.int8"] * block.blockType.outputs.getRealCount()) + position = getPosition(block, blockDependencies, reverseBlockDependencies, depths) + blocksContent += BLOCK_TEMPLATE % ( + block.name, + block.name, + block.blockType.name, + description, + inputs, + outputs, + position[0], + position[1]) + return blocksContent + +def getLinksContent(links): + linksContent = "" + for link in links: + fromPort = link.fromBlock.blockType.outputs.getRealPort(link.fromPort) + toPort = link.toBlock.blockType.inputs.getRealPort(link.toPort) + linksContent += LINK_TEMPLATE % (link.fromBlock.name, fromPort, link.toBlock.name, toPort) + return linksContent + +def write(filename, blocks, links): + with open(filename, "w+") as file: + print("writing to file %s" % filename) + file.truncate(0) + file.write(GRC_TEMPLATE % (getBlocksContent(blocks, links), getLinksContent(links))) diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3624768 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +__pycache__ +out +tacapp.tar.gz +Sources +tacapp +worryingFiles +cc.tar.gz diff --git a/errors.json b/errors.json new file mode 100644 index 0000000..5ec898a --- /dev/null +++ b/errors.json @@ -0,0 +1,4 @@ +{ + "missing_blocks": [], + "multiple_definitions": [] +} \ No newline at end of file diff --git a/hardcodedFiles/tacReadRmnBlock.c b/hardcodedFiles/tacReadRmnBlock.c new file mode 100644 index 0000000..8acbcfa --- /dev/null +++ b/hardcodedFiles/tacReadRmnBlock.c @@ -0,0 +1,568 @@ +/******************************************************************************* +* E.S.O. - VLT project +* +* "@(#) $Id: tacReadRmnBlock.c 305476 2018-01-19 08:56:18Z rfrahm $" +* +* who when what +* ------- -------- ---------------------------------------------- +* gzins 2010-07-27 ported to VLTSW2010 and VxWorks 6.4 +* swehner 2008-10-10 creation +*/ + +/************************************************************************ +* NAME +* tacReadRmnBlock - Implemements the standard functions for the +* tacReadRmn block and tacReadRfm block. +* tacReadRmnBlock - Reads from 1rst generation reflective memory network +* tacReadRfmBlock - Reads from 2nd generation reflective memory network + +* Parameters: +* field - token names for the RMN fields to read (up to 10) +* Inputs: 0 +* Outputs: 1 +* output - 1..10 depending on number of field parameters +* +* +* +* FILES +* +* ENVIRONMENT +* TAC +* +* RETURN VALUES +* +* CAUTIONS +* +* EXAMPLES +* TAC.BLOCK9.TYPE ReadRmn +* TAC.BLOCK9.NAME ReadRmn +* +* SEE ALSO +* +* BUGS +* +*------------------------------------------------------------------------ +*/ + +#define _POSIX_SOURCE 1 +#include "vltPort.h" + +ATTRIBUTE_UNUSED static const char *rcsId="@(#) $Id: tacReadRmnBlock.c 305476 2018-01-19 08:56:18Z rfrahm $"; + +/* + * System Headers + */ + +#include /* taskSpawn, taskDelay, ... */ +#include /* printf ... */ +#include /* malloc ... */ +#include /* malloc ... */ +#include +#include + +/* + * Local Headers + */ + +#include "tacStdBlock.h" +#include "tacRmnBlock.h" +#include "rmassPublic.h" +#include "rmassPrivate.h" + +/* + * Compilation directives + */ + +/* + * Constants + */ + +#define tacREAD_RMN_EXPECTED_PARAM 1 +#define tacREAD_RMN_DEFAULT_INPUT_NUMBER 0 +#define tacREAD_RMN_DEFAULT_OUTPUT_NUMBER tacMAX_DATA_NUMBER + +#define tacREAD_RMN_FIELD_STRING_LEN 256 +#define tacSTRLEN sizeof(double) + +/* + * Types + */ + +/* + * Local function declaration + */ + +/* + * Global variables + */ + +/* + * Function definition + */ + + +STATUS tacReadRmnBlockCheckParameter (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the ADDBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = NULL; + + pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + /* field string is built from block params */ + if ( tacRmnBlockCheckParameter ( pSelf, parameter, 0, error) != OK ) + { + return ERROR; + } + + /* useful information on the screen */ + printf ("ReadRmn %s: [%s]\n", pSelf->name, pSelfParam->fieldString); + + return OK; +} + +STATUS tacReadRfmBlockCheckParameter (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the ADDBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = NULL; + + pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + /* field string is built from block params */ + if ( tacRmnBlockCheckParameter ( pSelf, parameter, 0, error) != OK ) + { + return ERROR; + } + + /* useful information on the screen */ + printf ("ReadRfm %s: [%s]\n", pSelf->name, pSelfParam->fieldString); + + return OK; +} + +/* + * Constructor Hooks - Called when a block of this type is instanciated (CONFIG or ADDBLCK commands) + */ + +STATUS tacReadRmBlockConstructor (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the ADDBLCK command */ + vltLOGICAL isRmn, + tacERROR* error) /* Error structure - not a stack */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = NULL; + + /* Check that the expected number of parameters has been received */ + if (parameter->number < tacREAD_RMN_EXPECTED_PARAM) + { + char errorParam[40]; + + sprintf(errorParam, "Expected at least %d, received %d", tacREAD_RMN_EXPECTED_PARAM, parameter->number); + tacRTC_ERR(tacERR_PARAM_NUMBER, errorParam); + return ERROR; + } + + /* Allocate and initialize block-specific arrays */ + if (tacStdBlockAllocateArrays(pSelf, 0, tacREAD_RMN_DEFAULT_INPUT_NUMBER, tacREAD_RMN_DEFAULT_OUTPUT_NUMBER, error) == ERROR) + { + return ERROR; + } + + if (tacStdBlockAllocateArrayBySize(pSelf, tacSTDBLOCK_PARAM_ARRAY, sizeof(tacRMN_LOCAL_PARAMETER), error) == ERROR) + { + tacStdBlockReleaseArray(pSelf, tacSTDBLOCK_INPUT_ARRAY, error); + tacStdBlockReleaseArray(pSelf, tacSTDBLOCK_OUTPUT_ARRAY, error); + return ERROR; + } + + if ( isRmn ) + { + if ( tacReadRmnBlockCheckParameter (pSelf, parameter, error) == ERROR) + { + return ERROR; + } + } + else + { + if ( tacReadRfmBlockCheckParameter (pSelf, parameter, error) == ERROR) + { + return ERROR; + } + } + + pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + pSelfParam->handleValid = rmassACCESS_BLOCKED; + + /* Attach to RMN */ + if ( rmassReadAttach (&pSelfParam->handle, + pSelfParam->fieldString, + &pSelfParam->val[0], + &pSelfParam->val[1], + &pSelfParam->val[2], + &pSelfParam->val[3], + &pSelfParam->val[4], + &pSelfParam->val[5], + &pSelfParam->val[6], + &pSelfParam->val[7], + &pSelfParam->val[8], + &pSelfParam->val[9]) != SUCCESS ) + { + char errorParam[40]; + + sprintf(errorParam, "Attach to RMN failed."); + tacRTC_ERR(tacERR_INTERNAL, errorParam); + return ERROR; + } + + pSelfParam->handleValid = rmassACCESS_FREE; + + return OK; +} + +STATUS tacReadRmnBlockConstructor (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the ADDBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + if ( tacReadRmBlockConstructor (pSelf, parameter, ccsTRUE, error ) == ERROR ) + { + return ERROR; + } + return OK; +} + +STATUS tacReadRfmBlockConstructor (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the ADDBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + if ( tacReadRmBlockConstructor (pSelf, parameter, ccsFALSE, error ) == ERROR ) + { + return ERROR; + } + return OK; +} + + + +/* + * Destructor Hooks - Called when the block is removed from the algorithm (DELBLCK or new CONFIG commands) + */ + +void tacReadRmnBlockDestructor (tacSTDBLOCK* pSelf) /* Reference to the block instance */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = NULL; + pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + pSelfParam->handleValid = rmassACCESS_BLOCKED; + /* wait until semaphore is acknowledged by realtime algo + * or just procede if realtime is not active */ + while ((*pSelf->shared).active && pSelfParam->handleValid != rmassACCESS_BLOCK_ACKN) + { + taskDelay(1); + } + + rmassDetach (&pSelfParam->handle); + + return; +} + +/* + * Change parameters Hooks - Called when modifying the block parameters (MODBLCK command) + */ + +STATUS tacReadRmnBlockSetParameter (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the MODBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + if ( tacReadRmnBlockCheckParameter (pSelf, parameter, error) == ERROR) + { + return ERROR; + } + + pSelfParam->handleValid = rmassACCESS_BLOCKED; + /* wait until semaphore is acknowledged by realtime algo + * or just procede if realtime is not active */ + while ((*pSelf->shared).active && pSelfParam->handleValid != rmassACCESS_BLOCK_ACKN) + { + taskDelay(1); + } + + /* detach RMN handle */ + if ( rmassDetach (&pSelfParam->handle) != SUCCESS ) + { + char errorParam[40]; + + sprintf(errorParam, "rmassDetach returned error."); + tacRTC_ERR(tacERR_INTERNAL, errorParam); + return ERROR; + } + + if ( rmassReadAttach (&pSelfParam->handle, + pSelfParam->fieldString, + &pSelfParam->val[0], + &pSelfParam->val[1], + &pSelfParam->val[2], + &pSelfParam->val[3], + &pSelfParam->val[4], + &pSelfParam->val[5], + &pSelfParam->val[6], + &pSelfParam->val[7], + &pSelfParam->val[8], + &pSelfParam->val[9]) != SUCCESS ) + { + char errorParam[40]; + + sprintf(errorParam, "Attach to RMN failed."); + tacRTC_ERR(tacERR_INTERNAL, errorParam); + return ERROR; + } + + pSelfParam->handleValid = rmassACCESS_FREE; + + return OK; +} + +STATUS tacReadRfmBlockSetParameter (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the MODBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + if ( tacReadRfmBlockCheckParameter (pSelf, parameter, error) == ERROR) + { + return ERROR; + } + + pSelfParam->handleValid = rmassACCESS_BLOCKED; + /* wait until semaphore is acknowledged by realtime algo + * or just procede if realtime is not active */ + while ((*pSelf->shared).active && pSelfParam->handleValid != rmassACCESS_BLOCK_ACKN) + { + taskDelay(1); + } + + /* detach RMN handle */ + if ( rmassDetach (&pSelfParam->handle) != SUCCESS ) + { + char errorParam[40]; + + sprintf(errorParam, "rmassDetach returned error."); + tacRTC_ERR(tacERR_INTERNAL, errorParam); + return ERROR; + } + + if ( rmassReadAttach (&pSelfParam->handle, + pSelfParam->fieldString, + &pSelfParam->val[0], + &pSelfParam->val[1], + &pSelfParam->val[2], + &pSelfParam->val[3], + &pSelfParam->val[4], + &pSelfParam->val[5], + &pSelfParam->val[6], + &pSelfParam->val[7], + &pSelfParam->val[8], + &pSelfParam->val[9]) != SUCCESS ) + { + char errorParam[40]; + + sprintf(errorParam, "Attach to RFM failed."); + tacRTC_ERR(tacERR_INTERNAL, errorParam); + return ERROR; + } + + pSelfParam->handleValid = rmassACCESS_FREE; + + return OK; +} + +/* + * Algorithm Hooks - Called at each time the TAC algorithm is evaluated (ONLINE state) + */ + +void tacReadRmnBlockAlgorithm (tacSTDBLOCK* pSelf) /* Reference to the block instance */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + int i; + + if ( pSelfParam->handleValid == rmassACCESS_BLOCKED ) + { + pSelfParam->handleValid = rmassACCESS_BLOCK_ACKN; + } + + if ( pSelfParam->handleValid == rmassACCESS_FREE ) + { + /* actual RMN read operation */ + rmassReadAccessRmn (&pSelfParam->handle); + + /* Write to outputs */ + for (i=0; i < pSelfParam->numFields; i++) + { + switch (pSelfParam->type[i]) + { + case rmassTIMESEC: + case rmassUINT32: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).ui); + break; + case rmassTIMEUSEC: + case rmassINT32: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).i); + break; + case rmassFLOAT: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).f); + break; + default: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).d); + break; + } + } + + /* provide zero values at unsatisfied outputs + * I consider this a good thing to do since the block + * is always configured */ + for (i=pSelfParam->numFields; i < tacREAD_RMN_DEFAULT_OUTPUT_NUMBER; i++) + { + tacStdBlockSetOutput(pSelf, i, 0.0); + } + } +} + +void tacReadRfmBlockAlgorithm (tacSTDBLOCK* pSelf) /* Reference to the block instance */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + int i; + + if ( pSelfParam->handleValid == rmassACCESS_BLOCKED ) + { + pSelfParam->handleValid = rmassACCESS_BLOCK_ACKN; + } + + if ( pSelfParam->handleValid == rmassACCESS_FREE ) + { + /* actual RMN read operation */ + rmassReadAccessRfm (&pSelfParam->handle); + + /* Write to outputs */ + for (i=0; i < pSelfParam->numFields; i++) + { + switch (pSelfParam->type[i]) + { + case rmassTIMESEC: + case rmassUINT32: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).ui); + break; + case rmassTIMEUSEC: + case rmassINT32: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).i); + break; + case rmassFLOAT: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).f); + break; + default: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).d); + break; + } + } + + /* provide zero values at unsatisfied outputs + * I consider this a good thing to do since the block + * is always configured */ + for (i=pSelfParam->numFields; i < tacREAD_RMN_DEFAULT_OUTPUT_NUMBER; i++) + { + tacStdBlockSetOutput(pSelf, i, 0.0); + } + } +} + +/* + * Show Hooks - Called when the tacRtcTaskShow routine is executed + */ + +void tacReadRmnBlockShow (tacSTDBLOCK* pSelf) /* Reference to the block instance */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + /* Print parameter values */ + printf(" Attached: %s\n", pSelfParam->fieldString); + + return; +} + + +/***************************************************/ +/* The following code is common to all block types */ +/* Do not modify without any good reasons */ +/***************************************************/ + +/* + * Installation function + */ + +tacSTDBLOCK_TYPE tacReadRmnTypeInfo = { + "ReadRmn", + &tacReadRmnBlockConstructor, + &tacRmBlockGetParameter, + &tacReadRmnBlockAlgorithm, + &tacReadRmnBlockSetParameter, + NULL, + NULL, + &tacReadRmnBlockDestructor, + &tacReadRmnBlockShow +}; + +tacSTDBLOCK_TYPE tacReadRfmTypeInfo = { + "ReadRfm", + &tacReadRfmBlockConstructor, + &tacRmBlockGetParameter, + &tacReadRfmBlockAlgorithm, + &tacReadRmnBlockSetParameter, + NULL, + NULL, + &tacReadRmnBlockDestructor, + &tacReadRmnBlockShow +}; + +STATUS tacReadRmnBlockInitAll (void) +{ + /***************************************************/ + /* The following code is common to all block types */ + /* Do not modify without any good reasons */ + /***************************************************/ + + /* Install ReadRmn1g Block Hooks */ + tacStdBlockInstallNewType(&tacReadRmnTypeInfo); + + /*****************************/ + /* End of common code region */ + /*****************************/ + + /* Perform other library initialization operations */ + + return OK; +} + +STATUS tacReadRfmBlockInitAll (void) +{ + /***************************************************/ + /* The following code is common to all block types */ + /* Do not modify without any good reasons */ + /***************************************************/ + + /* Install ReadRmn1g Block Hooks */ + tacStdBlockInstallNewType(&tacReadRfmTypeInfo); + + /*****************************/ + /* End of common code region */ + /*****************************/ + + /* Perform other library initialization operations */ + + return OK; +} + +/*___oOo___*/ + + + diff --git a/hardcodedFiles/tacSinkBlock.c b/hardcodedFiles/tacSinkBlock.c new file mode 100644 index 0000000..df39833 --- /dev/null +++ b/hardcodedFiles/tacSinkBlock.c @@ -0,0 +1,1256 @@ +/******************************************************************************* +* E.S.O. - VLT project +* +* "@(#) $Id: tacSinkBlock.c 339094 2021-02-10 03:10:02Z jgil $" +* +* who when what +* ------- -------- ---------------------------------------------- +* rdembet 06/08/20 New MonitorState block with no data averaging +* swehner 28/11/09 SPR20090234 Correction in rate adjustment in reset hook +* swehner 27/11/09 Fixed message queue handling +* swehner 10/10/09 New block FastProbe for unlimited rec frequency +* swehner 22/09/09 PPRS 32341 Replaced specialized tacSINK_SHMSG stack +* with standard vxWorks message queue. +* bbauvir 21/09/04 VLTSW20040113 - One sample might be lost +* bbauvir 29/03/04 Monitor block averages over the reporting period +* bbauvir 29/12/02 Probe to the SampTask +* bbauvir 26/12/02 MsgQ access through DPC mechanism +* bbauvir 14/07/02 New MsgQ of TAC version 1.22 +* bbauvir 21/03/01 Created +*/ + +/************************************************************************ +* NAME +* tacSinkBlock - Standard data monitoring blocks +* +* SYNOPSIS +* lcubootAutoCdBoot 1,"tacsink.boot" +* < tacsink.boot +* +* DESCRIPTION +* Block type: Display +* Parameters: +* Inputs: 1 +* Outputs: none +* +* This function block samples the value of its input signal at the +* specified and issues a message containing the time +* and the value of the input on the vxWorks terminal. +* It does not allow modification of the parameter at runtime. +* +* Block type: Monitor +* Parameters: +* +* Inputs: 10max +* Outputs: none +* +* This function block samples the value of its input signals at the +* specified (0.0 to send a message at the system sampling +* period) and issues a message containing the time and the value of +* the inputs on the shared memory. This message is intercepted by the +* background task running on the master CPU. The monitored values are +* written into the online database. The number of inputs of the block +* is specified by parameter. +* This block does not allow modification of the parameters at runtime. +* +* Block type: MonitorState +* Parameters: +* +* Inputs: 10max +* Outputs: none +* +* Same as Monitor block but without the averaging of received data, +* see VLTSW-14260 JIRA ticket. +* +* Block type: Probe +* Parameters: +* +* Inputs: 10max +* Outputs: none +* +* Block type: FastProbe +* Parameters: +* +* Inputs: 10max +* Outputs: none +* +* This function block samples the value of its input signals at the +* specified (0.0 to send a message at the system sampling +* period) and issues a message containing the time and the value of +* the inputs on the shared memory. This message is intercepted by the +* background task running on the master CPU. The number of inputs of +* the block is specified by parameter. +* This message is passed to an external application callback if +* provided. +* This block does not allow modification of the parameters at runtime. +* The normal Probe block has a limited sampling frequency of not more +* than 2kHz. The reason is in particular the bottleneck between master +* and slave CPU which all samples have to pass through a mechanism of +* VME bus shared memory. On one-CPU-systems this limitation does not +* apply so you are free to choose faster sampling. You may of course +* hit other limitations (processor speed, network traffic etc.) +* +* FILES +* +* ENVIRONMENT +* TAC +* +* RETURN VALUES +* +* CAUTIONS +* All these blocks compute an decimation value to use to trigger the +* sampling of the input signals, from the system sampling period. +* They should be created after any synchronization block. +* +* In order to cope with system performances, a minimum +* is defined for each block. The minimum applied periods are 0.1 (10Hz), +* 0.01 (100Hz) and 0.5e-3 (2kHz) for the 'Display', 'Monitor' and +* 'Probe' blocks respectively. +* +* EXAMPLES +* # 5 signals @ 2Hz (monitored in the database) +* TAC.BLOCK9.TYPE Monitor +* TAC.BLOCK9.NAME Monitor +* TAC.BLOCK9.PARAM 0.5, 5 +* +* # 5 signals @ the RT algorithm sampling period (0.0) +* TAC.BLOCK10.TYPE Probe +* TAC.BLOCK10.NAME Probe +* TAC.BLOCK10.PARAM 0.0, 5 +* +* SEE ALSO +* tacServerInstallDataCallback, tacServerRemoveDataCallback +* +* BUGS +* +*------------------------------------------------------------------------ +*/ + +#define _POSIX_SOURCE 1 +#include "vltPort.h" + + +/* + * System Headers + */ + +#include +#include +#include /* logMsg ... */ +#include /* printf ... */ +#include /* malloc ... */ +#include /* memcpy ... */ +#include + +/* + * Local Headers + */ + +#include "tacStdBlock.h" +#include "tacShMsgQ.h" + +/* + * Compilation directives + */ + +/* + * Constants + */ + +#define tacSINK_DEFAULT_EXPECTED_PARAM 2 + +#define tacSINK_DEFAULT_INPUT_NUMBER tacMAX_DATA_NUMBER /* Up to 10 input channels */ +#define tacSINK_DEFAULT_OUTPUT_NUMBER tacMAX_DATA_NUMBER + +#define tacSINK_ONE_EXPECTED_PARAM 1 +#define tacSINK_ONE_INPUT_NUMBER 1 + +#define tacSINK_DISPLAY_MIN_SAMPLING_PERIOD .1 /* 10Hz */ +#define tacSINK_MONITOR_MIN_SAMPLING_PERIOD .01 /* 100Hz */ +#define tacSINK_PROBE_MIN_SAMPLING_PERIOD .5e-3 /* 2kHz */ + +#define tacSINK_DISPLAY_LOG_STRING_SIZE 128 + +#define tacSINK_MONITOR_DEFAULT_DB_POINT "tac:data:monitor" +#define tacSINK_MONITOR_MAX_DB_ADDR_SIZE 64 + +#define tacSINK_MONITOR_QUEUE_SIZE 6 +#define tacSINK_PROBE_QUEUE_SIZE 6 + + +typedef enum { + tacSINK_SAMPLING_PERIOD = 0, + tacSINK_INPUT_NUMBER, + tacSINK_MONITOR_DB_POINT, +}tacSINK_SCOPE_PARAM_INDEX; + +/* + * Types + */ + +typedef struct { + unsigned short rate; + unsigned short counter; + unsigned short inputNb; + unsigned int lost; + double rateParam; + char* dbPoint; + MSG_Q_ID msgq; + tacSHMSG shmMsg; +}tacSINK_SCOPE_LOCAL_PARAMETER; + +/* + * Function declaration + */ + +extern STATUS tacDpcPushRequest(tacVOIDFCTPTR pFunct, void* parameter); + +/* + * Local function declaration + */ + +/* + * Note: Routines called from within the algorithm must be declared with + * static __inline__ + */ + +STATUS tacSinkSendMonitorMessage(MSG_Q_ID * msgqvoid); +STATUS tacSinkSendMonitorStateMessage(MSG_Q_ID * msgqvoid); +STATUS tacSinkSendProbeMessage(MSG_Q_ID * msgq); +STATUS tacSinkDeleteMessageQueue(MSG_Q_ID * msgq); +STATUS tacSinkCommonBlockConstructor(tacSTDBLOCK* pSelf, tacERROR* error); + +/* + * Global variables + */ + +char logStr[tacSINK_DISPLAY_LOG_STRING_SIZE]; /* Logging string used for Display */ + + +/* + * Function definition + */ + +/* + * Constructor Hooks + */ + +STATUS tacSinkDisplayBlockConstructor (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = NULL; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = NULL; + + /* Check that the expected number of parameters has been received */ + if (parameter->number < tacSINK_ONE_EXPECTED_PARAM) + { + char errorParam[40]; + + sprintf(errorParam, "Expected %d, received %d", tacSINK_ONE_EXPECTED_PARAM, parameter->number); + tacRTC_ERR(tacERR_PARAM_NUMBER, errorParam); + return ERROR; + } + + /* Check that the parameters are valid */ + pRealParam = (double*) parameter->buffer; + + /* Passed parameter is the sampling period of the block */ + if (pRealParam[tacSINK_SAMPLING_PERIOD] < (*pSelf->shared).samplingPeriod) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = (*pSelf->shared).samplingPeriod; + } + + if (pRealParam[tacSINK_SAMPLING_PERIOD] < tacSINK_DISPLAY_MIN_SAMPLING_PERIOD) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = tacSINK_DISPLAY_MIN_SAMPLING_PERIOD; + } + + /* Call common constructor */ + if (tacSinkCommonBlockConstructor(pSelf, error) != OK) + { + return ERROR; + } + + /* Store parameters */ + pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; /* We will only store short integers */ + + /* + * Compute the rate at which data has to be processed - divide and take + * the integer part of the result + */ + + pSelfParam->rate = (unsigned short) (pRealParam[tacSINK_SAMPLING_PERIOD] / (*pSelf->shared).samplingPeriod); + pSelfParam->counter = 0; /* Decimation counter */ + + /* + * Perform other block initialization operations + */ + + return OK; +} + +STATUS tacSinkMonitorBlockConstructor (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = NULL; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = NULL; + unsigned short arrayIndex = 0; + + /* Check that the expected number of parameters has been received */ + if (parameter->number < tacSINK_DEFAULT_EXPECTED_PARAM) + { + char errorParam[40]; + + sprintf(errorParam, "Expected %d, received %d", tacSINK_DEFAULT_EXPECTED_PARAM, parameter->number); + tacRTC_ERR(tacERR_PARAM_NUMBER, errorParam); + return ERROR; + } + + /* Check that the parameters are valid */ + pRealParam = (double*) parameter->buffer; + + /* Passed parameter is the sampling period of the block */ + if (pRealParam[tacSINK_SAMPLING_PERIOD] < (*pSelf->shared).samplingPeriod) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = (*pSelf->shared).samplingPeriod; + } + + if (pRealParam[tacSINK_SAMPLING_PERIOD] < tacSINK_MONITOR_MIN_SAMPLING_PERIOD) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = tacSINK_MONITOR_MIN_SAMPLING_PERIOD; + } + + /* Number of inputs is minimum 1 up to tacMSG_MAX_DATA_NUMBER */ + if ((pRealParam[tacSINK_INPUT_NUMBER] < 1) || + (pRealParam[tacSINK_INPUT_NUMBER] > tacMAX_DATA_NUMBER)) + { + tacRTC_ERR(tacERR_PARAM_INVALID, ""); + return ERROR; + } + + /* Call common constructor */ + if (tacSinkCommonBlockConstructor(pSelf, error) != OK) + { + return ERROR; + } + + /* Store parameters */ + pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* + * Compute the rate at which data has to be processed - divide and take + * the integer part of the result + */ + + pSelfParam->rate = (unsigned short) (pRealParam[tacSINK_SAMPLING_PERIOD] / (*pSelf->shared).samplingPeriod); + pSelfParam->counter = 0; /* Decimation counter */ + pSelfParam->inputNb = (unsigned short) pRealParam[tacSINK_INPUT_NUMBER]; + + /* Optional parameter is an application-specific DB point */ + if (parameter->number == tacSINK_DEFAULT_EXPECTED_PARAM + 1) + { + printf("tacSinkMonitorBlockConstructor - DB point %s\n",(char*) &(pRealParam[tacSINK_MONITOR_DB_POINT])); + pSelfParam->dbPoint = (char*) malloc(tacSINK_MONITOR_MAX_DB_ADDR_SIZE); + strcpy(pSelfParam->dbPoint, (char*) &(pRealParam[tacSINK_MONITOR_DB_POINT])); + } + else + { + printf("tacSinkMonitorBlockConstructor - Default DB point\n"); + pSelfParam->dbPoint = NULL; + } + + /* Specify the number of input signals to attach to become resolved */ + tacStdBlockSetInputNumber(pSelf, pSelfParam->inputNb); + + /* + * Perform other block initialization operations + */ + + /* Create the block internal message queue which tosses the messages out of the + * interrupt context. They are buffered in the queue until the DPC tasks + * picks them up and sends them over the shared memory message queue. + * Sorry for that double-queuing, that's because of the M-S architecture */ + + pSelfParam->msgq = msgQCreate(tacSINK_MONITOR_QUEUE_SIZE, sizeof(tacSHMSG), 0); + if ( pSelfParam->msgq == NULL ) + { + char errorParam[40]; + + sprintf(errorParam, "Could not create probe block message queue"); + tacRTC_ERR(tacERR_MALLOC, errorParam); + return ERROR; + } + + /* will count if a message can't be pushed in the queue */ + pSelfParam->lost = 0; + + /* Warn the background task that a new probe block has been created */ + pSelfParam->shmMsg.type = tacSHMSG_ADD_MONITOR; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + + if (pSelfParam->dbPoint == NULL) + { + strcpy((char*) &(pSelfParam->shmMsg.msgBody.monitor.data), tacSINK_MONITOR_DEFAULT_DB_POINT); + } + else + { + strcpy((char*) &(pSelfParam->shmMsg.msgBody.monitor.data), *((char**) &(pSelfParam->dbPoint))); + } + + printf("tacSinkMonitorBlockConstructor - Attach to %s\n",(char*) &(pSelfParam->shmMsg.msgBody.monitor.data)); + + /* Send message */ + tacShMsgQSendBgInfo(&(pSelfParam->shmMsg)); + + /* Initialize the message parameters */ + pSelfParam->shmMsg.type = tacSHMSG_MONITOR_DATA; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + pSelfParam->shmMsg.msgBody.monitor.data.number = pSelfParam->inputNb; + + /* The output port is used to average the inputs over the reporting period */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pSelf->output[arrayIndex] = 0.0; + } + + return OK; +} + +STATUS tacSinkMonitorStateBlockConstructor (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = NULL; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = NULL; + unsigned short arrayIndex = 0; + + /* Check that the expected number of parameters has been received */ + if (parameter->number < tacSINK_DEFAULT_EXPECTED_PARAM) + { + char errorParam[40]; + + sprintf(errorParam, "Expected %d, received %d", tacSINK_DEFAULT_EXPECTED_PARAM, parameter->number); + tacRTC_ERR(tacERR_PARAM_NUMBER, errorParam); + return ERROR; + } + + /* Check that the parameters are valid */ + pRealParam = (double*) parameter->buffer; + + /* Passed parameter is the sampling period of the block */ + if (pRealParam[tacSINK_SAMPLING_PERIOD] < (*pSelf->shared).samplingPeriod) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = (*pSelf->shared).samplingPeriod; + } + + if (pRealParam[tacSINK_SAMPLING_PERIOD] < tacSINK_MONITOR_MIN_SAMPLING_PERIOD) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = tacSINK_MONITOR_MIN_SAMPLING_PERIOD; + } + + /* Number of inputs is minimum 1 up to tacMSG_MAX_DATA_NUMBER */ + if ((pRealParam[tacSINK_INPUT_NUMBER] < 1) || + (pRealParam[tacSINK_INPUT_NUMBER] > tacMAX_DATA_NUMBER)) + { + tacRTC_ERR(tacERR_PARAM_INVALID, ""); + return ERROR; + } + + /* Call common constructor */ + if (tacSinkCommonBlockConstructor(pSelf, error) != OK) + { + return ERROR; + } + + /* Store parameters */ + pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* + * Compute the rate at which data has to be processed - divide and take + * the integer part of the result + */ + + pSelfParam->rate = (unsigned short) (pRealParam[tacSINK_SAMPLING_PERIOD] / (*pSelf->shared).samplingPeriod); + pSelfParam->counter = 0; /* Decimation counter */ + pSelfParam->inputNb = (unsigned short) pRealParam[tacSINK_INPUT_NUMBER]; + + /* Optional parameter is an application-specific DB point */ + if (parameter->number == tacSINK_DEFAULT_EXPECTED_PARAM + 1) + { + printf("tacSinkMonitorStateBlockConstructor - DB point %s\n",(char*) &(pRealParam[tacSINK_MONITOR_DB_POINT])); + pSelfParam->dbPoint = (char*) malloc(tacSINK_MONITOR_MAX_DB_ADDR_SIZE); + strcpy(pSelfParam->dbPoint, (char*) &(pRealParam[tacSINK_MONITOR_DB_POINT])); + } + else + { + printf("tacSinkMonitorStateBlockConstructor - Default DB point\n"); + pSelfParam->dbPoint = NULL; + } + + /* Specify the number of input signals to attach to become resolved */ + tacStdBlockSetInputNumber(pSelf, pSelfParam->inputNb); + + /* + * Perform other block initialization operations + */ + + /* Create the block internal message queue which tosses the messages out of the + * interrupt context. They are buffered in the queue until the DPC tasks + * picks them up and sends them over the shared memory message queue. + * Sorry for that double-queuing, that's because of the M-S architecture */ + + pSelfParam->msgq = msgQCreate(tacSINK_MONITOR_QUEUE_SIZE, sizeof(tacSHMSG), 0); + if ( pSelfParam->msgq == NULL ) + { + char errorParam[40]; + + sprintf(errorParam, "Could not create probe block message queue"); + tacRTC_ERR(tacERR_MALLOC, errorParam); + return ERROR; + } + + /* will count if a message can't be pushed in the queue */ + pSelfParam->lost = 0; + + /* Warn the background task that a new probe block has been created */ + pSelfParam->shmMsg.type = tacSHMSG_ADD_MONITOR; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + + if (pSelfParam->dbPoint == NULL) + { + strcpy((char*) &(pSelfParam->shmMsg.msgBody.monitor.data), tacSINK_MONITOR_DEFAULT_DB_POINT); + } + else + { + strcpy((char*) &(pSelfParam->shmMsg.msgBody.monitor.data), *((char**) &(pSelfParam->dbPoint))); + } + + printf("tacSinkMonitorStateBlockConstructor - Attach to %s\n",(char*) &(pSelfParam->shmMsg.msgBody.monitor.data)); + + /* Send message */ + tacShMsgQSendBgInfo(&(pSelfParam->shmMsg)); + + /* Initialize the message parameters */ + pSelfParam->shmMsg.type = tacSHMSG_MONITOR_DATA; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + pSelfParam->shmMsg.msgBody.monitor.data.number = pSelfParam->inputNb; + + /* Init output port which won't be used to average the inputs over the reporting period */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pSelf->output[arrayIndex] = 0.0; + } + + return OK; +} + +STATUS tacSinkProbeBlockCommonConstructor (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + double minPeriod, + tacERROR* error) +{ + double* pRealParam = NULL; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = NULL; + + /* Check that the expected number of parameters has been received */ + if (parameter->number < tacSINK_DEFAULT_EXPECTED_PARAM) + { + char errorParam[40]; + + sprintf(errorParam, "Expected %d, received %d", tacSINK_DEFAULT_EXPECTED_PARAM, parameter->number); + tacRTC_ERR(tacERR_PARAM_NUMBER, errorParam); + return ERROR; + } + + /* Check that the parameters are valid */ + pRealParam = (double*) parameter->buffer; + + /* Passed parameter is the sampling period of the block */ + if (pRealParam[tacSINK_SAMPLING_PERIOD] < (*pSelf->shared).samplingPeriod) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = (*pSelf->shared).samplingPeriod; + } + + if (pRealParam[tacSINK_SAMPLING_PERIOD] < minPeriod) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = minPeriod; + } + + /* Number of inputs is minimum 1 up to tacMSG_MAX_DATA_NUMBER */ + if ((pRealParam[tacSINK_INPUT_NUMBER] < 1) || + (pRealParam[tacSINK_INPUT_NUMBER] > tacMAX_DATA_NUMBER)) + { + tacRTC_ERR(tacERR_PARAM_INVALID, ""); + return ERROR; + } + + /* Call common constructor */ + if (tacSinkCommonBlockConstructor(pSelf, error) != OK) + { + return ERROR; + } + + /* Store parameters */ + pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* + * Compute the rate at which data has to be processed - divide and take + * the integer part of the result + */ + + pSelfParam->rateParam = pRealParam[tacSINK_SAMPLING_PERIOD]; + pSelfParam->rate = (unsigned short) (pRealParam[tacSINK_SAMPLING_PERIOD] / (*pSelf->shared).samplingPeriod); + pSelfParam->counter = 0; /* Decimation counter */ + pSelfParam->inputNb = (unsigned short) pRealParam[tacSINK_INPUT_NUMBER]; + + /* Specify the number of input signals to attach to become resolved */ + tacStdBlockSetInputNumber(pSelf, pSelfParam->inputNb); + + /* + * Perform other block initialization operations + */ + + /* Create the block internal message queue which gets the messages out of the + * interrupt context. They are buffered in the queue until the DPC tasks + * picks them up and sends them over the shared memory message queue. + * Sorry for that double-queuing, that's because of the M-S architecture */ + + /* There is only one message queue for all probe blocks! */ + pSelfParam->msgq = msgQCreate(tacSINK_PROBE_QUEUE_SIZE, sizeof(tacSHMSG), 0); + if ( pSelfParam->msgq == NULL ) + { + char errorParam[40]; + + sprintf(errorParam, "Could not create probe block message queue"); + tacRTC_ERR(tacERR_MALLOC, errorParam); + return ERROR; + } + + /* will count if a message can't be pushed in the queue */ + pSelfParam->lost = 0; + + /* Warn the background task that a new probe block has been created */ + pSelfParam->shmMsg.type = tacSHMSG_ADD_PROBE; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + + /* Send message */ + tacShMsgQSendDataSample(&pSelfParam->shmMsg); + + /* Initialize the message parameters */ + pSelfParam->shmMsg.type = tacSHMSG_TRANSFER_DATA; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + pSelfParam->shmMsg.msgBody.monitor.data.number = pSelfParam->inputNb; + + return OK; +} + +/* Probe block has a max. sampling frequency of 2kHz */ +STATUS tacSinkProbeBlockConstructor (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + return tacSinkProbeBlockCommonConstructor (pSelf, parameter, tacSINK_PROBE_MIN_SAMPLING_PERIOD, error); +} + +/* Fast probe is the same as probe but not does have the + * limitation on the max. recording frequency */ +STATUS tacSinkFastProbeBlockConstructor (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + return tacSinkProbeBlockCommonConstructor (pSelf, parameter, 0.0, error); +} + +void tacSinkProbeBlockReset (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = + (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* + * Re-Compute the rate at which data has to be processed + */ + if (pSelfParam->rateParam < (*pSelf->shared).samplingPeriod ) + { + pSelfParam->rate = 1; + } + else + { + pSelfParam->rate = (unsigned short) + (pSelfParam->rateParam / (*pSelf->shared).samplingPeriod); + } + + return; +} + +/* + * Report parameters Hooks + */ + +STATUS tacSinkDisplayBlockGetParameter (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = (double*) parameter->buffer; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Send back the expected number of parameters */ + parameter->number = tacSINK_ONE_EXPECTED_PARAM; + + /* Report current parameters */ + pRealParam[tacSINK_SAMPLING_PERIOD] = (double) (pSelfParam->rate * (*pSelf->shared).samplingPeriod); + + return OK; +} + +STATUS tacSinkMonitorBlockGetParameter (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = (double*) parameter->buffer; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Send back the expected number of parameters */ + parameter->number = tacSINK_DEFAULT_EXPECTED_PARAM; + + /* Report current parameters */ + pRealParam[tacSINK_SAMPLING_PERIOD] = (double) (pSelfParam->rate * (*pSelf->shared).samplingPeriod); + pRealParam[tacSINK_INPUT_NUMBER] = (double) pSelfParam->inputNb; + + if (*((char**) &(pSelfParam->dbPoint)) != NULL) + { + parameter->number += 1; + parameter->type[tacSINK_MONITOR_DB_POINT] = tacPARAM_STRING; + strcpy((char*) &(pRealParam[tacSINK_MONITOR_DB_POINT]), *((char**) &(pSelfParam->dbPoint))); + } + + return OK; +} + +STATUS tacSinkMonitorStateBlockGetParameter (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = (double*) parameter->buffer; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Send back the expected number of parameters */ + parameter->number = tacSINK_DEFAULT_EXPECTED_PARAM; + + /* Report current parameters */ + pRealParam[tacSINK_SAMPLING_PERIOD] = (double) (pSelfParam->rate * (*pSelf->shared).samplingPeriod); + pRealParam[tacSINK_INPUT_NUMBER] = (double) pSelfParam->inputNb; + + if (*((char**) &(pSelfParam->dbPoint)) != NULL) + { + parameter->number += 1; + parameter->type[tacSINK_MONITOR_DB_POINT] = tacPARAM_STRING; + strcpy((char*) &(pRealParam[tacSINK_MONITOR_DB_POINT]), *((char**) &(pSelfParam->dbPoint))); + } + + return OK; +} + +STATUS tacSinkProbeBlockGetParameter (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = (double*) parameter->buffer; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Send back the expected number of parameters */ + parameter->number = tacSINK_DEFAULT_EXPECTED_PARAM; + + /* Report current parameters */ + pRealParam[tacSINK_SAMPLING_PERIOD] = (double) (pSelfParam->rate * (*pSelf->shared).samplingPeriod); + pRealParam[tacSINK_INPUT_NUMBER] = (double) pSelfParam->inputNb; + + return OK; +} + +/* + * Change parameters Hooks + */ + +/* + * Algorithm Hooks + */ + +void tacSinkDisplayBlockAlgorithm (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + if ((pSelfParam->counter % pSelfParam->rate) == 0) /* It's time to process data */ + { + sprintf(logStr,"Name: %s Time: %ld.%6ld Value: %g\n", + pSelf->name, + (*pSelf->shared).currentTime.seconds, + (*pSelf->shared).currentTime.microsec, + tacStdBlockGetInput(pSelf,0)); + + tacDpcPushRequest((tacVOIDFCTPTR) &printf, logStr); + + pSelfParam->counter = 0; + } + + pSelfParam->counter++; +} + +void tacSinkMonitorBlockAlgorithm (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + unsigned short arrayIndex = 0; + + /* The output port is used to average the inputs over the reporting period */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pSelf->output[arrayIndex] += tacStdBlockGetInput(pSelf,arrayIndex); + } + + if ((pSelfParam->counter % pSelfParam->rate) == 0) /* It's time to process data */ + { + tacDATA* pData = &(pSelfParam->shmMsg.msgBody.monitor.data); /* We are only interested in message body */ + + /* pData->number = pSelfParam->inputNb; */ + pData->timeStamp = (*pSelf->shared).currentTime; + + /* pData points to the body of the Message */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pData->buffer[arrayIndex] = pSelf->output[arrayIndex] / pSelfParam->rate; + } + + /* Push message into probe block's message que to get the + * data out of the interrupt comtext. */ + if ( msgQSend (pSelfParam->msgq, (char*) &(pSelfParam->shmMsg), sizeof(tacSHMSG), NO_WAIT, 0) != OK ) + { + (pSelfParam->lost)++; + } + + /* Defer procedure call */ + tacDpcPushRequest((tacVOIDFCTPTR) &tacSinkSendMonitorMessage, &pSelfParam->msgq); + + pSelfParam->counter = 0; + + /* The output port is used to average the inputs over the reporting period */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pSelf->output[arrayIndex] = 0.0; + } + } + + pSelfParam->counter++; +} + +void tacSinkMonitorStateBlockAlgorithm (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + unsigned short arrayIndex = 0; + + if ((pSelfParam->counter % pSelfParam->rate) == 0) /* It's time to process data */ + { + tacDATA* pData = &(pSelfParam->shmMsg.msgBody.monitor.data); /* We are only interested in message body */ + + /* pData->number = pSelfParam->inputNb; */ + pData->timeStamp = (*pSelf->shared).currentTime; + + /* pData points to the body of the Message */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pData->buffer[arrayIndex] = tacStdBlockGetInput(pSelf,arrayIndex); + } + + /* Push message into probe block's message que to get the + * data out of the interrupt comtext. */ + if ( msgQSend (pSelfParam->msgq, (char*) &(pSelfParam->shmMsg), sizeof(tacSHMSG), NO_WAIT, 0) != OK ) + { + (pSelfParam->lost)++; + } + + /* Defer procedure call */ + tacDpcPushRequest((tacVOIDFCTPTR) &tacSinkSendMonitorMessage, &pSelfParam->msgq); + + pSelfParam->counter = 0; + } + + pSelfParam->counter++; +} + +void tacSinkProbeBlockAlgorithm (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + unsigned short arrayIndex = 0; + + if ((pSelfParam->counter % pSelfParam->rate) == 0) /* It's time to process data */ + { + tacDATA* pData = &(pSelfParam->shmMsg.msgBody.monitor.data); /* We are only interested in message body */ + + pData->timeStamp = (*pSelf->shared).currentTime; + + /* pData points to the body of the Message */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pData->buffer[arrayIndex] = tacStdBlockGetInput(pSelf,arrayIndex); + } + + /* Push message into probe block's message que to get the + * data out of the interrupt comtext. */ + if ( msgQSend (pSelfParam->msgq, (char*) &(pSelfParam->shmMsg), sizeof(tacSHMSG), NO_WAIT, 0) != OK ) + { + (pSelfParam->lost)++; + } + + /* Defer procedure call: + * tacSinkSendProbeMessage is called outside the interrupt routine + * and will take care to pick up the message from the probe block's + * message queue and send it over the shared memory message queue */ + tacDpcPushRequest((tacVOIDFCTPTR) &tacSinkSendProbeMessage, &pSelfParam->msgq); + + pSelfParam->counter = 0; + } + + pSelfParam->counter++; +} + +/* + * Reset Hooks + */ + +/* + * Stop Hooks + */ + +/* + * Destructor Hooks + */ + +/* + * Note: This destructor is used mainly to send a MONITOR message containing + * 0.0 in order to reset the database array (otherwise going from an + * algorithm with 4 monitored data to one with 3 monitored data leaves + * the 4th value equal to the last ...) + */ + +void tacSinkMonitorBlockDestructor (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + tacDATA* pData = &(pSelfParam->shmMsg.msgBody.monitor.data); + unsigned short arrayIndex = 0; + + /* Reset DB values */ + pSelfParam->shmMsg.type = tacSHMSG_MONITOR_DATA; + pData = &(pSelfParam->shmMsg.msgBody.monitor.data); + + pData->number = pSelfParam->inputNb; + + /* pData points to the body of the Message */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pData->buffer[arrayIndex] = 0.0; + } + + /* Send message */ + tacShMsgQSendBgInfo(&pSelfParam->shmMsg); + + pSelfParam->shmMsg.type = tacSHMSG_REMOVE_MONITOR; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + + /* Send message */ + tacShMsgQSendBgInfo(&pSelfParam->shmMsg); + + free(pSelfParam->dbPoint); + + /* delete internal message queue. Do this as deferred procedure call + * to make sure it is only called when all messages have been send + * (through the same deferred call mechanism) */ + tacDpcPushRequest((tacVOIDFCTPTR) tacSinkDeleteMessageQueue, &(pSelfParam->msgq)); + + return; +} + +void tacSinkMonitorStateBlockDestructor (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + tacDATA* pData = &(pSelfParam->shmMsg.msgBody.monitor.data); + unsigned short arrayIndex = 0; + + /* Reset DB values */ + pSelfParam->shmMsg.type = tacSHMSG_MONITOR_DATA; + pData = &(pSelfParam->shmMsg.msgBody.monitor.data); + + pData->number = pSelfParam->inputNb; + + /* pData points to the body of the Message */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pData->buffer[arrayIndex] = 0.0; + } + + /* Send message */ + tacShMsgQSendBgInfo(&pSelfParam->shmMsg); + + pSelfParam->shmMsg.type = tacSHMSG_REMOVE_MONITOR; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + + /* Send message */ + tacShMsgQSendBgInfo(&pSelfParam->shmMsg); + + free(pSelfParam->dbPoint); + + /* delete internal message queue. Do this as deferred procedure call + * to make sure it is only called when all messages have been send + * (through the same deferred call mechanism) */ + tacDpcPushRequest((tacVOIDFCTPTR) tacSinkDeleteMessageQueue, &(pSelfParam->msgq)); + + return; +} + +void tacSinkProbeBlockDestructor (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + pSelfParam->shmMsg.type = tacSHMSG_REMOVE_PROBE; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + + /* Send message */ + tacShMsgQSendDataSample(&pSelfParam->shmMsg); + + /* delete internal message queue. Do this as deferred procedure call + * to make sure it is only called when all messages have been send + * (through the same deferred call mechanism) */ + tacDpcPushRequest((tacVOIDFCTPTR) tacSinkDeleteMessageQueue, &(pSelfParam->msgq)); + + return; +} + +/* + * Show Hooks + */ + +void tacSinkDisplayBlockShow (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Print parameter values */ + printf(" Update rate: %d\n",pSelfParam->rate); + + return; +} + +void tacSinkMonitorBlockShow (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Print parameter values */ + printf(" Update rate: %d\n",pSelfParam->rate); + printf(" Number of input signals: %d\n",pSelfParam->inputNb); + printf(" Queued samples: %d\n", msgQNumMsgs(pSelfParam->msgq)); + printf(" Lost samples: %d\n",pSelfParam->lost); + + if (pSelfParam->dbPoint != NULL) + { + printf(" DB Point: %s\n", pSelfParam->dbPoint); + } + + return; +} + +void tacSinkMonitorStateBlockShow (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Print parameter values */ + printf(" Using MonitorState block, not averaging received data\n"); + printf(" Update rate: %d\n",pSelfParam->rate); + printf(" Number of input signals: %d\n",pSelfParam->inputNb); + printf(" Queued samples: %d\n", msgQNumMsgs(pSelfParam->msgq)); + printf(" Lost samples: %d\n",pSelfParam->lost); + + if (pSelfParam->dbPoint != NULL) + { + printf(" DB Point: %s\n", pSelfParam->dbPoint); + } + + return; +} + +void tacSinkProbeBlockShow (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Print parameter values */ + printf(" Update rate: %d\n",pSelfParam->rate); + printf(" Update rate param (sec): %f\n",pSelfParam->rateParam); + printf(" Number of input signals: %d\n",pSelfParam->inputNb); + printf(" Queued samples: %d\n", msgQNumMsgs(pSelfParam->msgq)); + printf(" Lost samples: %d\n",pSelfParam->lost); + + return; +} + +/* + * Installation function + */ + +tacSTDBLOCK_TYPE tacSinkDisplayTypeInfo = { + "Display", + &tacSinkDisplayBlockConstructor, + &tacSinkDisplayBlockGetParameter, + &tacSinkDisplayBlockAlgorithm, + NULL, + NULL, + NULL, + NULL, + &tacSinkDisplayBlockShow, +}; + +tacSTDBLOCK_TYPE tacSinkMonitorTypeInfo = { + "Monitor", + &tacSinkMonitorBlockConstructor, + &tacSinkMonitorBlockGetParameter, + &tacSinkMonitorBlockAlgorithm, + NULL, + NULL, + NULL, + &tacSinkMonitorBlockDestructor, + &tacSinkMonitorBlockShow, +}; + +tacSTDBLOCK_TYPE tacSinkMonitorStateTypeInfo = { + "MonitorState", + &tacSinkMonitorStateBlockConstructor, + &tacSinkMonitorStateBlockGetParameter, + &tacSinkMonitorStateBlockAlgorithm, + NULL, + NULL, + NULL, + &tacSinkMonitorStateBlockDestructor, + &tacSinkMonitorStateBlockShow, +}; + +/* Probe with a maximal sampling rate of 2kHz */ +tacSTDBLOCK_TYPE tacSinkProbeTypeInfo = { + "Probe", + &tacSinkProbeBlockConstructor, + &tacSinkProbeBlockGetParameter, + &tacSinkProbeBlockAlgorithm, + NULL, + &tacSinkProbeBlockReset, + NULL, + &tacSinkProbeBlockDestructor, + &tacSinkProbeBlockShow, +}; + +/* Fast probe is the same as probe but not does have the + * limitation on the max. recording frequency */ +tacSTDBLOCK_TYPE tacSinkFastProbeTypeInfo = { + "FastProbe", + &tacSinkFastProbeBlockConstructor, + &tacSinkProbeBlockGetParameter, + &tacSinkProbeBlockAlgorithm, + NULL, + &tacSinkProbeBlockReset, + NULL, + &tacSinkProbeBlockDestructor, + &tacSinkProbeBlockShow, +}; + +STATUS tacSinkBlockInitAll (void) +{ + /* Install Sink Block Hooks */ + tacStdBlockInstallNewType(&tacSinkDisplayTypeInfo); + tacStdBlockInstallNewType(&tacSinkMonitorTypeInfo); + tacStdBlockInstallNewType(&tacSinkMonitorStateTypeInfo); + tacStdBlockInstallNewType(&tacSinkProbeTypeInfo); + tacStdBlockInstallNewType(&tacSinkFastProbeTypeInfo); + + /* + * Perform other library initialization operations + */ + + return OK; +} + +/* + * Local functions + */ + +/* + * Note: Routines called from within the algorithm must be declared with + * static __inline__ + */ + +STATUS tacSinkCommonBlockConstructor (tacSTDBLOCK* pSelf, + tacERROR* error) +{ + /* Allocate specific arrays (pointers are initialized to NULL by StdBlock) */ + if (tacStdBlockAllocateArrays(pSelf, 0, tacSINK_DEFAULT_INPUT_NUMBER, + tacSINK_DEFAULT_OUTPUT_NUMBER, error) == ERROR) + { + return ERROR; + } + + if (tacStdBlockAllocateArrayBySize(pSelf, tacSTDBLOCK_PARAM_ARRAY, + sizeof(tacSINK_SCOPE_LOCAL_PARAMETER), error) == ERROR) + { + tacStdBlockReleaseArray(pSelf, tacSTDBLOCK_INPUT_ARRAY, error); + tacStdBlockReleaseArray(pSelf, tacSTDBLOCK_OUTPUT_ARRAY, error); + return ERROR; + } + + /* Specify the number of input signals to attach to become resolved */ + tacStdBlockSetInputNumber(pSelf, tacSINK_ONE_INPUT_NUMBER); /* Required */ + + return OK; +} + +STATUS tacSinkSendMonitorMessage(MSG_Q_ID * msgq) +{ + /* Send message using provided function (different for Monitor and Probe blocks) */ + /* Send message using provided function (different for Monitor and Probe blocks) */ + tacSHMSG msg; + + if ( msgQReceive(*msgq, (char*) &msg, sizeof(tacSHMSG), NO_WAIT) == sizeof(tacSHMSG) ) + { + tacShMsgQSendBgInfo (&msg); + } + + return OK; +} + +STATUS tacSinkSendProbeMessage(MSG_Q_ID * msgq) +{ + /* Send message using provided function (different for Monitor and Probe blocks) */ + tacSHMSG msg; + + if ( msgq == NULL ) + { + return ERROR; + } + + if ( msgQReceive(*msgq, (char*) &msg, sizeof(tacSHMSG), NO_WAIT) == sizeof(tacSHMSG) ) + { + tacShMsgQSendDataSample (&msg); + } + return OK; +} + +STATUS tacSinkDeleteMessageQueue (MSG_Q_ID * msgq) +{ + /* Is called when block is destroyed and removes the internal message queue */ + STATUS status; + + status = msgQDelete (*msgq); + *msgq = NULL; + return status; +} + + +/*___oOo___*/ + + + + + + diff --git a/src/arguments.py b/src/arguments.py new file mode 100644 index 0000000..94e4cea --- /dev/null +++ b/src/arguments.py @@ -0,0 +1,26 @@ +import getopt + +def exitUsage(): + print("usage: %s <.tasrc file> -i -o " % sys.argv[0]) + sys.exit(1) + +def readArguments(args): + sourceDirectories = [] + outputFile = "" + try: + options, _ = getopt.getopt(args, "hi:o:") + except getopt.GetoptError: + exitUsage() + for option, arg in options: + if option == "-h": + exitUsage() + elif option == "-o": + outputFile = arg + elif option == "-i": + sourceDirectories.append(arg) + if outputFile == "": + exitUsage() + if len(sourceDirectories) == 0: + print("WARNING: no source directories specified!") + return outputFile, sourceDirectories + diff --git a/src/converter.py b/src/converter.py new file mode 100755 index 0000000..3e44058 --- /dev/null +++ b/src/converter.py @@ -0,0 +1,18 @@ +#!/usr/bin/python3 + +import sys + +import arguments +from tacsrc.tac import readTAC +import grc +import portNaming + +if __name__ == "__main__": + if len(sys.argv) == 1: + params.exitUsage() + inputFile = sys.argv[1] + outputFile, sourceDirectories = arguments.readArguments(sys.argv[2:]) + blocks, connections, blockTypes = readTAC(inputFile) + portNaming.resolvePortNames(blockTypes, sourceDirectories) + grc.write(outputFile, blocks, connections) + diff --git a/src/defaultBlockTypes.py b/src/defaultBlockTypes.py new file mode 100644 index 0000000..a7c7a7a --- /dev/null +++ b/src/defaultBlockTypes.py @@ -0,0 +1,74 @@ +from tacsrc.blockType import BlockType + +class VariablePorts: + def __init__(self, ioDescriptionName, sizeFunction): + self.ioDescriptionName = ioDescriptionName + self.sizeFunction = sizeFunction + + def mapName(self, position, name, index): + return + + def getRealPort(self, originalPort): + return 0 + + def ensureLength(self, length): + return + + def getIODescription(self, block): + return "\\\\n0:%s[%s]" % (self.ioDescriptionName, self.sizeFunction(block)) + + def getRealCount(self): + return 1 + +def inParameters(block): + return block.parameters[1] + +def parameterSize(block): + return len(block.parameters) + +monitor = BlockType("Monitor") +monitor.inputs = VariablePorts("input", inParameters) + +monitorState = BlockType("MonitorState") +monitorState.inputs = VariablePorts("input", inParameters) + +probe = BlockType("Probe") +probe.inputs = VariablePorts("input", inParameters) + +readRfm = BlockType("ReadRfm") +readRfm.outputs = VariablePorts("output", parameterSize) + +rms = BlockType("RMS") +rms.inputs.mapName(0, "input", 0) +rms.outputs.mapName(0, "output", 0) + +constant = BlockType("Constant") +constant.outputs.mapName(0, "CONST", 0) + +manual = BlockType("ManualSwitch") +manual.inputs.mapName(0, "input", 0) +manual.outputs.mapName(0, "output", 0) + +noise = BlockType("NormalNoise") +noise.outputs.mapName(0, "output", 0) + +writeRMNNoTim = BlockType("WriteRmNoTim") +writeRMNNoTim.inputs = VariablePorts("input", parameterSize) + +defaultBlockTypes = { + "Monitor": monitor, + "MonitorState": monitorState, + "Probe": probe, + "ReadRfm": readRfm, + "TIM": BlockType("TIM"), + "WAIT_RFM_INTERRUPT": BlockType("WAIT_RFM_INTERRUPT"), + "RMS": rms, + "Constant": constant, + "ManualSwitch": manual, + "NormalNoise": noise, + "WriteRmNoTim": writeRMNNoTim +} + +def addDefaultBlockTypes(blockTypes): + for key in defaultBlockTypes: + blockTypes[key] = defaultBlockTypes[key] diff --git a/src/grc.py b/src/grc.py new file mode 100644 index 0000000..ed02659 --- /dev/null +++ b/src/grc.py @@ -0,0 +1,94 @@ +GRC_TEMPLATE = ''' +options: + parameters: + title: 'TASRC to GRC converter output' + states: + coordinate: [-100, -100] + +blocks: +%s + +connections: +%s + +metadata: + file_format: 1 +''' + +BLOCK_TEMPLATE = ''' +- name: %s + id: epy_block + parameters: + _source_code: "from gnuradio import gr\\nimport numpy as np\\nclass BLOCK(gr.sync_block):\\n def __init__(self):\\n gr.sync_block.__init__(self,name='%s:%s%s',in_sig=%s,out_sig=%s)\\n def work(self, input_items, output_items):\\n return len(output_items[0])" + states: + coordinate: [%s, %s] +''' + +LINK_TEMPLATE = "- [%s, '%s', %s, '%s']\n" + +def getLongestDependencyRow(blocks, blockDependencies): + currentMax = 0 + for block in blocks: + current = getLongestDependencyRow(blockDependencies[block], blockDependencies) + 1 + if current > currentMax: + currentMax = current + return currentMax + +def getPosition(block, blockDependencies, reverseBlockDependencies, depths): + position = getLongestDependencyRow(blockDependencies[block], blockDependencies) + depths += [0] * (position+1 - len(depths)) + y = depths[position] + depths[position] += 50 # base offset + depths[position] += max( + (3+block.blockType.inputs.getRealCount()+block.blockType.outputs.getRealCount()) * 15, + max(block.blockType.inputs.getRealCount(), block.blockType.outputs.getRealCount()) * 30) + return position * 300, y + +def getBlockDependencies(blocks, links): + blockDependencies = {} + for block in blocks: + blockDependencies[block] = [] + for link in links: + if link.toBlock == block: + blockDependencies[block].append(link.fromBlock) + reverseBlockDependencies = {} + for block in blockDependencies: + for dependency in blockDependencies[block]: + if not dependency in reverseBlockDependencies: + reverseBlockDependencies[dependency] = [] + reverseBlockDependencies[dependency].append(block) + return blockDependencies, reverseBlockDependencies + +def getBlocksContent(blocks, links): + blockDependencies, reverseBlockDependencies = getBlockDependencies(blocks, links) + depths = [] + blocksContent = "" + for block in blocks: + description = block.blockType.getIODescription(block) + inputs = "[%s]" % ", ".join(["np.int8"] * block.blockType.inputs.getRealCount()) + outputs = "[%s]" % ", ".join(["np.int8"] * block.blockType.outputs.getRealCount()) + position = getPosition(block, blockDependencies, reverseBlockDependencies, depths) + blocksContent += BLOCK_TEMPLATE % ( + block.name, + block.name, + block.blockType.name, + description, + inputs, + outputs, + position[0], + position[1]) + return blocksContent + +def getLinksContent(links): + linksContent = "" + for link in links: + fromPort = link.fromBlock.blockType.outputs.getRealPort(link.fromPort) + toPort = link.toBlock.blockType.inputs.getRealPort(link.toPort) + linksContent += LINK_TEMPLATE % (link.fromBlock.name, fromPort, link.toBlock.name, toPort) + return linksContent + +def write(filename, blocks, links): + with open(filename, "w+") as file: + print("writing to file %s" % filename) + file.truncate(0) + file.write(GRC_TEMPLATE % (getBlocksContent(blocks, links), getLinksContent(links))) diff --git a/src/portNaming.py b/src/portNaming.py new file mode 100644 index 0000000..62be549 --- /dev/null +++ b/src/portNaming.py @@ -0,0 +1,104 @@ +import re +import os +import json +from defaultBlockTypes import defaultBlockTypes + +INPUT_FUNCTIONS = [ + "tacStdBlockGetInput", + "tacGraviMatrixGetPointerInput" + ] + +OUTPUT_FUNCTIONS = [ + "tacStdBlockSetOutput", + "tacGraviMatrixSetPointerOutput" + ] + +def getFiles(blockType, sourceDirectories): + files = [] + for sourceDirectory in sourceDirectories: + files += ["%s/%s" % (data[0], file) + for data in os.walk(sourceDirectory) + for file in data[2] if re.match(".*tac%sBlock.c" % blockType.name.replace("Rm", "Rmn"), file) != None] + return files + +def resolvePortNames(blockTypes, sourceDirectories): + missingBlocks = [] + multipleDefinitions = [] + for blockType in blockTypes: + if blockType.name in defaultBlockTypes: + continue + files = getFiles(blockType, sourceDirectories) + if len(files) == 0: + print("WARNING: no source file for block type %s found" % blockType.name) + missingBlocks.append(blockType.name) + continue + if len(files) > 1: + multipleDefinitions.append(blockType.name) + print("WARNING: more than one matching source file for block type %s found, skipping" % blockType.name) + continue + print("reading file %s" % files[0]) + with open(files[0], "r") as file: + content = "\n".join(file.readlines()) + for function in INPUT_FUNCTIONS: + mapInputs(content, function, blockType.inputs) + for function in OUTPUT_FUNCTIONS: + mapOutputs(content, function, blockType.outputs) + for entry in re.findall("\\w+ *= *\\*?\\(?pSelf->input\\[\\d+\\]\\)?", content): + name = re.search("^\\w+", entry).group() + position = int(re.search("(?<=\\[)\\d+(?=\\])", entry).group()) + blockType.inputs.mapName(position, name, 0) + for entry in re.findall("pSelf->output\\[\\d+\\] *= *\\w+", content): + name = re.search("\\w+$", entry).group() + position = int(re.search("(?<=\\[)\\d+(?=\\])", entry).group()) + blockType.outputs.mapName(position, name, 0) + if not os.path.exists("errors.json") or os.stat("errors.json").st_size == 0: + content = {"missing_blocks": [], "multiple_definitions": []} + else: + with open("errors.json", "r") as file: + content = json.load(file) + with open("errors.json", "w+") as file: + for blockTypeName in missingBlocks: + if not blockTypeName in content["missing_blocks"]: + content["missing_blocks"].append(blockTypeName) + for blockTypeName in multipleDefinitions: + if not blockTypeName in content["multiple_definitions"]: + content["multiple_definitions"].append(blockTypeName) + json.dump(content, file, indent=2) + file.close() + +def mapInputs(content, function, ports): + for entry in re.findall("\\w+ *= *%s\\(pSelf *, *\\d+\\);" % function, content): + name = re.search("^\\w+", entry).group() + position = int(re.search("\\d+(?= *\\) *;)", entry).group()) + ports.mapName(position, name, 0) + for entry in re.findall("\\w+->\\w+\\[\\d+\\] *= *%s\\(pSelf *, *\\d+\\);" % function, content): + name = re.search("(?<=\\->)\\w+", entry).group() + position = int(re.search("\\d+(?= *\\) *;)", entry).group()) + index = int(re.search("(?<=\\[)\\d+(?=\\])", entry).group()) + ports.mapName(position, name, index) + for entry in re.findall("\\w+\\[\\d+\\] *= *%s\\(pSelf *, *\\d+\\);" % function, content): + name = re.search("^\\w+", entry).group() + position = int(re.search("\\d+(?= *\\) *;)", entry).group()) + index = int(re.search("(?<=\\[)\\d+(?=\\])", entry).group()) + ports.mapName(position, name, index) + +def mapOutputs(content, function, ports): + for entry in re.findall("%s\\(pSelf *, *\\d+ *, *pSelfParam->\\w+\\);" % function, content): + name = re.search("\\w+(?=\\);$)", entry).group() + position = int(re.search("\\d+(?= *, *pSelfParam->\\w+\\);$)", entry).group()) + ports.mapName(position, name, 0) + for entry in re.findall("%s\\(pSelf *, *\\d+ *, *\\w+\\[\\d+\\]\\);" % function, content): + name = re.search("\\w+(?=\\[\\d+\\]\\);$)", entry).group() + position = int(re.search("\\d+(?= *, *\\w+\\[\\d+\\]\\);$)", entry).group()) + index = int(re.search("(?<=\\[)\\d+(?=\\])", entry).group()) + ports.mapName(position, name, index) + for entry in re.findall("%s\\(pSelf *, *\\d+ *, *pSelfParam->\\w+\\[\\d+\\]\\);" % function, content): + name = re.search("(?<=\\->)\\w+", entry).group() + position = int(re.search("\\d+(?= *, *pSelfParam->\\w+\\[\\d+\\]\\);$)", entry).group()) + index = int(re.search("(?<=\\[)\\d+(?=\\]\\);$)", entry).group()) + ports.mapName(position, name, index) + for entry in re.findall("%s\\(pSelf *, *\\d+ *, *\\w+\\);" % function, content): + name = re.search("\\w+(?= *\\);$)", entry).group() + position = int(re.search("\\d+(?= *, *\\w+\\);$)", entry).group()) + index = 0 + ports.mapName(position, name, index) diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3624768 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +__pycache__ +out +tacapp.tar.gz +Sources +tacapp +worryingFiles +cc.tar.gz diff --git a/errors.json b/errors.json new file mode 100644 index 0000000..5ec898a --- /dev/null +++ b/errors.json @@ -0,0 +1,4 @@ +{ + "missing_blocks": [], + "multiple_definitions": [] +} \ No newline at end of file diff --git a/hardcodedFiles/tacReadRmnBlock.c b/hardcodedFiles/tacReadRmnBlock.c new file mode 100644 index 0000000..8acbcfa --- /dev/null +++ b/hardcodedFiles/tacReadRmnBlock.c @@ -0,0 +1,568 @@ +/******************************************************************************* +* E.S.O. - VLT project +* +* "@(#) $Id: tacReadRmnBlock.c 305476 2018-01-19 08:56:18Z rfrahm $" +* +* who when what +* ------- -------- ---------------------------------------------- +* gzins 2010-07-27 ported to VLTSW2010 and VxWorks 6.4 +* swehner 2008-10-10 creation +*/ + +/************************************************************************ +* NAME +* tacReadRmnBlock - Implemements the standard functions for the +* tacReadRmn block and tacReadRfm block. +* tacReadRmnBlock - Reads from 1rst generation reflective memory network +* tacReadRfmBlock - Reads from 2nd generation reflective memory network + +* Parameters: +* field - token names for the RMN fields to read (up to 10) +* Inputs: 0 +* Outputs: 1 +* output - 1..10 depending on number of field parameters +* +* +* +* FILES +* +* ENVIRONMENT +* TAC +* +* RETURN VALUES +* +* CAUTIONS +* +* EXAMPLES +* TAC.BLOCK9.TYPE ReadRmn +* TAC.BLOCK9.NAME ReadRmn +* +* SEE ALSO +* +* BUGS +* +*------------------------------------------------------------------------ +*/ + +#define _POSIX_SOURCE 1 +#include "vltPort.h" + +ATTRIBUTE_UNUSED static const char *rcsId="@(#) $Id: tacReadRmnBlock.c 305476 2018-01-19 08:56:18Z rfrahm $"; + +/* + * System Headers + */ + +#include /* taskSpawn, taskDelay, ... */ +#include /* printf ... */ +#include /* malloc ... */ +#include /* malloc ... */ +#include +#include + +/* + * Local Headers + */ + +#include "tacStdBlock.h" +#include "tacRmnBlock.h" +#include "rmassPublic.h" +#include "rmassPrivate.h" + +/* + * Compilation directives + */ + +/* + * Constants + */ + +#define tacREAD_RMN_EXPECTED_PARAM 1 +#define tacREAD_RMN_DEFAULT_INPUT_NUMBER 0 +#define tacREAD_RMN_DEFAULT_OUTPUT_NUMBER tacMAX_DATA_NUMBER + +#define tacREAD_RMN_FIELD_STRING_LEN 256 +#define tacSTRLEN sizeof(double) + +/* + * Types + */ + +/* + * Local function declaration + */ + +/* + * Global variables + */ + +/* + * Function definition + */ + + +STATUS tacReadRmnBlockCheckParameter (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the ADDBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = NULL; + + pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + /* field string is built from block params */ + if ( tacRmnBlockCheckParameter ( pSelf, parameter, 0, error) != OK ) + { + return ERROR; + } + + /* useful information on the screen */ + printf ("ReadRmn %s: [%s]\n", pSelf->name, pSelfParam->fieldString); + + return OK; +} + +STATUS tacReadRfmBlockCheckParameter (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the ADDBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = NULL; + + pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + /* field string is built from block params */ + if ( tacRmnBlockCheckParameter ( pSelf, parameter, 0, error) != OK ) + { + return ERROR; + } + + /* useful information on the screen */ + printf ("ReadRfm %s: [%s]\n", pSelf->name, pSelfParam->fieldString); + + return OK; +} + +/* + * Constructor Hooks - Called when a block of this type is instanciated (CONFIG or ADDBLCK commands) + */ + +STATUS tacReadRmBlockConstructor (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the ADDBLCK command */ + vltLOGICAL isRmn, + tacERROR* error) /* Error structure - not a stack */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = NULL; + + /* Check that the expected number of parameters has been received */ + if (parameter->number < tacREAD_RMN_EXPECTED_PARAM) + { + char errorParam[40]; + + sprintf(errorParam, "Expected at least %d, received %d", tacREAD_RMN_EXPECTED_PARAM, parameter->number); + tacRTC_ERR(tacERR_PARAM_NUMBER, errorParam); + return ERROR; + } + + /* Allocate and initialize block-specific arrays */ + if (tacStdBlockAllocateArrays(pSelf, 0, tacREAD_RMN_DEFAULT_INPUT_NUMBER, tacREAD_RMN_DEFAULT_OUTPUT_NUMBER, error) == ERROR) + { + return ERROR; + } + + if (tacStdBlockAllocateArrayBySize(pSelf, tacSTDBLOCK_PARAM_ARRAY, sizeof(tacRMN_LOCAL_PARAMETER), error) == ERROR) + { + tacStdBlockReleaseArray(pSelf, tacSTDBLOCK_INPUT_ARRAY, error); + tacStdBlockReleaseArray(pSelf, tacSTDBLOCK_OUTPUT_ARRAY, error); + return ERROR; + } + + if ( isRmn ) + { + if ( tacReadRmnBlockCheckParameter (pSelf, parameter, error) == ERROR) + { + return ERROR; + } + } + else + { + if ( tacReadRfmBlockCheckParameter (pSelf, parameter, error) == ERROR) + { + return ERROR; + } + } + + pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + pSelfParam->handleValid = rmassACCESS_BLOCKED; + + /* Attach to RMN */ + if ( rmassReadAttach (&pSelfParam->handle, + pSelfParam->fieldString, + &pSelfParam->val[0], + &pSelfParam->val[1], + &pSelfParam->val[2], + &pSelfParam->val[3], + &pSelfParam->val[4], + &pSelfParam->val[5], + &pSelfParam->val[6], + &pSelfParam->val[7], + &pSelfParam->val[8], + &pSelfParam->val[9]) != SUCCESS ) + { + char errorParam[40]; + + sprintf(errorParam, "Attach to RMN failed."); + tacRTC_ERR(tacERR_INTERNAL, errorParam); + return ERROR; + } + + pSelfParam->handleValid = rmassACCESS_FREE; + + return OK; +} + +STATUS tacReadRmnBlockConstructor (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the ADDBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + if ( tacReadRmBlockConstructor (pSelf, parameter, ccsTRUE, error ) == ERROR ) + { + return ERROR; + } + return OK; +} + +STATUS tacReadRfmBlockConstructor (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the ADDBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + if ( tacReadRmBlockConstructor (pSelf, parameter, ccsFALSE, error ) == ERROR ) + { + return ERROR; + } + return OK; +} + + + +/* + * Destructor Hooks - Called when the block is removed from the algorithm (DELBLCK or new CONFIG commands) + */ + +void tacReadRmnBlockDestructor (tacSTDBLOCK* pSelf) /* Reference to the block instance */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = NULL; + pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + pSelfParam->handleValid = rmassACCESS_BLOCKED; + /* wait until semaphore is acknowledged by realtime algo + * or just procede if realtime is not active */ + while ((*pSelf->shared).active && pSelfParam->handleValid != rmassACCESS_BLOCK_ACKN) + { + taskDelay(1); + } + + rmassDetach (&pSelfParam->handle); + + return; +} + +/* + * Change parameters Hooks - Called when modifying the block parameters (MODBLCK command) + */ + +STATUS tacReadRmnBlockSetParameter (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the MODBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + if ( tacReadRmnBlockCheckParameter (pSelf, parameter, error) == ERROR) + { + return ERROR; + } + + pSelfParam->handleValid = rmassACCESS_BLOCKED; + /* wait until semaphore is acknowledged by realtime algo + * or just procede if realtime is not active */ + while ((*pSelf->shared).active && pSelfParam->handleValid != rmassACCESS_BLOCK_ACKN) + { + taskDelay(1); + } + + /* detach RMN handle */ + if ( rmassDetach (&pSelfParam->handle) != SUCCESS ) + { + char errorParam[40]; + + sprintf(errorParam, "rmassDetach returned error."); + tacRTC_ERR(tacERR_INTERNAL, errorParam); + return ERROR; + } + + if ( rmassReadAttach (&pSelfParam->handle, + pSelfParam->fieldString, + &pSelfParam->val[0], + &pSelfParam->val[1], + &pSelfParam->val[2], + &pSelfParam->val[3], + &pSelfParam->val[4], + &pSelfParam->val[5], + &pSelfParam->val[6], + &pSelfParam->val[7], + &pSelfParam->val[8], + &pSelfParam->val[9]) != SUCCESS ) + { + char errorParam[40]; + + sprintf(errorParam, "Attach to RMN failed."); + tacRTC_ERR(tacERR_INTERNAL, errorParam); + return ERROR; + } + + pSelfParam->handleValid = rmassACCESS_FREE; + + return OK; +} + +STATUS tacReadRfmBlockSetParameter (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the MODBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + if ( tacReadRfmBlockCheckParameter (pSelf, parameter, error) == ERROR) + { + return ERROR; + } + + pSelfParam->handleValid = rmassACCESS_BLOCKED; + /* wait until semaphore is acknowledged by realtime algo + * or just procede if realtime is not active */ + while ((*pSelf->shared).active && pSelfParam->handleValid != rmassACCESS_BLOCK_ACKN) + { + taskDelay(1); + } + + /* detach RMN handle */ + if ( rmassDetach (&pSelfParam->handle) != SUCCESS ) + { + char errorParam[40]; + + sprintf(errorParam, "rmassDetach returned error."); + tacRTC_ERR(tacERR_INTERNAL, errorParam); + return ERROR; + } + + if ( rmassReadAttach (&pSelfParam->handle, + pSelfParam->fieldString, + &pSelfParam->val[0], + &pSelfParam->val[1], + &pSelfParam->val[2], + &pSelfParam->val[3], + &pSelfParam->val[4], + &pSelfParam->val[5], + &pSelfParam->val[6], + &pSelfParam->val[7], + &pSelfParam->val[8], + &pSelfParam->val[9]) != SUCCESS ) + { + char errorParam[40]; + + sprintf(errorParam, "Attach to RFM failed."); + tacRTC_ERR(tacERR_INTERNAL, errorParam); + return ERROR; + } + + pSelfParam->handleValid = rmassACCESS_FREE; + + return OK; +} + +/* + * Algorithm Hooks - Called at each time the TAC algorithm is evaluated (ONLINE state) + */ + +void tacReadRmnBlockAlgorithm (tacSTDBLOCK* pSelf) /* Reference to the block instance */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + int i; + + if ( pSelfParam->handleValid == rmassACCESS_BLOCKED ) + { + pSelfParam->handleValid = rmassACCESS_BLOCK_ACKN; + } + + if ( pSelfParam->handleValid == rmassACCESS_FREE ) + { + /* actual RMN read operation */ + rmassReadAccessRmn (&pSelfParam->handle); + + /* Write to outputs */ + for (i=0; i < pSelfParam->numFields; i++) + { + switch (pSelfParam->type[i]) + { + case rmassTIMESEC: + case rmassUINT32: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).ui); + break; + case rmassTIMEUSEC: + case rmassINT32: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).i); + break; + case rmassFLOAT: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).f); + break; + default: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).d); + break; + } + } + + /* provide zero values at unsatisfied outputs + * I consider this a good thing to do since the block + * is always configured */ + for (i=pSelfParam->numFields; i < tacREAD_RMN_DEFAULT_OUTPUT_NUMBER; i++) + { + tacStdBlockSetOutput(pSelf, i, 0.0); + } + } +} + +void tacReadRfmBlockAlgorithm (tacSTDBLOCK* pSelf) /* Reference to the block instance */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + int i; + + if ( pSelfParam->handleValid == rmassACCESS_BLOCKED ) + { + pSelfParam->handleValid = rmassACCESS_BLOCK_ACKN; + } + + if ( pSelfParam->handleValid == rmassACCESS_FREE ) + { + /* actual RMN read operation */ + rmassReadAccessRfm (&pSelfParam->handle); + + /* Write to outputs */ + for (i=0; i < pSelfParam->numFields; i++) + { + switch (pSelfParam->type[i]) + { + case rmassTIMESEC: + case rmassUINT32: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).ui); + break; + case rmassTIMEUSEC: + case rmassINT32: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).i); + break; + case rmassFLOAT: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).f); + break; + default: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).d); + break; + } + } + + /* provide zero values at unsatisfied outputs + * I consider this a good thing to do since the block + * is always configured */ + for (i=pSelfParam->numFields; i < tacREAD_RMN_DEFAULT_OUTPUT_NUMBER; i++) + { + tacStdBlockSetOutput(pSelf, i, 0.0); + } + } +} + +/* + * Show Hooks - Called when the tacRtcTaskShow routine is executed + */ + +void tacReadRmnBlockShow (tacSTDBLOCK* pSelf) /* Reference to the block instance */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + /* Print parameter values */ + printf(" Attached: %s\n", pSelfParam->fieldString); + + return; +} + + +/***************************************************/ +/* The following code is common to all block types */ +/* Do not modify without any good reasons */ +/***************************************************/ + +/* + * Installation function + */ + +tacSTDBLOCK_TYPE tacReadRmnTypeInfo = { + "ReadRmn", + &tacReadRmnBlockConstructor, + &tacRmBlockGetParameter, + &tacReadRmnBlockAlgorithm, + &tacReadRmnBlockSetParameter, + NULL, + NULL, + &tacReadRmnBlockDestructor, + &tacReadRmnBlockShow +}; + +tacSTDBLOCK_TYPE tacReadRfmTypeInfo = { + "ReadRfm", + &tacReadRfmBlockConstructor, + &tacRmBlockGetParameter, + &tacReadRfmBlockAlgorithm, + &tacReadRmnBlockSetParameter, + NULL, + NULL, + &tacReadRmnBlockDestructor, + &tacReadRmnBlockShow +}; + +STATUS tacReadRmnBlockInitAll (void) +{ + /***************************************************/ + /* The following code is common to all block types */ + /* Do not modify without any good reasons */ + /***************************************************/ + + /* Install ReadRmn1g Block Hooks */ + tacStdBlockInstallNewType(&tacReadRmnTypeInfo); + + /*****************************/ + /* End of common code region */ + /*****************************/ + + /* Perform other library initialization operations */ + + return OK; +} + +STATUS tacReadRfmBlockInitAll (void) +{ + /***************************************************/ + /* The following code is common to all block types */ + /* Do not modify without any good reasons */ + /***************************************************/ + + /* Install ReadRmn1g Block Hooks */ + tacStdBlockInstallNewType(&tacReadRfmTypeInfo); + + /*****************************/ + /* End of common code region */ + /*****************************/ + + /* Perform other library initialization operations */ + + return OK; +} + +/*___oOo___*/ + + + diff --git a/hardcodedFiles/tacSinkBlock.c b/hardcodedFiles/tacSinkBlock.c new file mode 100644 index 0000000..df39833 --- /dev/null +++ b/hardcodedFiles/tacSinkBlock.c @@ -0,0 +1,1256 @@ +/******************************************************************************* +* E.S.O. - VLT project +* +* "@(#) $Id: tacSinkBlock.c 339094 2021-02-10 03:10:02Z jgil $" +* +* who when what +* ------- -------- ---------------------------------------------- +* rdembet 06/08/20 New MonitorState block with no data averaging +* swehner 28/11/09 SPR20090234 Correction in rate adjustment in reset hook +* swehner 27/11/09 Fixed message queue handling +* swehner 10/10/09 New block FastProbe for unlimited rec frequency +* swehner 22/09/09 PPRS 32341 Replaced specialized tacSINK_SHMSG stack +* with standard vxWorks message queue. +* bbauvir 21/09/04 VLTSW20040113 - One sample might be lost +* bbauvir 29/03/04 Monitor block averages over the reporting period +* bbauvir 29/12/02 Probe to the SampTask +* bbauvir 26/12/02 MsgQ access through DPC mechanism +* bbauvir 14/07/02 New MsgQ of TAC version 1.22 +* bbauvir 21/03/01 Created +*/ + +/************************************************************************ +* NAME +* tacSinkBlock - Standard data monitoring blocks +* +* SYNOPSIS +* lcubootAutoCdBoot 1,"tacsink.boot" +* < tacsink.boot +* +* DESCRIPTION +* Block type: Display +* Parameters: +* Inputs: 1 +* Outputs: none +* +* This function block samples the value of its input signal at the +* specified and issues a message containing the time +* and the value of the input on the vxWorks terminal. +* It does not allow modification of the parameter at runtime. +* +* Block type: Monitor +* Parameters: +* +* Inputs: 10max +* Outputs: none +* +* This function block samples the value of its input signals at the +* specified (0.0 to send a message at the system sampling +* period) and issues a message containing the time and the value of +* the inputs on the shared memory. This message is intercepted by the +* background task running on the master CPU. The monitored values are +* written into the online database. The number of inputs of the block +* is specified by parameter. +* This block does not allow modification of the parameters at runtime. +* +* Block type: MonitorState +* Parameters: +* +* Inputs: 10max +* Outputs: none +* +* Same as Monitor block but without the averaging of received data, +* see VLTSW-14260 JIRA ticket. +* +* Block type: Probe +* Parameters: +* +* Inputs: 10max +* Outputs: none +* +* Block type: FastProbe +* Parameters: +* +* Inputs: 10max +* Outputs: none +* +* This function block samples the value of its input signals at the +* specified (0.0 to send a message at the system sampling +* period) and issues a message containing the time and the value of +* the inputs on the shared memory. This message is intercepted by the +* background task running on the master CPU. The number of inputs of +* the block is specified by parameter. +* This message is passed to an external application callback if +* provided. +* This block does not allow modification of the parameters at runtime. +* The normal Probe block has a limited sampling frequency of not more +* than 2kHz. The reason is in particular the bottleneck between master +* and slave CPU which all samples have to pass through a mechanism of +* VME bus shared memory. On one-CPU-systems this limitation does not +* apply so you are free to choose faster sampling. You may of course +* hit other limitations (processor speed, network traffic etc.) +* +* FILES +* +* ENVIRONMENT +* TAC +* +* RETURN VALUES +* +* CAUTIONS +* All these blocks compute an decimation value to use to trigger the +* sampling of the input signals, from the system sampling period. +* They should be created after any synchronization block. +* +* In order to cope with system performances, a minimum +* is defined for each block. The minimum applied periods are 0.1 (10Hz), +* 0.01 (100Hz) and 0.5e-3 (2kHz) for the 'Display', 'Monitor' and +* 'Probe' blocks respectively. +* +* EXAMPLES +* # 5 signals @ 2Hz (monitored in the database) +* TAC.BLOCK9.TYPE Monitor +* TAC.BLOCK9.NAME Monitor +* TAC.BLOCK9.PARAM 0.5, 5 +* +* # 5 signals @ the RT algorithm sampling period (0.0) +* TAC.BLOCK10.TYPE Probe +* TAC.BLOCK10.NAME Probe +* TAC.BLOCK10.PARAM 0.0, 5 +* +* SEE ALSO +* tacServerInstallDataCallback, tacServerRemoveDataCallback +* +* BUGS +* +*------------------------------------------------------------------------ +*/ + +#define _POSIX_SOURCE 1 +#include "vltPort.h" + + +/* + * System Headers + */ + +#include +#include +#include /* logMsg ... */ +#include /* printf ... */ +#include /* malloc ... */ +#include /* memcpy ... */ +#include + +/* + * Local Headers + */ + +#include "tacStdBlock.h" +#include "tacShMsgQ.h" + +/* + * Compilation directives + */ + +/* + * Constants + */ + +#define tacSINK_DEFAULT_EXPECTED_PARAM 2 + +#define tacSINK_DEFAULT_INPUT_NUMBER tacMAX_DATA_NUMBER /* Up to 10 input channels */ +#define tacSINK_DEFAULT_OUTPUT_NUMBER tacMAX_DATA_NUMBER + +#define tacSINK_ONE_EXPECTED_PARAM 1 +#define tacSINK_ONE_INPUT_NUMBER 1 + +#define tacSINK_DISPLAY_MIN_SAMPLING_PERIOD .1 /* 10Hz */ +#define tacSINK_MONITOR_MIN_SAMPLING_PERIOD .01 /* 100Hz */ +#define tacSINK_PROBE_MIN_SAMPLING_PERIOD .5e-3 /* 2kHz */ + +#define tacSINK_DISPLAY_LOG_STRING_SIZE 128 + +#define tacSINK_MONITOR_DEFAULT_DB_POINT "tac:data:monitor" +#define tacSINK_MONITOR_MAX_DB_ADDR_SIZE 64 + +#define tacSINK_MONITOR_QUEUE_SIZE 6 +#define tacSINK_PROBE_QUEUE_SIZE 6 + + +typedef enum { + tacSINK_SAMPLING_PERIOD = 0, + tacSINK_INPUT_NUMBER, + tacSINK_MONITOR_DB_POINT, +}tacSINK_SCOPE_PARAM_INDEX; + +/* + * Types + */ + +typedef struct { + unsigned short rate; + unsigned short counter; + unsigned short inputNb; + unsigned int lost; + double rateParam; + char* dbPoint; + MSG_Q_ID msgq; + tacSHMSG shmMsg; +}tacSINK_SCOPE_LOCAL_PARAMETER; + +/* + * Function declaration + */ + +extern STATUS tacDpcPushRequest(tacVOIDFCTPTR pFunct, void* parameter); + +/* + * Local function declaration + */ + +/* + * Note: Routines called from within the algorithm must be declared with + * static __inline__ + */ + +STATUS tacSinkSendMonitorMessage(MSG_Q_ID * msgqvoid); +STATUS tacSinkSendMonitorStateMessage(MSG_Q_ID * msgqvoid); +STATUS tacSinkSendProbeMessage(MSG_Q_ID * msgq); +STATUS tacSinkDeleteMessageQueue(MSG_Q_ID * msgq); +STATUS tacSinkCommonBlockConstructor(tacSTDBLOCK* pSelf, tacERROR* error); + +/* + * Global variables + */ + +char logStr[tacSINK_DISPLAY_LOG_STRING_SIZE]; /* Logging string used for Display */ + + +/* + * Function definition + */ + +/* + * Constructor Hooks + */ + +STATUS tacSinkDisplayBlockConstructor (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = NULL; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = NULL; + + /* Check that the expected number of parameters has been received */ + if (parameter->number < tacSINK_ONE_EXPECTED_PARAM) + { + char errorParam[40]; + + sprintf(errorParam, "Expected %d, received %d", tacSINK_ONE_EXPECTED_PARAM, parameter->number); + tacRTC_ERR(tacERR_PARAM_NUMBER, errorParam); + return ERROR; + } + + /* Check that the parameters are valid */ + pRealParam = (double*) parameter->buffer; + + /* Passed parameter is the sampling period of the block */ + if (pRealParam[tacSINK_SAMPLING_PERIOD] < (*pSelf->shared).samplingPeriod) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = (*pSelf->shared).samplingPeriod; + } + + if (pRealParam[tacSINK_SAMPLING_PERIOD] < tacSINK_DISPLAY_MIN_SAMPLING_PERIOD) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = tacSINK_DISPLAY_MIN_SAMPLING_PERIOD; + } + + /* Call common constructor */ + if (tacSinkCommonBlockConstructor(pSelf, error) != OK) + { + return ERROR; + } + + /* Store parameters */ + pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; /* We will only store short integers */ + + /* + * Compute the rate at which data has to be processed - divide and take + * the integer part of the result + */ + + pSelfParam->rate = (unsigned short) (pRealParam[tacSINK_SAMPLING_PERIOD] / (*pSelf->shared).samplingPeriod); + pSelfParam->counter = 0; /* Decimation counter */ + + /* + * Perform other block initialization operations + */ + + return OK; +} + +STATUS tacSinkMonitorBlockConstructor (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = NULL; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = NULL; + unsigned short arrayIndex = 0; + + /* Check that the expected number of parameters has been received */ + if (parameter->number < tacSINK_DEFAULT_EXPECTED_PARAM) + { + char errorParam[40]; + + sprintf(errorParam, "Expected %d, received %d", tacSINK_DEFAULT_EXPECTED_PARAM, parameter->number); + tacRTC_ERR(tacERR_PARAM_NUMBER, errorParam); + return ERROR; + } + + /* Check that the parameters are valid */ + pRealParam = (double*) parameter->buffer; + + /* Passed parameter is the sampling period of the block */ + if (pRealParam[tacSINK_SAMPLING_PERIOD] < (*pSelf->shared).samplingPeriod) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = (*pSelf->shared).samplingPeriod; + } + + if (pRealParam[tacSINK_SAMPLING_PERIOD] < tacSINK_MONITOR_MIN_SAMPLING_PERIOD) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = tacSINK_MONITOR_MIN_SAMPLING_PERIOD; + } + + /* Number of inputs is minimum 1 up to tacMSG_MAX_DATA_NUMBER */ + if ((pRealParam[tacSINK_INPUT_NUMBER] < 1) || + (pRealParam[tacSINK_INPUT_NUMBER] > tacMAX_DATA_NUMBER)) + { + tacRTC_ERR(tacERR_PARAM_INVALID, ""); + return ERROR; + } + + /* Call common constructor */ + if (tacSinkCommonBlockConstructor(pSelf, error) != OK) + { + return ERROR; + } + + /* Store parameters */ + pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* + * Compute the rate at which data has to be processed - divide and take + * the integer part of the result + */ + + pSelfParam->rate = (unsigned short) (pRealParam[tacSINK_SAMPLING_PERIOD] / (*pSelf->shared).samplingPeriod); + pSelfParam->counter = 0; /* Decimation counter */ + pSelfParam->inputNb = (unsigned short) pRealParam[tacSINK_INPUT_NUMBER]; + + /* Optional parameter is an application-specific DB point */ + if (parameter->number == tacSINK_DEFAULT_EXPECTED_PARAM + 1) + { + printf("tacSinkMonitorBlockConstructor - DB point %s\n",(char*) &(pRealParam[tacSINK_MONITOR_DB_POINT])); + pSelfParam->dbPoint = (char*) malloc(tacSINK_MONITOR_MAX_DB_ADDR_SIZE); + strcpy(pSelfParam->dbPoint, (char*) &(pRealParam[tacSINK_MONITOR_DB_POINT])); + } + else + { + printf("tacSinkMonitorBlockConstructor - Default DB point\n"); + pSelfParam->dbPoint = NULL; + } + + /* Specify the number of input signals to attach to become resolved */ + tacStdBlockSetInputNumber(pSelf, pSelfParam->inputNb); + + /* + * Perform other block initialization operations + */ + + /* Create the block internal message queue which tosses the messages out of the + * interrupt context. They are buffered in the queue until the DPC tasks + * picks them up and sends them over the shared memory message queue. + * Sorry for that double-queuing, that's because of the M-S architecture */ + + pSelfParam->msgq = msgQCreate(tacSINK_MONITOR_QUEUE_SIZE, sizeof(tacSHMSG), 0); + if ( pSelfParam->msgq == NULL ) + { + char errorParam[40]; + + sprintf(errorParam, "Could not create probe block message queue"); + tacRTC_ERR(tacERR_MALLOC, errorParam); + return ERROR; + } + + /* will count if a message can't be pushed in the queue */ + pSelfParam->lost = 0; + + /* Warn the background task that a new probe block has been created */ + pSelfParam->shmMsg.type = tacSHMSG_ADD_MONITOR; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + + if (pSelfParam->dbPoint == NULL) + { + strcpy((char*) &(pSelfParam->shmMsg.msgBody.monitor.data), tacSINK_MONITOR_DEFAULT_DB_POINT); + } + else + { + strcpy((char*) &(pSelfParam->shmMsg.msgBody.monitor.data), *((char**) &(pSelfParam->dbPoint))); + } + + printf("tacSinkMonitorBlockConstructor - Attach to %s\n",(char*) &(pSelfParam->shmMsg.msgBody.monitor.data)); + + /* Send message */ + tacShMsgQSendBgInfo(&(pSelfParam->shmMsg)); + + /* Initialize the message parameters */ + pSelfParam->shmMsg.type = tacSHMSG_MONITOR_DATA; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + pSelfParam->shmMsg.msgBody.monitor.data.number = pSelfParam->inputNb; + + /* The output port is used to average the inputs over the reporting period */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pSelf->output[arrayIndex] = 0.0; + } + + return OK; +} + +STATUS tacSinkMonitorStateBlockConstructor (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = NULL; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = NULL; + unsigned short arrayIndex = 0; + + /* Check that the expected number of parameters has been received */ + if (parameter->number < tacSINK_DEFAULT_EXPECTED_PARAM) + { + char errorParam[40]; + + sprintf(errorParam, "Expected %d, received %d", tacSINK_DEFAULT_EXPECTED_PARAM, parameter->number); + tacRTC_ERR(tacERR_PARAM_NUMBER, errorParam); + return ERROR; + } + + /* Check that the parameters are valid */ + pRealParam = (double*) parameter->buffer; + + /* Passed parameter is the sampling period of the block */ + if (pRealParam[tacSINK_SAMPLING_PERIOD] < (*pSelf->shared).samplingPeriod) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = (*pSelf->shared).samplingPeriod; + } + + if (pRealParam[tacSINK_SAMPLING_PERIOD] < tacSINK_MONITOR_MIN_SAMPLING_PERIOD) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = tacSINK_MONITOR_MIN_SAMPLING_PERIOD; + } + + /* Number of inputs is minimum 1 up to tacMSG_MAX_DATA_NUMBER */ + if ((pRealParam[tacSINK_INPUT_NUMBER] < 1) || + (pRealParam[tacSINK_INPUT_NUMBER] > tacMAX_DATA_NUMBER)) + { + tacRTC_ERR(tacERR_PARAM_INVALID, ""); + return ERROR; + } + + /* Call common constructor */ + if (tacSinkCommonBlockConstructor(pSelf, error) != OK) + { + return ERROR; + } + + /* Store parameters */ + pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* + * Compute the rate at which data has to be processed - divide and take + * the integer part of the result + */ + + pSelfParam->rate = (unsigned short) (pRealParam[tacSINK_SAMPLING_PERIOD] / (*pSelf->shared).samplingPeriod); + pSelfParam->counter = 0; /* Decimation counter */ + pSelfParam->inputNb = (unsigned short) pRealParam[tacSINK_INPUT_NUMBER]; + + /* Optional parameter is an application-specific DB point */ + if (parameter->number == tacSINK_DEFAULT_EXPECTED_PARAM + 1) + { + printf("tacSinkMonitorStateBlockConstructor - DB point %s\n",(char*) &(pRealParam[tacSINK_MONITOR_DB_POINT])); + pSelfParam->dbPoint = (char*) malloc(tacSINK_MONITOR_MAX_DB_ADDR_SIZE); + strcpy(pSelfParam->dbPoint, (char*) &(pRealParam[tacSINK_MONITOR_DB_POINT])); + } + else + { + printf("tacSinkMonitorStateBlockConstructor - Default DB point\n"); + pSelfParam->dbPoint = NULL; + } + + /* Specify the number of input signals to attach to become resolved */ + tacStdBlockSetInputNumber(pSelf, pSelfParam->inputNb); + + /* + * Perform other block initialization operations + */ + + /* Create the block internal message queue which tosses the messages out of the + * interrupt context. They are buffered in the queue until the DPC tasks + * picks them up and sends them over the shared memory message queue. + * Sorry for that double-queuing, that's because of the M-S architecture */ + + pSelfParam->msgq = msgQCreate(tacSINK_MONITOR_QUEUE_SIZE, sizeof(tacSHMSG), 0); + if ( pSelfParam->msgq == NULL ) + { + char errorParam[40]; + + sprintf(errorParam, "Could not create probe block message queue"); + tacRTC_ERR(tacERR_MALLOC, errorParam); + return ERROR; + } + + /* will count if a message can't be pushed in the queue */ + pSelfParam->lost = 0; + + /* Warn the background task that a new probe block has been created */ + pSelfParam->shmMsg.type = tacSHMSG_ADD_MONITOR; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + + if (pSelfParam->dbPoint == NULL) + { + strcpy((char*) &(pSelfParam->shmMsg.msgBody.monitor.data), tacSINK_MONITOR_DEFAULT_DB_POINT); + } + else + { + strcpy((char*) &(pSelfParam->shmMsg.msgBody.monitor.data), *((char**) &(pSelfParam->dbPoint))); + } + + printf("tacSinkMonitorStateBlockConstructor - Attach to %s\n",(char*) &(pSelfParam->shmMsg.msgBody.monitor.data)); + + /* Send message */ + tacShMsgQSendBgInfo(&(pSelfParam->shmMsg)); + + /* Initialize the message parameters */ + pSelfParam->shmMsg.type = tacSHMSG_MONITOR_DATA; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + pSelfParam->shmMsg.msgBody.monitor.data.number = pSelfParam->inputNb; + + /* Init output port which won't be used to average the inputs over the reporting period */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pSelf->output[arrayIndex] = 0.0; + } + + return OK; +} + +STATUS tacSinkProbeBlockCommonConstructor (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + double minPeriod, + tacERROR* error) +{ + double* pRealParam = NULL; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = NULL; + + /* Check that the expected number of parameters has been received */ + if (parameter->number < tacSINK_DEFAULT_EXPECTED_PARAM) + { + char errorParam[40]; + + sprintf(errorParam, "Expected %d, received %d", tacSINK_DEFAULT_EXPECTED_PARAM, parameter->number); + tacRTC_ERR(tacERR_PARAM_NUMBER, errorParam); + return ERROR; + } + + /* Check that the parameters are valid */ + pRealParam = (double*) parameter->buffer; + + /* Passed parameter is the sampling period of the block */ + if (pRealParam[tacSINK_SAMPLING_PERIOD] < (*pSelf->shared).samplingPeriod) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = (*pSelf->shared).samplingPeriod; + } + + if (pRealParam[tacSINK_SAMPLING_PERIOD] < minPeriod) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = minPeriod; + } + + /* Number of inputs is minimum 1 up to tacMSG_MAX_DATA_NUMBER */ + if ((pRealParam[tacSINK_INPUT_NUMBER] < 1) || + (pRealParam[tacSINK_INPUT_NUMBER] > tacMAX_DATA_NUMBER)) + { + tacRTC_ERR(tacERR_PARAM_INVALID, ""); + return ERROR; + } + + /* Call common constructor */ + if (tacSinkCommonBlockConstructor(pSelf, error) != OK) + { + return ERROR; + } + + /* Store parameters */ + pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* + * Compute the rate at which data has to be processed - divide and take + * the integer part of the result + */ + + pSelfParam->rateParam = pRealParam[tacSINK_SAMPLING_PERIOD]; + pSelfParam->rate = (unsigned short) (pRealParam[tacSINK_SAMPLING_PERIOD] / (*pSelf->shared).samplingPeriod); + pSelfParam->counter = 0; /* Decimation counter */ + pSelfParam->inputNb = (unsigned short) pRealParam[tacSINK_INPUT_NUMBER]; + + /* Specify the number of input signals to attach to become resolved */ + tacStdBlockSetInputNumber(pSelf, pSelfParam->inputNb); + + /* + * Perform other block initialization operations + */ + + /* Create the block internal message queue which gets the messages out of the + * interrupt context. They are buffered in the queue until the DPC tasks + * picks them up and sends them over the shared memory message queue. + * Sorry for that double-queuing, that's because of the M-S architecture */ + + /* There is only one message queue for all probe blocks! */ + pSelfParam->msgq = msgQCreate(tacSINK_PROBE_QUEUE_SIZE, sizeof(tacSHMSG), 0); + if ( pSelfParam->msgq == NULL ) + { + char errorParam[40]; + + sprintf(errorParam, "Could not create probe block message queue"); + tacRTC_ERR(tacERR_MALLOC, errorParam); + return ERROR; + } + + /* will count if a message can't be pushed in the queue */ + pSelfParam->lost = 0; + + /* Warn the background task that a new probe block has been created */ + pSelfParam->shmMsg.type = tacSHMSG_ADD_PROBE; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + + /* Send message */ + tacShMsgQSendDataSample(&pSelfParam->shmMsg); + + /* Initialize the message parameters */ + pSelfParam->shmMsg.type = tacSHMSG_TRANSFER_DATA; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + pSelfParam->shmMsg.msgBody.monitor.data.number = pSelfParam->inputNb; + + return OK; +} + +/* Probe block has a max. sampling frequency of 2kHz */ +STATUS tacSinkProbeBlockConstructor (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + return tacSinkProbeBlockCommonConstructor (pSelf, parameter, tacSINK_PROBE_MIN_SAMPLING_PERIOD, error); +} + +/* Fast probe is the same as probe but not does have the + * limitation on the max. recording frequency */ +STATUS tacSinkFastProbeBlockConstructor (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + return tacSinkProbeBlockCommonConstructor (pSelf, parameter, 0.0, error); +} + +void tacSinkProbeBlockReset (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = + (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* + * Re-Compute the rate at which data has to be processed + */ + if (pSelfParam->rateParam < (*pSelf->shared).samplingPeriod ) + { + pSelfParam->rate = 1; + } + else + { + pSelfParam->rate = (unsigned short) + (pSelfParam->rateParam / (*pSelf->shared).samplingPeriod); + } + + return; +} + +/* + * Report parameters Hooks + */ + +STATUS tacSinkDisplayBlockGetParameter (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = (double*) parameter->buffer; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Send back the expected number of parameters */ + parameter->number = tacSINK_ONE_EXPECTED_PARAM; + + /* Report current parameters */ + pRealParam[tacSINK_SAMPLING_PERIOD] = (double) (pSelfParam->rate * (*pSelf->shared).samplingPeriod); + + return OK; +} + +STATUS tacSinkMonitorBlockGetParameter (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = (double*) parameter->buffer; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Send back the expected number of parameters */ + parameter->number = tacSINK_DEFAULT_EXPECTED_PARAM; + + /* Report current parameters */ + pRealParam[tacSINK_SAMPLING_PERIOD] = (double) (pSelfParam->rate * (*pSelf->shared).samplingPeriod); + pRealParam[tacSINK_INPUT_NUMBER] = (double) pSelfParam->inputNb; + + if (*((char**) &(pSelfParam->dbPoint)) != NULL) + { + parameter->number += 1; + parameter->type[tacSINK_MONITOR_DB_POINT] = tacPARAM_STRING; + strcpy((char*) &(pRealParam[tacSINK_MONITOR_DB_POINT]), *((char**) &(pSelfParam->dbPoint))); + } + + return OK; +} + +STATUS tacSinkMonitorStateBlockGetParameter (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = (double*) parameter->buffer; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Send back the expected number of parameters */ + parameter->number = tacSINK_DEFAULT_EXPECTED_PARAM; + + /* Report current parameters */ + pRealParam[tacSINK_SAMPLING_PERIOD] = (double) (pSelfParam->rate * (*pSelf->shared).samplingPeriod); + pRealParam[tacSINK_INPUT_NUMBER] = (double) pSelfParam->inputNb; + + if (*((char**) &(pSelfParam->dbPoint)) != NULL) + { + parameter->number += 1; + parameter->type[tacSINK_MONITOR_DB_POINT] = tacPARAM_STRING; + strcpy((char*) &(pRealParam[tacSINK_MONITOR_DB_POINT]), *((char**) &(pSelfParam->dbPoint))); + } + + return OK; +} + +STATUS tacSinkProbeBlockGetParameter (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = (double*) parameter->buffer; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Send back the expected number of parameters */ + parameter->number = tacSINK_DEFAULT_EXPECTED_PARAM; + + /* Report current parameters */ + pRealParam[tacSINK_SAMPLING_PERIOD] = (double) (pSelfParam->rate * (*pSelf->shared).samplingPeriod); + pRealParam[tacSINK_INPUT_NUMBER] = (double) pSelfParam->inputNb; + + return OK; +} + +/* + * Change parameters Hooks + */ + +/* + * Algorithm Hooks + */ + +void tacSinkDisplayBlockAlgorithm (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + if ((pSelfParam->counter % pSelfParam->rate) == 0) /* It's time to process data */ + { + sprintf(logStr,"Name: %s Time: %ld.%6ld Value: %g\n", + pSelf->name, + (*pSelf->shared).currentTime.seconds, + (*pSelf->shared).currentTime.microsec, + tacStdBlockGetInput(pSelf,0)); + + tacDpcPushRequest((tacVOIDFCTPTR) &printf, logStr); + + pSelfParam->counter = 0; + } + + pSelfParam->counter++; +} + +void tacSinkMonitorBlockAlgorithm (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + unsigned short arrayIndex = 0; + + /* The output port is used to average the inputs over the reporting period */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pSelf->output[arrayIndex] += tacStdBlockGetInput(pSelf,arrayIndex); + } + + if ((pSelfParam->counter % pSelfParam->rate) == 0) /* It's time to process data */ + { + tacDATA* pData = &(pSelfParam->shmMsg.msgBody.monitor.data); /* We are only interested in message body */ + + /* pData->number = pSelfParam->inputNb; */ + pData->timeStamp = (*pSelf->shared).currentTime; + + /* pData points to the body of the Message */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pData->buffer[arrayIndex] = pSelf->output[arrayIndex] / pSelfParam->rate; + } + + /* Push message into probe block's message que to get the + * data out of the interrupt comtext. */ + if ( msgQSend (pSelfParam->msgq, (char*) &(pSelfParam->shmMsg), sizeof(tacSHMSG), NO_WAIT, 0) != OK ) + { + (pSelfParam->lost)++; + } + + /* Defer procedure call */ + tacDpcPushRequest((tacVOIDFCTPTR) &tacSinkSendMonitorMessage, &pSelfParam->msgq); + + pSelfParam->counter = 0; + + /* The output port is used to average the inputs over the reporting period */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pSelf->output[arrayIndex] = 0.0; + } + } + + pSelfParam->counter++; +} + +void tacSinkMonitorStateBlockAlgorithm (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + unsigned short arrayIndex = 0; + + if ((pSelfParam->counter % pSelfParam->rate) == 0) /* It's time to process data */ + { + tacDATA* pData = &(pSelfParam->shmMsg.msgBody.monitor.data); /* We are only interested in message body */ + + /* pData->number = pSelfParam->inputNb; */ + pData->timeStamp = (*pSelf->shared).currentTime; + + /* pData points to the body of the Message */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pData->buffer[arrayIndex] = tacStdBlockGetInput(pSelf,arrayIndex); + } + + /* Push message into probe block's message que to get the + * data out of the interrupt comtext. */ + if ( msgQSend (pSelfParam->msgq, (char*) &(pSelfParam->shmMsg), sizeof(tacSHMSG), NO_WAIT, 0) != OK ) + { + (pSelfParam->lost)++; + } + + /* Defer procedure call */ + tacDpcPushRequest((tacVOIDFCTPTR) &tacSinkSendMonitorMessage, &pSelfParam->msgq); + + pSelfParam->counter = 0; + } + + pSelfParam->counter++; +} + +void tacSinkProbeBlockAlgorithm (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + unsigned short arrayIndex = 0; + + if ((pSelfParam->counter % pSelfParam->rate) == 0) /* It's time to process data */ + { + tacDATA* pData = &(pSelfParam->shmMsg.msgBody.monitor.data); /* We are only interested in message body */ + + pData->timeStamp = (*pSelf->shared).currentTime; + + /* pData points to the body of the Message */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pData->buffer[arrayIndex] = tacStdBlockGetInput(pSelf,arrayIndex); + } + + /* Push message into probe block's message que to get the + * data out of the interrupt comtext. */ + if ( msgQSend (pSelfParam->msgq, (char*) &(pSelfParam->shmMsg), sizeof(tacSHMSG), NO_WAIT, 0) != OK ) + { + (pSelfParam->lost)++; + } + + /* Defer procedure call: + * tacSinkSendProbeMessage is called outside the interrupt routine + * and will take care to pick up the message from the probe block's + * message queue and send it over the shared memory message queue */ + tacDpcPushRequest((tacVOIDFCTPTR) &tacSinkSendProbeMessage, &pSelfParam->msgq); + + pSelfParam->counter = 0; + } + + pSelfParam->counter++; +} + +/* + * Reset Hooks + */ + +/* + * Stop Hooks + */ + +/* + * Destructor Hooks + */ + +/* + * Note: This destructor is used mainly to send a MONITOR message containing + * 0.0 in order to reset the database array (otherwise going from an + * algorithm with 4 monitored data to one with 3 monitored data leaves + * the 4th value equal to the last ...) + */ + +void tacSinkMonitorBlockDestructor (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + tacDATA* pData = &(pSelfParam->shmMsg.msgBody.monitor.data); + unsigned short arrayIndex = 0; + + /* Reset DB values */ + pSelfParam->shmMsg.type = tacSHMSG_MONITOR_DATA; + pData = &(pSelfParam->shmMsg.msgBody.monitor.data); + + pData->number = pSelfParam->inputNb; + + /* pData points to the body of the Message */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pData->buffer[arrayIndex] = 0.0; + } + + /* Send message */ + tacShMsgQSendBgInfo(&pSelfParam->shmMsg); + + pSelfParam->shmMsg.type = tacSHMSG_REMOVE_MONITOR; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + + /* Send message */ + tacShMsgQSendBgInfo(&pSelfParam->shmMsg); + + free(pSelfParam->dbPoint); + + /* delete internal message queue. Do this as deferred procedure call + * to make sure it is only called when all messages have been send + * (through the same deferred call mechanism) */ + tacDpcPushRequest((tacVOIDFCTPTR) tacSinkDeleteMessageQueue, &(pSelfParam->msgq)); + + return; +} + +void tacSinkMonitorStateBlockDestructor (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + tacDATA* pData = &(pSelfParam->shmMsg.msgBody.monitor.data); + unsigned short arrayIndex = 0; + + /* Reset DB values */ + pSelfParam->shmMsg.type = tacSHMSG_MONITOR_DATA; + pData = &(pSelfParam->shmMsg.msgBody.monitor.data); + + pData->number = pSelfParam->inputNb; + + /* pData points to the body of the Message */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pData->buffer[arrayIndex] = 0.0; + } + + /* Send message */ + tacShMsgQSendBgInfo(&pSelfParam->shmMsg); + + pSelfParam->shmMsg.type = tacSHMSG_REMOVE_MONITOR; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + + /* Send message */ + tacShMsgQSendBgInfo(&pSelfParam->shmMsg); + + free(pSelfParam->dbPoint); + + /* delete internal message queue. Do this as deferred procedure call + * to make sure it is only called when all messages have been send + * (through the same deferred call mechanism) */ + tacDpcPushRequest((tacVOIDFCTPTR) tacSinkDeleteMessageQueue, &(pSelfParam->msgq)); + + return; +} + +void tacSinkProbeBlockDestructor (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + pSelfParam->shmMsg.type = tacSHMSG_REMOVE_PROBE; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + + /* Send message */ + tacShMsgQSendDataSample(&pSelfParam->shmMsg); + + /* delete internal message queue. Do this as deferred procedure call + * to make sure it is only called when all messages have been send + * (through the same deferred call mechanism) */ + tacDpcPushRequest((tacVOIDFCTPTR) tacSinkDeleteMessageQueue, &(pSelfParam->msgq)); + + return; +} + +/* + * Show Hooks + */ + +void tacSinkDisplayBlockShow (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Print parameter values */ + printf(" Update rate: %d\n",pSelfParam->rate); + + return; +} + +void tacSinkMonitorBlockShow (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Print parameter values */ + printf(" Update rate: %d\n",pSelfParam->rate); + printf(" Number of input signals: %d\n",pSelfParam->inputNb); + printf(" Queued samples: %d\n", msgQNumMsgs(pSelfParam->msgq)); + printf(" Lost samples: %d\n",pSelfParam->lost); + + if (pSelfParam->dbPoint != NULL) + { + printf(" DB Point: %s\n", pSelfParam->dbPoint); + } + + return; +} + +void tacSinkMonitorStateBlockShow (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Print parameter values */ + printf(" Using MonitorState block, not averaging received data\n"); + printf(" Update rate: %d\n",pSelfParam->rate); + printf(" Number of input signals: %d\n",pSelfParam->inputNb); + printf(" Queued samples: %d\n", msgQNumMsgs(pSelfParam->msgq)); + printf(" Lost samples: %d\n",pSelfParam->lost); + + if (pSelfParam->dbPoint != NULL) + { + printf(" DB Point: %s\n", pSelfParam->dbPoint); + } + + return; +} + +void tacSinkProbeBlockShow (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Print parameter values */ + printf(" Update rate: %d\n",pSelfParam->rate); + printf(" Update rate param (sec): %f\n",pSelfParam->rateParam); + printf(" Number of input signals: %d\n",pSelfParam->inputNb); + printf(" Queued samples: %d\n", msgQNumMsgs(pSelfParam->msgq)); + printf(" Lost samples: %d\n",pSelfParam->lost); + + return; +} + +/* + * Installation function + */ + +tacSTDBLOCK_TYPE tacSinkDisplayTypeInfo = { + "Display", + &tacSinkDisplayBlockConstructor, + &tacSinkDisplayBlockGetParameter, + &tacSinkDisplayBlockAlgorithm, + NULL, + NULL, + NULL, + NULL, + &tacSinkDisplayBlockShow, +}; + +tacSTDBLOCK_TYPE tacSinkMonitorTypeInfo = { + "Monitor", + &tacSinkMonitorBlockConstructor, + &tacSinkMonitorBlockGetParameter, + &tacSinkMonitorBlockAlgorithm, + NULL, + NULL, + NULL, + &tacSinkMonitorBlockDestructor, + &tacSinkMonitorBlockShow, +}; + +tacSTDBLOCK_TYPE tacSinkMonitorStateTypeInfo = { + "MonitorState", + &tacSinkMonitorStateBlockConstructor, + &tacSinkMonitorStateBlockGetParameter, + &tacSinkMonitorStateBlockAlgorithm, + NULL, + NULL, + NULL, + &tacSinkMonitorStateBlockDestructor, + &tacSinkMonitorStateBlockShow, +}; + +/* Probe with a maximal sampling rate of 2kHz */ +tacSTDBLOCK_TYPE tacSinkProbeTypeInfo = { + "Probe", + &tacSinkProbeBlockConstructor, + &tacSinkProbeBlockGetParameter, + &tacSinkProbeBlockAlgorithm, + NULL, + &tacSinkProbeBlockReset, + NULL, + &tacSinkProbeBlockDestructor, + &tacSinkProbeBlockShow, +}; + +/* Fast probe is the same as probe but not does have the + * limitation on the max. recording frequency */ +tacSTDBLOCK_TYPE tacSinkFastProbeTypeInfo = { + "FastProbe", + &tacSinkFastProbeBlockConstructor, + &tacSinkProbeBlockGetParameter, + &tacSinkProbeBlockAlgorithm, + NULL, + &tacSinkProbeBlockReset, + NULL, + &tacSinkProbeBlockDestructor, + &tacSinkProbeBlockShow, +}; + +STATUS tacSinkBlockInitAll (void) +{ + /* Install Sink Block Hooks */ + tacStdBlockInstallNewType(&tacSinkDisplayTypeInfo); + tacStdBlockInstallNewType(&tacSinkMonitorTypeInfo); + tacStdBlockInstallNewType(&tacSinkMonitorStateTypeInfo); + tacStdBlockInstallNewType(&tacSinkProbeTypeInfo); + tacStdBlockInstallNewType(&tacSinkFastProbeTypeInfo); + + /* + * Perform other library initialization operations + */ + + return OK; +} + +/* + * Local functions + */ + +/* + * Note: Routines called from within the algorithm must be declared with + * static __inline__ + */ + +STATUS tacSinkCommonBlockConstructor (tacSTDBLOCK* pSelf, + tacERROR* error) +{ + /* Allocate specific arrays (pointers are initialized to NULL by StdBlock) */ + if (tacStdBlockAllocateArrays(pSelf, 0, tacSINK_DEFAULT_INPUT_NUMBER, + tacSINK_DEFAULT_OUTPUT_NUMBER, error) == ERROR) + { + return ERROR; + } + + if (tacStdBlockAllocateArrayBySize(pSelf, tacSTDBLOCK_PARAM_ARRAY, + sizeof(tacSINK_SCOPE_LOCAL_PARAMETER), error) == ERROR) + { + tacStdBlockReleaseArray(pSelf, tacSTDBLOCK_INPUT_ARRAY, error); + tacStdBlockReleaseArray(pSelf, tacSTDBLOCK_OUTPUT_ARRAY, error); + return ERROR; + } + + /* Specify the number of input signals to attach to become resolved */ + tacStdBlockSetInputNumber(pSelf, tacSINK_ONE_INPUT_NUMBER); /* Required */ + + return OK; +} + +STATUS tacSinkSendMonitorMessage(MSG_Q_ID * msgq) +{ + /* Send message using provided function (different for Monitor and Probe blocks) */ + /* Send message using provided function (different for Monitor and Probe blocks) */ + tacSHMSG msg; + + if ( msgQReceive(*msgq, (char*) &msg, sizeof(tacSHMSG), NO_WAIT) == sizeof(tacSHMSG) ) + { + tacShMsgQSendBgInfo (&msg); + } + + return OK; +} + +STATUS tacSinkSendProbeMessage(MSG_Q_ID * msgq) +{ + /* Send message using provided function (different for Monitor and Probe blocks) */ + tacSHMSG msg; + + if ( msgq == NULL ) + { + return ERROR; + } + + if ( msgQReceive(*msgq, (char*) &msg, sizeof(tacSHMSG), NO_WAIT) == sizeof(tacSHMSG) ) + { + tacShMsgQSendDataSample (&msg); + } + return OK; +} + +STATUS tacSinkDeleteMessageQueue (MSG_Q_ID * msgq) +{ + /* Is called when block is destroyed and removes the internal message queue */ + STATUS status; + + status = msgQDelete (*msgq); + *msgq = NULL; + return status; +} + + +/*___oOo___*/ + + + + + + diff --git a/src/arguments.py b/src/arguments.py new file mode 100644 index 0000000..94e4cea --- /dev/null +++ b/src/arguments.py @@ -0,0 +1,26 @@ +import getopt + +def exitUsage(): + print("usage: %s <.tasrc file> -i -o " % sys.argv[0]) + sys.exit(1) + +def readArguments(args): + sourceDirectories = [] + outputFile = "" + try: + options, _ = getopt.getopt(args, "hi:o:") + except getopt.GetoptError: + exitUsage() + for option, arg in options: + if option == "-h": + exitUsage() + elif option == "-o": + outputFile = arg + elif option == "-i": + sourceDirectories.append(arg) + if outputFile == "": + exitUsage() + if len(sourceDirectories) == 0: + print("WARNING: no source directories specified!") + return outputFile, sourceDirectories + diff --git a/src/converter.py b/src/converter.py new file mode 100755 index 0000000..3e44058 --- /dev/null +++ b/src/converter.py @@ -0,0 +1,18 @@ +#!/usr/bin/python3 + +import sys + +import arguments +from tacsrc.tac import readTAC +import grc +import portNaming + +if __name__ == "__main__": + if len(sys.argv) == 1: + params.exitUsage() + inputFile = sys.argv[1] + outputFile, sourceDirectories = arguments.readArguments(sys.argv[2:]) + blocks, connections, blockTypes = readTAC(inputFile) + portNaming.resolvePortNames(blockTypes, sourceDirectories) + grc.write(outputFile, blocks, connections) + diff --git a/src/defaultBlockTypes.py b/src/defaultBlockTypes.py new file mode 100644 index 0000000..a7c7a7a --- /dev/null +++ b/src/defaultBlockTypes.py @@ -0,0 +1,74 @@ +from tacsrc.blockType import BlockType + +class VariablePorts: + def __init__(self, ioDescriptionName, sizeFunction): + self.ioDescriptionName = ioDescriptionName + self.sizeFunction = sizeFunction + + def mapName(self, position, name, index): + return + + def getRealPort(self, originalPort): + return 0 + + def ensureLength(self, length): + return + + def getIODescription(self, block): + return "\\\\n0:%s[%s]" % (self.ioDescriptionName, self.sizeFunction(block)) + + def getRealCount(self): + return 1 + +def inParameters(block): + return block.parameters[1] + +def parameterSize(block): + return len(block.parameters) + +monitor = BlockType("Monitor") +monitor.inputs = VariablePorts("input", inParameters) + +monitorState = BlockType("MonitorState") +monitorState.inputs = VariablePorts("input", inParameters) + +probe = BlockType("Probe") +probe.inputs = VariablePorts("input", inParameters) + +readRfm = BlockType("ReadRfm") +readRfm.outputs = VariablePorts("output", parameterSize) + +rms = BlockType("RMS") +rms.inputs.mapName(0, "input", 0) +rms.outputs.mapName(0, "output", 0) + +constant = BlockType("Constant") +constant.outputs.mapName(0, "CONST", 0) + +manual = BlockType("ManualSwitch") +manual.inputs.mapName(0, "input", 0) +manual.outputs.mapName(0, "output", 0) + +noise = BlockType("NormalNoise") +noise.outputs.mapName(0, "output", 0) + +writeRMNNoTim = BlockType("WriteRmNoTim") +writeRMNNoTim.inputs = VariablePorts("input", parameterSize) + +defaultBlockTypes = { + "Monitor": monitor, + "MonitorState": monitorState, + "Probe": probe, + "ReadRfm": readRfm, + "TIM": BlockType("TIM"), + "WAIT_RFM_INTERRUPT": BlockType("WAIT_RFM_INTERRUPT"), + "RMS": rms, + "Constant": constant, + "ManualSwitch": manual, + "NormalNoise": noise, + "WriteRmNoTim": writeRMNNoTim +} + +def addDefaultBlockTypes(blockTypes): + for key in defaultBlockTypes: + blockTypes[key] = defaultBlockTypes[key] diff --git a/src/grc.py b/src/grc.py new file mode 100644 index 0000000..ed02659 --- /dev/null +++ b/src/grc.py @@ -0,0 +1,94 @@ +GRC_TEMPLATE = ''' +options: + parameters: + title: 'TASRC to GRC converter output' + states: + coordinate: [-100, -100] + +blocks: +%s + +connections: +%s + +metadata: + file_format: 1 +''' + +BLOCK_TEMPLATE = ''' +- name: %s + id: epy_block + parameters: + _source_code: "from gnuradio import gr\\nimport numpy as np\\nclass BLOCK(gr.sync_block):\\n def __init__(self):\\n gr.sync_block.__init__(self,name='%s:%s%s',in_sig=%s,out_sig=%s)\\n def work(self, input_items, output_items):\\n return len(output_items[0])" + states: + coordinate: [%s, %s] +''' + +LINK_TEMPLATE = "- [%s, '%s', %s, '%s']\n" + +def getLongestDependencyRow(blocks, blockDependencies): + currentMax = 0 + for block in blocks: + current = getLongestDependencyRow(blockDependencies[block], blockDependencies) + 1 + if current > currentMax: + currentMax = current + return currentMax + +def getPosition(block, blockDependencies, reverseBlockDependencies, depths): + position = getLongestDependencyRow(blockDependencies[block], blockDependencies) + depths += [0] * (position+1 - len(depths)) + y = depths[position] + depths[position] += 50 # base offset + depths[position] += max( + (3+block.blockType.inputs.getRealCount()+block.blockType.outputs.getRealCount()) * 15, + max(block.blockType.inputs.getRealCount(), block.blockType.outputs.getRealCount()) * 30) + return position * 300, y + +def getBlockDependencies(blocks, links): + blockDependencies = {} + for block in blocks: + blockDependencies[block] = [] + for link in links: + if link.toBlock == block: + blockDependencies[block].append(link.fromBlock) + reverseBlockDependencies = {} + for block in blockDependencies: + for dependency in blockDependencies[block]: + if not dependency in reverseBlockDependencies: + reverseBlockDependencies[dependency] = [] + reverseBlockDependencies[dependency].append(block) + return blockDependencies, reverseBlockDependencies + +def getBlocksContent(blocks, links): + blockDependencies, reverseBlockDependencies = getBlockDependencies(blocks, links) + depths = [] + blocksContent = "" + for block in blocks: + description = block.blockType.getIODescription(block) + inputs = "[%s]" % ", ".join(["np.int8"] * block.blockType.inputs.getRealCount()) + outputs = "[%s]" % ", ".join(["np.int8"] * block.blockType.outputs.getRealCount()) + position = getPosition(block, blockDependencies, reverseBlockDependencies, depths) + blocksContent += BLOCK_TEMPLATE % ( + block.name, + block.name, + block.blockType.name, + description, + inputs, + outputs, + position[0], + position[1]) + return blocksContent + +def getLinksContent(links): + linksContent = "" + for link in links: + fromPort = link.fromBlock.blockType.outputs.getRealPort(link.fromPort) + toPort = link.toBlock.blockType.inputs.getRealPort(link.toPort) + linksContent += LINK_TEMPLATE % (link.fromBlock.name, fromPort, link.toBlock.name, toPort) + return linksContent + +def write(filename, blocks, links): + with open(filename, "w+") as file: + print("writing to file %s" % filename) + file.truncate(0) + file.write(GRC_TEMPLATE % (getBlocksContent(blocks, links), getLinksContent(links))) diff --git a/src/portNaming.py b/src/portNaming.py new file mode 100644 index 0000000..62be549 --- /dev/null +++ b/src/portNaming.py @@ -0,0 +1,104 @@ +import re +import os +import json +from defaultBlockTypes import defaultBlockTypes + +INPUT_FUNCTIONS = [ + "tacStdBlockGetInput", + "tacGraviMatrixGetPointerInput" + ] + +OUTPUT_FUNCTIONS = [ + "tacStdBlockSetOutput", + "tacGraviMatrixSetPointerOutput" + ] + +def getFiles(blockType, sourceDirectories): + files = [] + for sourceDirectory in sourceDirectories: + files += ["%s/%s" % (data[0], file) + for data in os.walk(sourceDirectory) + for file in data[2] if re.match(".*tac%sBlock.c" % blockType.name.replace("Rm", "Rmn"), file) != None] + return files + +def resolvePortNames(blockTypes, sourceDirectories): + missingBlocks = [] + multipleDefinitions = [] + for blockType in blockTypes: + if blockType.name in defaultBlockTypes: + continue + files = getFiles(blockType, sourceDirectories) + if len(files) == 0: + print("WARNING: no source file for block type %s found" % blockType.name) + missingBlocks.append(blockType.name) + continue + if len(files) > 1: + multipleDefinitions.append(blockType.name) + print("WARNING: more than one matching source file for block type %s found, skipping" % blockType.name) + continue + print("reading file %s" % files[0]) + with open(files[0], "r") as file: + content = "\n".join(file.readlines()) + for function in INPUT_FUNCTIONS: + mapInputs(content, function, blockType.inputs) + for function in OUTPUT_FUNCTIONS: + mapOutputs(content, function, blockType.outputs) + for entry in re.findall("\\w+ *= *\\*?\\(?pSelf->input\\[\\d+\\]\\)?", content): + name = re.search("^\\w+", entry).group() + position = int(re.search("(?<=\\[)\\d+(?=\\])", entry).group()) + blockType.inputs.mapName(position, name, 0) + for entry in re.findall("pSelf->output\\[\\d+\\] *= *\\w+", content): + name = re.search("\\w+$", entry).group() + position = int(re.search("(?<=\\[)\\d+(?=\\])", entry).group()) + blockType.outputs.mapName(position, name, 0) + if not os.path.exists("errors.json") or os.stat("errors.json").st_size == 0: + content = {"missing_blocks": [], "multiple_definitions": []} + else: + with open("errors.json", "r") as file: + content = json.load(file) + with open("errors.json", "w+") as file: + for blockTypeName in missingBlocks: + if not blockTypeName in content["missing_blocks"]: + content["missing_blocks"].append(blockTypeName) + for blockTypeName in multipleDefinitions: + if not blockTypeName in content["multiple_definitions"]: + content["multiple_definitions"].append(blockTypeName) + json.dump(content, file, indent=2) + file.close() + +def mapInputs(content, function, ports): + for entry in re.findall("\\w+ *= *%s\\(pSelf *, *\\d+\\);" % function, content): + name = re.search("^\\w+", entry).group() + position = int(re.search("\\d+(?= *\\) *;)", entry).group()) + ports.mapName(position, name, 0) + for entry in re.findall("\\w+->\\w+\\[\\d+\\] *= *%s\\(pSelf *, *\\d+\\);" % function, content): + name = re.search("(?<=\\->)\\w+", entry).group() + position = int(re.search("\\d+(?= *\\) *;)", entry).group()) + index = int(re.search("(?<=\\[)\\d+(?=\\])", entry).group()) + ports.mapName(position, name, index) + for entry in re.findall("\\w+\\[\\d+\\] *= *%s\\(pSelf *, *\\d+\\);" % function, content): + name = re.search("^\\w+", entry).group() + position = int(re.search("\\d+(?= *\\) *;)", entry).group()) + index = int(re.search("(?<=\\[)\\d+(?=\\])", entry).group()) + ports.mapName(position, name, index) + +def mapOutputs(content, function, ports): + for entry in re.findall("%s\\(pSelf *, *\\d+ *, *pSelfParam->\\w+\\);" % function, content): + name = re.search("\\w+(?=\\);$)", entry).group() + position = int(re.search("\\d+(?= *, *pSelfParam->\\w+\\);$)", entry).group()) + ports.mapName(position, name, 0) + for entry in re.findall("%s\\(pSelf *, *\\d+ *, *\\w+\\[\\d+\\]\\);" % function, content): + name = re.search("\\w+(?=\\[\\d+\\]\\);$)", entry).group() + position = int(re.search("\\d+(?= *, *\\w+\\[\\d+\\]\\);$)", entry).group()) + index = int(re.search("(?<=\\[)\\d+(?=\\])", entry).group()) + ports.mapName(position, name, index) + for entry in re.findall("%s\\(pSelf *, *\\d+ *, *pSelfParam->\\w+\\[\\d+\\]\\);" % function, content): + name = re.search("(?<=\\->)\\w+", entry).group() + position = int(re.search("\\d+(?= *, *pSelfParam->\\w+\\[\\d+\\]\\);$)", entry).group()) + index = int(re.search("(?<=\\[)\\d+(?=\\]\\);$)", entry).group()) + ports.mapName(position, name, index) + for entry in re.findall("%s\\(pSelf *, *\\d+ *, *\\w+\\);" % function, content): + name = re.search("\\w+(?= *\\);$)", entry).group() + position = int(re.search("\\d+(?= *, *\\w+\\);$)", entry).group()) + index = 0 + ports.mapName(position, name, index) diff --git a/src/tacsrc/block.py b/src/tacsrc/block.py new file mode 100644 index 0000000..737d9f1 --- /dev/null +++ b/src/tacsrc/block.py @@ -0,0 +1,6 @@ +class Block: + def __init__(self): + self.name = "" + self.blockType = None + self.parameters = [] + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3624768 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +__pycache__ +out +tacapp.tar.gz +Sources +tacapp +worryingFiles +cc.tar.gz diff --git a/errors.json b/errors.json new file mode 100644 index 0000000..5ec898a --- /dev/null +++ b/errors.json @@ -0,0 +1,4 @@ +{ + "missing_blocks": [], + "multiple_definitions": [] +} \ No newline at end of file diff --git a/hardcodedFiles/tacReadRmnBlock.c b/hardcodedFiles/tacReadRmnBlock.c new file mode 100644 index 0000000..8acbcfa --- /dev/null +++ b/hardcodedFiles/tacReadRmnBlock.c @@ -0,0 +1,568 @@ +/******************************************************************************* +* E.S.O. - VLT project +* +* "@(#) $Id: tacReadRmnBlock.c 305476 2018-01-19 08:56:18Z rfrahm $" +* +* who when what +* ------- -------- ---------------------------------------------- +* gzins 2010-07-27 ported to VLTSW2010 and VxWorks 6.4 +* swehner 2008-10-10 creation +*/ + +/************************************************************************ +* NAME +* tacReadRmnBlock - Implemements the standard functions for the +* tacReadRmn block and tacReadRfm block. +* tacReadRmnBlock - Reads from 1rst generation reflective memory network +* tacReadRfmBlock - Reads from 2nd generation reflective memory network + +* Parameters: +* field - token names for the RMN fields to read (up to 10) +* Inputs: 0 +* Outputs: 1 +* output - 1..10 depending on number of field parameters +* +* +* +* FILES +* +* ENVIRONMENT +* TAC +* +* RETURN VALUES +* +* CAUTIONS +* +* EXAMPLES +* TAC.BLOCK9.TYPE ReadRmn +* TAC.BLOCK9.NAME ReadRmn +* +* SEE ALSO +* +* BUGS +* +*------------------------------------------------------------------------ +*/ + +#define _POSIX_SOURCE 1 +#include "vltPort.h" + +ATTRIBUTE_UNUSED static const char *rcsId="@(#) $Id: tacReadRmnBlock.c 305476 2018-01-19 08:56:18Z rfrahm $"; + +/* + * System Headers + */ + +#include /* taskSpawn, taskDelay, ... */ +#include /* printf ... */ +#include /* malloc ... */ +#include /* malloc ... */ +#include +#include + +/* + * Local Headers + */ + +#include "tacStdBlock.h" +#include "tacRmnBlock.h" +#include "rmassPublic.h" +#include "rmassPrivate.h" + +/* + * Compilation directives + */ + +/* + * Constants + */ + +#define tacREAD_RMN_EXPECTED_PARAM 1 +#define tacREAD_RMN_DEFAULT_INPUT_NUMBER 0 +#define tacREAD_RMN_DEFAULT_OUTPUT_NUMBER tacMAX_DATA_NUMBER + +#define tacREAD_RMN_FIELD_STRING_LEN 256 +#define tacSTRLEN sizeof(double) + +/* + * Types + */ + +/* + * Local function declaration + */ + +/* + * Global variables + */ + +/* + * Function definition + */ + + +STATUS tacReadRmnBlockCheckParameter (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the ADDBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = NULL; + + pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + /* field string is built from block params */ + if ( tacRmnBlockCheckParameter ( pSelf, parameter, 0, error) != OK ) + { + return ERROR; + } + + /* useful information on the screen */ + printf ("ReadRmn %s: [%s]\n", pSelf->name, pSelfParam->fieldString); + + return OK; +} + +STATUS tacReadRfmBlockCheckParameter (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the ADDBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = NULL; + + pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + /* field string is built from block params */ + if ( tacRmnBlockCheckParameter ( pSelf, parameter, 0, error) != OK ) + { + return ERROR; + } + + /* useful information on the screen */ + printf ("ReadRfm %s: [%s]\n", pSelf->name, pSelfParam->fieldString); + + return OK; +} + +/* + * Constructor Hooks - Called when a block of this type is instanciated (CONFIG or ADDBLCK commands) + */ + +STATUS tacReadRmBlockConstructor (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the ADDBLCK command */ + vltLOGICAL isRmn, + tacERROR* error) /* Error structure - not a stack */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = NULL; + + /* Check that the expected number of parameters has been received */ + if (parameter->number < tacREAD_RMN_EXPECTED_PARAM) + { + char errorParam[40]; + + sprintf(errorParam, "Expected at least %d, received %d", tacREAD_RMN_EXPECTED_PARAM, parameter->number); + tacRTC_ERR(tacERR_PARAM_NUMBER, errorParam); + return ERROR; + } + + /* Allocate and initialize block-specific arrays */ + if (tacStdBlockAllocateArrays(pSelf, 0, tacREAD_RMN_DEFAULT_INPUT_NUMBER, tacREAD_RMN_DEFAULT_OUTPUT_NUMBER, error) == ERROR) + { + return ERROR; + } + + if (tacStdBlockAllocateArrayBySize(pSelf, tacSTDBLOCK_PARAM_ARRAY, sizeof(tacRMN_LOCAL_PARAMETER), error) == ERROR) + { + tacStdBlockReleaseArray(pSelf, tacSTDBLOCK_INPUT_ARRAY, error); + tacStdBlockReleaseArray(pSelf, tacSTDBLOCK_OUTPUT_ARRAY, error); + return ERROR; + } + + if ( isRmn ) + { + if ( tacReadRmnBlockCheckParameter (pSelf, parameter, error) == ERROR) + { + return ERROR; + } + } + else + { + if ( tacReadRfmBlockCheckParameter (pSelf, parameter, error) == ERROR) + { + return ERROR; + } + } + + pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + pSelfParam->handleValid = rmassACCESS_BLOCKED; + + /* Attach to RMN */ + if ( rmassReadAttach (&pSelfParam->handle, + pSelfParam->fieldString, + &pSelfParam->val[0], + &pSelfParam->val[1], + &pSelfParam->val[2], + &pSelfParam->val[3], + &pSelfParam->val[4], + &pSelfParam->val[5], + &pSelfParam->val[6], + &pSelfParam->val[7], + &pSelfParam->val[8], + &pSelfParam->val[9]) != SUCCESS ) + { + char errorParam[40]; + + sprintf(errorParam, "Attach to RMN failed."); + tacRTC_ERR(tacERR_INTERNAL, errorParam); + return ERROR; + } + + pSelfParam->handleValid = rmassACCESS_FREE; + + return OK; +} + +STATUS tacReadRmnBlockConstructor (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the ADDBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + if ( tacReadRmBlockConstructor (pSelf, parameter, ccsTRUE, error ) == ERROR ) + { + return ERROR; + } + return OK; +} + +STATUS tacReadRfmBlockConstructor (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the ADDBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + if ( tacReadRmBlockConstructor (pSelf, parameter, ccsFALSE, error ) == ERROR ) + { + return ERROR; + } + return OK; +} + + + +/* + * Destructor Hooks - Called when the block is removed from the algorithm (DELBLCK or new CONFIG commands) + */ + +void tacReadRmnBlockDestructor (tacSTDBLOCK* pSelf) /* Reference to the block instance */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = NULL; + pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + pSelfParam->handleValid = rmassACCESS_BLOCKED; + /* wait until semaphore is acknowledged by realtime algo + * or just procede if realtime is not active */ + while ((*pSelf->shared).active && pSelfParam->handleValid != rmassACCESS_BLOCK_ACKN) + { + taskDelay(1); + } + + rmassDetach (&pSelfParam->handle); + + return; +} + +/* + * Change parameters Hooks - Called when modifying the block parameters (MODBLCK command) + */ + +STATUS tacReadRmnBlockSetParameter (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the MODBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + if ( tacReadRmnBlockCheckParameter (pSelf, parameter, error) == ERROR) + { + return ERROR; + } + + pSelfParam->handleValid = rmassACCESS_BLOCKED; + /* wait until semaphore is acknowledged by realtime algo + * or just procede if realtime is not active */ + while ((*pSelf->shared).active && pSelfParam->handleValid != rmassACCESS_BLOCK_ACKN) + { + taskDelay(1); + } + + /* detach RMN handle */ + if ( rmassDetach (&pSelfParam->handle) != SUCCESS ) + { + char errorParam[40]; + + sprintf(errorParam, "rmassDetach returned error."); + tacRTC_ERR(tacERR_INTERNAL, errorParam); + return ERROR; + } + + if ( rmassReadAttach (&pSelfParam->handle, + pSelfParam->fieldString, + &pSelfParam->val[0], + &pSelfParam->val[1], + &pSelfParam->val[2], + &pSelfParam->val[3], + &pSelfParam->val[4], + &pSelfParam->val[5], + &pSelfParam->val[6], + &pSelfParam->val[7], + &pSelfParam->val[8], + &pSelfParam->val[9]) != SUCCESS ) + { + char errorParam[40]; + + sprintf(errorParam, "Attach to RMN failed."); + tacRTC_ERR(tacERR_INTERNAL, errorParam); + return ERROR; + } + + pSelfParam->handleValid = rmassACCESS_FREE; + + return OK; +} + +STATUS tacReadRfmBlockSetParameter (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the MODBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + if ( tacReadRfmBlockCheckParameter (pSelf, parameter, error) == ERROR) + { + return ERROR; + } + + pSelfParam->handleValid = rmassACCESS_BLOCKED; + /* wait until semaphore is acknowledged by realtime algo + * or just procede if realtime is not active */ + while ((*pSelf->shared).active && pSelfParam->handleValid != rmassACCESS_BLOCK_ACKN) + { + taskDelay(1); + } + + /* detach RMN handle */ + if ( rmassDetach (&pSelfParam->handle) != SUCCESS ) + { + char errorParam[40]; + + sprintf(errorParam, "rmassDetach returned error."); + tacRTC_ERR(tacERR_INTERNAL, errorParam); + return ERROR; + } + + if ( rmassReadAttach (&pSelfParam->handle, + pSelfParam->fieldString, + &pSelfParam->val[0], + &pSelfParam->val[1], + &pSelfParam->val[2], + &pSelfParam->val[3], + &pSelfParam->val[4], + &pSelfParam->val[5], + &pSelfParam->val[6], + &pSelfParam->val[7], + &pSelfParam->val[8], + &pSelfParam->val[9]) != SUCCESS ) + { + char errorParam[40]; + + sprintf(errorParam, "Attach to RFM failed."); + tacRTC_ERR(tacERR_INTERNAL, errorParam); + return ERROR; + } + + pSelfParam->handleValid = rmassACCESS_FREE; + + return OK; +} + +/* + * Algorithm Hooks - Called at each time the TAC algorithm is evaluated (ONLINE state) + */ + +void tacReadRmnBlockAlgorithm (tacSTDBLOCK* pSelf) /* Reference to the block instance */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + int i; + + if ( pSelfParam->handleValid == rmassACCESS_BLOCKED ) + { + pSelfParam->handleValid = rmassACCESS_BLOCK_ACKN; + } + + if ( pSelfParam->handleValid == rmassACCESS_FREE ) + { + /* actual RMN read operation */ + rmassReadAccessRmn (&pSelfParam->handle); + + /* Write to outputs */ + for (i=0; i < pSelfParam->numFields; i++) + { + switch (pSelfParam->type[i]) + { + case rmassTIMESEC: + case rmassUINT32: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).ui); + break; + case rmassTIMEUSEC: + case rmassINT32: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).i); + break; + case rmassFLOAT: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).f); + break; + default: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).d); + break; + } + } + + /* provide zero values at unsatisfied outputs + * I consider this a good thing to do since the block + * is always configured */ + for (i=pSelfParam->numFields; i < tacREAD_RMN_DEFAULT_OUTPUT_NUMBER; i++) + { + tacStdBlockSetOutput(pSelf, i, 0.0); + } + } +} + +void tacReadRfmBlockAlgorithm (tacSTDBLOCK* pSelf) /* Reference to the block instance */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + int i; + + if ( pSelfParam->handleValid == rmassACCESS_BLOCKED ) + { + pSelfParam->handleValid = rmassACCESS_BLOCK_ACKN; + } + + if ( pSelfParam->handleValid == rmassACCESS_FREE ) + { + /* actual RMN read operation */ + rmassReadAccessRfm (&pSelfParam->handle); + + /* Write to outputs */ + for (i=0; i < pSelfParam->numFields; i++) + { + switch (pSelfParam->type[i]) + { + case rmassTIMESEC: + case rmassUINT32: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).ui); + break; + case rmassTIMEUSEC: + case rmassINT32: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).i); + break; + case rmassFLOAT: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).f); + break; + default: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).d); + break; + } + } + + /* provide zero values at unsatisfied outputs + * I consider this a good thing to do since the block + * is always configured */ + for (i=pSelfParam->numFields; i < tacREAD_RMN_DEFAULT_OUTPUT_NUMBER; i++) + { + tacStdBlockSetOutput(pSelf, i, 0.0); + } + } +} + +/* + * Show Hooks - Called when the tacRtcTaskShow routine is executed + */ + +void tacReadRmnBlockShow (tacSTDBLOCK* pSelf) /* Reference to the block instance */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + /* Print parameter values */ + printf(" Attached: %s\n", pSelfParam->fieldString); + + return; +} + + +/***************************************************/ +/* The following code is common to all block types */ +/* Do not modify without any good reasons */ +/***************************************************/ + +/* + * Installation function + */ + +tacSTDBLOCK_TYPE tacReadRmnTypeInfo = { + "ReadRmn", + &tacReadRmnBlockConstructor, + &tacRmBlockGetParameter, + &tacReadRmnBlockAlgorithm, + &tacReadRmnBlockSetParameter, + NULL, + NULL, + &tacReadRmnBlockDestructor, + &tacReadRmnBlockShow +}; + +tacSTDBLOCK_TYPE tacReadRfmTypeInfo = { + "ReadRfm", + &tacReadRfmBlockConstructor, + &tacRmBlockGetParameter, + &tacReadRfmBlockAlgorithm, + &tacReadRmnBlockSetParameter, + NULL, + NULL, + &tacReadRmnBlockDestructor, + &tacReadRmnBlockShow +}; + +STATUS tacReadRmnBlockInitAll (void) +{ + /***************************************************/ + /* The following code is common to all block types */ + /* Do not modify without any good reasons */ + /***************************************************/ + + /* Install ReadRmn1g Block Hooks */ + tacStdBlockInstallNewType(&tacReadRmnTypeInfo); + + /*****************************/ + /* End of common code region */ + /*****************************/ + + /* Perform other library initialization operations */ + + return OK; +} + +STATUS tacReadRfmBlockInitAll (void) +{ + /***************************************************/ + /* The following code is common to all block types */ + /* Do not modify without any good reasons */ + /***************************************************/ + + /* Install ReadRmn1g Block Hooks */ + tacStdBlockInstallNewType(&tacReadRfmTypeInfo); + + /*****************************/ + /* End of common code region */ + /*****************************/ + + /* Perform other library initialization operations */ + + return OK; +} + +/*___oOo___*/ + + + diff --git a/hardcodedFiles/tacSinkBlock.c b/hardcodedFiles/tacSinkBlock.c new file mode 100644 index 0000000..df39833 --- /dev/null +++ b/hardcodedFiles/tacSinkBlock.c @@ -0,0 +1,1256 @@ +/******************************************************************************* +* E.S.O. - VLT project +* +* "@(#) $Id: tacSinkBlock.c 339094 2021-02-10 03:10:02Z jgil $" +* +* who when what +* ------- -------- ---------------------------------------------- +* rdembet 06/08/20 New MonitorState block with no data averaging +* swehner 28/11/09 SPR20090234 Correction in rate adjustment in reset hook +* swehner 27/11/09 Fixed message queue handling +* swehner 10/10/09 New block FastProbe for unlimited rec frequency +* swehner 22/09/09 PPRS 32341 Replaced specialized tacSINK_SHMSG stack +* with standard vxWorks message queue. +* bbauvir 21/09/04 VLTSW20040113 - One sample might be lost +* bbauvir 29/03/04 Monitor block averages over the reporting period +* bbauvir 29/12/02 Probe to the SampTask +* bbauvir 26/12/02 MsgQ access through DPC mechanism +* bbauvir 14/07/02 New MsgQ of TAC version 1.22 +* bbauvir 21/03/01 Created +*/ + +/************************************************************************ +* NAME +* tacSinkBlock - Standard data monitoring blocks +* +* SYNOPSIS +* lcubootAutoCdBoot 1,"tacsink.boot" +* < tacsink.boot +* +* DESCRIPTION +* Block type: Display +* Parameters: +* Inputs: 1 +* Outputs: none +* +* This function block samples the value of its input signal at the +* specified and issues a message containing the time +* and the value of the input on the vxWorks terminal. +* It does not allow modification of the parameter at runtime. +* +* Block type: Monitor +* Parameters: +* +* Inputs: 10max +* Outputs: none +* +* This function block samples the value of its input signals at the +* specified (0.0 to send a message at the system sampling +* period) and issues a message containing the time and the value of +* the inputs on the shared memory. This message is intercepted by the +* background task running on the master CPU. The monitored values are +* written into the online database. The number of inputs of the block +* is specified by parameter. +* This block does not allow modification of the parameters at runtime. +* +* Block type: MonitorState +* Parameters: +* +* Inputs: 10max +* Outputs: none +* +* Same as Monitor block but without the averaging of received data, +* see VLTSW-14260 JIRA ticket. +* +* Block type: Probe +* Parameters: +* +* Inputs: 10max +* Outputs: none +* +* Block type: FastProbe +* Parameters: +* +* Inputs: 10max +* Outputs: none +* +* This function block samples the value of its input signals at the +* specified (0.0 to send a message at the system sampling +* period) and issues a message containing the time and the value of +* the inputs on the shared memory. This message is intercepted by the +* background task running on the master CPU. The number of inputs of +* the block is specified by parameter. +* This message is passed to an external application callback if +* provided. +* This block does not allow modification of the parameters at runtime. +* The normal Probe block has a limited sampling frequency of not more +* than 2kHz. The reason is in particular the bottleneck between master +* and slave CPU which all samples have to pass through a mechanism of +* VME bus shared memory. On one-CPU-systems this limitation does not +* apply so you are free to choose faster sampling. You may of course +* hit other limitations (processor speed, network traffic etc.) +* +* FILES +* +* ENVIRONMENT +* TAC +* +* RETURN VALUES +* +* CAUTIONS +* All these blocks compute an decimation value to use to trigger the +* sampling of the input signals, from the system sampling period. +* They should be created after any synchronization block. +* +* In order to cope with system performances, a minimum +* is defined for each block. The minimum applied periods are 0.1 (10Hz), +* 0.01 (100Hz) and 0.5e-3 (2kHz) for the 'Display', 'Monitor' and +* 'Probe' blocks respectively. +* +* EXAMPLES +* # 5 signals @ 2Hz (monitored in the database) +* TAC.BLOCK9.TYPE Monitor +* TAC.BLOCK9.NAME Monitor +* TAC.BLOCK9.PARAM 0.5, 5 +* +* # 5 signals @ the RT algorithm sampling period (0.0) +* TAC.BLOCK10.TYPE Probe +* TAC.BLOCK10.NAME Probe +* TAC.BLOCK10.PARAM 0.0, 5 +* +* SEE ALSO +* tacServerInstallDataCallback, tacServerRemoveDataCallback +* +* BUGS +* +*------------------------------------------------------------------------ +*/ + +#define _POSIX_SOURCE 1 +#include "vltPort.h" + + +/* + * System Headers + */ + +#include +#include +#include /* logMsg ... */ +#include /* printf ... */ +#include /* malloc ... */ +#include /* memcpy ... */ +#include + +/* + * Local Headers + */ + +#include "tacStdBlock.h" +#include "tacShMsgQ.h" + +/* + * Compilation directives + */ + +/* + * Constants + */ + +#define tacSINK_DEFAULT_EXPECTED_PARAM 2 + +#define tacSINK_DEFAULT_INPUT_NUMBER tacMAX_DATA_NUMBER /* Up to 10 input channels */ +#define tacSINK_DEFAULT_OUTPUT_NUMBER tacMAX_DATA_NUMBER + +#define tacSINK_ONE_EXPECTED_PARAM 1 +#define tacSINK_ONE_INPUT_NUMBER 1 + +#define tacSINK_DISPLAY_MIN_SAMPLING_PERIOD .1 /* 10Hz */ +#define tacSINK_MONITOR_MIN_SAMPLING_PERIOD .01 /* 100Hz */ +#define tacSINK_PROBE_MIN_SAMPLING_PERIOD .5e-3 /* 2kHz */ + +#define tacSINK_DISPLAY_LOG_STRING_SIZE 128 + +#define tacSINK_MONITOR_DEFAULT_DB_POINT "tac:data:monitor" +#define tacSINK_MONITOR_MAX_DB_ADDR_SIZE 64 + +#define tacSINK_MONITOR_QUEUE_SIZE 6 +#define tacSINK_PROBE_QUEUE_SIZE 6 + + +typedef enum { + tacSINK_SAMPLING_PERIOD = 0, + tacSINK_INPUT_NUMBER, + tacSINK_MONITOR_DB_POINT, +}tacSINK_SCOPE_PARAM_INDEX; + +/* + * Types + */ + +typedef struct { + unsigned short rate; + unsigned short counter; + unsigned short inputNb; + unsigned int lost; + double rateParam; + char* dbPoint; + MSG_Q_ID msgq; + tacSHMSG shmMsg; +}tacSINK_SCOPE_LOCAL_PARAMETER; + +/* + * Function declaration + */ + +extern STATUS tacDpcPushRequest(tacVOIDFCTPTR pFunct, void* parameter); + +/* + * Local function declaration + */ + +/* + * Note: Routines called from within the algorithm must be declared with + * static __inline__ + */ + +STATUS tacSinkSendMonitorMessage(MSG_Q_ID * msgqvoid); +STATUS tacSinkSendMonitorStateMessage(MSG_Q_ID * msgqvoid); +STATUS tacSinkSendProbeMessage(MSG_Q_ID * msgq); +STATUS tacSinkDeleteMessageQueue(MSG_Q_ID * msgq); +STATUS tacSinkCommonBlockConstructor(tacSTDBLOCK* pSelf, tacERROR* error); + +/* + * Global variables + */ + +char logStr[tacSINK_DISPLAY_LOG_STRING_SIZE]; /* Logging string used for Display */ + + +/* + * Function definition + */ + +/* + * Constructor Hooks + */ + +STATUS tacSinkDisplayBlockConstructor (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = NULL; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = NULL; + + /* Check that the expected number of parameters has been received */ + if (parameter->number < tacSINK_ONE_EXPECTED_PARAM) + { + char errorParam[40]; + + sprintf(errorParam, "Expected %d, received %d", tacSINK_ONE_EXPECTED_PARAM, parameter->number); + tacRTC_ERR(tacERR_PARAM_NUMBER, errorParam); + return ERROR; + } + + /* Check that the parameters are valid */ + pRealParam = (double*) parameter->buffer; + + /* Passed parameter is the sampling period of the block */ + if (pRealParam[tacSINK_SAMPLING_PERIOD] < (*pSelf->shared).samplingPeriod) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = (*pSelf->shared).samplingPeriod; + } + + if (pRealParam[tacSINK_SAMPLING_PERIOD] < tacSINK_DISPLAY_MIN_SAMPLING_PERIOD) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = tacSINK_DISPLAY_MIN_SAMPLING_PERIOD; + } + + /* Call common constructor */ + if (tacSinkCommonBlockConstructor(pSelf, error) != OK) + { + return ERROR; + } + + /* Store parameters */ + pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; /* We will only store short integers */ + + /* + * Compute the rate at which data has to be processed - divide and take + * the integer part of the result + */ + + pSelfParam->rate = (unsigned short) (pRealParam[tacSINK_SAMPLING_PERIOD] / (*pSelf->shared).samplingPeriod); + pSelfParam->counter = 0; /* Decimation counter */ + + /* + * Perform other block initialization operations + */ + + return OK; +} + +STATUS tacSinkMonitorBlockConstructor (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = NULL; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = NULL; + unsigned short arrayIndex = 0; + + /* Check that the expected number of parameters has been received */ + if (parameter->number < tacSINK_DEFAULT_EXPECTED_PARAM) + { + char errorParam[40]; + + sprintf(errorParam, "Expected %d, received %d", tacSINK_DEFAULT_EXPECTED_PARAM, parameter->number); + tacRTC_ERR(tacERR_PARAM_NUMBER, errorParam); + return ERROR; + } + + /* Check that the parameters are valid */ + pRealParam = (double*) parameter->buffer; + + /* Passed parameter is the sampling period of the block */ + if (pRealParam[tacSINK_SAMPLING_PERIOD] < (*pSelf->shared).samplingPeriod) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = (*pSelf->shared).samplingPeriod; + } + + if (pRealParam[tacSINK_SAMPLING_PERIOD] < tacSINK_MONITOR_MIN_SAMPLING_PERIOD) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = tacSINK_MONITOR_MIN_SAMPLING_PERIOD; + } + + /* Number of inputs is minimum 1 up to tacMSG_MAX_DATA_NUMBER */ + if ((pRealParam[tacSINK_INPUT_NUMBER] < 1) || + (pRealParam[tacSINK_INPUT_NUMBER] > tacMAX_DATA_NUMBER)) + { + tacRTC_ERR(tacERR_PARAM_INVALID, ""); + return ERROR; + } + + /* Call common constructor */ + if (tacSinkCommonBlockConstructor(pSelf, error) != OK) + { + return ERROR; + } + + /* Store parameters */ + pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* + * Compute the rate at which data has to be processed - divide and take + * the integer part of the result + */ + + pSelfParam->rate = (unsigned short) (pRealParam[tacSINK_SAMPLING_PERIOD] / (*pSelf->shared).samplingPeriod); + pSelfParam->counter = 0; /* Decimation counter */ + pSelfParam->inputNb = (unsigned short) pRealParam[tacSINK_INPUT_NUMBER]; + + /* Optional parameter is an application-specific DB point */ + if (parameter->number == tacSINK_DEFAULT_EXPECTED_PARAM + 1) + { + printf("tacSinkMonitorBlockConstructor - DB point %s\n",(char*) &(pRealParam[tacSINK_MONITOR_DB_POINT])); + pSelfParam->dbPoint = (char*) malloc(tacSINK_MONITOR_MAX_DB_ADDR_SIZE); + strcpy(pSelfParam->dbPoint, (char*) &(pRealParam[tacSINK_MONITOR_DB_POINT])); + } + else + { + printf("tacSinkMonitorBlockConstructor - Default DB point\n"); + pSelfParam->dbPoint = NULL; + } + + /* Specify the number of input signals to attach to become resolved */ + tacStdBlockSetInputNumber(pSelf, pSelfParam->inputNb); + + /* + * Perform other block initialization operations + */ + + /* Create the block internal message queue which tosses the messages out of the + * interrupt context. They are buffered in the queue until the DPC tasks + * picks them up and sends them over the shared memory message queue. + * Sorry for that double-queuing, that's because of the M-S architecture */ + + pSelfParam->msgq = msgQCreate(tacSINK_MONITOR_QUEUE_SIZE, sizeof(tacSHMSG), 0); + if ( pSelfParam->msgq == NULL ) + { + char errorParam[40]; + + sprintf(errorParam, "Could not create probe block message queue"); + tacRTC_ERR(tacERR_MALLOC, errorParam); + return ERROR; + } + + /* will count if a message can't be pushed in the queue */ + pSelfParam->lost = 0; + + /* Warn the background task that a new probe block has been created */ + pSelfParam->shmMsg.type = tacSHMSG_ADD_MONITOR; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + + if (pSelfParam->dbPoint == NULL) + { + strcpy((char*) &(pSelfParam->shmMsg.msgBody.monitor.data), tacSINK_MONITOR_DEFAULT_DB_POINT); + } + else + { + strcpy((char*) &(pSelfParam->shmMsg.msgBody.monitor.data), *((char**) &(pSelfParam->dbPoint))); + } + + printf("tacSinkMonitorBlockConstructor - Attach to %s\n",(char*) &(pSelfParam->shmMsg.msgBody.monitor.data)); + + /* Send message */ + tacShMsgQSendBgInfo(&(pSelfParam->shmMsg)); + + /* Initialize the message parameters */ + pSelfParam->shmMsg.type = tacSHMSG_MONITOR_DATA; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + pSelfParam->shmMsg.msgBody.monitor.data.number = pSelfParam->inputNb; + + /* The output port is used to average the inputs over the reporting period */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pSelf->output[arrayIndex] = 0.0; + } + + return OK; +} + +STATUS tacSinkMonitorStateBlockConstructor (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = NULL; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = NULL; + unsigned short arrayIndex = 0; + + /* Check that the expected number of parameters has been received */ + if (parameter->number < tacSINK_DEFAULT_EXPECTED_PARAM) + { + char errorParam[40]; + + sprintf(errorParam, "Expected %d, received %d", tacSINK_DEFAULT_EXPECTED_PARAM, parameter->number); + tacRTC_ERR(tacERR_PARAM_NUMBER, errorParam); + return ERROR; + } + + /* Check that the parameters are valid */ + pRealParam = (double*) parameter->buffer; + + /* Passed parameter is the sampling period of the block */ + if (pRealParam[tacSINK_SAMPLING_PERIOD] < (*pSelf->shared).samplingPeriod) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = (*pSelf->shared).samplingPeriod; + } + + if (pRealParam[tacSINK_SAMPLING_PERIOD] < tacSINK_MONITOR_MIN_SAMPLING_PERIOD) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = tacSINK_MONITOR_MIN_SAMPLING_PERIOD; + } + + /* Number of inputs is minimum 1 up to tacMSG_MAX_DATA_NUMBER */ + if ((pRealParam[tacSINK_INPUT_NUMBER] < 1) || + (pRealParam[tacSINK_INPUT_NUMBER] > tacMAX_DATA_NUMBER)) + { + tacRTC_ERR(tacERR_PARAM_INVALID, ""); + return ERROR; + } + + /* Call common constructor */ + if (tacSinkCommonBlockConstructor(pSelf, error) != OK) + { + return ERROR; + } + + /* Store parameters */ + pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* + * Compute the rate at which data has to be processed - divide and take + * the integer part of the result + */ + + pSelfParam->rate = (unsigned short) (pRealParam[tacSINK_SAMPLING_PERIOD] / (*pSelf->shared).samplingPeriod); + pSelfParam->counter = 0; /* Decimation counter */ + pSelfParam->inputNb = (unsigned short) pRealParam[tacSINK_INPUT_NUMBER]; + + /* Optional parameter is an application-specific DB point */ + if (parameter->number == tacSINK_DEFAULT_EXPECTED_PARAM + 1) + { + printf("tacSinkMonitorStateBlockConstructor - DB point %s\n",(char*) &(pRealParam[tacSINK_MONITOR_DB_POINT])); + pSelfParam->dbPoint = (char*) malloc(tacSINK_MONITOR_MAX_DB_ADDR_SIZE); + strcpy(pSelfParam->dbPoint, (char*) &(pRealParam[tacSINK_MONITOR_DB_POINT])); + } + else + { + printf("tacSinkMonitorStateBlockConstructor - Default DB point\n"); + pSelfParam->dbPoint = NULL; + } + + /* Specify the number of input signals to attach to become resolved */ + tacStdBlockSetInputNumber(pSelf, pSelfParam->inputNb); + + /* + * Perform other block initialization operations + */ + + /* Create the block internal message queue which tosses the messages out of the + * interrupt context. They are buffered in the queue until the DPC tasks + * picks them up and sends them over the shared memory message queue. + * Sorry for that double-queuing, that's because of the M-S architecture */ + + pSelfParam->msgq = msgQCreate(tacSINK_MONITOR_QUEUE_SIZE, sizeof(tacSHMSG), 0); + if ( pSelfParam->msgq == NULL ) + { + char errorParam[40]; + + sprintf(errorParam, "Could not create probe block message queue"); + tacRTC_ERR(tacERR_MALLOC, errorParam); + return ERROR; + } + + /* will count if a message can't be pushed in the queue */ + pSelfParam->lost = 0; + + /* Warn the background task that a new probe block has been created */ + pSelfParam->shmMsg.type = tacSHMSG_ADD_MONITOR; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + + if (pSelfParam->dbPoint == NULL) + { + strcpy((char*) &(pSelfParam->shmMsg.msgBody.monitor.data), tacSINK_MONITOR_DEFAULT_DB_POINT); + } + else + { + strcpy((char*) &(pSelfParam->shmMsg.msgBody.monitor.data), *((char**) &(pSelfParam->dbPoint))); + } + + printf("tacSinkMonitorStateBlockConstructor - Attach to %s\n",(char*) &(pSelfParam->shmMsg.msgBody.monitor.data)); + + /* Send message */ + tacShMsgQSendBgInfo(&(pSelfParam->shmMsg)); + + /* Initialize the message parameters */ + pSelfParam->shmMsg.type = tacSHMSG_MONITOR_DATA; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + pSelfParam->shmMsg.msgBody.monitor.data.number = pSelfParam->inputNb; + + /* Init output port which won't be used to average the inputs over the reporting period */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pSelf->output[arrayIndex] = 0.0; + } + + return OK; +} + +STATUS tacSinkProbeBlockCommonConstructor (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + double minPeriod, + tacERROR* error) +{ + double* pRealParam = NULL; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = NULL; + + /* Check that the expected number of parameters has been received */ + if (parameter->number < tacSINK_DEFAULT_EXPECTED_PARAM) + { + char errorParam[40]; + + sprintf(errorParam, "Expected %d, received %d", tacSINK_DEFAULT_EXPECTED_PARAM, parameter->number); + tacRTC_ERR(tacERR_PARAM_NUMBER, errorParam); + return ERROR; + } + + /* Check that the parameters are valid */ + pRealParam = (double*) parameter->buffer; + + /* Passed parameter is the sampling period of the block */ + if (pRealParam[tacSINK_SAMPLING_PERIOD] < (*pSelf->shared).samplingPeriod) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = (*pSelf->shared).samplingPeriod; + } + + if (pRealParam[tacSINK_SAMPLING_PERIOD] < minPeriod) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = minPeriod; + } + + /* Number of inputs is minimum 1 up to tacMSG_MAX_DATA_NUMBER */ + if ((pRealParam[tacSINK_INPUT_NUMBER] < 1) || + (pRealParam[tacSINK_INPUT_NUMBER] > tacMAX_DATA_NUMBER)) + { + tacRTC_ERR(tacERR_PARAM_INVALID, ""); + return ERROR; + } + + /* Call common constructor */ + if (tacSinkCommonBlockConstructor(pSelf, error) != OK) + { + return ERROR; + } + + /* Store parameters */ + pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* + * Compute the rate at which data has to be processed - divide and take + * the integer part of the result + */ + + pSelfParam->rateParam = pRealParam[tacSINK_SAMPLING_PERIOD]; + pSelfParam->rate = (unsigned short) (pRealParam[tacSINK_SAMPLING_PERIOD] / (*pSelf->shared).samplingPeriod); + pSelfParam->counter = 0; /* Decimation counter */ + pSelfParam->inputNb = (unsigned short) pRealParam[tacSINK_INPUT_NUMBER]; + + /* Specify the number of input signals to attach to become resolved */ + tacStdBlockSetInputNumber(pSelf, pSelfParam->inputNb); + + /* + * Perform other block initialization operations + */ + + /* Create the block internal message queue which gets the messages out of the + * interrupt context. They are buffered in the queue until the DPC tasks + * picks them up and sends them over the shared memory message queue. + * Sorry for that double-queuing, that's because of the M-S architecture */ + + /* There is only one message queue for all probe blocks! */ + pSelfParam->msgq = msgQCreate(tacSINK_PROBE_QUEUE_SIZE, sizeof(tacSHMSG), 0); + if ( pSelfParam->msgq == NULL ) + { + char errorParam[40]; + + sprintf(errorParam, "Could not create probe block message queue"); + tacRTC_ERR(tacERR_MALLOC, errorParam); + return ERROR; + } + + /* will count if a message can't be pushed in the queue */ + pSelfParam->lost = 0; + + /* Warn the background task that a new probe block has been created */ + pSelfParam->shmMsg.type = tacSHMSG_ADD_PROBE; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + + /* Send message */ + tacShMsgQSendDataSample(&pSelfParam->shmMsg); + + /* Initialize the message parameters */ + pSelfParam->shmMsg.type = tacSHMSG_TRANSFER_DATA; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + pSelfParam->shmMsg.msgBody.monitor.data.number = pSelfParam->inputNb; + + return OK; +} + +/* Probe block has a max. sampling frequency of 2kHz */ +STATUS tacSinkProbeBlockConstructor (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + return tacSinkProbeBlockCommonConstructor (pSelf, parameter, tacSINK_PROBE_MIN_SAMPLING_PERIOD, error); +} + +/* Fast probe is the same as probe but not does have the + * limitation on the max. recording frequency */ +STATUS tacSinkFastProbeBlockConstructor (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + return tacSinkProbeBlockCommonConstructor (pSelf, parameter, 0.0, error); +} + +void tacSinkProbeBlockReset (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = + (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* + * Re-Compute the rate at which data has to be processed + */ + if (pSelfParam->rateParam < (*pSelf->shared).samplingPeriod ) + { + pSelfParam->rate = 1; + } + else + { + pSelfParam->rate = (unsigned short) + (pSelfParam->rateParam / (*pSelf->shared).samplingPeriod); + } + + return; +} + +/* + * Report parameters Hooks + */ + +STATUS tacSinkDisplayBlockGetParameter (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = (double*) parameter->buffer; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Send back the expected number of parameters */ + parameter->number = tacSINK_ONE_EXPECTED_PARAM; + + /* Report current parameters */ + pRealParam[tacSINK_SAMPLING_PERIOD] = (double) (pSelfParam->rate * (*pSelf->shared).samplingPeriod); + + return OK; +} + +STATUS tacSinkMonitorBlockGetParameter (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = (double*) parameter->buffer; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Send back the expected number of parameters */ + parameter->number = tacSINK_DEFAULT_EXPECTED_PARAM; + + /* Report current parameters */ + pRealParam[tacSINK_SAMPLING_PERIOD] = (double) (pSelfParam->rate * (*pSelf->shared).samplingPeriod); + pRealParam[tacSINK_INPUT_NUMBER] = (double) pSelfParam->inputNb; + + if (*((char**) &(pSelfParam->dbPoint)) != NULL) + { + parameter->number += 1; + parameter->type[tacSINK_MONITOR_DB_POINT] = tacPARAM_STRING; + strcpy((char*) &(pRealParam[tacSINK_MONITOR_DB_POINT]), *((char**) &(pSelfParam->dbPoint))); + } + + return OK; +} + +STATUS tacSinkMonitorStateBlockGetParameter (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = (double*) parameter->buffer; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Send back the expected number of parameters */ + parameter->number = tacSINK_DEFAULT_EXPECTED_PARAM; + + /* Report current parameters */ + pRealParam[tacSINK_SAMPLING_PERIOD] = (double) (pSelfParam->rate * (*pSelf->shared).samplingPeriod); + pRealParam[tacSINK_INPUT_NUMBER] = (double) pSelfParam->inputNb; + + if (*((char**) &(pSelfParam->dbPoint)) != NULL) + { + parameter->number += 1; + parameter->type[tacSINK_MONITOR_DB_POINT] = tacPARAM_STRING; + strcpy((char*) &(pRealParam[tacSINK_MONITOR_DB_POINT]), *((char**) &(pSelfParam->dbPoint))); + } + + return OK; +} + +STATUS tacSinkProbeBlockGetParameter (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = (double*) parameter->buffer; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Send back the expected number of parameters */ + parameter->number = tacSINK_DEFAULT_EXPECTED_PARAM; + + /* Report current parameters */ + pRealParam[tacSINK_SAMPLING_PERIOD] = (double) (pSelfParam->rate * (*pSelf->shared).samplingPeriod); + pRealParam[tacSINK_INPUT_NUMBER] = (double) pSelfParam->inputNb; + + return OK; +} + +/* + * Change parameters Hooks + */ + +/* + * Algorithm Hooks + */ + +void tacSinkDisplayBlockAlgorithm (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + if ((pSelfParam->counter % pSelfParam->rate) == 0) /* It's time to process data */ + { + sprintf(logStr,"Name: %s Time: %ld.%6ld Value: %g\n", + pSelf->name, + (*pSelf->shared).currentTime.seconds, + (*pSelf->shared).currentTime.microsec, + tacStdBlockGetInput(pSelf,0)); + + tacDpcPushRequest((tacVOIDFCTPTR) &printf, logStr); + + pSelfParam->counter = 0; + } + + pSelfParam->counter++; +} + +void tacSinkMonitorBlockAlgorithm (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + unsigned short arrayIndex = 0; + + /* The output port is used to average the inputs over the reporting period */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pSelf->output[arrayIndex] += tacStdBlockGetInput(pSelf,arrayIndex); + } + + if ((pSelfParam->counter % pSelfParam->rate) == 0) /* It's time to process data */ + { + tacDATA* pData = &(pSelfParam->shmMsg.msgBody.monitor.data); /* We are only interested in message body */ + + /* pData->number = pSelfParam->inputNb; */ + pData->timeStamp = (*pSelf->shared).currentTime; + + /* pData points to the body of the Message */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pData->buffer[arrayIndex] = pSelf->output[arrayIndex] / pSelfParam->rate; + } + + /* Push message into probe block's message que to get the + * data out of the interrupt comtext. */ + if ( msgQSend (pSelfParam->msgq, (char*) &(pSelfParam->shmMsg), sizeof(tacSHMSG), NO_WAIT, 0) != OK ) + { + (pSelfParam->lost)++; + } + + /* Defer procedure call */ + tacDpcPushRequest((tacVOIDFCTPTR) &tacSinkSendMonitorMessage, &pSelfParam->msgq); + + pSelfParam->counter = 0; + + /* The output port is used to average the inputs over the reporting period */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pSelf->output[arrayIndex] = 0.0; + } + } + + pSelfParam->counter++; +} + +void tacSinkMonitorStateBlockAlgorithm (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + unsigned short arrayIndex = 0; + + if ((pSelfParam->counter % pSelfParam->rate) == 0) /* It's time to process data */ + { + tacDATA* pData = &(pSelfParam->shmMsg.msgBody.monitor.data); /* We are only interested in message body */ + + /* pData->number = pSelfParam->inputNb; */ + pData->timeStamp = (*pSelf->shared).currentTime; + + /* pData points to the body of the Message */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pData->buffer[arrayIndex] = tacStdBlockGetInput(pSelf,arrayIndex); + } + + /* Push message into probe block's message que to get the + * data out of the interrupt comtext. */ + if ( msgQSend (pSelfParam->msgq, (char*) &(pSelfParam->shmMsg), sizeof(tacSHMSG), NO_WAIT, 0) != OK ) + { + (pSelfParam->lost)++; + } + + /* Defer procedure call */ + tacDpcPushRequest((tacVOIDFCTPTR) &tacSinkSendMonitorMessage, &pSelfParam->msgq); + + pSelfParam->counter = 0; + } + + pSelfParam->counter++; +} + +void tacSinkProbeBlockAlgorithm (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + unsigned short arrayIndex = 0; + + if ((pSelfParam->counter % pSelfParam->rate) == 0) /* It's time to process data */ + { + tacDATA* pData = &(pSelfParam->shmMsg.msgBody.monitor.data); /* We are only interested in message body */ + + pData->timeStamp = (*pSelf->shared).currentTime; + + /* pData points to the body of the Message */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pData->buffer[arrayIndex] = tacStdBlockGetInput(pSelf,arrayIndex); + } + + /* Push message into probe block's message que to get the + * data out of the interrupt comtext. */ + if ( msgQSend (pSelfParam->msgq, (char*) &(pSelfParam->shmMsg), sizeof(tacSHMSG), NO_WAIT, 0) != OK ) + { + (pSelfParam->lost)++; + } + + /* Defer procedure call: + * tacSinkSendProbeMessage is called outside the interrupt routine + * and will take care to pick up the message from the probe block's + * message queue and send it over the shared memory message queue */ + tacDpcPushRequest((tacVOIDFCTPTR) &tacSinkSendProbeMessage, &pSelfParam->msgq); + + pSelfParam->counter = 0; + } + + pSelfParam->counter++; +} + +/* + * Reset Hooks + */ + +/* + * Stop Hooks + */ + +/* + * Destructor Hooks + */ + +/* + * Note: This destructor is used mainly to send a MONITOR message containing + * 0.0 in order to reset the database array (otherwise going from an + * algorithm with 4 monitored data to one with 3 monitored data leaves + * the 4th value equal to the last ...) + */ + +void tacSinkMonitorBlockDestructor (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + tacDATA* pData = &(pSelfParam->shmMsg.msgBody.monitor.data); + unsigned short arrayIndex = 0; + + /* Reset DB values */ + pSelfParam->shmMsg.type = tacSHMSG_MONITOR_DATA; + pData = &(pSelfParam->shmMsg.msgBody.monitor.data); + + pData->number = pSelfParam->inputNb; + + /* pData points to the body of the Message */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pData->buffer[arrayIndex] = 0.0; + } + + /* Send message */ + tacShMsgQSendBgInfo(&pSelfParam->shmMsg); + + pSelfParam->shmMsg.type = tacSHMSG_REMOVE_MONITOR; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + + /* Send message */ + tacShMsgQSendBgInfo(&pSelfParam->shmMsg); + + free(pSelfParam->dbPoint); + + /* delete internal message queue. Do this as deferred procedure call + * to make sure it is only called when all messages have been send + * (through the same deferred call mechanism) */ + tacDpcPushRequest((tacVOIDFCTPTR) tacSinkDeleteMessageQueue, &(pSelfParam->msgq)); + + return; +} + +void tacSinkMonitorStateBlockDestructor (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + tacDATA* pData = &(pSelfParam->shmMsg.msgBody.monitor.data); + unsigned short arrayIndex = 0; + + /* Reset DB values */ + pSelfParam->shmMsg.type = tacSHMSG_MONITOR_DATA; + pData = &(pSelfParam->shmMsg.msgBody.monitor.data); + + pData->number = pSelfParam->inputNb; + + /* pData points to the body of the Message */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pData->buffer[arrayIndex] = 0.0; + } + + /* Send message */ + tacShMsgQSendBgInfo(&pSelfParam->shmMsg); + + pSelfParam->shmMsg.type = tacSHMSG_REMOVE_MONITOR; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + + /* Send message */ + tacShMsgQSendBgInfo(&pSelfParam->shmMsg); + + free(pSelfParam->dbPoint); + + /* delete internal message queue. Do this as deferred procedure call + * to make sure it is only called when all messages have been send + * (through the same deferred call mechanism) */ + tacDpcPushRequest((tacVOIDFCTPTR) tacSinkDeleteMessageQueue, &(pSelfParam->msgq)); + + return; +} + +void tacSinkProbeBlockDestructor (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + pSelfParam->shmMsg.type = tacSHMSG_REMOVE_PROBE; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + + /* Send message */ + tacShMsgQSendDataSample(&pSelfParam->shmMsg); + + /* delete internal message queue. Do this as deferred procedure call + * to make sure it is only called when all messages have been send + * (through the same deferred call mechanism) */ + tacDpcPushRequest((tacVOIDFCTPTR) tacSinkDeleteMessageQueue, &(pSelfParam->msgq)); + + return; +} + +/* + * Show Hooks + */ + +void tacSinkDisplayBlockShow (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Print parameter values */ + printf(" Update rate: %d\n",pSelfParam->rate); + + return; +} + +void tacSinkMonitorBlockShow (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Print parameter values */ + printf(" Update rate: %d\n",pSelfParam->rate); + printf(" Number of input signals: %d\n",pSelfParam->inputNb); + printf(" Queued samples: %d\n", msgQNumMsgs(pSelfParam->msgq)); + printf(" Lost samples: %d\n",pSelfParam->lost); + + if (pSelfParam->dbPoint != NULL) + { + printf(" DB Point: %s\n", pSelfParam->dbPoint); + } + + return; +} + +void tacSinkMonitorStateBlockShow (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Print parameter values */ + printf(" Using MonitorState block, not averaging received data\n"); + printf(" Update rate: %d\n",pSelfParam->rate); + printf(" Number of input signals: %d\n",pSelfParam->inputNb); + printf(" Queued samples: %d\n", msgQNumMsgs(pSelfParam->msgq)); + printf(" Lost samples: %d\n",pSelfParam->lost); + + if (pSelfParam->dbPoint != NULL) + { + printf(" DB Point: %s\n", pSelfParam->dbPoint); + } + + return; +} + +void tacSinkProbeBlockShow (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Print parameter values */ + printf(" Update rate: %d\n",pSelfParam->rate); + printf(" Update rate param (sec): %f\n",pSelfParam->rateParam); + printf(" Number of input signals: %d\n",pSelfParam->inputNb); + printf(" Queued samples: %d\n", msgQNumMsgs(pSelfParam->msgq)); + printf(" Lost samples: %d\n",pSelfParam->lost); + + return; +} + +/* + * Installation function + */ + +tacSTDBLOCK_TYPE tacSinkDisplayTypeInfo = { + "Display", + &tacSinkDisplayBlockConstructor, + &tacSinkDisplayBlockGetParameter, + &tacSinkDisplayBlockAlgorithm, + NULL, + NULL, + NULL, + NULL, + &tacSinkDisplayBlockShow, +}; + +tacSTDBLOCK_TYPE tacSinkMonitorTypeInfo = { + "Monitor", + &tacSinkMonitorBlockConstructor, + &tacSinkMonitorBlockGetParameter, + &tacSinkMonitorBlockAlgorithm, + NULL, + NULL, + NULL, + &tacSinkMonitorBlockDestructor, + &tacSinkMonitorBlockShow, +}; + +tacSTDBLOCK_TYPE tacSinkMonitorStateTypeInfo = { + "MonitorState", + &tacSinkMonitorStateBlockConstructor, + &tacSinkMonitorStateBlockGetParameter, + &tacSinkMonitorStateBlockAlgorithm, + NULL, + NULL, + NULL, + &tacSinkMonitorStateBlockDestructor, + &tacSinkMonitorStateBlockShow, +}; + +/* Probe with a maximal sampling rate of 2kHz */ +tacSTDBLOCK_TYPE tacSinkProbeTypeInfo = { + "Probe", + &tacSinkProbeBlockConstructor, + &tacSinkProbeBlockGetParameter, + &tacSinkProbeBlockAlgorithm, + NULL, + &tacSinkProbeBlockReset, + NULL, + &tacSinkProbeBlockDestructor, + &tacSinkProbeBlockShow, +}; + +/* Fast probe is the same as probe but not does have the + * limitation on the max. recording frequency */ +tacSTDBLOCK_TYPE tacSinkFastProbeTypeInfo = { + "FastProbe", + &tacSinkFastProbeBlockConstructor, + &tacSinkProbeBlockGetParameter, + &tacSinkProbeBlockAlgorithm, + NULL, + &tacSinkProbeBlockReset, + NULL, + &tacSinkProbeBlockDestructor, + &tacSinkProbeBlockShow, +}; + +STATUS tacSinkBlockInitAll (void) +{ + /* Install Sink Block Hooks */ + tacStdBlockInstallNewType(&tacSinkDisplayTypeInfo); + tacStdBlockInstallNewType(&tacSinkMonitorTypeInfo); + tacStdBlockInstallNewType(&tacSinkMonitorStateTypeInfo); + tacStdBlockInstallNewType(&tacSinkProbeTypeInfo); + tacStdBlockInstallNewType(&tacSinkFastProbeTypeInfo); + + /* + * Perform other library initialization operations + */ + + return OK; +} + +/* + * Local functions + */ + +/* + * Note: Routines called from within the algorithm must be declared with + * static __inline__ + */ + +STATUS tacSinkCommonBlockConstructor (tacSTDBLOCK* pSelf, + tacERROR* error) +{ + /* Allocate specific arrays (pointers are initialized to NULL by StdBlock) */ + if (tacStdBlockAllocateArrays(pSelf, 0, tacSINK_DEFAULT_INPUT_NUMBER, + tacSINK_DEFAULT_OUTPUT_NUMBER, error) == ERROR) + { + return ERROR; + } + + if (tacStdBlockAllocateArrayBySize(pSelf, tacSTDBLOCK_PARAM_ARRAY, + sizeof(tacSINK_SCOPE_LOCAL_PARAMETER), error) == ERROR) + { + tacStdBlockReleaseArray(pSelf, tacSTDBLOCK_INPUT_ARRAY, error); + tacStdBlockReleaseArray(pSelf, tacSTDBLOCK_OUTPUT_ARRAY, error); + return ERROR; + } + + /* Specify the number of input signals to attach to become resolved */ + tacStdBlockSetInputNumber(pSelf, tacSINK_ONE_INPUT_NUMBER); /* Required */ + + return OK; +} + +STATUS tacSinkSendMonitorMessage(MSG_Q_ID * msgq) +{ + /* Send message using provided function (different for Monitor and Probe blocks) */ + /* Send message using provided function (different for Monitor and Probe blocks) */ + tacSHMSG msg; + + if ( msgQReceive(*msgq, (char*) &msg, sizeof(tacSHMSG), NO_WAIT) == sizeof(tacSHMSG) ) + { + tacShMsgQSendBgInfo (&msg); + } + + return OK; +} + +STATUS tacSinkSendProbeMessage(MSG_Q_ID * msgq) +{ + /* Send message using provided function (different for Monitor and Probe blocks) */ + tacSHMSG msg; + + if ( msgq == NULL ) + { + return ERROR; + } + + if ( msgQReceive(*msgq, (char*) &msg, sizeof(tacSHMSG), NO_WAIT) == sizeof(tacSHMSG) ) + { + tacShMsgQSendDataSample (&msg); + } + return OK; +} + +STATUS tacSinkDeleteMessageQueue (MSG_Q_ID * msgq) +{ + /* Is called when block is destroyed and removes the internal message queue */ + STATUS status; + + status = msgQDelete (*msgq); + *msgq = NULL; + return status; +} + + +/*___oOo___*/ + + + + + + diff --git a/src/arguments.py b/src/arguments.py new file mode 100644 index 0000000..94e4cea --- /dev/null +++ b/src/arguments.py @@ -0,0 +1,26 @@ +import getopt + +def exitUsage(): + print("usage: %s <.tasrc file> -i -o " % sys.argv[0]) + sys.exit(1) + +def readArguments(args): + sourceDirectories = [] + outputFile = "" + try: + options, _ = getopt.getopt(args, "hi:o:") + except getopt.GetoptError: + exitUsage() + for option, arg in options: + if option == "-h": + exitUsage() + elif option == "-o": + outputFile = arg + elif option == "-i": + sourceDirectories.append(arg) + if outputFile == "": + exitUsage() + if len(sourceDirectories) == 0: + print("WARNING: no source directories specified!") + return outputFile, sourceDirectories + diff --git a/src/converter.py b/src/converter.py new file mode 100755 index 0000000..3e44058 --- /dev/null +++ b/src/converter.py @@ -0,0 +1,18 @@ +#!/usr/bin/python3 + +import sys + +import arguments +from tacsrc.tac import readTAC +import grc +import portNaming + +if __name__ == "__main__": + if len(sys.argv) == 1: + params.exitUsage() + inputFile = sys.argv[1] + outputFile, sourceDirectories = arguments.readArguments(sys.argv[2:]) + blocks, connections, blockTypes = readTAC(inputFile) + portNaming.resolvePortNames(blockTypes, sourceDirectories) + grc.write(outputFile, blocks, connections) + diff --git a/src/defaultBlockTypes.py b/src/defaultBlockTypes.py new file mode 100644 index 0000000..a7c7a7a --- /dev/null +++ b/src/defaultBlockTypes.py @@ -0,0 +1,74 @@ +from tacsrc.blockType import BlockType + +class VariablePorts: + def __init__(self, ioDescriptionName, sizeFunction): + self.ioDescriptionName = ioDescriptionName + self.sizeFunction = sizeFunction + + def mapName(self, position, name, index): + return + + def getRealPort(self, originalPort): + return 0 + + def ensureLength(self, length): + return + + def getIODescription(self, block): + return "\\\\n0:%s[%s]" % (self.ioDescriptionName, self.sizeFunction(block)) + + def getRealCount(self): + return 1 + +def inParameters(block): + return block.parameters[1] + +def parameterSize(block): + return len(block.parameters) + +monitor = BlockType("Monitor") +monitor.inputs = VariablePorts("input", inParameters) + +monitorState = BlockType("MonitorState") +monitorState.inputs = VariablePorts("input", inParameters) + +probe = BlockType("Probe") +probe.inputs = VariablePorts("input", inParameters) + +readRfm = BlockType("ReadRfm") +readRfm.outputs = VariablePorts("output", parameterSize) + +rms = BlockType("RMS") +rms.inputs.mapName(0, "input", 0) +rms.outputs.mapName(0, "output", 0) + +constant = BlockType("Constant") +constant.outputs.mapName(0, "CONST", 0) + +manual = BlockType("ManualSwitch") +manual.inputs.mapName(0, "input", 0) +manual.outputs.mapName(0, "output", 0) + +noise = BlockType("NormalNoise") +noise.outputs.mapName(0, "output", 0) + +writeRMNNoTim = BlockType("WriteRmNoTim") +writeRMNNoTim.inputs = VariablePorts("input", parameterSize) + +defaultBlockTypes = { + "Monitor": monitor, + "MonitorState": monitorState, + "Probe": probe, + "ReadRfm": readRfm, + "TIM": BlockType("TIM"), + "WAIT_RFM_INTERRUPT": BlockType("WAIT_RFM_INTERRUPT"), + "RMS": rms, + "Constant": constant, + "ManualSwitch": manual, + "NormalNoise": noise, + "WriteRmNoTim": writeRMNNoTim +} + +def addDefaultBlockTypes(blockTypes): + for key in defaultBlockTypes: + blockTypes[key] = defaultBlockTypes[key] diff --git a/src/grc.py b/src/grc.py new file mode 100644 index 0000000..ed02659 --- /dev/null +++ b/src/grc.py @@ -0,0 +1,94 @@ +GRC_TEMPLATE = ''' +options: + parameters: + title: 'TASRC to GRC converter output' + states: + coordinate: [-100, -100] + +blocks: +%s + +connections: +%s + +metadata: + file_format: 1 +''' + +BLOCK_TEMPLATE = ''' +- name: %s + id: epy_block + parameters: + _source_code: "from gnuradio import gr\\nimport numpy as np\\nclass BLOCK(gr.sync_block):\\n def __init__(self):\\n gr.sync_block.__init__(self,name='%s:%s%s',in_sig=%s,out_sig=%s)\\n def work(self, input_items, output_items):\\n return len(output_items[0])" + states: + coordinate: [%s, %s] +''' + +LINK_TEMPLATE = "- [%s, '%s', %s, '%s']\n" + +def getLongestDependencyRow(blocks, blockDependencies): + currentMax = 0 + for block in blocks: + current = getLongestDependencyRow(blockDependencies[block], blockDependencies) + 1 + if current > currentMax: + currentMax = current + return currentMax + +def getPosition(block, blockDependencies, reverseBlockDependencies, depths): + position = getLongestDependencyRow(blockDependencies[block], blockDependencies) + depths += [0] * (position+1 - len(depths)) + y = depths[position] + depths[position] += 50 # base offset + depths[position] += max( + (3+block.blockType.inputs.getRealCount()+block.blockType.outputs.getRealCount()) * 15, + max(block.blockType.inputs.getRealCount(), block.blockType.outputs.getRealCount()) * 30) + return position * 300, y + +def getBlockDependencies(blocks, links): + blockDependencies = {} + for block in blocks: + blockDependencies[block] = [] + for link in links: + if link.toBlock == block: + blockDependencies[block].append(link.fromBlock) + reverseBlockDependencies = {} + for block in blockDependencies: + for dependency in blockDependencies[block]: + if not dependency in reverseBlockDependencies: + reverseBlockDependencies[dependency] = [] + reverseBlockDependencies[dependency].append(block) + return blockDependencies, reverseBlockDependencies + +def getBlocksContent(blocks, links): + blockDependencies, reverseBlockDependencies = getBlockDependencies(blocks, links) + depths = [] + blocksContent = "" + for block in blocks: + description = block.blockType.getIODescription(block) + inputs = "[%s]" % ", ".join(["np.int8"] * block.blockType.inputs.getRealCount()) + outputs = "[%s]" % ", ".join(["np.int8"] * block.blockType.outputs.getRealCount()) + position = getPosition(block, blockDependencies, reverseBlockDependencies, depths) + blocksContent += BLOCK_TEMPLATE % ( + block.name, + block.name, + block.blockType.name, + description, + inputs, + outputs, + position[0], + position[1]) + return blocksContent + +def getLinksContent(links): + linksContent = "" + for link in links: + fromPort = link.fromBlock.blockType.outputs.getRealPort(link.fromPort) + toPort = link.toBlock.blockType.inputs.getRealPort(link.toPort) + linksContent += LINK_TEMPLATE % (link.fromBlock.name, fromPort, link.toBlock.name, toPort) + return linksContent + +def write(filename, blocks, links): + with open(filename, "w+") as file: + print("writing to file %s" % filename) + file.truncate(0) + file.write(GRC_TEMPLATE % (getBlocksContent(blocks, links), getLinksContent(links))) diff --git a/src/portNaming.py b/src/portNaming.py new file mode 100644 index 0000000..62be549 --- /dev/null +++ b/src/portNaming.py @@ -0,0 +1,104 @@ +import re +import os +import json +from defaultBlockTypes import defaultBlockTypes + +INPUT_FUNCTIONS = [ + "tacStdBlockGetInput", + "tacGraviMatrixGetPointerInput" + ] + +OUTPUT_FUNCTIONS = [ + "tacStdBlockSetOutput", + "tacGraviMatrixSetPointerOutput" + ] + +def getFiles(blockType, sourceDirectories): + files = [] + for sourceDirectory in sourceDirectories: + files += ["%s/%s" % (data[0], file) + for data in os.walk(sourceDirectory) + for file in data[2] if re.match(".*tac%sBlock.c" % blockType.name.replace("Rm", "Rmn"), file) != None] + return files + +def resolvePortNames(blockTypes, sourceDirectories): + missingBlocks = [] + multipleDefinitions = [] + for blockType in blockTypes: + if blockType.name in defaultBlockTypes: + continue + files = getFiles(blockType, sourceDirectories) + if len(files) == 0: + print("WARNING: no source file for block type %s found" % blockType.name) + missingBlocks.append(blockType.name) + continue + if len(files) > 1: + multipleDefinitions.append(blockType.name) + print("WARNING: more than one matching source file for block type %s found, skipping" % blockType.name) + continue + print("reading file %s" % files[0]) + with open(files[0], "r") as file: + content = "\n".join(file.readlines()) + for function in INPUT_FUNCTIONS: + mapInputs(content, function, blockType.inputs) + for function in OUTPUT_FUNCTIONS: + mapOutputs(content, function, blockType.outputs) + for entry in re.findall("\\w+ *= *\\*?\\(?pSelf->input\\[\\d+\\]\\)?", content): + name = re.search("^\\w+", entry).group() + position = int(re.search("(?<=\\[)\\d+(?=\\])", entry).group()) + blockType.inputs.mapName(position, name, 0) + for entry in re.findall("pSelf->output\\[\\d+\\] *= *\\w+", content): + name = re.search("\\w+$", entry).group() + position = int(re.search("(?<=\\[)\\d+(?=\\])", entry).group()) + blockType.outputs.mapName(position, name, 0) + if not os.path.exists("errors.json") or os.stat("errors.json").st_size == 0: + content = {"missing_blocks": [], "multiple_definitions": []} + else: + with open("errors.json", "r") as file: + content = json.load(file) + with open("errors.json", "w+") as file: + for blockTypeName in missingBlocks: + if not blockTypeName in content["missing_blocks"]: + content["missing_blocks"].append(blockTypeName) + for blockTypeName in multipleDefinitions: + if not blockTypeName in content["multiple_definitions"]: + content["multiple_definitions"].append(blockTypeName) + json.dump(content, file, indent=2) + file.close() + +def mapInputs(content, function, ports): + for entry in re.findall("\\w+ *= *%s\\(pSelf *, *\\d+\\);" % function, content): + name = re.search("^\\w+", entry).group() + position = int(re.search("\\d+(?= *\\) *;)", entry).group()) + ports.mapName(position, name, 0) + for entry in re.findall("\\w+->\\w+\\[\\d+\\] *= *%s\\(pSelf *, *\\d+\\);" % function, content): + name = re.search("(?<=\\->)\\w+", entry).group() + position = int(re.search("\\d+(?= *\\) *;)", entry).group()) + index = int(re.search("(?<=\\[)\\d+(?=\\])", entry).group()) + ports.mapName(position, name, index) + for entry in re.findall("\\w+\\[\\d+\\] *= *%s\\(pSelf *, *\\d+\\);" % function, content): + name = re.search("^\\w+", entry).group() + position = int(re.search("\\d+(?= *\\) *;)", entry).group()) + index = int(re.search("(?<=\\[)\\d+(?=\\])", entry).group()) + ports.mapName(position, name, index) + +def mapOutputs(content, function, ports): + for entry in re.findall("%s\\(pSelf *, *\\d+ *, *pSelfParam->\\w+\\);" % function, content): + name = re.search("\\w+(?=\\);$)", entry).group() + position = int(re.search("\\d+(?= *, *pSelfParam->\\w+\\);$)", entry).group()) + ports.mapName(position, name, 0) + for entry in re.findall("%s\\(pSelf *, *\\d+ *, *\\w+\\[\\d+\\]\\);" % function, content): + name = re.search("\\w+(?=\\[\\d+\\]\\);$)", entry).group() + position = int(re.search("\\d+(?= *, *\\w+\\[\\d+\\]\\);$)", entry).group()) + index = int(re.search("(?<=\\[)\\d+(?=\\])", entry).group()) + ports.mapName(position, name, index) + for entry in re.findall("%s\\(pSelf *, *\\d+ *, *pSelfParam->\\w+\\[\\d+\\]\\);" % function, content): + name = re.search("(?<=\\->)\\w+", entry).group() + position = int(re.search("\\d+(?= *, *pSelfParam->\\w+\\[\\d+\\]\\);$)", entry).group()) + index = int(re.search("(?<=\\[)\\d+(?=\\]\\);$)", entry).group()) + ports.mapName(position, name, index) + for entry in re.findall("%s\\(pSelf *, *\\d+ *, *\\w+\\);" % function, content): + name = re.search("\\w+(?= *\\);$)", entry).group() + position = int(re.search("\\d+(?= *, *\\w+\\);$)", entry).group()) + index = 0 + ports.mapName(position, name, index) diff --git a/src/tacsrc/block.py b/src/tacsrc/block.py new file mode 100644 index 0000000..737d9f1 --- /dev/null +++ b/src/tacsrc/block.py @@ -0,0 +1,6 @@ +class Block: + def __init__(self): + self.name = "" + self.blockType = None + self.parameters = [] + diff --git a/src/tacsrc/blockType.py b/src/tacsrc/blockType.py new file mode 100644 index 0000000..8930836 --- /dev/null +++ b/src/tacsrc/blockType.py @@ -0,0 +1,19 @@ +from tacsrc.ports import Ports + +class BlockType: + def __init__(self, name): + self.name = name + self.inputs = Ports() + self.outputs = Ports() + + def getIODescription(self, block): + result = "" + inputDescription = self.inputs.getIODescription(block) + if len(inputDescription) != 0: + result += "\\\\nINPUTS:" + result += inputDescription + outputDescription = self.outputs.getIODescription(block) + if len(outputDescription) != 0: + result += "\\\\nOUTPUTS:" + result += outputDescription + return result diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3624768 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +__pycache__ +out +tacapp.tar.gz +Sources +tacapp +worryingFiles +cc.tar.gz diff --git a/errors.json b/errors.json new file mode 100644 index 0000000..5ec898a --- /dev/null +++ b/errors.json @@ -0,0 +1,4 @@ +{ + "missing_blocks": [], + "multiple_definitions": [] +} \ No newline at end of file diff --git a/hardcodedFiles/tacReadRmnBlock.c b/hardcodedFiles/tacReadRmnBlock.c new file mode 100644 index 0000000..8acbcfa --- /dev/null +++ b/hardcodedFiles/tacReadRmnBlock.c @@ -0,0 +1,568 @@ +/******************************************************************************* +* E.S.O. - VLT project +* +* "@(#) $Id: tacReadRmnBlock.c 305476 2018-01-19 08:56:18Z rfrahm $" +* +* who when what +* ------- -------- ---------------------------------------------- +* gzins 2010-07-27 ported to VLTSW2010 and VxWorks 6.4 +* swehner 2008-10-10 creation +*/ + +/************************************************************************ +* NAME +* tacReadRmnBlock - Implemements the standard functions for the +* tacReadRmn block and tacReadRfm block. +* tacReadRmnBlock - Reads from 1rst generation reflective memory network +* tacReadRfmBlock - Reads from 2nd generation reflective memory network + +* Parameters: +* field - token names for the RMN fields to read (up to 10) +* Inputs: 0 +* Outputs: 1 +* output - 1..10 depending on number of field parameters +* +* +* +* FILES +* +* ENVIRONMENT +* TAC +* +* RETURN VALUES +* +* CAUTIONS +* +* EXAMPLES +* TAC.BLOCK9.TYPE ReadRmn +* TAC.BLOCK9.NAME ReadRmn +* +* SEE ALSO +* +* BUGS +* +*------------------------------------------------------------------------ +*/ + +#define _POSIX_SOURCE 1 +#include "vltPort.h" + +ATTRIBUTE_UNUSED static const char *rcsId="@(#) $Id: tacReadRmnBlock.c 305476 2018-01-19 08:56:18Z rfrahm $"; + +/* + * System Headers + */ + +#include /* taskSpawn, taskDelay, ... */ +#include /* printf ... */ +#include /* malloc ... */ +#include /* malloc ... */ +#include +#include + +/* + * Local Headers + */ + +#include "tacStdBlock.h" +#include "tacRmnBlock.h" +#include "rmassPublic.h" +#include "rmassPrivate.h" + +/* + * Compilation directives + */ + +/* + * Constants + */ + +#define tacREAD_RMN_EXPECTED_PARAM 1 +#define tacREAD_RMN_DEFAULT_INPUT_NUMBER 0 +#define tacREAD_RMN_DEFAULT_OUTPUT_NUMBER tacMAX_DATA_NUMBER + +#define tacREAD_RMN_FIELD_STRING_LEN 256 +#define tacSTRLEN sizeof(double) + +/* + * Types + */ + +/* + * Local function declaration + */ + +/* + * Global variables + */ + +/* + * Function definition + */ + + +STATUS tacReadRmnBlockCheckParameter (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the ADDBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = NULL; + + pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + /* field string is built from block params */ + if ( tacRmnBlockCheckParameter ( pSelf, parameter, 0, error) != OK ) + { + return ERROR; + } + + /* useful information on the screen */ + printf ("ReadRmn %s: [%s]\n", pSelf->name, pSelfParam->fieldString); + + return OK; +} + +STATUS tacReadRfmBlockCheckParameter (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the ADDBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = NULL; + + pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + /* field string is built from block params */ + if ( tacRmnBlockCheckParameter ( pSelf, parameter, 0, error) != OK ) + { + return ERROR; + } + + /* useful information on the screen */ + printf ("ReadRfm %s: [%s]\n", pSelf->name, pSelfParam->fieldString); + + return OK; +} + +/* + * Constructor Hooks - Called when a block of this type is instanciated (CONFIG or ADDBLCK commands) + */ + +STATUS tacReadRmBlockConstructor (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the ADDBLCK command */ + vltLOGICAL isRmn, + tacERROR* error) /* Error structure - not a stack */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = NULL; + + /* Check that the expected number of parameters has been received */ + if (parameter->number < tacREAD_RMN_EXPECTED_PARAM) + { + char errorParam[40]; + + sprintf(errorParam, "Expected at least %d, received %d", tacREAD_RMN_EXPECTED_PARAM, parameter->number); + tacRTC_ERR(tacERR_PARAM_NUMBER, errorParam); + return ERROR; + } + + /* Allocate and initialize block-specific arrays */ + if (tacStdBlockAllocateArrays(pSelf, 0, tacREAD_RMN_DEFAULT_INPUT_NUMBER, tacREAD_RMN_DEFAULT_OUTPUT_NUMBER, error) == ERROR) + { + return ERROR; + } + + if (tacStdBlockAllocateArrayBySize(pSelf, tacSTDBLOCK_PARAM_ARRAY, sizeof(tacRMN_LOCAL_PARAMETER), error) == ERROR) + { + tacStdBlockReleaseArray(pSelf, tacSTDBLOCK_INPUT_ARRAY, error); + tacStdBlockReleaseArray(pSelf, tacSTDBLOCK_OUTPUT_ARRAY, error); + return ERROR; + } + + if ( isRmn ) + { + if ( tacReadRmnBlockCheckParameter (pSelf, parameter, error) == ERROR) + { + return ERROR; + } + } + else + { + if ( tacReadRfmBlockCheckParameter (pSelf, parameter, error) == ERROR) + { + return ERROR; + } + } + + pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + pSelfParam->handleValid = rmassACCESS_BLOCKED; + + /* Attach to RMN */ + if ( rmassReadAttach (&pSelfParam->handle, + pSelfParam->fieldString, + &pSelfParam->val[0], + &pSelfParam->val[1], + &pSelfParam->val[2], + &pSelfParam->val[3], + &pSelfParam->val[4], + &pSelfParam->val[5], + &pSelfParam->val[6], + &pSelfParam->val[7], + &pSelfParam->val[8], + &pSelfParam->val[9]) != SUCCESS ) + { + char errorParam[40]; + + sprintf(errorParam, "Attach to RMN failed."); + tacRTC_ERR(tacERR_INTERNAL, errorParam); + return ERROR; + } + + pSelfParam->handleValid = rmassACCESS_FREE; + + return OK; +} + +STATUS tacReadRmnBlockConstructor (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the ADDBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + if ( tacReadRmBlockConstructor (pSelf, parameter, ccsTRUE, error ) == ERROR ) + { + return ERROR; + } + return OK; +} + +STATUS tacReadRfmBlockConstructor (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the ADDBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + if ( tacReadRmBlockConstructor (pSelf, parameter, ccsFALSE, error ) == ERROR ) + { + return ERROR; + } + return OK; +} + + + +/* + * Destructor Hooks - Called when the block is removed from the algorithm (DELBLCK or new CONFIG commands) + */ + +void tacReadRmnBlockDestructor (tacSTDBLOCK* pSelf) /* Reference to the block instance */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = NULL; + pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + pSelfParam->handleValid = rmassACCESS_BLOCKED; + /* wait until semaphore is acknowledged by realtime algo + * or just procede if realtime is not active */ + while ((*pSelf->shared).active && pSelfParam->handleValid != rmassACCESS_BLOCK_ACKN) + { + taskDelay(1); + } + + rmassDetach (&pSelfParam->handle); + + return; +} + +/* + * Change parameters Hooks - Called when modifying the block parameters (MODBLCK command) + */ + +STATUS tacReadRmnBlockSetParameter (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the MODBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + if ( tacReadRmnBlockCheckParameter (pSelf, parameter, error) == ERROR) + { + return ERROR; + } + + pSelfParam->handleValid = rmassACCESS_BLOCKED; + /* wait until semaphore is acknowledged by realtime algo + * or just procede if realtime is not active */ + while ((*pSelf->shared).active && pSelfParam->handleValid != rmassACCESS_BLOCK_ACKN) + { + taskDelay(1); + } + + /* detach RMN handle */ + if ( rmassDetach (&pSelfParam->handle) != SUCCESS ) + { + char errorParam[40]; + + sprintf(errorParam, "rmassDetach returned error."); + tacRTC_ERR(tacERR_INTERNAL, errorParam); + return ERROR; + } + + if ( rmassReadAttach (&pSelfParam->handle, + pSelfParam->fieldString, + &pSelfParam->val[0], + &pSelfParam->val[1], + &pSelfParam->val[2], + &pSelfParam->val[3], + &pSelfParam->val[4], + &pSelfParam->val[5], + &pSelfParam->val[6], + &pSelfParam->val[7], + &pSelfParam->val[8], + &pSelfParam->val[9]) != SUCCESS ) + { + char errorParam[40]; + + sprintf(errorParam, "Attach to RMN failed."); + tacRTC_ERR(tacERR_INTERNAL, errorParam); + return ERROR; + } + + pSelfParam->handleValid = rmassACCESS_FREE; + + return OK; +} + +STATUS tacReadRfmBlockSetParameter (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the MODBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + if ( tacReadRfmBlockCheckParameter (pSelf, parameter, error) == ERROR) + { + return ERROR; + } + + pSelfParam->handleValid = rmassACCESS_BLOCKED; + /* wait until semaphore is acknowledged by realtime algo + * or just procede if realtime is not active */ + while ((*pSelf->shared).active && pSelfParam->handleValid != rmassACCESS_BLOCK_ACKN) + { + taskDelay(1); + } + + /* detach RMN handle */ + if ( rmassDetach (&pSelfParam->handle) != SUCCESS ) + { + char errorParam[40]; + + sprintf(errorParam, "rmassDetach returned error."); + tacRTC_ERR(tacERR_INTERNAL, errorParam); + return ERROR; + } + + if ( rmassReadAttach (&pSelfParam->handle, + pSelfParam->fieldString, + &pSelfParam->val[0], + &pSelfParam->val[1], + &pSelfParam->val[2], + &pSelfParam->val[3], + &pSelfParam->val[4], + &pSelfParam->val[5], + &pSelfParam->val[6], + &pSelfParam->val[7], + &pSelfParam->val[8], + &pSelfParam->val[9]) != SUCCESS ) + { + char errorParam[40]; + + sprintf(errorParam, "Attach to RFM failed."); + tacRTC_ERR(tacERR_INTERNAL, errorParam); + return ERROR; + } + + pSelfParam->handleValid = rmassACCESS_FREE; + + return OK; +} + +/* + * Algorithm Hooks - Called at each time the TAC algorithm is evaluated (ONLINE state) + */ + +void tacReadRmnBlockAlgorithm (tacSTDBLOCK* pSelf) /* Reference to the block instance */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + int i; + + if ( pSelfParam->handleValid == rmassACCESS_BLOCKED ) + { + pSelfParam->handleValid = rmassACCESS_BLOCK_ACKN; + } + + if ( pSelfParam->handleValid == rmassACCESS_FREE ) + { + /* actual RMN read operation */ + rmassReadAccessRmn (&pSelfParam->handle); + + /* Write to outputs */ + for (i=0; i < pSelfParam->numFields; i++) + { + switch (pSelfParam->type[i]) + { + case rmassTIMESEC: + case rmassUINT32: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).ui); + break; + case rmassTIMEUSEC: + case rmassINT32: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).i); + break; + case rmassFLOAT: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).f); + break; + default: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).d); + break; + } + } + + /* provide zero values at unsatisfied outputs + * I consider this a good thing to do since the block + * is always configured */ + for (i=pSelfParam->numFields; i < tacREAD_RMN_DEFAULT_OUTPUT_NUMBER; i++) + { + tacStdBlockSetOutput(pSelf, i, 0.0); + } + } +} + +void tacReadRfmBlockAlgorithm (tacSTDBLOCK* pSelf) /* Reference to the block instance */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + int i; + + if ( pSelfParam->handleValid == rmassACCESS_BLOCKED ) + { + pSelfParam->handleValid = rmassACCESS_BLOCK_ACKN; + } + + if ( pSelfParam->handleValid == rmassACCESS_FREE ) + { + /* actual RMN read operation */ + rmassReadAccessRfm (&pSelfParam->handle); + + /* Write to outputs */ + for (i=0; i < pSelfParam->numFields; i++) + { + switch (pSelfParam->type[i]) + { + case rmassTIMESEC: + case rmassUINT32: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).ui); + break; + case rmassTIMEUSEC: + case rmassINT32: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).i); + break; + case rmassFLOAT: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).f); + break; + default: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).d); + break; + } + } + + /* provide zero values at unsatisfied outputs + * I consider this a good thing to do since the block + * is always configured */ + for (i=pSelfParam->numFields; i < tacREAD_RMN_DEFAULT_OUTPUT_NUMBER; i++) + { + tacStdBlockSetOutput(pSelf, i, 0.0); + } + } +} + +/* + * Show Hooks - Called when the tacRtcTaskShow routine is executed + */ + +void tacReadRmnBlockShow (tacSTDBLOCK* pSelf) /* Reference to the block instance */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + /* Print parameter values */ + printf(" Attached: %s\n", pSelfParam->fieldString); + + return; +} + + +/***************************************************/ +/* The following code is common to all block types */ +/* Do not modify without any good reasons */ +/***************************************************/ + +/* + * Installation function + */ + +tacSTDBLOCK_TYPE tacReadRmnTypeInfo = { + "ReadRmn", + &tacReadRmnBlockConstructor, + &tacRmBlockGetParameter, + &tacReadRmnBlockAlgorithm, + &tacReadRmnBlockSetParameter, + NULL, + NULL, + &tacReadRmnBlockDestructor, + &tacReadRmnBlockShow +}; + +tacSTDBLOCK_TYPE tacReadRfmTypeInfo = { + "ReadRfm", + &tacReadRfmBlockConstructor, + &tacRmBlockGetParameter, + &tacReadRfmBlockAlgorithm, + &tacReadRmnBlockSetParameter, + NULL, + NULL, + &tacReadRmnBlockDestructor, + &tacReadRmnBlockShow +}; + +STATUS tacReadRmnBlockInitAll (void) +{ + /***************************************************/ + /* The following code is common to all block types */ + /* Do not modify without any good reasons */ + /***************************************************/ + + /* Install ReadRmn1g Block Hooks */ + tacStdBlockInstallNewType(&tacReadRmnTypeInfo); + + /*****************************/ + /* End of common code region */ + /*****************************/ + + /* Perform other library initialization operations */ + + return OK; +} + +STATUS tacReadRfmBlockInitAll (void) +{ + /***************************************************/ + /* The following code is common to all block types */ + /* Do not modify without any good reasons */ + /***************************************************/ + + /* Install ReadRmn1g Block Hooks */ + tacStdBlockInstallNewType(&tacReadRfmTypeInfo); + + /*****************************/ + /* End of common code region */ + /*****************************/ + + /* Perform other library initialization operations */ + + return OK; +} + +/*___oOo___*/ + + + diff --git a/hardcodedFiles/tacSinkBlock.c b/hardcodedFiles/tacSinkBlock.c new file mode 100644 index 0000000..df39833 --- /dev/null +++ b/hardcodedFiles/tacSinkBlock.c @@ -0,0 +1,1256 @@ +/******************************************************************************* +* E.S.O. - VLT project +* +* "@(#) $Id: tacSinkBlock.c 339094 2021-02-10 03:10:02Z jgil $" +* +* who when what +* ------- -------- ---------------------------------------------- +* rdembet 06/08/20 New MonitorState block with no data averaging +* swehner 28/11/09 SPR20090234 Correction in rate adjustment in reset hook +* swehner 27/11/09 Fixed message queue handling +* swehner 10/10/09 New block FastProbe for unlimited rec frequency +* swehner 22/09/09 PPRS 32341 Replaced specialized tacSINK_SHMSG stack +* with standard vxWorks message queue. +* bbauvir 21/09/04 VLTSW20040113 - One sample might be lost +* bbauvir 29/03/04 Monitor block averages over the reporting period +* bbauvir 29/12/02 Probe to the SampTask +* bbauvir 26/12/02 MsgQ access through DPC mechanism +* bbauvir 14/07/02 New MsgQ of TAC version 1.22 +* bbauvir 21/03/01 Created +*/ + +/************************************************************************ +* NAME +* tacSinkBlock - Standard data monitoring blocks +* +* SYNOPSIS +* lcubootAutoCdBoot 1,"tacsink.boot" +* < tacsink.boot +* +* DESCRIPTION +* Block type: Display +* Parameters: +* Inputs: 1 +* Outputs: none +* +* This function block samples the value of its input signal at the +* specified and issues a message containing the time +* and the value of the input on the vxWorks terminal. +* It does not allow modification of the parameter at runtime. +* +* Block type: Monitor +* Parameters: +* +* Inputs: 10max +* Outputs: none +* +* This function block samples the value of its input signals at the +* specified (0.0 to send a message at the system sampling +* period) and issues a message containing the time and the value of +* the inputs on the shared memory. This message is intercepted by the +* background task running on the master CPU. The monitored values are +* written into the online database. The number of inputs of the block +* is specified by parameter. +* This block does not allow modification of the parameters at runtime. +* +* Block type: MonitorState +* Parameters: +* +* Inputs: 10max +* Outputs: none +* +* Same as Monitor block but without the averaging of received data, +* see VLTSW-14260 JIRA ticket. +* +* Block type: Probe +* Parameters: +* +* Inputs: 10max +* Outputs: none +* +* Block type: FastProbe +* Parameters: +* +* Inputs: 10max +* Outputs: none +* +* This function block samples the value of its input signals at the +* specified (0.0 to send a message at the system sampling +* period) and issues a message containing the time and the value of +* the inputs on the shared memory. This message is intercepted by the +* background task running on the master CPU. The number of inputs of +* the block is specified by parameter. +* This message is passed to an external application callback if +* provided. +* This block does not allow modification of the parameters at runtime. +* The normal Probe block has a limited sampling frequency of not more +* than 2kHz. The reason is in particular the bottleneck between master +* and slave CPU which all samples have to pass through a mechanism of +* VME bus shared memory. On one-CPU-systems this limitation does not +* apply so you are free to choose faster sampling. You may of course +* hit other limitations (processor speed, network traffic etc.) +* +* FILES +* +* ENVIRONMENT +* TAC +* +* RETURN VALUES +* +* CAUTIONS +* All these blocks compute an decimation value to use to trigger the +* sampling of the input signals, from the system sampling period. +* They should be created after any synchronization block. +* +* In order to cope with system performances, a minimum +* is defined for each block. The minimum applied periods are 0.1 (10Hz), +* 0.01 (100Hz) and 0.5e-3 (2kHz) for the 'Display', 'Monitor' and +* 'Probe' blocks respectively. +* +* EXAMPLES +* # 5 signals @ 2Hz (monitored in the database) +* TAC.BLOCK9.TYPE Monitor +* TAC.BLOCK9.NAME Monitor +* TAC.BLOCK9.PARAM 0.5, 5 +* +* # 5 signals @ the RT algorithm sampling period (0.0) +* TAC.BLOCK10.TYPE Probe +* TAC.BLOCK10.NAME Probe +* TAC.BLOCK10.PARAM 0.0, 5 +* +* SEE ALSO +* tacServerInstallDataCallback, tacServerRemoveDataCallback +* +* BUGS +* +*------------------------------------------------------------------------ +*/ + +#define _POSIX_SOURCE 1 +#include "vltPort.h" + + +/* + * System Headers + */ + +#include +#include +#include /* logMsg ... */ +#include /* printf ... */ +#include /* malloc ... */ +#include /* memcpy ... */ +#include + +/* + * Local Headers + */ + +#include "tacStdBlock.h" +#include "tacShMsgQ.h" + +/* + * Compilation directives + */ + +/* + * Constants + */ + +#define tacSINK_DEFAULT_EXPECTED_PARAM 2 + +#define tacSINK_DEFAULT_INPUT_NUMBER tacMAX_DATA_NUMBER /* Up to 10 input channels */ +#define tacSINK_DEFAULT_OUTPUT_NUMBER tacMAX_DATA_NUMBER + +#define tacSINK_ONE_EXPECTED_PARAM 1 +#define tacSINK_ONE_INPUT_NUMBER 1 + +#define tacSINK_DISPLAY_MIN_SAMPLING_PERIOD .1 /* 10Hz */ +#define tacSINK_MONITOR_MIN_SAMPLING_PERIOD .01 /* 100Hz */ +#define tacSINK_PROBE_MIN_SAMPLING_PERIOD .5e-3 /* 2kHz */ + +#define tacSINK_DISPLAY_LOG_STRING_SIZE 128 + +#define tacSINK_MONITOR_DEFAULT_DB_POINT "tac:data:monitor" +#define tacSINK_MONITOR_MAX_DB_ADDR_SIZE 64 + +#define tacSINK_MONITOR_QUEUE_SIZE 6 +#define tacSINK_PROBE_QUEUE_SIZE 6 + + +typedef enum { + tacSINK_SAMPLING_PERIOD = 0, + tacSINK_INPUT_NUMBER, + tacSINK_MONITOR_DB_POINT, +}tacSINK_SCOPE_PARAM_INDEX; + +/* + * Types + */ + +typedef struct { + unsigned short rate; + unsigned short counter; + unsigned short inputNb; + unsigned int lost; + double rateParam; + char* dbPoint; + MSG_Q_ID msgq; + tacSHMSG shmMsg; +}tacSINK_SCOPE_LOCAL_PARAMETER; + +/* + * Function declaration + */ + +extern STATUS tacDpcPushRequest(tacVOIDFCTPTR pFunct, void* parameter); + +/* + * Local function declaration + */ + +/* + * Note: Routines called from within the algorithm must be declared with + * static __inline__ + */ + +STATUS tacSinkSendMonitorMessage(MSG_Q_ID * msgqvoid); +STATUS tacSinkSendMonitorStateMessage(MSG_Q_ID * msgqvoid); +STATUS tacSinkSendProbeMessage(MSG_Q_ID * msgq); +STATUS tacSinkDeleteMessageQueue(MSG_Q_ID * msgq); +STATUS tacSinkCommonBlockConstructor(tacSTDBLOCK* pSelf, tacERROR* error); + +/* + * Global variables + */ + +char logStr[tacSINK_DISPLAY_LOG_STRING_SIZE]; /* Logging string used for Display */ + + +/* + * Function definition + */ + +/* + * Constructor Hooks + */ + +STATUS tacSinkDisplayBlockConstructor (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = NULL; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = NULL; + + /* Check that the expected number of parameters has been received */ + if (parameter->number < tacSINK_ONE_EXPECTED_PARAM) + { + char errorParam[40]; + + sprintf(errorParam, "Expected %d, received %d", tacSINK_ONE_EXPECTED_PARAM, parameter->number); + tacRTC_ERR(tacERR_PARAM_NUMBER, errorParam); + return ERROR; + } + + /* Check that the parameters are valid */ + pRealParam = (double*) parameter->buffer; + + /* Passed parameter is the sampling period of the block */ + if (pRealParam[tacSINK_SAMPLING_PERIOD] < (*pSelf->shared).samplingPeriod) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = (*pSelf->shared).samplingPeriod; + } + + if (pRealParam[tacSINK_SAMPLING_PERIOD] < tacSINK_DISPLAY_MIN_SAMPLING_PERIOD) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = tacSINK_DISPLAY_MIN_SAMPLING_PERIOD; + } + + /* Call common constructor */ + if (tacSinkCommonBlockConstructor(pSelf, error) != OK) + { + return ERROR; + } + + /* Store parameters */ + pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; /* We will only store short integers */ + + /* + * Compute the rate at which data has to be processed - divide and take + * the integer part of the result + */ + + pSelfParam->rate = (unsigned short) (pRealParam[tacSINK_SAMPLING_PERIOD] / (*pSelf->shared).samplingPeriod); + pSelfParam->counter = 0; /* Decimation counter */ + + /* + * Perform other block initialization operations + */ + + return OK; +} + +STATUS tacSinkMonitorBlockConstructor (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = NULL; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = NULL; + unsigned short arrayIndex = 0; + + /* Check that the expected number of parameters has been received */ + if (parameter->number < tacSINK_DEFAULT_EXPECTED_PARAM) + { + char errorParam[40]; + + sprintf(errorParam, "Expected %d, received %d", tacSINK_DEFAULT_EXPECTED_PARAM, parameter->number); + tacRTC_ERR(tacERR_PARAM_NUMBER, errorParam); + return ERROR; + } + + /* Check that the parameters are valid */ + pRealParam = (double*) parameter->buffer; + + /* Passed parameter is the sampling period of the block */ + if (pRealParam[tacSINK_SAMPLING_PERIOD] < (*pSelf->shared).samplingPeriod) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = (*pSelf->shared).samplingPeriod; + } + + if (pRealParam[tacSINK_SAMPLING_PERIOD] < tacSINK_MONITOR_MIN_SAMPLING_PERIOD) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = tacSINK_MONITOR_MIN_SAMPLING_PERIOD; + } + + /* Number of inputs is minimum 1 up to tacMSG_MAX_DATA_NUMBER */ + if ((pRealParam[tacSINK_INPUT_NUMBER] < 1) || + (pRealParam[tacSINK_INPUT_NUMBER] > tacMAX_DATA_NUMBER)) + { + tacRTC_ERR(tacERR_PARAM_INVALID, ""); + return ERROR; + } + + /* Call common constructor */ + if (tacSinkCommonBlockConstructor(pSelf, error) != OK) + { + return ERROR; + } + + /* Store parameters */ + pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* + * Compute the rate at which data has to be processed - divide and take + * the integer part of the result + */ + + pSelfParam->rate = (unsigned short) (pRealParam[tacSINK_SAMPLING_PERIOD] / (*pSelf->shared).samplingPeriod); + pSelfParam->counter = 0; /* Decimation counter */ + pSelfParam->inputNb = (unsigned short) pRealParam[tacSINK_INPUT_NUMBER]; + + /* Optional parameter is an application-specific DB point */ + if (parameter->number == tacSINK_DEFAULT_EXPECTED_PARAM + 1) + { + printf("tacSinkMonitorBlockConstructor - DB point %s\n",(char*) &(pRealParam[tacSINK_MONITOR_DB_POINT])); + pSelfParam->dbPoint = (char*) malloc(tacSINK_MONITOR_MAX_DB_ADDR_SIZE); + strcpy(pSelfParam->dbPoint, (char*) &(pRealParam[tacSINK_MONITOR_DB_POINT])); + } + else + { + printf("tacSinkMonitorBlockConstructor - Default DB point\n"); + pSelfParam->dbPoint = NULL; + } + + /* Specify the number of input signals to attach to become resolved */ + tacStdBlockSetInputNumber(pSelf, pSelfParam->inputNb); + + /* + * Perform other block initialization operations + */ + + /* Create the block internal message queue which tosses the messages out of the + * interrupt context. They are buffered in the queue until the DPC tasks + * picks them up and sends them over the shared memory message queue. + * Sorry for that double-queuing, that's because of the M-S architecture */ + + pSelfParam->msgq = msgQCreate(tacSINK_MONITOR_QUEUE_SIZE, sizeof(tacSHMSG), 0); + if ( pSelfParam->msgq == NULL ) + { + char errorParam[40]; + + sprintf(errorParam, "Could not create probe block message queue"); + tacRTC_ERR(tacERR_MALLOC, errorParam); + return ERROR; + } + + /* will count if a message can't be pushed in the queue */ + pSelfParam->lost = 0; + + /* Warn the background task that a new probe block has been created */ + pSelfParam->shmMsg.type = tacSHMSG_ADD_MONITOR; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + + if (pSelfParam->dbPoint == NULL) + { + strcpy((char*) &(pSelfParam->shmMsg.msgBody.monitor.data), tacSINK_MONITOR_DEFAULT_DB_POINT); + } + else + { + strcpy((char*) &(pSelfParam->shmMsg.msgBody.monitor.data), *((char**) &(pSelfParam->dbPoint))); + } + + printf("tacSinkMonitorBlockConstructor - Attach to %s\n",(char*) &(pSelfParam->shmMsg.msgBody.monitor.data)); + + /* Send message */ + tacShMsgQSendBgInfo(&(pSelfParam->shmMsg)); + + /* Initialize the message parameters */ + pSelfParam->shmMsg.type = tacSHMSG_MONITOR_DATA; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + pSelfParam->shmMsg.msgBody.monitor.data.number = pSelfParam->inputNb; + + /* The output port is used to average the inputs over the reporting period */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pSelf->output[arrayIndex] = 0.0; + } + + return OK; +} + +STATUS tacSinkMonitorStateBlockConstructor (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = NULL; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = NULL; + unsigned short arrayIndex = 0; + + /* Check that the expected number of parameters has been received */ + if (parameter->number < tacSINK_DEFAULT_EXPECTED_PARAM) + { + char errorParam[40]; + + sprintf(errorParam, "Expected %d, received %d", tacSINK_DEFAULT_EXPECTED_PARAM, parameter->number); + tacRTC_ERR(tacERR_PARAM_NUMBER, errorParam); + return ERROR; + } + + /* Check that the parameters are valid */ + pRealParam = (double*) parameter->buffer; + + /* Passed parameter is the sampling period of the block */ + if (pRealParam[tacSINK_SAMPLING_PERIOD] < (*pSelf->shared).samplingPeriod) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = (*pSelf->shared).samplingPeriod; + } + + if (pRealParam[tacSINK_SAMPLING_PERIOD] < tacSINK_MONITOR_MIN_SAMPLING_PERIOD) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = tacSINK_MONITOR_MIN_SAMPLING_PERIOD; + } + + /* Number of inputs is minimum 1 up to tacMSG_MAX_DATA_NUMBER */ + if ((pRealParam[tacSINK_INPUT_NUMBER] < 1) || + (pRealParam[tacSINK_INPUT_NUMBER] > tacMAX_DATA_NUMBER)) + { + tacRTC_ERR(tacERR_PARAM_INVALID, ""); + return ERROR; + } + + /* Call common constructor */ + if (tacSinkCommonBlockConstructor(pSelf, error) != OK) + { + return ERROR; + } + + /* Store parameters */ + pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* + * Compute the rate at which data has to be processed - divide and take + * the integer part of the result + */ + + pSelfParam->rate = (unsigned short) (pRealParam[tacSINK_SAMPLING_PERIOD] / (*pSelf->shared).samplingPeriod); + pSelfParam->counter = 0; /* Decimation counter */ + pSelfParam->inputNb = (unsigned short) pRealParam[tacSINK_INPUT_NUMBER]; + + /* Optional parameter is an application-specific DB point */ + if (parameter->number == tacSINK_DEFAULT_EXPECTED_PARAM + 1) + { + printf("tacSinkMonitorStateBlockConstructor - DB point %s\n",(char*) &(pRealParam[tacSINK_MONITOR_DB_POINT])); + pSelfParam->dbPoint = (char*) malloc(tacSINK_MONITOR_MAX_DB_ADDR_SIZE); + strcpy(pSelfParam->dbPoint, (char*) &(pRealParam[tacSINK_MONITOR_DB_POINT])); + } + else + { + printf("tacSinkMonitorStateBlockConstructor - Default DB point\n"); + pSelfParam->dbPoint = NULL; + } + + /* Specify the number of input signals to attach to become resolved */ + tacStdBlockSetInputNumber(pSelf, pSelfParam->inputNb); + + /* + * Perform other block initialization operations + */ + + /* Create the block internal message queue which tosses the messages out of the + * interrupt context. They are buffered in the queue until the DPC tasks + * picks them up and sends them over the shared memory message queue. + * Sorry for that double-queuing, that's because of the M-S architecture */ + + pSelfParam->msgq = msgQCreate(tacSINK_MONITOR_QUEUE_SIZE, sizeof(tacSHMSG), 0); + if ( pSelfParam->msgq == NULL ) + { + char errorParam[40]; + + sprintf(errorParam, "Could not create probe block message queue"); + tacRTC_ERR(tacERR_MALLOC, errorParam); + return ERROR; + } + + /* will count if a message can't be pushed in the queue */ + pSelfParam->lost = 0; + + /* Warn the background task that a new probe block has been created */ + pSelfParam->shmMsg.type = tacSHMSG_ADD_MONITOR; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + + if (pSelfParam->dbPoint == NULL) + { + strcpy((char*) &(pSelfParam->shmMsg.msgBody.monitor.data), tacSINK_MONITOR_DEFAULT_DB_POINT); + } + else + { + strcpy((char*) &(pSelfParam->shmMsg.msgBody.monitor.data), *((char**) &(pSelfParam->dbPoint))); + } + + printf("tacSinkMonitorStateBlockConstructor - Attach to %s\n",(char*) &(pSelfParam->shmMsg.msgBody.monitor.data)); + + /* Send message */ + tacShMsgQSendBgInfo(&(pSelfParam->shmMsg)); + + /* Initialize the message parameters */ + pSelfParam->shmMsg.type = tacSHMSG_MONITOR_DATA; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + pSelfParam->shmMsg.msgBody.monitor.data.number = pSelfParam->inputNb; + + /* Init output port which won't be used to average the inputs over the reporting period */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pSelf->output[arrayIndex] = 0.0; + } + + return OK; +} + +STATUS tacSinkProbeBlockCommonConstructor (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + double minPeriod, + tacERROR* error) +{ + double* pRealParam = NULL; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = NULL; + + /* Check that the expected number of parameters has been received */ + if (parameter->number < tacSINK_DEFAULT_EXPECTED_PARAM) + { + char errorParam[40]; + + sprintf(errorParam, "Expected %d, received %d", tacSINK_DEFAULT_EXPECTED_PARAM, parameter->number); + tacRTC_ERR(tacERR_PARAM_NUMBER, errorParam); + return ERROR; + } + + /* Check that the parameters are valid */ + pRealParam = (double*) parameter->buffer; + + /* Passed parameter is the sampling period of the block */ + if (pRealParam[tacSINK_SAMPLING_PERIOD] < (*pSelf->shared).samplingPeriod) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = (*pSelf->shared).samplingPeriod; + } + + if (pRealParam[tacSINK_SAMPLING_PERIOD] < minPeriod) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = minPeriod; + } + + /* Number of inputs is minimum 1 up to tacMSG_MAX_DATA_NUMBER */ + if ((pRealParam[tacSINK_INPUT_NUMBER] < 1) || + (pRealParam[tacSINK_INPUT_NUMBER] > tacMAX_DATA_NUMBER)) + { + tacRTC_ERR(tacERR_PARAM_INVALID, ""); + return ERROR; + } + + /* Call common constructor */ + if (tacSinkCommonBlockConstructor(pSelf, error) != OK) + { + return ERROR; + } + + /* Store parameters */ + pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* + * Compute the rate at which data has to be processed - divide and take + * the integer part of the result + */ + + pSelfParam->rateParam = pRealParam[tacSINK_SAMPLING_PERIOD]; + pSelfParam->rate = (unsigned short) (pRealParam[tacSINK_SAMPLING_PERIOD] / (*pSelf->shared).samplingPeriod); + pSelfParam->counter = 0; /* Decimation counter */ + pSelfParam->inputNb = (unsigned short) pRealParam[tacSINK_INPUT_NUMBER]; + + /* Specify the number of input signals to attach to become resolved */ + tacStdBlockSetInputNumber(pSelf, pSelfParam->inputNb); + + /* + * Perform other block initialization operations + */ + + /* Create the block internal message queue which gets the messages out of the + * interrupt context. They are buffered in the queue until the DPC tasks + * picks them up and sends them over the shared memory message queue. + * Sorry for that double-queuing, that's because of the M-S architecture */ + + /* There is only one message queue for all probe blocks! */ + pSelfParam->msgq = msgQCreate(tacSINK_PROBE_QUEUE_SIZE, sizeof(tacSHMSG), 0); + if ( pSelfParam->msgq == NULL ) + { + char errorParam[40]; + + sprintf(errorParam, "Could not create probe block message queue"); + tacRTC_ERR(tacERR_MALLOC, errorParam); + return ERROR; + } + + /* will count if a message can't be pushed in the queue */ + pSelfParam->lost = 0; + + /* Warn the background task that a new probe block has been created */ + pSelfParam->shmMsg.type = tacSHMSG_ADD_PROBE; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + + /* Send message */ + tacShMsgQSendDataSample(&pSelfParam->shmMsg); + + /* Initialize the message parameters */ + pSelfParam->shmMsg.type = tacSHMSG_TRANSFER_DATA; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + pSelfParam->shmMsg.msgBody.monitor.data.number = pSelfParam->inputNb; + + return OK; +} + +/* Probe block has a max. sampling frequency of 2kHz */ +STATUS tacSinkProbeBlockConstructor (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + return tacSinkProbeBlockCommonConstructor (pSelf, parameter, tacSINK_PROBE_MIN_SAMPLING_PERIOD, error); +} + +/* Fast probe is the same as probe but not does have the + * limitation on the max. recording frequency */ +STATUS tacSinkFastProbeBlockConstructor (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + return tacSinkProbeBlockCommonConstructor (pSelf, parameter, 0.0, error); +} + +void tacSinkProbeBlockReset (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = + (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* + * Re-Compute the rate at which data has to be processed + */ + if (pSelfParam->rateParam < (*pSelf->shared).samplingPeriod ) + { + pSelfParam->rate = 1; + } + else + { + pSelfParam->rate = (unsigned short) + (pSelfParam->rateParam / (*pSelf->shared).samplingPeriod); + } + + return; +} + +/* + * Report parameters Hooks + */ + +STATUS tacSinkDisplayBlockGetParameter (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = (double*) parameter->buffer; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Send back the expected number of parameters */ + parameter->number = tacSINK_ONE_EXPECTED_PARAM; + + /* Report current parameters */ + pRealParam[tacSINK_SAMPLING_PERIOD] = (double) (pSelfParam->rate * (*pSelf->shared).samplingPeriod); + + return OK; +} + +STATUS tacSinkMonitorBlockGetParameter (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = (double*) parameter->buffer; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Send back the expected number of parameters */ + parameter->number = tacSINK_DEFAULT_EXPECTED_PARAM; + + /* Report current parameters */ + pRealParam[tacSINK_SAMPLING_PERIOD] = (double) (pSelfParam->rate * (*pSelf->shared).samplingPeriod); + pRealParam[tacSINK_INPUT_NUMBER] = (double) pSelfParam->inputNb; + + if (*((char**) &(pSelfParam->dbPoint)) != NULL) + { + parameter->number += 1; + parameter->type[tacSINK_MONITOR_DB_POINT] = tacPARAM_STRING; + strcpy((char*) &(pRealParam[tacSINK_MONITOR_DB_POINT]), *((char**) &(pSelfParam->dbPoint))); + } + + return OK; +} + +STATUS tacSinkMonitorStateBlockGetParameter (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = (double*) parameter->buffer; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Send back the expected number of parameters */ + parameter->number = tacSINK_DEFAULT_EXPECTED_PARAM; + + /* Report current parameters */ + pRealParam[tacSINK_SAMPLING_PERIOD] = (double) (pSelfParam->rate * (*pSelf->shared).samplingPeriod); + pRealParam[tacSINK_INPUT_NUMBER] = (double) pSelfParam->inputNb; + + if (*((char**) &(pSelfParam->dbPoint)) != NULL) + { + parameter->number += 1; + parameter->type[tacSINK_MONITOR_DB_POINT] = tacPARAM_STRING; + strcpy((char*) &(pRealParam[tacSINK_MONITOR_DB_POINT]), *((char**) &(pSelfParam->dbPoint))); + } + + return OK; +} + +STATUS tacSinkProbeBlockGetParameter (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = (double*) parameter->buffer; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Send back the expected number of parameters */ + parameter->number = tacSINK_DEFAULT_EXPECTED_PARAM; + + /* Report current parameters */ + pRealParam[tacSINK_SAMPLING_PERIOD] = (double) (pSelfParam->rate * (*pSelf->shared).samplingPeriod); + pRealParam[tacSINK_INPUT_NUMBER] = (double) pSelfParam->inputNb; + + return OK; +} + +/* + * Change parameters Hooks + */ + +/* + * Algorithm Hooks + */ + +void tacSinkDisplayBlockAlgorithm (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + if ((pSelfParam->counter % pSelfParam->rate) == 0) /* It's time to process data */ + { + sprintf(logStr,"Name: %s Time: %ld.%6ld Value: %g\n", + pSelf->name, + (*pSelf->shared).currentTime.seconds, + (*pSelf->shared).currentTime.microsec, + tacStdBlockGetInput(pSelf,0)); + + tacDpcPushRequest((tacVOIDFCTPTR) &printf, logStr); + + pSelfParam->counter = 0; + } + + pSelfParam->counter++; +} + +void tacSinkMonitorBlockAlgorithm (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + unsigned short arrayIndex = 0; + + /* The output port is used to average the inputs over the reporting period */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pSelf->output[arrayIndex] += tacStdBlockGetInput(pSelf,arrayIndex); + } + + if ((pSelfParam->counter % pSelfParam->rate) == 0) /* It's time to process data */ + { + tacDATA* pData = &(pSelfParam->shmMsg.msgBody.monitor.data); /* We are only interested in message body */ + + /* pData->number = pSelfParam->inputNb; */ + pData->timeStamp = (*pSelf->shared).currentTime; + + /* pData points to the body of the Message */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pData->buffer[arrayIndex] = pSelf->output[arrayIndex] / pSelfParam->rate; + } + + /* Push message into probe block's message que to get the + * data out of the interrupt comtext. */ + if ( msgQSend (pSelfParam->msgq, (char*) &(pSelfParam->shmMsg), sizeof(tacSHMSG), NO_WAIT, 0) != OK ) + { + (pSelfParam->lost)++; + } + + /* Defer procedure call */ + tacDpcPushRequest((tacVOIDFCTPTR) &tacSinkSendMonitorMessage, &pSelfParam->msgq); + + pSelfParam->counter = 0; + + /* The output port is used to average the inputs over the reporting period */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pSelf->output[arrayIndex] = 0.0; + } + } + + pSelfParam->counter++; +} + +void tacSinkMonitorStateBlockAlgorithm (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + unsigned short arrayIndex = 0; + + if ((pSelfParam->counter % pSelfParam->rate) == 0) /* It's time to process data */ + { + tacDATA* pData = &(pSelfParam->shmMsg.msgBody.monitor.data); /* We are only interested in message body */ + + /* pData->number = pSelfParam->inputNb; */ + pData->timeStamp = (*pSelf->shared).currentTime; + + /* pData points to the body of the Message */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pData->buffer[arrayIndex] = tacStdBlockGetInput(pSelf,arrayIndex); + } + + /* Push message into probe block's message que to get the + * data out of the interrupt comtext. */ + if ( msgQSend (pSelfParam->msgq, (char*) &(pSelfParam->shmMsg), sizeof(tacSHMSG), NO_WAIT, 0) != OK ) + { + (pSelfParam->lost)++; + } + + /* Defer procedure call */ + tacDpcPushRequest((tacVOIDFCTPTR) &tacSinkSendMonitorMessage, &pSelfParam->msgq); + + pSelfParam->counter = 0; + } + + pSelfParam->counter++; +} + +void tacSinkProbeBlockAlgorithm (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + unsigned short arrayIndex = 0; + + if ((pSelfParam->counter % pSelfParam->rate) == 0) /* It's time to process data */ + { + tacDATA* pData = &(pSelfParam->shmMsg.msgBody.monitor.data); /* We are only interested in message body */ + + pData->timeStamp = (*pSelf->shared).currentTime; + + /* pData points to the body of the Message */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pData->buffer[arrayIndex] = tacStdBlockGetInput(pSelf,arrayIndex); + } + + /* Push message into probe block's message que to get the + * data out of the interrupt comtext. */ + if ( msgQSend (pSelfParam->msgq, (char*) &(pSelfParam->shmMsg), sizeof(tacSHMSG), NO_WAIT, 0) != OK ) + { + (pSelfParam->lost)++; + } + + /* Defer procedure call: + * tacSinkSendProbeMessage is called outside the interrupt routine + * and will take care to pick up the message from the probe block's + * message queue and send it over the shared memory message queue */ + tacDpcPushRequest((tacVOIDFCTPTR) &tacSinkSendProbeMessage, &pSelfParam->msgq); + + pSelfParam->counter = 0; + } + + pSelfParam->counter++; +} + +/* + * Reset Hooks + */ + +/* + * Stop Hooks + */ + +/* + * Destructor Hooks + */ + +/* + * Note: This destructor is used mainly to send a MONITOR message containing + * 0.0 in order to reset the database array (otherwise going from an + * algorithm with 4 monitored data to one with 3 monitored data leaves + * the 4th value equal to the last ...) + */ + +void tacSinkMonitorBlockDestructor (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + tacDATA* pData = &(pSelfParam->shmMsg.msgBody.monitor.data); + unsigned short arrayIndex = 0; + + /* Reset DB values */ + pSelfParam->shmMsg.type = tacSHMSG_MONITOR_DATA; + pData = &(pSelfParam->shmMsg.msgBody.monitor.data); + + pData->number = pSelfParam->inputNb; + + /* pData points to the body of the Message */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pData->buffer[arrayIndex] = 0.0; + } + + /* Send message */ + tacShMsgQSendBgInfo(&pSelfParam->shmMsg); + + pSelfParam->shmMsg.type = tacSHMSG_REMOVE_MONITOR; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + + /* Send message */ + tacShMsgQSendBgInfo(&pSelfParam->shmMsg); + + free(pSelfParam->dbPoint); + + /* delete internal message queue. Do this as deferred procedure call + * to make sure it is only called when all messages have been send + * (through the same deferred call mechanism) */ + tacDpcPushRequest((tacVOIDFCTPTR) tacSinkDeleteMessageQueue, &(pSelfParam->msgq)); + + return; +} + +void tacSinkMonitorStateBlockDestructor (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + tacDATA* pData = &(pSelfParam->shmMsg.msgBody.monitor.data); + unsigned short arrayIndex = 0; + + /* Reset DB values */ + pSelfParam->shmMsg.type = tacSHMSG_MONITOR_DATA; + pData = &(pSelfParam->shmMsg.msgBody.monitor.data); + + pData->number = pSelfParam->inputNb; + + /* pData points to the body of the Message */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pData->buffer[arrayIndex] = 0.0; + } + + /* Send message */ + tacShMsgQSendBgInfo(&pSelfParam->shmMsg); + + pSelfParam->shmMsg.type = tacSHMSG_REMOVE_MONITOR; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + + /* Send message */ + tacShMsgQSendBgInfo(&pSelfParam->shmMsg); + + free(pSelfParam->dbPoint); + + /* delete internal message queue. Do this as deferred procedure call + * to make sure it is only called when all messages have been send + * (through the same deferred call mechanism) */ + tacDpcPushRequest((tacVOIDFCTPTR) tacSinkDeleteMessageQueue, &(pSelfParam->msgq)); + + return; +} + +void tacSinkProbeBlockDestructor (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + pSelfParam->shmMsg.type = tacSHMSG_REMOVE_PROBE; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + + /* Send message */ + tacShMsgQSendDataSample(&pSelfParam->shmMsg); + + /* delete internal message queue. Do this as deferred procedure call + * to make sure it is only called when all messages have been send + * (through the same deferred call mechanism) */ + tacDpcPushRequest((tacVOIDFCTPTR) tacSinkDeleteMessageQueue, &(pSelfParam->msgq)); + + return; +} + +/* + * Show Hooks + */ + +void tacSinkDisplayBlockShow (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Print parameter values */ + printf(" Update rate: %d\n",pSelfParam->rate); + + return; +} + +void tacSinkMonitorBlockShow (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Print parameter values */ + printf(" Update rate: %d\n",pSelfParam->rate); + printf(" Number of input signals: %d\n",pSelfParam->inputNb); + printf(" Queued samples: %d\n", msgQNumMsgs(pSelfParam->msgq)); + printf(" Lost samples: %d\n",pSelfParam->lost); + + if (pSelfParam->dbPoint != NULL) + { + printf(" DB Point: %s\n", pSelfParam->dbPoint); + } + + return; +} + +void tacSinkMonitorStateBlockShow (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Print parameter values */ + printf(" Using MonitorState block, not averaging received data\n"); + printf(" Update rate: %d\n",pSelfParam->rate); + printf(" Number of input signals: %d\n",pSelfParam->inputNb); + printf(" Queued samples: %d\n", msgQNumMsgs(pSelfParam->msgq)); + printf(" Lost samples: %d\n",pSelfParam->lost); + + if (pSelfParam->dbPoint != NULL) + { + printf(" DB Point: %s\n", pSelfParam->dbPoint); + } + + return; +} + +void tacSinkProbeBlockShow (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Print parameter values */ + printf(" Update rate: %d\n",pSelfParam->rate); + printf(" Update rate param (sec): %f\n",pSelfParam->rateParam); + printf(" Number of input signals: %d\n",pSelfParam->inputNb); + printf(" Queued samples: %d\n", msgQNumMsgs(pSelfParam->msgq)); + printf(" Lost samples: %d\n",pSelfParam->lost); + + return; +} + +/* + * Installation function + */ + +tacSTDBLOCK_TYPE tacSinkDisplayTypeInfo = { + "Display", + &tacSinkDisplayBlockConstructor, + &tacSinkDisplayBlockGetParameter, + &tacSinkDisplayBlockAlgorithm, + NULL, + NULL, + NULL, + NULL, + &tacSinkDisplayBlockShow, +}; + +tacSTDBLOCK_TYPE tacSinkMonitorTypeInfo = { + "Monitor", + &tacSinkMonitorBlockConstructor, + &tacSinkMonitorBlockGetParameter, + &tacSinkMonitorBlockAlgorithm, + NULL, + NULL, + NULL, + &tacSinkMonitorBlockDestructor, + &tacSinkMonitorBlockShow, +}; + +tacSTDBLOCK_TYPE tacSinkMonitorStateTypeInfo = { + "MonitorState", + &tacSinkMonitorStateBlockConstructor, + &tacSinkMonitorStateBlockGetParameter, + &tacSinkMonitorStateBlockAlgorithm, + NULL, + NULL, + NULL, + &tacSinkMonitorStateBlockDestructor, + &tacSinkMonitorStateBlockShow, +}; + +/* Probe with a maximal sampling rate of 2kHz */ +tacSTDBLOCK_TYPE tacSinkProbeTypeInfo = { + "Probe", + &tacSinkProbeBlockConstructor, + &tacSinkProbeBlockGetParameter, + &tacSinkProbeBlockAlgorithm, + NULL, + &tacSinkProbeBlockReset, + NULL, + &tacSinkProbeBlockDestructor, + &tacSinkProbeBlockShow, +}; + +/* Fast probe is the same as probe but not does have the + * limitation on the max. recording frequency */ +tacSTDBLOCK_TYPE tacSinkFastProbeTypeInfo = { + "FastProbe", + &tacSinkFastProbeBlockConstructor, + &tacSinkProbeBlockGetParameter, + &tacSinkProbeBlockAlgorithm, + NULL, + &tacSinkProbeBlockReset, + NULL, + &tacSinkProbeBlockDestructor, + &tacSinkProbeBlockShow, +}; + +STATUS tacSinkBlockInitAll (void) +{ + /* Install Sink Block Hooks */ + tacStdBlockInstallNewType(&tacSinkDisplayTypeInfo); + tacStdBlockInstallNewType(&tacSinkMonitorTypeInfo); + tacStdBlockInstallNewType(&tacSinkMonitorStateTypeInfo); + tacStdBlockInstallNewType(&tacSinkProbeTypeInfo); + tacStdBlockInstallNewType(&tacSinkFastProbeTypeInfo); + + /* + * Perform other library initialization operations + */ + + return OK; +} + +/* + * Local functions + */ + +/* + * Note: Routines called from within the algorithm must be declared with + * static __inline__ + */ + +STATUS tacSinkCommonBlockConstructor (tacSTDBLOCK* pSelf, + tacERROR* error) +{ + /* Allocate specific arrays (pointers are initialized to NULL by StdBlock) */ + if (tacStdBlockAllocateArrays(pSelf, 0, tacSINK_DEFAULT_INPUT_NUMBER, + tacSINK_DEFAULT_OUTPUT_NUMBER, error) == ERROR) + { + return ERROR; + } + + if (tacStdBlockAllocateArrayBySize(pSelf, tacSTDBLOCK_PARAM_ARRAY, + sizeof(tacSINK_SCOPE_LOCAL_PARAMETER), error) == ERROR) + { + tacStdBlockReleaseArray(pSelf, tacSTDBLOCK_INPUT_ARRAY, error); + tacStdBlockReleaseArray(pSelf, tacSTDBLOCK_OUTPUT_ARRAY, error); + return ERROR; + } + + /* Specify the number of input signals to attach to become resolved */ + tacStdBlockSetInputNumber(pSelf, tacSINK_ONE_INPUT_NUMBER); /* Required */ + + return OK; +} + +STATUS tacSinkSendMonitorMessage(MSG_Q_ID * msgq) +{ + /* Send message using provided function (different for Monitor and Probe blocks) */ + /* Send message using provided function (different for Monitor and Probe blocks) */ + tacSHMSG msg; + + if ( msgQReceive(*msgq, (char*) &msg, sizeof(tacSHMSG), NO_WAIT) == sizeof(tacSHMSG) ) + { + tacShMsgQSendBgInfo (&msg); + } + + return OK; +} + +STATUS tacSinkSendProbeMessage(MSG_Q_ID * msgq) +{ + /* Send message using provided function (different for Monitor and Probe blocks) */ + tacSHMSG msg; + + if ( msgq == NULL ) + { + return ERROR; + } + + if ( msgQReceive(*msgq, (char*) &msg, sizeof(tacSHMSG), NO_WAIT) == sizeof(tacSHMSG) ) + { + tacShMsgQSendDataSample (&msg); + } + return OK; +} + +STATUS tacSinkDeleteMessageQueue (MSG_Q_ID * msgq) +{ + /* Is called when block is destroyed and removes the internal message queue */ + STATUS status; + + status = msgQDelete (*msgq); + *msgq = NULL; + return status; +} + + +/*___oOo___*/ + + + + + + diff --git a/src/arguments.py b/src/arguments.py new file mode 100644 index 0000000..94e4cea --- /dev/null +++ b/src/arguments.py @@ -0,0 +1,26 @@ +import getopt + +def exitUsage(): + print("usage: %s <.tasrc file> -i -o " % sys.argv[0]) + sys.exit(1) + +def readArguments(args): + sourceDirectories = [] + outputFile = "" + try: + options, _ = getopt.getopt(args, "hi:o:") + except getopt.GetoptError: + exitUsage() + for option, arg in options: + if option == "-h": + exitUsage() + elif option == "-o": + outputFile = arg + elif option == "-i": + sourceDirectories.append(arg) + if outputFile == "": + exitUsage() + if len(sourceDirectories) == 0: + print("WARNING: no source directories specified!") + return outputFile, sourceDirectories + diff --git a/src/converter.py b/src/converter.py new file mode 100755 index 0000000..3e44058 --- /dev/null +++ b/src/converter.py @@ -0,0 +1,18 @@ +#!/usr/bin/python3 + +import sys + +import arguments +from tacsrc.tac import readTAC +import grc +import portNaming + +if __name__ == "__main__": + if len(sys.argv) == 1: + params.exitUsage() + inputFile = sys.argv[1] + outputFile, sourceDirectories = arguments.readArguments(sys.argv[2:]) + blocks, connections, blockTypes = readTAC(inputFile) + portNaming.resolvePortNames(blockTypes, sourceDirectories) + grc.write(outputFile, blocks, connections) + diff --git a/src/defaultBlockTypes.py b/src/defaultBlockTypes.py new file mode 100644 index 0000000..a7c7a7a --- /dev/null +++ b/src/defaultBlockTypes.py @@ -0,0 +1,74 @@ +from tacsrc.blockType import BlockType + +class VariablePorts: + def __init__(self, ioDescriptionName, sizeFunction): + self.ioDescriptionName = ioDescriptionName + self.sizeFunction = sizeFunction + + def mapName(self, position, name, index): + return + + def getRealPort(self, originalPort): + return 0 + + def ensureLength(self, length): + return + + def getIODescription(self, block): + return "\\\\n0:%s[%s]" % (self.ioDescriptionName, self.sizeFunction(block)) + + def getRealCount(self): + return 1 + +def inParameters(block): + return block.parameters[1] + +def parameterSize(block): + return len(block.parameters) + +monitor = BlockType("Monitor") +monitor.inputs = VariablePorts("input", inParameters) + +monitorState = BlockType("MonitorState") +monitorState.inputs = VariablePorts("input", inParameters) + +probe = BlockType("Probe") +probe.inputs = VariablePorts("input", inParameters) + +readRfm = BlockType("ReadRfm") +readRfm.outputs = VariablePorts("output", parameterSize) + +rms = BlockType("RMS") +rms.inputs.mapName(0, "input", 0) +rms.outputs.mapName(0, "output", 0) + +constant = BlockType("Constant") +constant.outputs.mapName(0, "CONST", 0) + +manual = BlockType("ManualSwitch") +manual.inputs.mapName(0, "input", 0) +manual.outputs.mapName(0, "output", 0) + +noise = BlockType("NormalNoise") +noise.outputs.mapName(0, "output", 0) + +writeRMNNoTim = BlockType("WriteRmNoTim") +writeRMNNoTim.inputs = VariablePorts("input", parameterSize) + +defaultBlockTypes = { + "Monitor": monitor, + "MonitorState": monitorState, + "Probe": probe, + "ReadRfm": readRfm, + "TIM": BlockType("TIM"), + "WAIT_RFM_INTERRUPT": BlockType("WAIT_RFM_INTERRUPT"), + "RMS": rms, + "Constant": constant, + "ManualSwitch": manual, + "NormalNoise": noise, + "WriteRmNoTim": writeRMNNoTim +} + +def addDefaultBlockTypes(blockTypes): + for key in defaultBlockTypes: + blockTypes[key] = defaultBlockTypes[key] diff --git a/src/grc.py b/src/grc.py new file mode 100644 index 0000000..ed02659 --- /dev/null +++ b/src/grc.py @@ -0,0 +1,94 @@ +GRC_TEMPLATE = ''' +options: + parameters: + title: 'TASRC to GRC converter output' + states: + coordinate: [-100, -100] + +blocks: +%s + +connections: +%s + +metadata: + file_format: 1 +''' + +BLOCK_TEMPLATE = ''' +- name: %s + id: epy_block + parameters: + _source_code: "from gnuradio import gr\\nimport numpy as np\\nclass BLOCK(gr.sync_block):\\n def __init__(self):\\n gr.sync_block.__init__(self,name='%s:%s%s',in_sig=%s,out_sig=%s)\\n def work(self, input_items, output_items):\\n return len(output_items[0])" + states: + coordinate: [%s, %s] +''' + +LINK_TEMPLATE = "- [%s, '%s', %s, '%s']\n" + +def getLongestDependencyRow(blocks, blockDependencies): + currentMax = 0 + for block in blocks: + current = getLongestDependencyRow(blockDependencies[block], blockDependencies) + 1 + if current > currentMax: + currentMax = current + return currentMax + +def getPosition(block, blockDependencies, reverseBlockDependencies, depths): + position = getLongestDependencyRow(blockDependencies[block], blockDependencies) + depths += [0] * (position+1 - len(depths)) + y = depths[position] + depths[position] += 50 # base offset + depths[position] += max( + (3+block.blockType.inputs.getRealCount()+block.blockType.outputs.getRealCount()) * 15, + max(block.blockType.inputs.getRealCount(), block.blockType.outputs.getRealCount()) * 30) + return position * 300, y + +def getBlockDependencies(blocks, links): + blockDependencies = {} + for block in blocks: + blockDependencies[block] = [] + for link in links: + if link.toBlock == block: + blockDependencies[block].append(link.fromBlock) + reverseBlockDependencies = {} + for block in blockDependencies: + for dependency in blockDependencies[block]: + if not dependency in reverseBlockDependencies: + reverseBlockDependencies[dependency] = [] + reverseBlockDependencies[dependency].append(block) + return blockDependencies, reverseBlockDependencies + +def getBlocksContent(blocks, links): + blockDependencies, reverseBlockDependencies = getBlockDependencies(blocks, links) + depths = [] + blocksContent = "" + for block in blocks: + description = block.blockType.getIODescription(block) + inputs = "[%s]" % ", ".join(["np.int8"] * block.blockType.inputs.getRealCount()) + outputs = "[%s]" % ", ".join(["np.int8"] * block.blockType.outputs.getRealCount()) + position = getPosition(block, blockDependencies, reverseBlockDependencies, depths) + blocksContent += BLOCK_TEMPLATE % ( + block.name, + block.name, + block.blockType.name, + description, + inputs, + outputs, + position[0], + position[1]) + return blocksContent + +def getLinksContent(links): + linksContent = "" + for link in links: + fromPort = link.fromBlock.blockType.outputs.getRealPort(link.fromPort) + toPort = link.toBlock.blockType.inputs.getRealPort(link.toPort) + linksContent += LINK_TEMPLATE % (link.fromBlock.name, fromPort, link.toBlock.name, toPort) + return linksContent + +def write(filename, blocks, links): + with open(filename, "w+") as file: + print("writing to file %s" % filename) + file.truncate(0) + file.write(GRC_TEMPLATE % (getBlocksContent(blocks, links), getLinksContent(links))) diff --git a/src/portNaming.py b/src/portNaming.py new file mode 100644 index 0000000..62be549 --- /dev/null +++ b/src/portNaming.py @@ -0,0 +1,104 @@ +import re +import os +import json +from defaultBlockTypes import defaultBlockTypes + +INPUT_FUNCTIONS = [ + "tacStdBlockGetInput", + "tacGraviMatrixGetPointerInput" + ] + +OUTPUT_FUNCTIONS = [ + "tacStdBlockSetOutput", + "tacGraviMatrixSetPointerOutput" + ] + +def getFiles(blockType, sourceDirectories): + files = [] + for sourceDirectory in sourceDirectories: + files += ["%s/%s" % (data[0], file) + for data in os.walk(sourceDirectory) + for file in data[2] if re.match(".*tac%sBlock.c" % blockType.name.replace("Rm", "Rmn"), file) != None] + return files + +def resolvePortNames(blockTypes, sourceDirectories): + missingBlocks = [] + multipleDefinitions = [] + for blockType in blockTypes: + if blockType.name in defaultBlockTypes: + continue + files = getFiles(blockType, sourceDirectories) + if len(files) == 0: + print("WARNING: no source file for block type %s found" % blockType.name) + missingBlocks.append(blockType.name) + continue + if len(files) > 1: + multipleDefinitions.append(blockType.name) + print("WARNING: more than one matching source file for block type %s found, skipping" % blockType.name) + continue + print("reading file %s" % files[0]) + with open(files[0], "r") as file: + content = "\n".join(file.readlines()) + for function in INPUT_FUNCTIONS: + mapInputs(content, function, blockType.inputs) + for function in OUTPUT_FUNCTIONS: + mapOutputs(content, function, blockType.outputs) + for entry in re.findall("\\w+ *= *\\*?\\(?pSelf->input\\[\\d+\\]\\)?", content): + name = re.search("^\\w+", entry).group() + position = int(re.search("(?<=\\[)\\d+(?=\\])", entry).group()) + blockType.inputs.mapName(position, name, 0) + for entry in re.findall("pSelf->output\\[\\d+\\] *= *\\w+", content): + name = re.search("\\w+$", entry).group() + position = int(re.search("(?<=\\[)\\d+(?=\\])", entry).group()) + blockType.outputs.mapName(position, name, 0) + if not os.path.exists("errors.json") or os.stat("errors.json").st_size == 0: + content = {"missing_blocks": [], "multiple_definitions": []} + else: + with open("errors.json", "r") as file: + content = json.load(file) + with open("errors.json", "w+") as file: + for blockTypeName in missingBlocks: + if not blockTypeName in content["missing_blocks"]: + content["missing_blocks"].append(blockTypeName) + for blockTypeName in multipleDefinitions: + if not blockTypeName in content["multiple_definitions"]: + content["multiple_definitions"].append(blockTypeName) + json.dump(content, file, indent=2) + file.close() + +def mapInputs(content, function, ports): + for entry in re.findall("\\w+ *= *%s\\(pSelf *, *\\d+\\);" % function, content): + name = re.search("^\\w+", entry).group() + position = int(re.search("\\d+(?= *\\) *;)", entry).group()) + ports.mapName(position, name, 0) + for entry in re.findall("\\w+->\\w+\\[\\d+\\] *= *%s\\(pSelf *, *\\d+\\);" % function, content): + name = re.search("(?<=\\->)\\w+", entry).group() + position = int(re.search("\\d+(?= *\\) *;)", entry).group()) + index = int(re.search("(?<=\\[)\\d+(?=\\])", entry).group()) + ports.mapName(position, name, index) + for entry in re.findall("\\w+\\[\\d+\\] *= *%s\\(pSelf *, *\\d+\\);" % function, content): + name = re.search("^\\w+", entry).group() + position = int(re.search("\\d+(?= *\\) *;)", entry).group()) + index = int(re.search("(?<=\\[)\\d+(?=\\])", entry).group()) + ports.mapName(position, name, index) + +def mapOutputs(content, function, ports): + for entry in re.findall("%s\\(pSelf *, *\\d+ *, *pSelfParam->\\w+\\);" % function, content): + name = re.search("\\w+(?=\\);$)", entry).group() + position = int(re.search("\\d+(?= *, *pSelfParam->\\w+\\);$)", entry).group()) + ports.mapName(position, name, 0) + for entry in re.findall("%s\\(pSelf *, *\\d+ *, *\\w+\\[\\d+\\]\\);" % function, content): + name = re.search("\\w+(?=\\[\\d+\\]\\);$)", entry).group() + position = int(re.search("\\d+(?= *, *\\w+\\[\\d+\\]\\);$)", entry).group()) + index = int(re.search("(?<=\\[)\\d+(?=\\])", entry).group()) + ports.mapName(position, name, index) + for entry in re.findall("%s\\(pSelf *, *\\d+ *, *pSelfParam->\\w+\\[\\d+\\]\\);" % function, content): + name = re.search("(?<=\\->)\\w+", entry).group() + position = int(re.search("\\d+(?= *, *pSelfParam->\\w+\\[\\d+\\]\\);$)", entry).group()) + index = int(re.search("(?<=\\[)\\d+(?=\\]\\);$)", entry).group()) + ports.mapName(position, name, index) + for entry in re.findall("%s\\(pSelf *, *\\d+ *, *\\w+\\);" % function, content): + name = re.search("\\w+(?= *\\);$)", entry).group() + position = int(re.search("\\d+(?= *, *\\w+\\);$)", entry).group()) + index = 0 + ports.mapName(position, name, index) diff --git a/src/tacsrc/block.py b/src/tacsrc/block.py new file mode 100644 index 0000000..737d9f1 --- /dev/null +++ b/src/tacsrc/block.py @@ -0,0 +1,6 @@ +class Block: + def __init__(self): + self.name = "" + self.blockType = None + self.parameters = [] + diff --git a/src/tacsrc/blockType.py b/src/tacsrc/blockType.py new file mode 100644 index 0000000..8930836 --- /dev/null +++ b/src/tacsrc/blockType.py @@ -0,0 +1,19 @@ +from tacsrc.ports import Ports + +class BlockType: + def __init__(self, name): + self.name = name + self.inputs = Ports() + self.outputs = Ports() + + def getIODescription(self, block): + result = "" + inputDescription = self.inputs.getIODescription(block) + if len(inputDescription) != 0: + result += "\\\\nINPUTS:" + result += inputDescription + outputDescription = self.outputs.getIODescription(block) + if len(outputDescription) != 0: + result += "\\\\nOUTPUTS:" + result += outputDescription + return result diff --git a/src/tacsrc/link.py b/src/tacsrc/link.py new file mode 100644 index 0000000..d89b459 --- /dev/null +++ b/src/tacsrc/link.py @@ -0,0 +1,6 @@ +class Link: + def __init__(self): + self.fromBlock = None + self.fromPort = 0 + self.toBlock = None + self.toPort = 0 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3624768 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +__pycache__ +out +tacapp.tar.gz +Sources +tacapp +worryingFiles +cc.tar.gz diff --git a/errors.json b/errors.json new file mode 100644 index 0000000..5ec898a --- /dev/null +++ b/errors.json @@ -0,0 +1,4 @@ +{ + "missing_blocks": [], + "multiple_definitions": [] +} \ No newline at end of file diff --git a/hardcodedFiles/tacReadRmnBlock.c b/hardcodedFiles/tacReadRmnBlock.c new file mode 100644 index 0000000..8acbcfa --- /dev/null +++ b/hardcodedFiles/tacReadRmnBlock.c @@ -0,0 +1,568 @@ +/******************************************************************************* +* E.S.O. - VLT project +* +* "@(#) $Id: tacReadRmnBlock.c 305476 2018-01-19 08:56:18Z rfrahm $" +* +* who when what +* ------- -------- ---------------------------------------------- +* gzins 2010-07-27 ported to VLTSW2010 and VxWorks 6.4 +* swehner 2008-10-10 creation +*/ + +/************************************************************************ +* NAME +* tacReadRmnBlock - Implemements the standard functions for the +* tacReadRmn block and tacReadRfm block. +* tacReadRmnBlock - Reads from 1rst generation reflective memory network +* tacReadRfmBlock - Reads from 2nd generation reflective memory network + +* Parameters: +* field - token names for the RMN fields to read (up to 10) +* Inputs: 0 +* Outputs: 1 +* output - 1..10 depending on number of field parameters +* +* +* +* FILES +* +* ENVIRONMENT +* TAC +* +* RETURN VALUES +* +* CAUTIONS +* +* EXAMPLES +* TAC.BLOCK9.TYPE ReadRmn +* TAC.BLOCK9.NAME ReadRmn +* +* SEE ALSO +* +* BUGS +* +*------------------------------------------------------------------------ +*/ + +#define _POSIX_SOURCE 1 +#include "vltPort.h" + +ATTRIBUTE_UNUSED static const char *rcsId="@(#) $Id: tacReadRmnBlock.c 305476 2018-01-19 08:56:18Z rfrahm $"; + +/* + * System Headers + */ + +#include /* taskSpawn, taskDelay, ... */ +#include /* printf ... */ +#include /* malloc ... */ +#include /* malloc ... */ +#include +#include + +/* + * Local Headers + */ + +#include "tacStdBlock.h" +#include "tacRmnBlock.h" +#include "rmassPublic.h" +#include "rmassPrivate.h" + +/* + * Compilation directives + */ + +/* + * Constants + */ + +#define tacREAD_RMN_EXPECTED_PARAM 1 +#define tacREAD_RMN_DEFAULT_INPUT_NUMBER 0 +#define tacREAD_RMN_DEFAULT_OUTPUT_NUMBER tacMAX_DATA_NUMBER + +#define tacREAD_RMN_FIELD_STRING_LEN 256 +#define tacSTRLEN sizeof(double) + +/* + * Types + */ + +/* + * Local function declaration + */ + +/* + * Global variables + */ + +/* + * Function definition + */ + + +STATUS tacReadRmnBlockCheckParameter (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the ADDBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = NULL; + + pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + /* field string is built from block params */ + if ( tacRmnBlockCheckParameter ( pSelf, parameter, 0, error) != OK ) + { + return ERROR; + } + + /* useful information on the screen */ + printf ("ReadRmn %s: [%s]\n", pSelf->name, pSelfParam->fieldString); + + return OK; +} + +STATUS tacReadRfmBlockCheckParameter (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the ADDBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = NULL; + + pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + /* field string is built from block params */ + if ( tacRmnBlockCheckParameter ( pSelf, parameter, 0, error) != OK ) + { + return ERROR; + } + + /* useful information on the screen */ + printf ("ReadRfm %s: [%s]\n", pSelf->name, pSelfParam->fieldString); + + return OK; +} + +/* + * Constructor Hooks - Called when a block of this type is instanciated (CONFIG or ADDBLCK commands) + */ + +STATUS tacReadRmBlockConstructor (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the ADDBLCK command */ + vltLOGICAL isRmn, + tacERROR* error) /* Error structure - not a stack */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = NULL; + + /* Check that the expected number of parameters has been received */ + if (parameter->number < tacREAD_RMN_EXPECTED_PARAM) + { + char errorParam[40]; + + sprintf(errorParam, "Expected at least %d, received %d", tacREAD_RMN_EXPECTED_PARAM, parameter->number); + tacRTC_ERR(tacERR_PARAM_NUMBER, errorParam); + return ERROR; + } + + /* Allocate and initialize block-specific arrays */ + if (tacStdBlockAllocateArrays(pSelf, 0, tacREAD_RMN_DEFAULT_INPUT_NUMBER, tacREAD_RMN_DEFAULT_OUTPUT_NUMBER, error) == ERROR) + { + return ERROR; + } + + if (tacStdBlockAllocateArrayBySize(pSelf, tacSTDBLOCK_PARAM_ARRAY, sizeof(tacRMN_LOCAL_PARAMETER), error) == ERROR) + { + tacStdBlockReleaseArray(pSelf, tacSTDBLOCK_INPUT_ARRAY, error); + tacStdBlockReleaseArray(pSelf, tacSTDBLOCK_OUTPUT_ARRAY, error); + return ERROR; + } + + if ( isRmn ) + { + if ( tacReadRmnBlockCheckParameter (pSelf, parameter, error) == ERROR) + { + return ERROR; + } + } + else + { + if ( tacReadRfmBlockCheckParameter (pSelf, parameter, error) == ERROR) + { + return ERROR; + } + } + + pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + pSelfParam->handleValid = rmassACCESS_BLOCKED; + + /* Attach to RMN */ + if ( rmassReadAttach (&pSelfParam->handle, + pSelfParam->fieldString, + &pSelfParam->val[0], + &pSelfParam->val[1], + &pSelfParam->val[2], + &pSelfParam->val[3], + &pSelfParam->val[4], + &pSelfParam->val[5], + &pSelfParam->val[6], + &pSelfParam->val[7], + &pSelfParam->val[8], + &pSelfParam->val[9]) != SUCCESS ) + { + char errorParam[40]; + + sprintf(errorParam, "Attach to RMN failed."); + tacRTC_ERR(tacERR_INTERNAL, errorParam); + return ERROR; + } + + pSelfParam->handleValid = rmassACCESS_FREE; + + return OK; +} + +STATUS tacReadRmnBlockConstructor (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the ADDBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + if ( tacReadRmBlockConstructor (pSelf, parameter, ccsTRUE, error ) == ERROR ) + { + return ERROR; + } + return OK; +} + +STATUS tacReadRfmBlockConstructor (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the ADDBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + if ( tacReadRmBlockConstructor (pSelf, parameter, ccsFALSE, error ) == ERROR ) + { + return ERROR; + } + return OK; +} + + + +/* + * Destructor Hooks - Called when the block is removed from the algorithm (DELBLCK or new CONFIG commands) + */ + +void tacReadRmnBlockDestructor (tacSTDBLOCK* pSelf) /* Reference to the block instance */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = NULL; + pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + pSelfParam->handleValid = rmassACCESS_BLOCKED; + /* wait until semaphore is acknowledged by realtime algo + * or just procede if realtime is not active */ + while ((*pSelf->shared).active && pSelfParam->handleValid != rmassACCESS_BLOCK_ACKN) + { + taskDelay(1); + } + + rmassDetach (&pSelfParam->handle); + + return; +} + +/* + * Change parameters Hooks - Called when modifying the block parameters (MODBLCK command) + */ + +STATUS tacReadRmnBlockSetParameter (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the MODBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + if ( tacReadRmnBlockCheckParameter (pSelf, parameter, error) == ERROR) + { + return ERROR; + } + + pSelfParam->handleValid = rmassACCESS_BLOCKED; + /* wait until semaphore is acknowledged by realtime algo + * or just procede if realtime is not active */ + while ((*pSelf->shared).active && pSelfParam->handleValid != rmassACCESS_BLOCK_ACKN) + { + taskDelay(1); + } + + /* detach RMN handle */ + if ( rmassDetach (&pSelfParam->handle) != SUCCESS ) + { + char errorParam[40]; + + sprintf(errorParam, "rmassDetach returned error."); + tacRTC_ERR(tacERR_INTERNAL, errorParam); + return ERROR; + } + + if ( rmassReadAttach (&pSelfParam->handle, + pSelfParam->fieldString, + &pSelfParam->val[0], + &pSelfParam->val[1], + &pSelfParam->val[2], + &pSelfParam->val[3], + &pSelfParam->val[4], + &pSelfParam->val[5], + &pSelfParam->val[6], + &pSelfParam->val[7], + &pSelfParam->val[8], + &pSelfParam->val[9]) != SUCCESS ) + { + char errorParam[40]; + + sprintf(errorParam, "Attach to RMN failed."); + tacRTC_ERR(tacERR_INTERNAL, errorParam); + return ERROR; + } + + pSelfParam->handleValid = rmassACCESS_FREE; + + return OK; +} + +STATUS tacReadRfmBlockSetParameter (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the MODBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + if ( tacReadRfmBlockCheckParameter (pSelf, parameter, error) == ERROR) + { + return ERROR; + } + + pSelfParam->handleValid = rmassACCESS_BLOCKED; + /* wait until semaphore is acknowledged by realtime algo + * or just procede if realtime is not active */ + while ((*pSelf->shared).active && pSelfParam->handleValid != rmassACCESS_BLOCK_ACKN) + { + taskDelay(1); + } + + /* detach RMN handle */ + if ( rmassDetach (&pSelfParam->handle) != SUCCESS ) + { + char errorParam[40]; + + sprintf(errorParam, "rmassDetach returned error."); + tacRTC_ERR(tacERR_INTERNAL, errorParam); + return ERROR; + } + + if ( rmassReadAttach (&pSelfParam->handle, + pSelfParam->fieldString, + &pSelfParam->val[0], + &pSelfParam->val[1], + &pSelfParam->val[2], + &pSelfParam->val[3], + &pSelfParam->val[4], + &pSelfParam->val[5], + &pSelfParam->val[6], + &pSelfParam->val[7], + &pSelfParam->val[8], + &pSelfParam->val[9]) != SUCCESS ) + { + char errorParam[40]; + + sprintf(errorParam, "Attach to RFM failed."); + tacRTC_ERR(tacERR_INTERNAL, errorParam); + return ERROR; + } + + pSelfParam->handleValid = rmassACCESS_FREE; + + return OK; +} + +/* + * Algorithm Hooks - Called at each time the TAC algorithm is evaluated (ONLINE state) + */ + +void tacReadRmnBlockAlgorithm (tacSTDBLOCK* pSelf) /* Reference to the block instance */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + int i; + + if ( pSelfParam->handleValid == rmassACCESS_BLOCKED ) + { + pSelfParam->handleValid = rmassACCESS_BLOCK_ACKN; + } + + if ( pSelfParam->handleValid == rmassACCESS_FREE ) + { + /* actual RMN read operation */ + rmassReadAccessRmn (&pSelfParam->handle); + + /* Write to outputs */ + for (i=0; i < pSelfParam->numFields; i++) + { + switch (pSelfParam->type[i]) + { + case rmassTIMESEC: + case rmassUINT32: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).ui); + break; + case rmassTIMEUSEC: + case rmassINT32: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).i); + break; + case rmassFLOAT: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).f); + break; + default: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).d); + break; + } + } + + /* provide zero values at unsatisfied outputs + * I consider this a good thing to do since the block + * is always configured */ + for (i=pSelfParam->numFields; i < tacREAD_RMN_DEFAULT_OUTPUT_NUMBER; i++) + { + tacStdBlockSetOutput(pSelf, i, 0.0); + } + } +} + +void tacReadRfmBlockAlgorithm (tacSTDBLOCK* pSelf) /* Reference to the block instance */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + int i; + + if ( pSelfParam->handleValid == rmassACCESS_BLOCKED ) + { + pSelfParam->handleValid = rmassACCESS_BLOCK_ACKN; + } + + if ( pSelfParam->handleValid == rmassACCESS_FREE ) + { + /* actual RMN read operation */ + rmassReadAccessRfm (&pSelfParam->handle); + + /* Write to outputs */ + for (i=0; i < pSelfParam->numFields; i++) + { + switch (pSelfParam->type[i]) + { + case rmassTIMESEC: + case rmassUINT32: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).ui); + break; + case rmassTIMEUSEC: + case rmassINT32: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).i); + break; + case rmassFLOAT: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).f); + break; + default: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).d); + break; + } + } + + /* provide zero values at unsatisfied outputs + * I consider this a good thing to do since the block + * is always configured */ + for (i=pSelfParam->numFields; i < tacREAD_RMN_DEFAULT_OUTPUT_NUMBER; i++) + { + tacStdBlockSetOutput(pSelf, i, 0.0); + } + } +} + +/* + * Show Hooks - Called when the tacRtcTaskShow routine is executed + */ + +void tacReadRmnBlockShow (tacSTDBLOCK* pSelf) /* Reference to the block instance */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + /* Print parameter values */ + printf(" Attached: %s\n", pSelfParam->fieldString); + + return; +} + + +/***************************************************/ +/* The following code is common to all block types */ +/* Do not modify without any good reasons */ +/***************************************************/ + +/* + * Installation function + */ + +tacSTDBLOCK_TYPE tacReadRmnTypeInfo = { + "ReadRmn", + &tacReadRmnBlockConstructor, + &tacRmBlockGetParameter, + &tacReadRmnBlockAlgorithm, + &tacReadRmnBlockSetParameter, + NULL, + NULL, + &tacReadRmnBlockDestructor, + &tacReadRmnBlockShow +}; + +tacSTDBLOCK_TYPE tacReadRfmTypeInfo = { + "ReadRfm", + &tacReadRfmBlockConstructor, + &tacRmBlockGetParameter, + &tacReadRfmBlockAlgorithm, + &tacReadRmnBlockSetParameter, + NULL, + NULL, + &tacReadRmnBlockDestructor, + &tacReadRmnBlockShow +}; + +STATUS tacReadRmnBlockInitAll (void) +{ + /***************************************************/ + /* The following code is common to all block types */ + /* Do not modify without any good reasons */ + /***************************************************/ + + /* Install ReadRmn1g Block Hooks */ + tacStdBlockInstallNewType(&tacReadRmnTypeInfo); + + /*****************************/ + /* End of common code region */ + /*****************************/ + + /* Perform other library initialization operations */ + + return OK; +} + +STATUS tacReadRfmBlockInitAll (void) +{ + /***************************************************/ + /* The following code is common to all block types */ + /* Do not modify without any good reasons */ + /***************************************************/ + + /* Install ReadRmn1g Block Hooks */ + tacStdBlockInstallNewType(&tacReadRfmTypeInfo); + + /*****************************/ + /* End of common code region */ + /*****************************/ + + /* Perform other library initialization operations */ + + return OK; +} + +/*___oOo___*/ + + + diff --git a/hardcodedFiles/tacSinkBlock.c b/hardcodedFiles/tacSinkBlock.c new file mode 100644 index 0000000..df39833 --- /dev/null +++ b/hardcodedFiles/tacSinkBlock.c @@ -0,0 +1,1256 @@ +/******************************************************************************* +* E.S.O. - VLT project +* +* "@(#) $Id: tacSinkBlock.c 339094 2021-02-10 03:10:02Z jgil $" +* +* who when what +* ------- -------- ---------------------------------------------- +* rdembet 06/08/20 New MonitorState block with no data averaging +* swehner 28/11/09 SPR20090234 Correction in rate adjustment in reset hook +* swehner 27/11/09 Fixed message queue handling +* swehner 10/10/09 New block FastProbe for unlimited rec frequency +* swehner 22/09/09 PPRS 32341 Replaced specialized tacSINK_SHMSG stack +* with standard vxWorks message queue. +* bbauvir 21/09/04 VLTSW20040113 - One sample might be lost +* bbauvir 29/03/04 Monitor block averages over the reporting period +* bbauvir 29/12/02 Probe to the SampTask +* bbauvir 26/12/02 MsgQ access through DPC mechanism +* bbauvir 14/07/02 New MsgQ of TAC version 1.22 +* bbauvir 21/03/01 Created +*/ + +/************************************************************************ +* NAME +* tacSinkBlock - Standard data monitoring blocks +* +* SYNOPSIS +* lcubootAutoCdBoot 1,"tacsink.boot" +* < tacsink.boot +* +* DESCRIPTION +* Block type: Display +* Parameters: +* Inputs: 1 +* Outputs: none +* +* This function block samples the value of its input signal at the +* specified and issues a message containing the time +* and the value of the input on the vxWorks terminal. +* It does not allow modification of the parameter at runtime. +* +* Block type: Monitor +* Parameters: +* +* Inputs: 10max +* Outputs: none +* +* This function block samples the value of its input signals at the +* specified (0.0 to send a message at the system sampling +* period) and issues a message containing the time and the value of +* the inputs on the shared memory. This message is intercepted by the +* background task running on the master CPU. The monitored values are +* written into the online database. The number of inputs of the block +* is specified by parameter. +* This block does not allow modification of the parameters at runtime. +* +* Block type: MonitorState +* Parameters: +* +* Inputs: 10max +* Outputs: none +* +* Same as Monitor block but without the averaging of received data, +* see VLTSW-14260 JIRA ticket. +* +* Block type: Probe +* Parameters: +* +* Inputs: 10max +* Outputs: none +* +* Block type: FastProbe +* Parameters: +* +* Inputs: 10max +* Outputs: none +* +* This function block samples the value of its input signals at the +* specified (0.0 to send a message at the system sampling +* period) and issues a message containing the time and the value of +* the inputs on the shared memory. This message is intercepted by the +* background task running on the master CPU. The number of inputs of +* the block is specified by parameter. +* This message is passed to an external application callback if +* provided. +* This block does not allow modification of the parameters at runtime. +* The normal Probe block has a limited sampling frequency of not more +* than 2kHz. The reason is in particular the bottleneck between master +* and slave CPU which all samples have to pass through a mechanism of +* VME bus shared memory. On one-CPU-systems this limitation does not +* apply so you are free to choose faster sampling. You may of course +* hit other limitations (processor speed, network traffic etc.) +* +* FILES +* +* ENVIRONMENT +* TAC +* +* RETURN VALUES +* +* CAUTIONS +* All these blocks compute an decimation value to use to trigger the +* sampling of the input signals, from the system sampling period. +* They should be created after any synchronization block. +* +* In order to cope with system performances, a minimum +* is defined for each block. The minimum applied periods are 0.1 (10Hz), +* 0.01 (100Hz) and 0.5e-3 (2kHz) for the 'Display', 'Monitor' and +* 'Probe' blocks respectively. +* +* EXAMPLES +* # 5 signals @ 2Hz (monitored in the database) +* TAC.BLOCK9.TYPE Monitor +* TAC.BLOCK9.NAME Monitor +* TAC.BLOCK9.PARAM 0.5, 5 +* +* # 5 signals @ the RT algorithm sampling period (0.0) +* TAC.BLOCK10.TYPE Probe +* TAC.BLOCK10.NAME Probe +* TAC.BLOCK10.PARAM 0.0, 5 +* +* SEE ALSO +* tacServerInstallDataCallback, tacServerRemoveDataCallback +* +* BUGS +* +*------------------------------------------------------------------------ +*/ + +#define _POSIX_SOURCE 1 +#include "vltPort.h" + + +/* + * System Headers + */ + +#include +#include +#include /* logMsg ... */ +#include /* printf ... */ +#include /* malloc ... */ +#include /* memcpy ... */ +#include + +/* + * Local Headers + */ + +#include "tacStdBlock.h" +#include "tacShMsgQ.h" + +/* + * Compilation directives + */ + +/* + * Constants + */ + +#define tacSINK_DEFAULT_EXPECTED_PARAM 2 + +#define tacSINK_DEFAULT_INPUT_NUMBER tacMAX_DATA_NUMBER /* Up to 10 input channels */ +#define tacSINK_DEFAULT_OUTPUT_NUMBER tacMAX_DATA_NUMBER + +#define tacSINK_ONE_EXPECTED_PARAM 1 +#define tacSINK_ONE_INPUT_NUMBER 1 + +#define tacSINK_DISPLAY_MIN_SAMPLING_PERIOD .1 /* 10Hz */ +#define tacSINK_MONITOR_MIN_SAMPLING_PERIOD .01 /* 100Hz */ +#define tacSINK_PROBE_MIN_SAMPLING_PERIOD .5e-3 /* 2kHz */ + +#define tacSINK_DISPLAY_LOG_STRING_SIZE 128 + +#define tacSINK_MONITOR_DEFAULT_DB_POINT "tac:data:monitor" +#define tacSINK_MONITOR_MAX_DB_ADDR_SIZE 64 + +#define tacSINK_MONITOR_QUEUE_SIZE 6 +#define tacSINK_PROBE_QUEUE_SIZE 6 + + +typedef enum { + tacSINK_SAMPLING_PERIOD = 0, + tacSINK_INPUT_NUMBER, + tacSINK_MONITOR_DB_POINT, +}tacSINK_SCOPE_PARAM_INDEX; + +/* + * Types + */ + +typedef struct { + unsigned short rate; + unsigned short counter; + unsigned short inputNb; + unsigned int lost; + double rateParam; + char* dbPoint; + MSG_Q_ID msgq; + tacSHMSG shmMsg; +}tacSINK_SCOPE_LOCAL_PARAMETER; + +/* + * Function declaration + */ + +extern STATUS tacDpcPushRequest(tacVOIDFCTPTR pFunct, void* parameter); + +/* + * Local function declaration + */ + +/* + * Note: Routines called from within the algorithm must be declared with + * static __inline__ + */ + +STATUS tacSinkSendMonitorMessage(MSG_Q_ID * msgqvoid); +STATUS tacSinkSendMonitorStateMessage(MSG_Q_ID * msgqvoid); +STATUS tacSinkSendProbeMessage(MSG_Q_ID * msgq); +STATUS tacSinkDeleteMessageQueue(MSG_Q_ID * msgq); +STATUS tacSinkCommonBlockConstructor(tacSTDBLOCK* pSelf, tacERROR* error); + +/* + * Global variables + */ + +char logStr[tacSINK_DISPLAY_LOG_STRING_SIZE]; /* Logging string used for Display */ + + +/* + * Function definition + */ + +/* + * Constructor Hooks + */ + +STATUS tacSinkDisplayBlockConstructor (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = NULL; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = NULL; + + /* Check that the expected number of parameters has been received */ + if (parameter->number < tacSINK_ONE_EXPECTED_PARAM) + { + char errorParam[40]; + + sprintf(errorParam, "Expected %d, received %d", tacSINK_ONE_EXPECTED_PARAM, parameter->number); + tacRTC_ERR(tacERR_PARAM_NUMBER, errorParam); + return ERROR; + } + + /* Check that the parameters are valid */ + pRealParam = (double*) parameter->buffer; + + /* Passed parameter is the sampling period of the block */ + if (pRealParam[tacSINK_SAMPLING_PERIOD] < (*pSelf->shared).samplingPeriod) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = (*pSelf->shared).samplingPeriod; + } + + if (pRealParam[tacSINK_SAMPLING_PERIOD] < tacSINK_DISPLAY_MIN_SAMPLING_PERIOD) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = tacSINK_DISPLAY_MIN_SAMPLING_PERIOD; + } + + /* Call common constructor */ + if (tacSinkCommonBlockConstructor(pSelf, error) != OK) + { + return ERROR; + } + + /* Store parameters */ + pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; /* We will only store short integers */ + + /* + * Compute the rate at which data has to be processed - divide and take + * the integer part of the result + */ + + pSelfParam->rate = (unsigned short) (pRealParam[tacSINK_SAMPLING_PERIOD] / (*pSelf->shared).samplingPeriod); + pSelfParam->counter = 0; /* Decimation counter */ + + /* + * Perform other block initialization operations + */ + + return OK; +} + +STATUS tacSinkMonitorBlockConstructor (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = NULL; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = NULL; + unsigned short arrayIndex = 0; + + /* Check that the expected number of parameters has been received */ + if (parameter->number < tacSINK_DEFAULT_EXPECTED_PARAM) + { + char errorParam[40]; + + sprintf(errorParam, "Expected %d, received %d", tacSINK_DEFAULT_EXPECTED_PARAM, parameter->number); + tacRTC_ERR(tacERR_PARAM_NUMBER, errorParam); + return ERROR; + } + + /* Check that the parameters are valid */ + pRealParam = (double*) parameter->buffer; + + /* Passed parameter is the sampling period of the block */ + if (pRealParam[tacSINK_SAMPLING_PERIOD] < (*pSelf->shared).samplingPeriod) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = (*pSelf->shared).samplingPeriod; + } + + if (pRealParam[tacSINK_SAMPLING_PERIOD] < tacSINK_MONITOR_MIN_SAMPLING_PERIOD) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = tacSINK_MONITOR_MIN_SAMPLING_PERIOD; + } + + /* Number of inputs is minimum 1 up to tacMSG_MAX_DATA_NUMBER */ + if ((pRealParam[tacSINK_INPUT_NUMBER] < 1) || + (pRealParam[tacSINK_INPUT_NUMBER] > tacMAX_DATA_NUMBER)) + { + tacRTC_ERR(tacERR_PARAM_INVALID, ""); + return ERROR; + } + + /* Call common constructor */ + if (tacSinkCommonBlockConstructor(pSelf, error) != OK) + { + return ERROR; + } + + /* Store parameters */ + pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* + * Compute the rate at which data has to be processed - divide and take + * the integer part of the result + */ + + pSelfParam->rate = (unsigned short) (pRealParam[tacSINK_SAMPLING_PERIOD] / (*pSelf->shared).samplingPeriod); + pSelfParam->counter = 0; /* Decimation counter */ + pSelfParam->inputNb = (unsigned short) pRealParam[tacSINK_INPUT_NUMBER]; + + /* Optional parameter is an application-specific DB point */ + if (parameter->number == tacSINK_DEFAULT_EXPECTED_PARAM + 1) + { + printf("tacSinkMonitorBlockConstructor - DB point %s\n",(char*) &(pRealParam[tacSINK_MONITOR_DB_POINT])); + pSelfParam->dbPoint = (char*) malloc(tacSINK_MONITOR_MAX_DB_ADDR_SIZE); + strcpy(pSelfParam->dbPoint, (char*) &(pRealParam[tacSINK_MONITOR_DB_POINT])); + } + else + { + printf("tacSinkMonitorBlockConstructor - Default DB point\n"); + pSelfParam->dbPoint = NULL; + } + + /* Specify the number of input signals to attach to become resolved */ + tacStdBlockSetInputNumber(pSelf, pSelfParam->inputNb); + + /* + * Perform other block initialization operations + */ + + /* Create the block internal message queue which tosses the messages out of the + * interrupt context. They are buffered in the queue until the DPC tasks + * picks them up and sends them over the shared memory message queue. + * Sorry for that double-queuing, that's because of the M-S architecture */ + + pSelfParam->msgq = msgQCreate(tacSINK_MONITOR_QUEUE_SIZE, sizeof(tacSHMSG), 0); + if ( pSelfParam->msgq == NULL ) + { + char errorParam[40]; + + sprintf(errorParam, "Could not create probe block message queue"); + tacRTC_ERR(tacERR_MALLOC, errorParam); + return ERROR; + } + + /* will count if a message can't be pushed in the queue */ + pSelfParam->lost = 0; + + /* Warn the background task that a new probe block has been created */ + pSelfParam->shmMsg.type = tacSHMSG_ADD_MONITOR; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + + if (pSelfParam->dbPoint == NULL) + { + strcpy((char*) &(pSelfParam->shmMsg.msgBody.monitor.data), tacSINK_MONITOR_DEFAULT_DB_POINT); + } + else + { + strcpy((char*) &(pSelfParam->shmMsg.msgBody.monitor.data), *((char**) &(pSelfParam->dbPoint))); + } + + printf("tacSinkMonitorBlockConstructor - Attach to %s\n",(char*) &(pSelfParam->shmMsg.msgBody.monitor.data)); + + /* Send message */ + tacShMsgQSendBgInfo(&(pSelfParam->shmMsg)); + + /* Initialize the message parameters */ + pSelfParam->shmMsg.type = tacSHMSG_MONITOR_DATA; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + pSelfParam->shmMsg.msgBody.monitor.data.number = pSelfParam->inputNb; + + /* The output port is used to average the inputs over the reporting period */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pSelf->output[arrayIndex] = 0.0; + } + + return OK; +} + +STATUS tacSinkMonitorStateBlockConstructor (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = NULL; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = NULL; + unsigned short arrayIndex = 0; + + /* Check that the expected number of parameters has been received */ + if (parameter->number < tacSINK_DEFAULT_EXPECTED_PARAM) + { + char errorParam[40]; + + sprintf(errorParam, "Expected %d, received %d", tacSINK_DEFAULT_EXPECTED_PARAM, parameter->number); + tacRTC_ERR(tacERR_PARAM_NUMBER, errorParam); + return ERROR; + } + + /* Check that the parameters are valid */ + pRealParam = (double*) parameter->buffer; + + /* Passed parameter is the sampling period of the block */ + if (pRealParam[tacSINK_SAMPLING_PERIOD] < (*pSelf->shared).samplingPeriod) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = (*pSelf->shared).samplingPeriod; + } + + if (pRealParam[tacSINK_SAMPLING_PERIOD] < tacSINK_MONITOR_MIN_SAMPLING_PERIOD) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = tacSINK_MONITOR_MIN_SAMPLING_PERIOD; + } + + /* Number of inputs is minimum 1 up to tacMSG_MAX_DATA_NUMBER */ + if ((pRealParam[tacSINK_INPUT_NUMBER] < 1) || + (pRealParam[tacSINK_INPUT_NUMBER] > tacMAX_DATA_NUMBER)) + { + tacRTC_ERR(tacERR_PARAM_INVALID, ""); + return ERROR; + } + + /* Call common constructor */ + if (tacSinkCommonBlockConstructor(pSelf, error) != OK) + { + return ERROR; + } + + /* Store parameters */ + pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* + * Compute the rate at which data has to be processed - divide and take + * the integer part of the result + */ + + pSelfParam->rate = (unsigned short) (pRealParam[tacSINK_SAMPLING_PERIOD] / (*pSelf->shared).samplingPeriod); + pSelfParam->counter = 0; /* Decimation counter */ + pSelfParam->inputNb = (unsigned short) pRealParam[tacSINK_INPUT_NUMBER]; + + /* Optional parameter is an application-specific DB point */ + if (parameter->number == tacSINK_DEFAULT_EXPECTED_PARAM + 1) + { + printf("tacSinkMonitorStateBlockConstructor - DB point %s\n",(char*) &(pRealParam[tacSINK_MONITOR_DB_POINT])); + pSelfParam->dbPoint = (char*) malloc(tacSINK_MONITOR_MAX_DB_ADDR_SIZE); + strcpy(pSelfParam->dbPoint, (char*) &(pRealParam[tacSINK_MONITOR_DB_POINT])); + } + else + { + printf("tacSinkMonitorStateBlockConstructor - Default DB point\n"); + pSelfParam->dbPoint = NULL; + } + + /* Specify the number of input signals to attach to become resolved */ + tacStdBlockSetInputNumber(pSelf, pSelfParam->inputNb); + + /* + * Perform other block initialization operations + */ + + /* Create the block internal message queue which tosses the messages out of the + * interrupt context. They are buffered in the queue until the DPC tasks + * picks them up and sends them over the shared memory message queue. + * Sorry for that double-queuing, that's because of the M-S architecture */ + + pSelfParam->msgq = msgQCreate(tacSINK_MONITOR_QUEUE_SIZE, sizeof(tacSHMSG), 0); + if ( pSelfParam->msgq == NULL ) + { + char errorParam[40]; + + sprintf(errorParam, "Could not create probe block message queue"); + tacRTC_ERR(tacERR_MALLOC, errorParam); + return ERROR; + } + + /* will count if a message can't be pushed in the queue */ + pSelfParam->lost = 0; + + /* Warn the background task that a new probe block has been created */ + pSelfParam->shmMsg.type = tacSHMSG_ADD_MONITOR; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + + if (pSelfParam->dbPoint == NULL) + { + strcpy((char*) &(pSelfParam->shmMsg.msgBody.monitor.data), tacSINK_MONITOR_DEFAULT_DB_POINT); + } + else + { + strcpy((char*) &(pSelfParam->shmMsg.msgBody.monitor.data), *((char**) &(pSelfParam->dbPoint))); + } + + printf("tacSinkMonitorStateBlockConstructor - Attach to %s\n",(char*) &(pSelfParam->shmMsg.msgBody.monitor.data)); + + /* Send message */ + tacShMsgQSendBgInfo(&(pSelfParam->shmMsg)); + + /* Initialize the message parameters */ + pSelfParam->shmMsg.type = tacSHMSG_MONITOR_DATA; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + pSelfParam->shmMsg.msgBody.monitor.data.number = pSelfParam->inputNb; + + /* Init output port which won't be used to average the inputs over the reporting period */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pSelf->output[arrayIndex] = 0.0; + } + + return OK; +} + +STATUS tacSinkProbeBlockCommonConstructor (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + double minPeriod, + tacERROR* error) +{ + double* pRealParam = NULL; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = NULL; + + /* Check that the expected number of parameters has been received */ + if (parameter->number < tacSINK_DEFAULT_EXPECTED_PARAM) + { + char errorParam[40]; + + sprintf(errorParam, "Expected %d, received %d", tacSINK_DEFAULT_EXPECTED_PARAM, parameter->number); + tacRTC_ERR(tacERR_PARAM_NUMBER, errorParam); + return ERROR; + } + + /* Check that the parameters are valid */ + pRealParam = (double*) parameter->buffer; + + /* Passed parameter is the sampling period of the block */ + if (pRealParam[tacSINK_SAMPLING_PERIOD] < (*pSelf->shared).samplingPeriod) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = (*pSelf->shared).samplingPeriod; + } + + if (pRealParam[tacSINK_SAMPLING_PERIOD] < minPeriod) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = minPeriod; + } + + /* Number of inputs is minimum 1 up to tacMSG_MAX_DATA_NUMBER */ + if ((pRealParam[tacSINK_INPUT_NUMBER] < 1) || + (pRealParam[tacSINK_INPUT_NUMBER] > tacMAX_DATA_NUMBER)) + { + tacRTC_ERR(tacERR_PARAM_INVALID, ""); + return ERROR; + } + + /* Call common constructor */ + if (tacSinkCommonBlockConstructor(pSelf, error) != OK) + { + return ERROR; + } + + /* Store parameters */ + pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* + * Compute the rate at which data has to be processed - divide and take + * the integer part of the result + */ + + pSelfParam->rateParam = pRealParam[tacSINK_SAMPLING_PERIOD]; + pSelfParam->rate = (unsigned short) (pRealParam[tacSINK_SAMPLING_PERIOD] / (*pSelf->shared).samplingPeriod); + pSelfParam->counter = 0; /* Decimation counter */ + pSelfParam->inputNb = (unsigned short) pRealParam[tacSINK_INPUT_NUMBER]; + + /* Specify the number of input signals to attach to become resolved */ + tacStdBlockSetInputNumber(pSelf, pSelfParam->inputNb); + + /* + * Perform other block initialization operations + */ + + /* Create the block internal message queue which gets the messages out of the + * interrupt context. They are buffered in the queue until the DPC tasks + * picks them up and sends them over the shared memory message queue. + * Sorry for that double-queuing, that's because of the M-S architecture */ + + /* There is only one message queue for all probe blocks! */ + pSelfParam->msgq = msgQCreate(tacSINK_PROBE_QUEUE_SIZE, sizeof(tacSHMSG), 0); + if ( pSelfParam->msgq == NULL ) + { + char errorParam[40]; + + sprintf(errorParam, "Could not create probe block message queue"); + tacRTC_ERR(tacERR_MALLOC, errorParam); + return ERROR; + } + + /* will count if a message can't be pushed in the queue */ + pSelfParam->lost = 0; + + /* Warn the background task that a new probe block has been created */ + pSelfParam->shmMsg.type = tacSHMSG_ADD_PROBE; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + + /* Send message */ + tacShMsgQSendDataSample(&pSelfParam->shmMsg); + + /* Initialize the message parameters */ + pSelfParam->shmMsg.type = tacSHMSG_TRANSFER_DATA; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + pSelfParam->shmMsg.msgBody.monitor.data.number = pSelfParam->inputNb; + + return OK; +} + +/* Probe block has a max. sampling frequency of 2kHz */ +STATUS tacSinkProbeBlockConstructor (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + return tacSinkProbeBlockCommonConstructor (pSelf, parameter, tacSINK_PROBE_MIN_SAMPLING_PERIOD, error); +} + +/* Fast probe is the same as probe but not does have the + * limitation on the max. recording frequency */ +STATUS tacSinkFastProbeBlockConstructor (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + return tacSinkProbeBlockCommonConstructor (pSelf, parameter, 0.0, error); +} + +void tacSinkProbeBlockReset (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = + (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* + * Re-Compute the rate at which data has to be processed + */ + if (pSelfParam->rateParam < (*pSelf->shared).samplingPeriod ) + { + pSelfParam->rate = 1; + } + else + { + pSelfParam->rate = (unsigned short) + (pSelfParam->rateParam / (*pSelf->shared).samplingPeriod); + } + + return; +} + +/* + * Report parameters Hooks + */ + +STATUS tacSinkDisplayBlockGetParameter (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = (double*) parameter->buffer; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Send back the expected number of parameters */ + parameter->number = tacSINK_ONE_EXPECTED_PARAM; + + /* Report current parameters */ + pRealParam[tacSINK_SAMPLING_PERIOD] = (double) (pSelfParam->rate * (*pSelf->shared).samplingPeriod); + + return OK; +} + +STATUS tacSinkMonitorBlockGetParameter (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = (double*) parameter->buffer; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Send back the expected number of parameters */ + parameter->number = tacSINK_DEFAULT_EXPECTED_PARAM; + + /* Report current parameters */ + pRealParam[tacSINK_SAMPLING_PERIOD] = (double) (pSelfParam->rate * (*pSelf->shared).samplingPeriod); + pRealParam[tacSINK_INPUT_NUMBER] = (double) pSelfParam->inputNb; + + if (*((char**) &(pSelfParam->dbPoint)) != NULL) + { + parameter->number += 1; + parameter->type[tacSINK_MONITOR_DB_POINT] = tacPARAM_STRING; + strcpy((char*) &(pRealParam[tacSINK_MONITOR_DB_POINT]), *((char**) &(pSelfParam->dbPoint))); + } + + return OK; +} + +STATUS tacSinkMonitorStateBlockGetParameter (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = (double*) parameter->buffer; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Send back the expected number of parameters */ + parameter->number = tacSINK_DEFAULT_EXPECTED_PARAM; + + /* Report current parameters */ + pRealParam[tacSINK_SAMPLING_PERIOD] = (double) (pSelfParam->rate * (*pSelf->shared).samplingPeriod); + pRealParam[tacSINK_INPUT_NUMBER] = (double) pSelfParam->inputNb; + + if (*((char**) &(pSelfParam->dbPoint)) != NULL) + { + parameter->number += 1; + parameter->type[tacSINK_MONITOR_DB_POINT] = tacPARAM_STRING; + strcpy((char*) &(pRealParam[tacSINK_MONITOR_DB_POINT]), *((char**) &(pSelfParam->dbPoint))); + } + + return OK; +} + +STATUS tacSinkProbeBlockGetParameter (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = (double*) parameter->buffer; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Send back the expected number of parameters */ + parameter->number = tacSINK_DEFAULT_EXPECTED_PARAM; + + /* Report current parameters */ + pRealParam[tacSINK_SAMPLING_PERIOD] = (double) (pSelfParam->rate * (*pSelf->shared).samplingPeriod); + pRealParam[tacSINK_INPUT_NUMBER] = (double) pSelfParam->inputNb; + + return OK; +} + +/* + * Change parameters Hooks + */ + +/* + * Algorithm Hooks + */ + +void tacSinkDisplayBlockAlgorithm (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + if ((pSelfParam->counter % pSelfParam->rate) == 0) /* It's time to process data */ + { + sprintf(logStr,"Name: %s Time: %ld.%6ld Value: %g\n", + pSelf->name, + (*pSelf->shared).currentTime.seconds, + (*pSelf->shared).currentTime.microsec, + tacStdBlockGetInput(pSelf,0)); + + tacDpcPushRequest((tacVOIDFCTPTR) &printf, logStr); + + pSelfParam->counter = 0; + } + + pSelfParam->counter++; +} + +void tacSinkMonitorBlockAlgorithm (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + unsigned short arrayIndex = 0; + + /* The output port is used to average the inputs over the reporting period */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pSelf->output[arrayIndex] += tacStdBlockGetInput(pSelf,arrayIndex); + } + + if ((pSelfParam->counter % pSelfParam->rate) == 0) /* It's time to process data */ + { + tacDATA* pData = &(pSelfParam->shmMsg.msgBody.monitor.data); /* We are only interested in message body */ + + /* pData->number = pSelfParam->inputNb; */ + pData->timeStamp = (*pSelf->shared).currentTime; + + /* pData points to the body of the Message */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pData->buffer[arrayIndex] = pSelf->output[arrayIndex] / pSelfParam->rate; + } + + /* Push message into probe block's message que to get the + * data out of the interrupt comtext. */ + if ( msgQSend (pSelfParam->msgq, (char*) &(pSelfParam->shmMsg), sizeof(tacSHMSG), NO_WAIT, 0) != OK ) + { + (pSelfParam->lost)++; + } + + /* Defer procedure call */ + tacDpcPushRequest((tacVOIDFCTPTR) &tacSinkSendMonitorMessage, &pSelfParam->msgq); + + pSelfParam->counter = 0; + + /* The output port is used to average the inputs over the reporting period */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pSelf->output[arrayIndex] = 0.0; + } + } + + pSelfParam->counter++; +} + +void tacSinkMonitorStateBlockAlgorithm (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + unsigned short arrayIndex = 0; + + if ((pSelfParam->counter % pSelfParam->rate) == 0) /* It's time to process data */ + { + tacDATA* pData = &(pSelfParam->shmMsg.msgBody.monitor.data); /* We are only interested in message body */ + + /* pData->number = pSelfParam->inputNb; */ + pData->timeStamp = (*pSelf->shared).currentTime; + + /* pData points to the body of the Message */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pData->buffer[arrayIndex] = tacStdBlockGetInput(pSelf,arrayIndex); + } + + /* Push message into probe block's message que to get the + * data out of the interrupt comtext. */ + if ( msgQSend (pSelfParam->msgq, (char*) &(pSelfParam->shmMsg), sizeof(tacSHMSG), NO_WAIT, 0) != OK ) + { + (pSelfParam->lost)++; + } + + /* Defer procedure call */ + tacDpcPushRequest((tacVOIDFCTPTR) &tacSinkSendMonitorMessage, &pSelfParam->msgq); + + pSelfParam->counter = 0; + } + + pSelfParam->counter++; +} + +void tacSinkProbeBlockAlgorithm (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + unsigned short arrayIndex = 0; + + if ((pSelfParam->counter % pSelfParam->rate) == 0) /* It's time to process data */ + { + tacDATA* pData = &(pSelfParam->shmMsg.msgBody.monitor.data); /* We are only interested in message body */ + + pData->timeStamp = (*pSelf->shared).currentTime; + + /* pData points to the body of the Message */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pData->buffer[arrayIndex] = tacStdBlockGetInput(pSelf,arrayIndex); + } + + /* Push message into probe block's message que to get the + * data out of the interrupt comtext. */ + if ( msgQSend (pSelfParam->msgq, (char*) &(pSelfParam->shmMsg), sizeof(tacSHMSG), NO_WAIT, 0) != OK ) + { + (pSelfParam->lost)++; + } + + /* Defer procedure call: + * tacSinkSendProbeMessage is called outside the interrupt routine + * and will take care to pick up the message from the probe block's + * message queue and send it over the shared memory message queue */ + tacDpcPushRequest((tacVOIDFCTPTR) &tacSinkSendProbeMessage, &pSelfParam->msgq); + + pSelfParam->counter = 0; + } + + pSelfParam->counter++; +} + +/* + * Reset Hooks + */ + +/* + * Stop Hooks + */ + +/* + * Destructor Hooks + */ + +/* + * Note: This destructor is used mainly to send a MONITOR message containing + * 0.0 in order to reset the database array (otherwise going from an + * algorithm with 4 monitored data to one with 3 monitored data leaves + * the 4th value equal to the last ...) + */ + +void tacSinkMonitorBlockDestructor (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + tacDATA* pData = &(pSelfParam->shmMsg.msgBody.monitor.data); + unsigned short arrayIndex = 0; + + /* Reset DB values */ + pSelfParam->shmMsg.type = tacSHMSG_MONITOR_DATA; + pData = &(pSelfParam->shmMsg.msgBody.monitor.data); + + pData->number = pSelfParam->inputNb; + + /* pData points to the body of the Message */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pData->buffer[arrayIndex] = 0.0; + } + + /* Send message */ + tacShMsgQSendBgInfo(&pSelfParam->shmMsg); + + pSelfParam->shmMsg.type = tacSHMSG_REMOVE_MONITOR; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + + /* Send message */ + tacShMsgQSendBgInfo(&pSelfParam->shmMsg); + + free(pSelfParam->dbPoint); + + /* delete internal message queue. Do this as deferred procedure call + * to make sure it is only called when all messages have been send + * (through the same deferred call mechanism) */ + tacDpcPushRequest((tacVOIDFCTPTR) tacSinkDeleteMessageQueue, &(pSelfParam->msgq)); + + return; +} + +void tacSinkMonitorStateBlockDestructor (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + tacDATA* pData = &(pSelfParam->shmMsg.msgBody.monitor.data); + unsigned short arrayIndex = 0; + + /* Reset DB values */ + pSelfParam->shmMsg.type = tacSHMSG_MONITOR_DATA; + pData = &(pSelfParam->shmMsg.msgBody.monitor.data); + + pData->number = pSelfParam->inputNb; + + /* pData points to the body of the Message */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pData->buffer[arrayIndex] = 0.0; + } + + /* Send message */ + tacShMsgQSendBgInfo(&pSelfParam->shmMsg); + + pSelfParam->shmMsg.type = tacSHMSG_REMOVE_MONITOR; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + + /* Send message */ + tacShMsgQSendBgInfo(&pSelfParam->shmMsg); + + free(pSelfParam->dbPoint); + + /* delete internal message queue. Do this as deferred procedure call + * to make sure it is only called when all messages have been send + * (through the same deferred call mechanism) */ + tacDpcPushRequest((tacVOIDFCTPTR) tacSinkDeleteMessageQueue, &(pSelfParam->msgq)); + + return; +} + +void tacSinkProbeBlockDestructor (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + pSelfParam->shmMsg.type = tacSHMSG_REMOVE_PROBE; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + + /* Send message */ + tacShMsgQSendDataSample(&pSelfParam->shmMsg); + + /* delete internal message queue. Do this as deferred procedure call + * to make sure it is only called when all messages have been send + * (through the same deferred call mechanism) */ + tacDpcPushRequest((tacVOIDFCTPTR) tacSinkDeleteMessageQueue, &(pSelfParam->msgq)); + + return; +} + +/* + * Show Hooks + */ + +void tacSinkDisplayBlockShow (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Print parameter values */ + printf(" Update rate: %d\n",pSelfParam->rate); + + return; +} + +void tacSinkMonitorBlockShow (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Print parameter values */ + printf(" Update rate: %d\n",pSelfParam->rate); + printf(" Number of input signals: %d\n",pSelfParam->inputNb); + printf(" Queued samples: %d\n", msgQNumMsgs(pSelfParam->msgq)); + printf(" Lost samples: %d\n",pSelfParam->lost); + + if (pSelfParam->dbPoint != NULL) + { + printf(" DB Point: %s\n", pSelfParam->dbPoint); + } + + return; +} + +void tacSinkMonitorStateBlockShow (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Print parameter values */ + printf(" Using MonitorState block, not averaging received data\n"); + printf(" Update rate: %d\n",pSelfParam->rate); + printf(" Number of input signals: %d\n",pSelfParam->inputNb); + printf(" Queued samples: %d\n", msgQNumMsgs(pSelfParam->msgq)); + printf(" Lost samples: %d\n",pSelfParam->lost); + + if (pSelfParam->dbPoint != NULL) + { + printf(" DB Point: %s\n", pSelfParam->dbPoint); + } + + return; +} + +void tacSinkProbeBlockShow (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Print parameter values */ + printf(" Update rate: %d\n",pSelfParam->rate); + printf(" Update rate param (sec): %f\n",pSelfParam->rateParam); + printf(" Number of input signals: %d\n",pSelfParam->inputNb); + printf(" Queued samples: %d\n", msgQNumMsgs(pSelfParam->msgq)); + printf(" Lost samples: %d\n",pSelfParam->lost); + + return; +} + +/* + * Installation function + */ + +tacSTDBLOCK_TYPE tacSinkDisplayTypeInfo = { + "Display", + &tacSinkDisplayBlockConstructor, + &tacSinkDisplayBlockGetParameter, + &tacSinkDisplayBlockAlgorithm, + NULL, + NULL, + NULL, + NULL, + &tacSinkDisplayBlockShow, +}; + +tacSTDBLOCK_TYPE tacSinkMonitorTypeInfo = { + "Monitor", + &tacSinkMonitorBlockConstructor, + &tacSinkMonitorBlockGetParameter, + &tacSinkMonitorBlockAlgorithm, + NULL, + NULL, + NULL, + &tacSinkMonitorBlockDestructor, + &tacSinkMonitorBlockShow, +}; + +tacSTDBLOCK_TYPE tacSinkMonitorStateTypeInfo = { + "MonitorState", + &tacSinkMonitorStateBlockConstructor, + &tacSinkMonitorStateBlockGetParameter, + &tacSinkMonitorStateBlockAlgorithm, + NULL, + NULL, + NULL, + &tacSinkMonitorStateBlockDestructor, + &tacSinkMonitorStateBlockShow, +}; + +/* Probe with a maximal sampling rate of 2kHz */ +tacSTDBLOCK_TYPE tacSinkProbeTypeInfo = { + "Probe", + &tacSinkProbeBlockConstructor, + &tacSinkProbeBlockGetParameter, + &tacSinkProbeBlockAlgorithm, + NULL, + &tacSinkProbeBlockReset, + NULL, + &tacSinkProbeBlockDestructor, + &tacSinkProbeBlockShow, +}; + +/* Fast probe is the same as probe but not does have the + * limitation on the max. recording frequency */ +tacSTDBLOCK_TYPE tacSinkFastProbeTypeInfo = { + "FastProbe", + &tacSinkFastProbeBlockConstructor, + &tacSinkProbeBlockGetParameter, + &tacSinkProbeBlockAlgorithm, + NULL, + &tacSinkProbeBlockReset, + NULL, + &tacSinkProbeBlockDestructor, + &tacSinkProbeBlockShow, +}; + +STATUS tacSinkBlockInitAll (void) +{ + /* Install Sink Block Hooks */ + tacStdBlockInstallNewType(&tacSinkDisplayTypeInfo); + tacStdBlockInstallNewType(&tacSinkMonitorTypeInfo); + tacStdBlockInstallNewType(&tacSinkMonitorStateTypeInfo); + tacStdBlockInstallNewType(&tacSinkProbeTypeInfo); + tacStdBlockInstallNewType(&tacSinkFastProbeTypeInfo); + + /* + * Perform other library initialization operations + */ + + return OK; +} + +/* + * Local functions + */ + +/* + * Note: Routines called from within the algorithm must be declared with + * static __inline__ + */ + +STATUS tacSinkCommonBlockConstructor (tacSTDBLOCK* pSelf, + tacERROR* error) +{ + /* Allocate specific arrays (pointers are initialized to NULL by StdBlock) */ + if (tacStdBlockAllocateArrays(pSelf, 0, tacSINK_DEFAULT_INPUT_NUMBER, + tacSINK_DEFAULT_OUTPUT_NUMBER, error) == ERROR) + { + return ERROR; + } + + if (tacStdBlockAllocateArrayBySize(pSelf, tacSTDBLOCK_PARAM_ARRAY, + sizeof(tacSINK_SCOPE_LOCAL_PARAMETER), error) == ERROR) + { + tacStdBlockReleaseArray(pSelf, tacSTDBLOCK_INPUT_ARRAY, error); + tacStdBlockReleaseArray(pSelf, tacSTDBLOCK_OUTPUT_ARRAY, error); + return ERROR; + } + + /* Specify the number of input signals to attach to become resolved */ + tacStdBlockSetInputNumber(pSelf, tacSINK_ONE_INPUT_NUMBER); /* Required */ + + return OK; +} + +STATUS tacSinkSendMonitorMessage(MSG_Q_ID * msgq) +{ + /* Send message using provided function (different for Monitor and Probe blocks) */ + /* Send message using provided function (different for Monitor and Probe blocks) */ + tacSHMSG msg; + + if ( msgQReceive(*msgq, (char*) &msg, sizeof(tacSHMSG), NO_WAIT) == sizeof(tacSHMSG) ) + { + tacShMsgQSendBgInfo (&msg); + } + + return OK; +} + +STATUS tacSinkSendProbeMessage(MSG_Q_ID * msgq) +{ + /* Send message using provided function (different for Monitor and Probe blocks) */ + tacSHMSG msg; + + if ( msgq == NULL ) + { + return ERROR; + } + + if ( msgQReceive(*msgq, (char*) &msg, sizeof(tacSHMSG), NO_WAIT) == sizeof(tacSHMSG) ) + { + tacShMsgQSendDataSample (&msg); + } + return OK; +} + +STATUS tacSinkDeleteMessageQueue (MSG_Q_ID * msgq) +{ + /* Is called when block is destroyed and removes the internal message queue */ + STATUS status; + + status = msgQDelete (*msgq); + *msgq = NULL; + return status; +} + + +/*___oOo___*/ + + + + + + diff --git a/src/arguments.py b/src/arguments.py new file mode 100644 index 0000000..94e4cea --- /dev/null +++ b/src/arguments.py @@ -0,0 +1,26 @@ +import getopt + +def exitUsage(): + print("usage: %s <.tasrc file> -i -o " % sys.argv[0]) + sys.exit(1) + +def readArguments(args): + sourceDirectories = [] + outputFile = "" + try: + options, _ = getopt.getopt(args, "hi:o:") + except getopt.GetoptError: + exitUsage() + for option, arg in options: + if option == "-h": + exitUsage() + elif option == "-o": + outputFile = arg + elif option == "-i": + sourceDirectories.append(arg) + if outputFile == "": + exitUsage() + if len(sourceDirectories) == 0: + print("WARNING: no source directories specified!") + return outputFile, sourceDirectories + diff --git a/src/converter.py b/src/converter.py new file mode 100755 index 0000000..3e44058 --- /dev/null +++ b/src/converter.py @@ -0,0 +1,18 @@ +#!/usr/bin/python3 + +import sys + +import arguments +from tacsrc.tac import readTAC +import grc +import portNaming + +if __name__ == "__main__": + if len(sys.argv) == 1: + params.exitUsage() + inputFile = sys.argv[1] + outputFile, sourceDirectories = arguments.readArguments(sys.argv[2:]) + blocks, connections, blockTypes = readTAC(inputFile) + portNaming.resolvePortNames(blockTypes, sourceDirectories) + grc.write(outputFile, blocks, connections) + diff --git a/src/defaultBlockTypes.py b/src/defaultBlockTypes.py new file mode 100644 index 0000000..a7c7a7a --- /dev/null +++ b/src/defaultBlockTypes.py @@ -0,0 +1,74 @@ +from tacsrc.blockType import BlockType + +class VariablePorts: + def __init__(self, ioDescriptionName, sizeFunction): + self.ioDescriptionName = ioDescriptionName + self.sizeFunction = sizeFunction + + def mapName(self, position, name, index): + return + + def getRealPort(self, originalPort): + return 0 + + def ensureLength(self, length): + return + + def getIODescription(self, block): + return "\\\\n0:%s[%s]" % (self.ioDescriptionName, self.sizeFunction(block)) + + def getRealCount(self): + return 1 + +def inParameters(block): + return block.parameters[1] + +def parameterSize(block): + return len(block.parameters) + +monitor = BlockType("Monitor") +monitor.inputs = VariablePorts("input", inParameters) + +monitorState = BlockType("MonitorState") +monitorState.inputs = VariablePorts("input", inParameters) + +probe = BlockType("Probe") +probe.inputs = VariablePorts("input", inParameters) + +readRfm = BlockType("ReadRfm") +readRfm.outputs = VariablePorts("output", parameterSize) + +rms = BlockType("RMS") +rms.inputs.mapName(0, "input", 0) +rms.outputs.mapName(0, "output", 0) + +constant = BlockType("Constant") +constant.outputs.mapName(0, "CONST", 0) + +manual = BlockType("ManualSwitch") +manual.inputs.mapName(0, "input", 0) +manual.outputs.mapName(0, "output", 0) + +noise = BlockType("NormalNoise") +noise.outputs.mapName(0, "output", 0) + +writeRMNNoTim = BlockType("WriteRmNoTim") +writeRMNNoTim.inputs = VariablePorts("input", parameterSize) + +defaultBlockTypes = { + "Monitor": monitor, + "MonitorState": monitorState, + "Probe": probe, + "ReadRfm": readRfm, + "TIM": BlockType("TIM"), + "WAIT_RFM_INTERRUPT": BlockType("WAIT_RFM_INTERRUPT"), + "RMS": rms, + "Constant": constant, + "ManualSwitch": manual, + "NormalNoise": noise, + "WriteRmNoTim": writeRMNNoTim +} + +def addDefaultBlockTypes(blockTypes): + for key in defaultBlockTypes: + blockTypes[key] = defaultBlockTypes[key] diff --git a/src/grc.py b/src/grc.py new file mode 100644 index 0000000..ed02659 --- /dev/null +++ b/src/grc.py @@ -0,0 +1,94 @@ +GRC_TEMPLATE = ''' +options: + parameters: + title: 'TASRC to GRC converter output' + states: + coordinate: [-100, -100] + +blocks: +%s + +connections: +%s + +metadata: + file_format: 1 +''' + +BLOCK_TEMPLATE = ''' +- name: %s + id: epy_block + parameters: + _source_code: "from gnuradio import gr\\nimport numpy as np\\nclass BLOCK(gr.sync_block):\\n def __init__(self):\\n gr.sync_block.__init__(self,name='%s:%s%s',in_sig=%s,out_sig=%s)\\n def work(self, input_items, output_items):\\n return len(output_items[0])" + states: + coordinate: [%s, %s] +''' + +LINK_TEMPLATE = "- [%s, '%s', %s, '%s']\n" + +def getLongestDependencyRow(blocks, blockDependencies): + currentMax = 0 + for block in blocks: + current = getLongestDependencyRow(blockDependencies[block], blockDependencies) + 1 + if current > currentMax: + currentMax = current + return currentMax + +def getPosition(block, blockDependencies, reverseBlockDependencies, depths): + position = getLongestDependencyRow(blockDependencies[block], blockDependencies) + depths += [0] * (position+1 - len(depths)) + y = depths[position] + depths[position] += 50 # base offset + depths[position] += max( + (3+block.blockType.inputs.getRealCount()+block.blockType.outputs.getRealCount()) * 15, + max(block.blockType.inputs.getRealCount(), block.blockType.outputs.getRealCount()) * 30) + return position * 300, y + +def getBlockDependencies(blocks, links): + blockDependencies = {} + for block in blocks: + blockDependencies[block] = [] + for link in links: + if link.toBlock == block: + blockDependencies[block].append(link.fromBlock) + reverseBlockDependencies = {} + for block in blockDependencies: + for dependency in blockDependencies[block]: + if not dependency in reverseBlockDependencies: + reverseBlockDependencies[dependency] = [] + reverseBlockDependencies[dependency].append(block) + return blockDependencies, reverseBlockDependencies + +def getBlocksContent(blocks, links): + blockDependencies, reverseBlockDependencies = getBlockDependencies(blocks, links) + depths = [] + blocksContent = "" + for block in blocks: + description = block.blockType.getIODescription(block) + inputs = "[%s]" % ", ".join(["np.int8"] * block.blockType.inputs.getRealCount()) + outputs = "[%s]" % ", ".join(["np.int8"] * block.blockType.outputs.getRealCount()) + position = getPosition(block, blockDependencies, reverseBlockDependencies, depths) + blocksContent += BLOCK_TEMPLATE % ( + block.name, + block.name, + block.blockType.name, + description, + inputs, + outputs, + position[0], + position[1]) + return blocksContent + +def getLinksContent(links): + linksContent = "" + for link in links: + fromPort = link.fromBlock.blockType.outputs.getRealPort(link.fromPort) + toPort = link.toBlock.blockType.inputs.getRealPort(link.toPort) + linksContent += LINK_TEMPLATE % (link.fromBlock.name, fromPort, link.toBlock.name, toPort) + return linksContent + +def write(filename, blocks, links): + with open(filename, "w+") as file: + print("writing to file %s" % filename) + file.truncate(0) + file.write(GRC_TEMPLATE % (getBlocksContent(blocks, links), getLinksContent(links))) diff --git a/src/portNaming.py b/src/portNaming.py new file mode 100644 index 0000000..62be549 --- /dev/null +++ b/src/portNaming.py @@ -0,0 +1,104 @@ +import re +import os +import json +from defaultBlockTypes import defaultBlockTypes + +INPUT_FUNCTIONS = [ + "tacStdBlockGetInput", + "tacGraviMatrixGetPointerInput" + ] + +OUTPUT_FUNCTIONS = [ + "tacStdBlockSetOutput", + "tacGraviMatrixSetPointerOutput" + ] + +def getFiles(blockType, sourceDirectories): + files = [] + for sourceDirectory in sourceDirectories: + files += ["%s/%s" % (data[0], file) + for data in os.walk(sourceDirectory) + for file in data[2] if re.match(".*tac%sBlock.c" % blockType.name.replace("Rm", "Rmn"), file) != None] + return files + +def resolvePortNames(blockTypes, sourceDirectories): + missingBlocks = [] + multipleDefinitions = [] + for blockType in blockTypes: + if blockType.name in defaultBlockTypes: + continue + files = getFiles(blockType, sourceDirectories) + if len(files) == 0: + print("WARNING: no source file for block type %s found" % blockType.name) + missingBlocks.append(blockType.name) + continue + if len(files) > 1: + multipleDefinitions.append(blockType.name) + print("WARNING: more than one matching source file for block type %s found, skipping" % blockType.name) + continue + print("reading file %s" % files[0]) + with open(files[0], "r") as file: + content = "\n".join(file.readlines()) + for function in INPUT_FUNCTIONS: + mapInputs(content, function, blockType.inputs) + for function in OUTPUT_FUNCTIONS: + mapOutputs(content, function, blockType.outputs) + for entry in re.findall("\\w+ *= *\\*?\\(?pSelf->input\\[\\d+\\]\\)?", content): + name = re.search("^\\w+", entry).group() + position = int(re.search("(?<=\\[)\\d+(?=\\])", entry).group()) + blockType.inputs.mapName(position, name, 0) + for entry in re.findall("pSelf->output\\[\\d+\\] *= *\\w+", content): + name = re.search("\\w+$", entry).group() + position = int(re.search("(?<=\\[)\\d+(?=\\])", entry).group()) + blockType.outputs.mapName(position, name, 0) + if not os.path.exists("errors.json") or os.stat("errors.json").st_size == 0: + content = {"missing_blocks": [], "multiple_definitions": []} + else: + with open("errors.json", "r") as file: + content = json.load(file) + with open("errors.json", "w+") as file: + for blockTypeName in missingBlocks: + if not blockTypeName in content["missing_blocks"]: + content["missing_blocks"].append(blockTypeName) + for blockTypeName in multipleDefinitions: + if not blockTypeName in content["multiple_definitions"]: + content["multiple_definitions"].append(blockTypeName) + json.dump(content, file, indent=2) + file.close() + +def mapInputs(content, function, ports): + for entry in re.findall("\\w+ *= *%s\\(pSelf *, *\\d+\\);" % function, content): + name = re.search("^\\w+", entry).group() + position = int(re.search("\\d+(?= *\\) *;)", entry).group()) + ports.mapName(position, name, 0) + for entry in re.findall("\\w+->\\w+\\[\\d+\\] *= *%s\\(pSelf *, *\\d+\\);" % function, content): + name = re.search("(?<=\\->)\\w+", entry).group() + position = int(re.search("\\d+(?= *\\) *;)", entry).group()) + index = int(re.search("(?<=\\[)\\d+(?=\\])", entry).group()) + ports.mapName(position, name, index) + for entry in re.findall("\\w+\\[\\d+\\] *= *%s\\(pSelf *, *\\d+\\);" % function, content): + name = re.search("^\\w+", entry).group() + position = int(re.search("\\d+(?= *\\) *;)", entry).group()) + index = int(re.search("(?<=\\[)\\d+(?=\\])", entry).group()) + ports.mapName(position, name, index) + +def mapOutputs(content, function, ports): + for entry in re.findall("%s\\(pSelf *, *\\d+ *, *pSelfParam->\\w+\\);" % function, content): + name = re.search("\\w+(?=\\);$)", entry).group() + position = int(re.search("\\d+(?= *, *pSelfParam->\\w+\\);$)", entry).group()) + ports.mapName(position, name, 0) + for entry in re.findall("%s\\(pSelf *, *\\d+ *, *\\w+\\[\\d+\\]\\);" % function, content): + name = re.search("\\w+(?=\\[\\d+\\]\\);$)", entry).group() + position = int(re.search("\\d+(?= *, *\\w+\\[\\d+\\]\\);$)", entry).group()) + index = int(re.search("(?<=\\[)\\d+(?=\\])", entry).group()) + ports.mapName(position, name, index) + for entry in re.findall("%s\\(pSelf *, *\\d+ *, *pSelfParam->\\w+\\[\\d+\\]\\);" % function, content): + name = re.search("(?<=\\->)\\w+", entry).group() + position = int(re.search("\\d+(?= *, *pSelfParam->\\w+\\[\\d+\\]\\);$)", entry).group()) + index = int(re.search("(?<=\\[)\\d+(?=\\]\\);$)", entry).group()) + ports.mapName(position, name, index) + for entry in re.findall("%s\\(pSelf *, *\\d+ *, *\\w+\\);" % function, content): + name = re.search("\\w+(?= *\\);$)", entry).group() + position = int(re.search("\\d+(?= *, *\\w+\\);$)", entry).group()) + index = 0 + ports.mapName(position, name, index) diff --git a/src/tacsrc/block.py b/src/tacsrc/block.py new file mode 100644 index 0000000..737d9f1 --- /dev/null +++ b/src/tacsrc/block.py @@ -0,0 +1,6 @@ +class Block: + def __init__(self): + self.name = "" + self.blockType = None + self.parameters = [] + diff --git a/src/tacsrc/blockType.py b/src/tacsrc/blockType.py new file mode 100644 index 0000000..8930836 --- /dev/null +++ b/src/tacsrc/blockType.py @@ -0,0 +1,19 @@ +from tacsrc.ports import Ports + +class BlockType: + def __init__(self, name): + self.name = name + self.inputs = Ports() + self.outputs = Ports() + + def getIODescription(self, block): + result = "" + inputDescription = self.inputs.getIODescription(block) + if len(inputDescription) != 0: + result += "\\\\nINPUTS:" + result += inputDescription + outputDescription = self.outputs.getIODescription(block) + if len(outputDescription) != 0: + result += "\\\\nOUTPUTS:" + result += outputDescription + return result diff --git a/src/tacsrc/link.py b/src/tacsrc/link.py new file mode 100644 index 0000000..d89b459 --- /dev/null +++ b/src/tacsrc/link.py @@ -0,0 +1,6 @@ +class Link: + def __init__(self): + self.fromBlock = None + self.fromPort = 0 + self.toBlock = None + self.toPort = 0 diff --git a/src/tacsrc/ports.py b/src/tacsrc/ports.py new file mode 100644 index 0000000..4b26f22 --- /dev/null +++ b/src/tacsrc/ports.py @@ -0,0 +1,47 @@ +class Ports: + def __init__(self): + self.labels = [] + self.labelSizes = {} + + def mapName(self, position, name, index): + self.labels += [0] * (position+1 - len(self.labels)) + self.labels[position] = name + if not name in self.labelSizes: + self.labelSizes[name] = 0 + self.labelSizes[name] = max(self.labelSizes[name], index+1) + + def getRealPort(self, originalPort): + labelsDone = [] + for i in range(min(len(self.labels),originalPort)): + label = self.labels[i] + if label != 0 and label in labelsDone: + continue + labelsDone.append(label) + return len(labelsDone) - 1 + + def getIODescription(self, block): + result = "" + labelsDone = [] + for i in range(len(self.labels)): + label = self.labels[i] + if label != 0 and label in labelsDone: + continue + labelsDone.append(label) + if label == 0: + result += "\\\\n%s: unknown" % i + elif self.labelSizes[label] == 1: + result += "\\\\n%s: %s" % (i, label) + else: + result += "\\\\n%s: %s[%s]" % (i, label, self.labelSizes[label]) + return result + + def ensureLength(self, count): + self.labels += [0] * (count - len(self.labels)) + + def getRealCount(self): + labelsDone = [] + for label in self.labels: + if label != 0 and label in labelsDone: + continue + labelsDone.append(label) + return len(labelsDone) diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3624768 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +__pycache__ +out +tacapp.tar.gz +Sources +tacapp +worryingFiles +cc.tar.gz diff --git a/errors.json b/errors.json new file mode 100644 index 0000000..5ec898a --- /dev/null +++ b/errors.json @@ -0,0 +1,4 @@ +{ + "missing_blocks": [], + "multiple_definitions": [] +} \ No newline at end of file diff --git a/hardcodedFiles/tacReadRmnBlock.c b/hardcodedFiles/tacReadRmnBlock.c new file mode 100644 index 0000000..8acbcfa --- /dev/null +++ b/hardcodedFiles/tacReadRmnBlock.c @@ -0,0 +1,568 @@ +/******************************************************************************* +* E.S.O. - VLT project +* +* "@(#) $Id: tacReadRmnBlock.c 305476 2018-01-19 08:56:18Z rfrahm $" +* +* who when what +* ------- -------- ---------------------------------------------- +* gzins 2010-07-27 ported to VLTSW2010 and VxWorks 6.4 +* swehner 2008-10-10 creation +*/ + +/************************************************************************ +* NAME +* tacReadRmnBlock - Implemements the standard functions for the +* tacReadRmn block and tacReadRfm block. +* tacReadRmnBlock - Reads from 1rst generation reflective memory network +* tacReadRfmBlock - Reads from 2nd generation reflective memory network + +* Parameters: +* field - token names for the RMN fields to read (up to 10) +* Inputs: 0 +* Outputs: 1 +* output - 1..10 depending on number of field parameters +* +* +* +* FILES +* +* ENVIRONMENT +* TAC +* +* RETURN VALUES +* +* CAUTIONS +* +* EXAMPLES +* TAC.BLOCK9.TYPE ReadRmn +* TAC.BLOCK9.NAME ReadRmn +* +* SEE ALSO +* +* BUGS +* +*------------------------------------------------------------------------ +*/ + +#define _POSIX_SOURCE 1 +#include "vltPort.h" + +ATTRIBUTE_UNUSED static const char *rcsId="@(#) $Id: tacReadRmnBlock.c 305476 2018-01-19 08:56:18Z rfrahm $"; + +/* + * System Headers + */ + +#include /* taskSpawn, taskDelay, ... */ +#include /* printf ... */ +#include /* malloc ... */ +#include /* malloc ... */ +#include +#include + +/* + * Local Headers + */ + +#include "tacStdBlock.h" +#include "tacRmnBlock.h" +#include "rmassPublic.h" +#include "rmassPrivate.h" + +/* + * Compilation directives + */ + +/* + * Constants + */ + +#define tacREAD_RMN_EXPECTED_PARAM 1 +#define tacREAD_RMN_DEFAULT_INPUT_NUMBER 0 +#define tacREAD_RMN_DEFAULT_OUTPUT_NUMBER tacMAX_DATA_NUMBER + +#define tacREAD_RMN_FIELD_STRING_LEN 256 +#define tacSTRLEN sizeof(double) + +/* + * Types + */ + +/* + * Local function declaration + */ + +/* + * Global variables + */ + +/* + * Function definition + */ + + +STATUS tacReadRmnBlockCheckParameter (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the ADDBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = NULL; + + pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + /* field string is built from block params */ + if ( tacRmnBlockCheckParameter ( pSelf, parameter, 0, error) != OK ) + { + return ERROR; + } + + /* useful information on the screen */ + printf ("ReadRmn %s: [%s]\n", pSelf->name, pSelfParam->fieldString); + + return OK; +} + +STATUS tacReadRfmBlockCheckParameter (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the ADDBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = NULL; + + pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + /* field string is built from block params */ + if ( tacRmnBlockCheckParameter ( pSelf, parameter, 0, error) != OK ) + { + return ERROR; + } + + /* useful information on the screen */ + printf ("ReadRfm %s: [%s]\n", pSelf->name, pSelfParam->fieldString); + + return OK; +} + +/* + * Constructor Hooks - Called when a block of this type is instanciated (CONFIG or ADDBLCK commands) + */ + +STATUS tacReadRmBlockConstructor (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the ADDBLCK command */ + vltLOGICAL isRmn, + tacERROR* error) /* Error structure - not a stack */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = NULL; + + /* Check that the expected number of parameters has been received */ + if (parameter->number < tacREAD_RMN_EXPECTED_PARAM) + { + char errorParam[40]; + + sprintf(errorParam, "Expected at least %d, received %d", tacREAD_RMN_EXPECTED_PARAM, parameter->number); + tacRTC_ERR(tacERR_PARAM_NUMBER, errorParam); + return ERROR; + } + + /* Allocate and initialize block-specific arrays */ + if (tacStdBlockAllocateArrays(pSelf, 0, tacREAD_RMN_DEFAULT_INPUT_NUMBER, tacREAD_RMN_DEFAULT_OUTPUT_NUMBER, error) == ERROR) + { + return ERROR; + } + + if (tacStdBlockAllocateArrayBySize(pSelf, tacSTDBLOCK_PARAM_ARRAY, sizeof(tacRMN_LOCAL_PARAMETER), error) == ERROR) + { + tacStdBlockReleaseArray(pSelf, tacSTDBLOCK_INPUT_ARRAY, error); + tacStdBlockReleaseArray(pSelf, tacSTDBLOCK_OUTPUT_ARRAY, error); + return ERROR; + } + + if ( isRmn ) + { + if ( tacReadRmnBlockCheckParameter (pSelf, parameter, error) == ERROR) + { + return ERROR; + } + } + else + { + if ( tacReadRfmBlockCheckParameter (pSelf, parameter, error) == ERROR) + { + return ERROR; + } + } + + pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + pSelfParam->handleValid = rmassACCESS_BLOCKED; + + /* Attach to RMN */ + if ( rmassReadAttach (&pSelfParam->handle, + pSelfParam->fieldString, + &pSelfParam->val[0], + &pSelfParam->val[1], + &pSelfParam->val[2], + &pSelfParam->val[3], + &pSelfParam->val[4], + &pSelfParam->val[5], + &pSelfParam->val[6], + &pSelfParam->val[7], + &pSelfParam->val[8], + &pSelfParam->val[9]) != SUCCESS ) + { + char errorParam[40]; + + sprintf(errorParam, "Attach to RMN failed."); + tacRTC_ERR(tacERR_INTERNAL, errorParam); + return ERROR; + } + + pSelfParam->handleValid = rmassACCESS_FREE; + + return OK; +} + +STATUS tacReadRmnBlockConstructor (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the ADDBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + if ( tacReadRmBlockConstructor (pSelf, parameter, ccsTRUE, error ) == ERROR ) + { + return ERROR; + } + return OK; +} + +STATUS tacReadRfmBlockConstructor (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the ADDBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + if ( tacReadRmBlockConstructor (pSelf, parameter, ccsFALSE, error ) == ERROR ) + { + return ERROR; + } + return OK; +} + + + +/* + * Destructor Hooks - Called when the block is removed from the algorithm (DELBLCK or new CONFIG commands) + */ + +void tacReadRmnBlockDestructor (tacSTDBLOCK* pSelf) /* Reference to the block instance */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = NULL; + pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + pSelfParam->handleValid = rmassACCESS_BLOCKED; + /* wait until semaphore is acknowledged by realtime algo + * or just procede if realtime is not active */ + while ((*pSelf->shared).active && pSelfParam->handleValid != rmassACCESS_BLOCK_ACKN) + { + taskDelay(1); + } + + rmassDetach (&pSelfParam->handle); + + return; +} + +/* + * Change parameters Hooks - Called when modifying the block parameters (MODBLCK command) + */ + +STATUS tacReadRmnBlockSetParameter (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the MODBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + if ( tacReadRmnBlockCheckParameter (pSelf, parameter, error) == ERROR) + { + return ERROR; + } + + pSelfParam->handleValid = rmassACCESS_BLOCKED; + /* wait until semaphore is acknowledged by realtime algo + * or just procede if realtime is not active */ + while ((*pSelf->shared).active && pSelfParam->handleValid != rmassACCESS_BLOCK_ACKN) + { + taskDelay(1); + } + + /* detach RMN handle */ + if ( rmassDetach (&pSelfParam->handle) != SUCCESS ) + { + char errorParam[40]; + + sprintf(errorParam, "rmassDetach returned error."); + tacRTC_ERR(tacERR_INTERNAL, errorParam); + return ERROR; + } + + if ( rmassReadAttach (&pSelfParam->handle, + pSelfParam->fieldString, + &pSelfParam->val[0], + &pSelfParam->val[1], + &pSelfParam->val[2], + &pSelfParam->val[3], + &pSelfParam->val[4], + &pSelfParam->val[5], + &pSelfParam->val[6], + &pSelfParam->val[7], + &pSelfParam->val[8], + &pSelfParam->val[9]) != SUCCESS ) + { + char errorParam[40]; + + sprintf(errorParam, "Attach to RMN failed."); + tacRTC_ERR(tacERR_INTERNAL, errorParam); + return ERROR; + } + + pSelfParam->handleValid = rmassACCESS_FREE; + + return OK; +} + +STATUS tacReadRfmBlockSetParameter (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the MODBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + if ( tacReadRfmBlockCheckParameter (pSelf, parameter, error) == ERROR) + { + return ERROR; + } + + pSelfParam->handleValid = rmassACCESS_BLOCKED; + /* wait until semaphore is acknowledged by realtime algo + * or just procede if realtime is not active */ + while ((*pSelf->shared).active && pSelfParam->handleValid != rmassACCESS_BLOCK_ACKN) + { + taskDelay(1); + } + + /* detach RMN handle */ + if ( rmassDetach (&pSelfParam->handle) != SUCCESS ) + { + char errorParam[40]; + + sprintf(errorParam, "rmassDetach returned error."); + tacRTC_ERR(tacERR_INTERNAL, errorParam); + return ERROR; + } + + if ( rmassReadAttach (&pSelfParam->handle, + pSelfParam->fieldString, + &pSelfParam->val[0], + &pSelfParam->val[1], + &pSelfParam->val[2], + &pSelfParam->val[3], + &pSelfParam->val[4], + &pSelfParam->val[5], + &pSelfParam->val[6], + &pSelfParam->val[7], + &pSelfParam->val[8], + &pSelfParam->val[9]) != SUCCESS ) + { + char errorParam[40]; + + sprintf(errorParam, "Attach to RFM failed."); + tacRTC_ERR(tacERR_INTERNAL, errorParam); + return ERROR; + } + + pSelfParam->handleValid = rmassACCESS_FREE; + + return OK; +} + +/* + * Algorithm Hooks - Called at each time the TAC algorithm is evaluated (ONLINE state) + */ + +void tacReadRmnBlockAlgorithm (tacSTDBLOCK* pSelf) /* Reference to the block instance */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + int i; + + if ( pSelfParam->handleValid == rmassACCESS_BLOCKED ) + { + pSelfParam->handleValid = rmassACCESS_BLOCK_ACKN; + } + + if ( pSelfParam->handleValid == rmassACCESS_FREE ) + { + /* actual RMN read operation */ + rmassReadAccessRmn (&pSelfParam->handle); + + /* Write to outputs */ + for (i=0; i < pSelfParam->numFields; i++) + { + switch (pSelfParam->type[i]) + { + case rmassTIMESEC: + case rmassUINT32: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).ui); + break; + case rmassTIMEUSEC: + case rmassINT32: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).i); + break; + case rmassFLOAT: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).f); + break; + default: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).d); + break; + } + } + + /* provide zero values at unsatisfied outputs + * I consider this a good thing to do since the block + * is always configured */ + for (i=pSelfParam->numFields; i < tacREAD_RMN_DEFAULT_OUTPUT_NUMBER; i++) + { + tacStdBlockSetOutput(pSelf, i, 0.0); + } + } +} + +void tacReadRfmBlockAlgorithm (tacSTDBLOCK* pSelf) /* Reference to the block instance */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + int i; + + if ( pSelfParam->handleValid == rmassACCESS_BLOCKED ) + { + pSelfParam->handleValid = rmassACCESS_BLOCK_ACKN; + } + + if ( pSelfParam->handleValid == rmassACCESS_FREE ) + { + /* actual RMN read operation */ + rmassReadAccessRfm (&pSelfParam->handle); + + /* Write to outputs */ + for (i=0; i < pSelfParam->numFields; i++) + { + switch (pSelfParam->type[i]) + { + case rmassTIMESEC: + case rmassUINT32: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).ui); + break; + case rmassTIMEUSEC: + case rmassINT32: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).i); + break; + case rmassFLOAT: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).f); + break; + default: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).d); + break; + } + } + + /* provide zero values at unsatisfied outputs + * I consider this a good thing to do since the block + * is always configured */ + for (i=pSelfParam->numFields; i < tacREAD_RMN_DEFAULT_OUTPUT_NUMBER; i++) + { + tacStdBlockSetOutput(pSelf, i, 0.0); + } + } +} + +/* + * Show Hooks - Called when the tacRtcTaskShow routine is executed + */ + +void tacReadRmnBlockShow (tacSTDBLOCK* pSelf) /* Reference to the block instance */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + /* Print parameter values */ + printf(" Attached: %s\n", pSelfParam->fieldString); + + return; +} + + +/***************************************************/ +/* The following code is common to all block types */ +/* Do not modify without any good reasons */ +/***************************************************/ + +/* + * Installation function + */ + +tacSTDBLOCK_TYPE tacReadRmnTypeInfo = { + "ReadRmn", + &tacReadRmnBlockConstructor, + &tacRmBlockGetParameter, + &tacReadRmnBlockAlgorithm, + &tacReadRmnBlockSetParameter, + NULL, + NULL, + &tacReadRmnBlockDestructor, + &tacReadRmnBlockShow +}; + +tacSTDBLOCK_TYPE tacReadRfmTypeInfo = { + "ReadRfm", + &tacReadRfmBlockConstructor, + &tacRmBlockGetParameter, + &tacReadRfmBlockAlgorithm, + &tacReadRmnBlockSetParameter, + NULL, + NULL, + &tacReadRmnBlockDestructor, + &tacReadRmnBlockShow +}; + +STATUS tacReadRmnBlockInitAll (void) +{ + /***************************************************/ + /* The following code is common to all block types */ + /* Do not modify without any good reasons */ + /***************************************************/ + + /* Install ReadRmn1g Block Hooks */ + tacStdBlockInstallNewType(&tacReadRmnTypeInfo); + + /*****************************/ + /* End of common code region */ + /*****************************/ + + /* Perform other library initialization operations */ + + return OK; +} + +STATUS tacReadRfmBlockInitAll (void) +{ + /***************************************************/ + /* The following code is common to all block types */ + /* Do not modify without any good reasons */ + /***************************************************/ + + /* Install ReadRmn1g Block Hooks */ + tacStdBlockInstallNewType(&tacReadRfmTypeInfo); + + /*****************************/ + /* End of common code region */ + /*****************************/ + + /* Perform other library initialization operations */ + + return OK; +} + +/*___oOo___*/ + + + diff --git a/hardcodedFiles/tacSinkBlock.c b/hardcodedFiles/tacSinkBlock.c new file mode 100644 index 0000000..df39833 --- /dev/null +++ b/hardcodedFiles/tacSinkBlock.c @@ -0,0 +1,1256 @@ +/******************************************************************************* +* E.S.O. - VLT project +* +* "@(#) $Id: tacSinkBlock.c 339094 2021-02-10 03:10:02Z jgil $" +* +* who when what +* ------- -------- ---------------------------------------------- +* rdembet 06/08/20 New MonitorState block with no data averaging +* swehner 28/11/09 SPR20090234 Correction in rate adjustment in reset hook +* swehner 27/11/09 Fixed message queue handling +* swehner 10/10/09 New block FastProbe for unlimited rec frequency +* swehner 22/09/09 PPRS 32341 Replaced specialized tacSINK_SHMSG stack +* with standard vxWorks message queue. +* bbauvir 21/09/04 VLTSW20040113 - One sample might be lost +* bbauvir 29/03/04 Monitor block averages over the reporting period +* bbauvir 29/12/02 Probe to the SampTask +* bbauvir 26/12/02 MsgQ access through DPC mechanism +* bbauvir 14/07/02 New MsgQ of TAC version 1.22 +* bbauvir 21/03/01 Created +*/ + +/************************************************************************ +* NAME +* tacSinkBlock - Standard data monitoring blocks +* +* SYNOPSIS +* lcubootAutoCdBoot 1,"tacsink.boot" +* < tacsink.boot +* +* DESCRIPTION +* Block type: Display +* Parameters: +* Inputs: 1 +* Outputs: none +* +* This function block samples the value of its input signal at the +* specified and issues a message containing the time +* and the value of the input on the vxWorks terminal. +* It does not allow modification of the parameter at runtime. +* +* Block type: Monitor +* Parameters: +* +* Inputs: 10max +* Outputs: none +* +* This function block samples the value of its input signals at the +* specified (0.0 to send a message at the system sampling +* period) and issues a message containing the time and the value of +* the inputs on the shared memory. This message is intercepted by the +* background task running on the master CPU. The monitored values are +* written into the online database. The number of inputs of the block +* is specified by parameter. +* This block does not allow modification of the parameters at runtime. +* +* Block type: MonitorState +* Parameters: +* +* Inputs: 10max +* Outputs: none +* +* Same as Monitor block but without the averaging of received data, +* see VLTSW-14260 JIRA ticket. +* +* Block type: Probe +* Parameters: +* +* Inputs: 10max +* Outputs: none +* +* Block type: FastProbe +* Parameters: +* +* Inputs: 10max +* Outputs: none +* +* This function block samples the value of its input signals at the +* specified (0.0 to send a message at the system sampling +* period) and issues a message containing the time and the value of +* the inputs on the shared memory. This message is intercepted by the +* background task running on the master CPU. The number of inputs of +* the block is specified by parameter. +* This message is passed to an external application callback if +* provided. +* This block does not allow modification of the parameters at runtime. +* The normal Probe block has a limited sampling frequency of not more +* than 2kHz. The reason is in particular the bottleneck between master +* and slave CPU which all samples have to pass through a mechanism of +* VME bus shared memory. On one-CPU-systems this limitation does not +* apply so you are free to choose faster sampling. You may of course +* hit other limitations (processor speed, network traffic etc.) +* +* FILES +* +* ENVIRONMENT +* TAC +* +* RETURN VALUES +* +* CAUTIONS +* All these blocks compute an decimation value to use to trigger the +* sampling of the input signals, from the system sampling period. +* They should be created after any synchronization block. +* +* In order to cope with system performances, a minimum +* is defined for each block. The minimum applied periods are 0.1 (10Hz), +* 0.01 (100Hz) and 0.5e-3 (2kHz) for the 'Display', 'Monitor' and +* 'Probe' blocks respectively. +* +* EXAMPLES +* # 5 signals @ 2Hz (monitored in the database) +* TAC.BLOCK9.TYPE Monitor +* TAC.BLOCK9.NAME Monitor +* TAC.BLOCK9.PARAM 0.5, 5 +* +* # 5 signals @ the RT algorithm sampling period (0.0) +* TAC.BLOCK10.TYPE Probe +* TAC.BLOCK10.NAME Probe +* TAC.BLOCK10.PARAM 0.0, 5 +* +* SEE ALSO +* tacServerInstallDataCallback, tacServerRemoveDataCallback +* +* BUGS +* +*------------------------------------------------------------------------ +*/ + +#define _POSIX_SOURCE 1 +#include "vltPort.h" + + +/* + * System Headers + */ + +#include +#include +#include /* logMsg ... */ +#include /* printf ... */ +#include /* malloc ... */ +#include /* memcpy ... */ +#include + +/* + * Local Headers + */ + +#include "tacStdBlock.h" +#include "tacShMsgQ.h" + +/* + * Compilation directives + */ + +/* + * Constants + */ + +#define tacSINK_DEFAULT_EXPECTED_PARAM 2 + +#define tacSINK_DEFAULT_INPUT_NUMBER tacMAX_DATA_NUMBER /* Up to 10 input channels */ +#define tacSINK_DEFAULT_OUTPUT_NUMBER tacMAX_DATA_NUMBER + +#define tacSINK_ONE_EXPECTED_PARAM 1 +#define tacSINK_ONE_INPUT_NUMBER 1 + +#define tacSINK_DISPLAY_MIN_SAMPLING_PERIOD .1 /* 10Hz */ +#define tacSINK_MONITOR_MIN_SAMPLING_PERIOD .01 /* 100Hz */ +#define tacSINK_PROBE_MIN_SAMPLING_PERIOD .5e-3 /* 2kHz */ + +#define tacSINK_DISPLAY_LOG_STRING_SIZE 128 + +#define tacSINK_MONITOR_DEFAULT_DB_POINT "tac:data:monitor" +#define tacSINK_MONITOR_MAX_DB_ADDR_SIZE 64 + +#define tacSINK_MONITOR_QUEUE_SIZE 6 +#define tacSINK_PROBE_QUEUE_SIZE 6 + + +typedef enum { + tacSINK_SAMPLING_PERIOD = 0, + tacSINK_INPUT_NUMBER, + tacSINK_MONITOR_DB_POINT, +}tacSINK_SCOPE_PARAM_INDEX; + +/* + * Types + */ + +typedef struct { + unsigned short rate; + unsigned short counter; + unsigned short inputNb; + unsigned int lost; + double rateParam; + char* dbPoint; + MSG_Q_ID msgq; + tacSHMSG shmMsg; +}tacSINK_SCOPE_LOCAL_PARAMETER; + +/* + * Function declaration + */ + +extern STATUS tacDpcPushRequest(tacVOIDFCTPTR pFunct, void* parameter); + +/* + * Local function declaration + */ + +/* + * Note: Routines called from within the algorithm must be declared with + * static __inline__ + */ + +STATUS tacSinkSendMonitorMessage(MSG_Q_ID * msgqvoid); +STATUS tacSinkSendMonitorStateMessage(MSG_Q_ID * msgqvoid); +STATUS tacSinkSendProbeMessage(MSG_Q_ID * msgq); +STATUS tacSinkDeleteMessageQueue(MSG_Q_ID * msgq); +STATUS tacSinkCommonBlockConstructor(tacSTDBLOCK* pSelf, tacERROR* error); + +/* + * Global variables + */ + +char logStr[tacSINK_DISPLAY_LOG_STRING_SIZE]; /* Logging string used for Display */ + + +/* + * Function definition + */ + +/* + * Constructor Hooks + */ + +STATUS tacSinkDisplayBlockConstructor (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = NULL; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = NULL; + + /* Check that the expected number of parameters has been received */ + if (parameter->number < tacSINK_ONE_EXPECTED_PARAM) + { + char errorParam[40]; + + sprintf(errorParam, "Expected %d, received %d", tacSINK_ONE_EXPECTED_PARAM, parameter->number); + tacRTC_ERR(tacERR_PARAM_NUMBER, errorParam); + return ERROR; + } + + /* Check that the parameters are valid */ + pRealParam = (double*) parameter->buffer; + + /* Passed parameter is the sampling period of the block */ + if (pRealParam[tacSINK_SAMPLING_PERIOD] < (*pSelf->shared).samplingPeriod) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = (*pSelf->shared).samplingPeriod; + } + + if (pRealParam[tacSINK_SAMPLING_PERIOD] < tacSINK_DISPLAY_MIN_SAMPLING_PERIOD) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = tacSINK_DISPLAY_MIN_SAMPLING_PERIOD; + } + + /* Call common constructor */ + if (tacSinkCommonBlockConstructor(pSelf, error) != OK) + { + return ERROR; + } + + /* Store parameters */ + pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; /* We will only store short integers */ + + /* + * Compute the rate at which data has to be processed - divide and take + * the integer part of the result + */ + + pSelfParam->rate = (unsigned short) (pRealParam[tacSINK_SAMPLING_PERIOD] / (*pSelf->shared).samplingPeriod); + pSelfParam->counter = 0; /* Decimation counter */ + + /* + * Perform other block initialization operations + */ + + return OK; +} + +STATUS tacSinkMonitorBlockConstructor (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = NULL; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = NULL; + unsigned short arrayIndex = 0; + + /* Check that the expected number of parameters has been received */ + if (parameter->number < tacSINK_DEFAULT_EXPECTED_PARAM) + { + char errorParam[40]; + + sprintf(errorParam, "Expected %d, received %d", tacSINK_DEFAULT_EXPECTED_PARAM, parameter->number); + tacRTC_ERR(tacERR_PARAM_NUMBER, errorParam); + return ERROR; + } + + /* Check that the parameters are valid */ + pRealParam = (double*) parameter->buffer; + + /* Passed parameter is the sampling period of the block */ + if (pRealParam[tacSINK_SAMPLING_PERIOD] < (*pSelf->shared).samplingPeriod) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = (*pSelf->shared).samplingPeriod; + } + + if (pRealParam[tacSINK_SAMPLING_PERIOD] < tacSINK_MONITOR_MIN_SAMPLING_PERIOD) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = tacSINK_MONITOR_MIN_SAMPLING_PERIOD; + } + + /* Number of inputs is minimum 1 up to tacMSG_MAX_DATA_NUMBER */ + if ((pRealParam[tacSINK_INPUT_NUMBER] < 1) || + (pRealParam[tacSINK_INPUT_NUMBER] > tacMAX_DATA_NUMBER)) + { + tacRTC_ERR(tacERR_PARAM_INVALID, ""); + return ERROR; + } + + /* Call common constructor */ + if (tacSinkCommonBlockConstructor(pSelf, error) != OK) + { + return ERROR; + } + + /* Store parameters */ + pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* + * Compute the rate at which data has to be processed - divide and take + * the integer part of the result + */ + + pSelfParam->rate = (unsigned short) (pRealParam[tacSINK_SAMPLING_PERIOD] / (*pSelf->shared).samplingPeriod); + pSelfParam->counter = 0; /* Decimation counter */ + pSelfParam->inputNb = (unsigned short) pRealParam[tacSINK_INPUT_NUMBER]; + + /* Optional parameter is an application-specific DB point */ + if (parameter->number == tacSINK_DEFAULT_EXPECTED_PARAM + 1) + { + printf("tacSinkMonitorBlockConstructor - DB point %s\n",(char*) &(pRealParam[tacSINK_MONITOR_DB_POINT])); + pSelfParam->dbPoint = (char*) malloc(tacSINK_MONITOR_MAX_DB_ADDR_SIZE); + strcpy(pSelfParam->dbPoint, (char*) &(pRealParam[tacSINK_MONITOR_DB_POINT])); + } + else + { + printf("tacSinkMonitorBlockConstructor - Default DB point\n"); + pSelfParam->dbPoint = NULL; + } + + /* Specify the number of input signals to attach to become resolved */ + tacStdBlockSetInputNumber(pSelf, pSelfParam->inputNb); + + /* + * Perform other block initialization operations + */ + + /* Create the block internal message queue which tosses the messages out of the + * interrupt context. They are buffered in the queue until the DPC tasks + * picks them up and sends them over the shared memory message queue. + * Sorry for that double-queuing, that's because of the M-S architecture */ + + pSelfParam->msgq = msgQCreate(tacSINK_MONITOR_QUEUE_SIZE, sizeof(tacSHMSG), 0); + if ( pSelfParam->msgq == NULL ) + { + char errorParam[40]; + + sprintf(errorParam, "Could not create probe block message queue"); + tacRTC_ERR(tacERR_MALLOC, errorParam); + return ERROR; + } + + /* will count if a message can't be pushed in the queue */ + pSelfParam->lost = 0; + + /* Warn the background task that a new probe block has been created */ + pSelfParam->shmMsg.type = tacSHMSG_ADD_MONITOR; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + + if (pSelfParam->dbPoint == NULL) + { + strcpy((char*) &(pSelfParam->shmMsg.msgBody.monitor.data), tacSINK_MONITOR_DEFAULT_DB_POINT); + } + else + { + strcpy((char*) &(pSelfParam->shmMsg.msgBody.monitor.data), *((char**) &(pSelfParam->dbPoint))); + } + + printf("tacSinkMonitorBlockConstructor - Attach to %s\n",(char*) &(pSelfParam->shmMsg.msgBody.monitor.data)); + + /* Send message */ + tacShMsgQSendBgInfo(&(pSelfParam->shmMsg)); + + /* Initialize the message parameters */ + pSelfParam->shmMsg.type = tacSHMSG_MONITOR_DATA; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + pSelfParam->shmMsg.msgBody.monitor.data.number = pSelfParam->inputNb; + + /* The output port is used to average the inputs over the reporting period */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pSelf->output[arrayIndex] = 0.0; + } + + return OK; +} + +STATUS tacSinkMonitorStateBlockConstructor (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = NULL; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = NULL; + unsigned short arrayIndex = 0; + + /* Check that the expected number of parameters has been received */ + if (parameter->number < tacSINK_DEFAULT_EXPECTED_PARAM) + { + char errorParam[40]; + + sprintf(errorParam, "Expected %d, received %d", tacSINK_DEFAULT_EXPECTED_PARAM, parameter->number); + tacRTC_ERR(tacERR_PARAM_NUMBER, errorParam); + return ERROR; + } + + /* Check that the parameters are valid */ + pRealParam = (double*) parameter->buffer; + + /* Passed parameter is the sampling period of the block */ + if (pRealParam[tacSINK_SAMPLING_PERIOD] < (*pSelf->shared).samplingPeriod) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = (*pSelf->shared).samplingPeriod; + } + + if (pRealParam[tacSINK_SAMPLING_PERIOD] < tacSINK_MONITOR_MIN_SAMPLING_PERIOD) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = tacSINK_MONITOR_MIN_SAMPLING_PERIOD; + } + + /* Number of inputs is minimum 1 up to tacMSG_MAX_DATA_NUMBER */ + if ((pRealParam[tacSINK_INPUT_NUMBER] < 1) || + (pRealParam[tacSINK_INPUT_NUMBER] > tacMAX_DATA_NUMBER)) + { + tacRTC_ERR(tacERR_PARAM_INVALID, ""); + return ERROR; + } + + /* Call common constructor */ + if (tacSinkCommonBlockConstructor(pSelf, error) != OK) + { + return ERROR; + } + + /* Store parameters */ + pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* + * Compute the rate at which data has to be processed - divide and take + * the integer part of the result + */ + + pSelfParam->rate = (unsigned short) (pRealParam[tacSINK_SAMPLING_PERIOD] / (*pSelf->shared).samplingPeriod); + pSelfParam->counter = 0; /* Decimation counter */ + pSelfParam->inputNb = (unsigned short) pRealParam[tacSINK_INPUT_NUMBER]; + + /* Optional parameter is an application-specific DB point */ + if (parameter->number == tacSINK_DEFAULT_EXPECTED_PARAM + 1) + { + printf("tacSinkMonitorStateBlockConstructor - DB point %s\n",(char*) &(pRealParam[tacSINK_MONITOR_DB_POINT])); + pSelfParam->dbPoint = (char*) malloc(tacSINK_MONITOR_MAX_DB_ADDR_SIZE); + strcpy(pSelfParam->dbPoint, (char*) &(pRealParam[tacSINK_MONITOR_DB_POINT])); + } + else + { + printf("tacSinkMonitorStateBlockConstructor - Default DB point\n"); + pSelfParam->dbPoint = NULL; + } + + /* Specify the number of input signals to attach to become resolved */ + tacStdBlockSetInputNumber(pSelf, pSelfParam->inputNb); + + /* + * Perform other block initialization operations + */ + + /* Create the block internal message queue which tosses the messages out of the + * interrupt context. They are buffered in the queue until the DPC tasks + * picks them up and sends them over the shared memory message queue. + * Sorry for that double-queuing, that's because of the M-S architecture */ + + pSelfParam->msgq = msgQCreate(tacSINK_MONITOR_QUEUE_SIZE, sizeof(tacSHMSG), 0); + if ( pSelfParam->msgq == NULL ) + { + char errorParam[40]; + + sprintf(errorParam, "Could not create probe block message queue"); + tacRTC_ERR(tacERR_MALLOC, errorParam); + return ERROR; + } + + /* will count if a message can't be pushed in the queue */ + pSelfParam->lost = 0; + + /* Warn the background task that a new probe block has been created */ + pSelfParam->shmMsg.type = tacSHMSG_ADD_MONITOR; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + + if (pSelfParam->dbPoint == NULL) + { + strcpy((char*) &(pSelfParam->shmMsg.msgBody.monitor.data), tacSINK_MONITOR_DEFAULT_DB_POINT); + } + else + { + strcpy((char*) &(pSelfParam->shmMsg.msgBody.monitor.data), *((char**) &(pSelfParam->dbPoint))); + } + + printf("tacSinkMonitorStateBlockConstructor - Attach to %s\n",(char*) &(pSelfParam->shmMsg.msgBody.monitor.data)); + + /* Send message */ + tacShMsgQSendBgInfo(&(pSelfParam->shmMsg)); + + /* Initialize the message parameters */ + pSelfParam->shmMsg.type = tacSHMSG_MONITOR_DATA; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + pSelfParam->shmMsg.msgBody.monitor.data.number = pSelfParam->inputNb; + + /* Init output port which won't be used to average the inputs over the reporting period */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pSelf->output[arrayIndex] = 0.0; + } + + return OK; +} + +STATUS tacSinkProbeBlockCommonConstructor (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + double minPeriod, + tacERROR* error) +{ + double* pRealParam = NULL; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = NULL; + + /* Check that the expected number of parameters has been received */ + if (parameter->number < tacSINK_DEFAULT_EXPECTED_PARAM) + { + char errorParam[40]; + + sprintf(errorParam, "Expected %d, received %d", tacSINK_DEFAULT_EXPECTED_PARAM, parameter->number); + tacRTC_ERR(tacERR_PARAM_NUMBER, errorParam); + return ERROR; + } + + /* Check that the parameters are valid */ + pRealParam = (double*) parameter->buffer; + + /* Passed parameter is the sampling period of the block */ + if (pRealParam[tacSINK_SAMPLING_PERIOD] < (*pSelf->shared).samplingPeriod) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = (*pSelf->shared).samplingPeriod; + } + + if (pRealParam[tacSINK_SAMPLING_PERIOD] < minPeriod) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = minPeriod; + } + + /* Number of inputs is minimum 1 up to tacMSG_MAX_DATA_NUMBER */ + if ((pRealParam[tacSINK_INPUT_NUMBER] < 1) || + (pRealParam[tacSINK_INPUT_NUMBER] > tacMAX_DATA_NUMBER)) + { + tacRTC_ERR(tacERR_PARAM_INVALID, ""); + return ERROR; + } + + /* Call common constructor */ + if (tacSinkCommonBlockConstructor(pSelf, error) != OK) + { + return ERROR; + } + + /* Store parameters */ + pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* + * Compute the rate at which data has to be processed - divide and take + * the integer part of the result + */ + + pSelfParam->rateParam = pRealParam[tacSINK_SAMPLING_PERIOD]; + pSelfParam->rate = (unsigned short) (pRealParam[tacSINK_SAMPLING_PERIOD] / (*pSelf->shared).samplingPeriod); + pSelfParam->counter = 0; /* Decimation counter */ + pSelfParam->inputNb = (unsigned short) pRealParam[tacSINK_INPUT_NUMBER]; + + /* Specify the number of input signals to attach to become resolved */ + tacStdBlockSetInputNumber(pSelf, pSelfParam->inputNb); + + /* + * Perform other block initialization operations + */ + + /* Create the block internal message queue which gets the messages out of the + * interrupt context. They are buffered in the queue until the DPC tasks + * picks them up and sends them over the shared memory message queue. + * Sorry for that double-queuing, that's because of the M-S architecture */ + + /* There is only one message queue for all probe blocks! */ + pSelfParam->msgq = msgQCreate(tacSINK_PROBE_QUEUE_SIZE, sizeof(tacSHMSG), 0); + if ( pSelfParam->msgq == NULL ) + { + char errorParam[40]; + + sprintf(errorParam, "Could not create probe block message queue"); + tacRTC_ERR(tacERR_MALLOC, errorParam); + return ERROR; + } + + /* will count if a message can't be pushed in the queue */ + pSelfParam->lost = 0; + + /* Warn the background task that a new probe block has been created */ + pSelfParam->shmMsg.type = tacSHMSG_ADD_PROBE; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + + /* Send message */ + tacShMsgQSendDataSample(&pSelfParam->shmMsg); + + /* Initialize the message parameters */ + pSelfParam->shmMsg.type = tacSHMSG_TRANSFER_DATA; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + pSelfParam->shmMsg.msgBody.monitor.data.number = pSelfParam->inputNb; + + return OK; +} + +/* Probe block has a max. sampling frequency of 2kHz */ +STATUS tacSinkProbeBlockConstructor (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + return tacSinkProbeBlockCommonConstructor (pSelf, parameter, tacSINK_PROBE_MIN_SAMPLING_PERIOD, error); +} + +/* Fast probe is the same as probe but not does have the + * limitation on the max. recording frequency */ +STATUS tacSinkFastProbeBlockConstructor (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + return tacSinkProbeBlockCommonConstructor (pSelf, parameter, 0.0, error); +} + +void tacSinkProbeBlockReset (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = + (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* + * Re-Compute the rate at which data has to be processed + */ + if (pSelfParam->rateParam < (*pSelf->shared).samplingPeriod ) + { + pSelfParam->rate = 1; + } + else + { + pSelfParam->rate = (unsigned short) + (pSelfParam->rateParam / (*pSelf->shared).samplingPeriod); + } + + return; +} + +/* + * Report parameters Hooks + */ + +STATUS tacSinkDisplayBlockGetParameter (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = (double*) parameter->buffer; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Send back the expected number of parameters */ + parameter->number = tacSINK_ONE_EXPECTED_PARAM; + + /* Report current parameters */ + pRealParam[tacSINK_SAMPLING_PERIOD] = (double) (pSelfParam->rate * (*pSelf->shared).samplingPeriod); + + return OK; +} + +STATUS tacSinkMonitorBlockGetParameter (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = (double*) parameter->buffer; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Send back the expected number of parameters */ + parameter->number = tacSINK_DEFAULT_EXPECTED_PARAM; + + /* Report current parameters */ + pRealParam[tacSINK_SAMPLING_PERIOD] = (double) (pSelfParam->rate * (*pSelf->shared).samplingPeriod); + pRealParam[tacSINK_INPUT_NUMBER] = (double) pSelfParam->inputNb; + + if (*((char**) &(pSelfParam->dbPoint)) != NULL) + { + parameter->number += 1; + parameter->type[tacSINK_MONITOR_DB_POINT] = tacPARAM_STRING; + strcpy((char*) &(pRealParam[tacSINK_MONITOR_DB_POINT]), *((char**) &(pSelfParam->dbPoint))); + } + + return OK; +} + +STATUS tacSinkMonitorStateBlockGetParameter (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = (double*) parameter->buffer; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Send back the expected number of parameters */ + parameter->number = tacSINK_DEFAULT_EXPECTED_PARAM; + + /* Report current parameters */ + pRealParam[tacSINK_SAMPLING_PERIOD] = (double) (pSelfParam->rate * (*pSelf->shared).samplingPeriod); + pRealParam[tacSINK_INPUT_NUMBER] = (double) pSelfParam->inputNb; + + if (*((char**) &(pSelfParam->dbPoint)) != NULL) + { + parameter->number += 1; + parameter->type[tacSINK_MONITOR_DB_POINT] = tacPARAM_STRING; + strcpy((char*) &(pRealParam[tacSINK_MONITOR_DB_POINT]), *((char**) &(pSelfParam->dbPoint))); + } + + return OK; +} + +STATUS tacSinkProbeBlockGetParameter (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = (double*) parameter->buffer; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Send back the expected number of parameters */ + parameter->number = tacSINK_DEFAULT_EXPECTED_PARAM; + + /* Report current parameters */ + pRealParam[tacSINK_SAMPLING_PERIOD] = (double) (pSelfParam->rate * (*pSelf->shared).samplingPeriod); + pRealParam[tacSINK_INPUT_NUMBER] = (double) pSelfParam->inputNb; + + return OK; +} + +/* + * Change parameters Hooks + */ + +/* + * Algorithm Hooks + */ + +void tacSinkDisplayBlockAlgorithm (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + if ((pSelfParam->counter % pSelfParam->rate) == 0) /* It's time to process data */ + { + sprintf(logStr,"Name: %s Time: %ld.%6ld Value: %g\n", + pSelf->name, + (*pSelf->shared).currentTime.seconds, + (*pSelf->shared).currentTime.microsec, + tacStdBlockGetInput(pSelf,0)); + + tacDpcPushRequest((tacVOIDFCTPTR) &printf, logStr); + + pSelfParam->counter = 0; + } + + pSelfParam->counter++; +} + +void tacSinkMonitorBlockAlgorithm (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + unsigned short arrayIndex = 0; + + /* The output port is used to average the inputs over the reporting period */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pSelf->output[arrayIndex] += tacStdBlockGetInput(pSelf,arrayIndex); + } + + if ((pSelfParam->counter % pSelfParam->rate) == 0) /* It's time to process data */ + { + tacDATA* pData = &(pSelfParam->shmMsg.msgBody.monitor.data); /* We are only interested in message body */ + + /* pData->number = pSelfParam->inputNb; */ + pData->timeStamp = (*pSelf->shared).currentTime; + + /* pData points to the body of the Message */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pData->buffer[arrayIndex] = pSelf->output[arrayIndex] / pSelfParam->rate; + } + + /* Push message into probe block's message que to get the + * data out of the interrupt comtext. */ + if ( msgQSend (pSelfParam->msgq, (char*) &(pSelfParam->shmMsg), sizeof(tacSHMSG), NO_WAIT, 0) != OK ) + { + (pSelfParam->lost)++; + } + + /* Defer procedure call */ + tacDpcPushRequest((tacVOIDFCTPTR) &tacSinkSendMonitorMessage, &pSelfParam->msgq); + + pSelfParam->counter = 0; + + /* The output port is used to average the inputs over the reporting period */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pSelf->output[arrayIndex] = 0.0; + } + } + + pSelfParam->counter++; +} + +void tacSinkMonitorStateBlockAlgorithm (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + unsigned short arrayIndex = 0; + + if ((pSelfParam->counter % pSelfParam->rate) == 0) /* It's time to process data */ + { + tacDATA* pData = &(pSelfParam->shmMsg.msgBody.monitor.data); /* We are only interested in message body */ + + /* pData->number = pSelfParam->inputNb; */ + pData->timeStamp = (*pSelf->shared).currentTime; + + /* pData points to the body of the Message */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pData->buffer[arrayIndex] = tacStdBlockGetInput(pSelf,arrayIndex); + } + + /* Push message into probe block's message que to get the + * data out of the interrupt comtext. */ + if ( msgQSend (pSelfParam->msgq, (char*) &(pSelfParam->shmMsg), sizeof(tacSHMSG), NO_WAIT, 0) != OK ) + { + (pSelfParam->lost)++; + } + + /* Defer procedure call */ + tacDpcPushRequest((tacVOIDFCTPTR) &tacSinkSendMonitorMessage, &pSelfParam->msgq); + + pSelfParam->counter = 0; + } + + pSelfParam->counter++; +} + +void tacSinkProbeBlockAlgorithm (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + unsigned short arrayIndex = 0; + + if ((pSelfParam->counter % pSelfParam->rate) == 0) /* It's time to process data */ + { + tacDATA* pData = &(pSelfParam->shmMsg.msgBody.monitor.data); /* We are only interested in message body */ + + pData->timeStamp = (*pSelf->shared).currentTime; + + /* pData points to the body of the Message */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pData->buffer[arrayIndex] = tacStdBlockGetInput(pSelf,arrayIndex); + } + + /* Push message into probe block's message que to get the + * data out of the interrupt comtext. */ + if ( msgQSend (pSelfParam->msgq, (char*) &(pSelfParam->shmMsg), sizeof(tacSHMSG), NO_WAIT, 0) != OK ) + { + (pSelfParam->lost)++; + } + + /* Defer procedure call: + * tacSinkSendProbeMessage is called outside the interrupt routine + * and will take care to pick up the message from the probe block's + * message queue and send it over the shared memory message queue */ + tacDpcPushRequest((tacVOIDFCTPTR) &tacSinkSendProbeMessage, &pSelfParam->msgq); + + pSelfParam->counter = 0; + } + + pSelfParam->counter++; +} + +/* + * Reset Hooks + */ + +/* + * Stop Hooks + */ + +/* + * Destructor Hooks + */ + +/* + * Note: This destructor is used mainly to send a MONITOR message containing + * 0.0 in order to reset the database array (otherwise going from an + * algorithm with 4 monitored data to one with 3 monitored data leaves + * the 4th value equal to the last ...) + */ + +void tacSinkMonitorBlockDestructor (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + tacDATA* pData = &(pSelfParam->shmMsg.msgBody.monitor.data); + unsigned short arrayIndex = 0; + + /* Reset DB values */ + pSelfParam->shmMsg.type = tacSHMSG_MONITOR_DATA; + pData = &(pSelfParam->shmMsg.msgBody.monitor.data); + + pData->number = pSelfParam->inputNb; + + /* pData points to the body of the Message */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pData->buffer[arrayIndex] = 0.0; + } + + /* Send message */ + tacShMsgQSendBgInfo(&pSelfParam->shmMsg); + + pSelfParam->shmMsg.type = tacSHMSG_REMOVE_MONITOR; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + + /* Send message */ + tacShMsgQSendBgInfo(&pSelfParam->shmMsg); + + free(pSelfParam->dbPoint); + + /* delete internal message queue. Do this as deferred procedure call + * to make sure it is only called when all messages have been send + * (through the same deferred call mechanism) */ + tacDpcPushRequest((tacVOIDFCTPTR) tacSinkDeleteMessageQueue, &(pSelfParam->msgq)); + + return; +} + +void tacSinkMonitorStateBlockDestructor (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + tacDATA* pData = &(pSelfParam->shmMsg.msgBody.monitor.data); + unsigned short arrayIndex = 0; + + /* Reset DB values */ + pSelfParam->shmMsg.type = tacSHMSG_MONITOR_DATA; + pData = &(pSelfParam->shmMsg.msgBody.monitor.data); + + pData->number = pSelfParam->inputNb; + + /* pData points to the body of the Message */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pData->buffer[arrayIndex] = 0.0; + } + + /* Send message */ + tacShMsgQSendBgInfo(&pSelfParam->shmMsg); + + pSelfParam->shmMsg.type = tacSHMSG_REMOVE_MONITOR; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + + /* Send message */ + tacShMsgQSendBgInfo(&pSelfParam->shmMsg); + + free(pSelfParam->dbPoint); + + /* delete internal message queue. Do this as deferred procedure call + * to make sure it is only called when all messages have been send + * (through the same deferred call mechanism) */ + tacDpcPushRequest((tacVOIDFCTPTR) tacSinkDeleteMessageQueue, &(pSelfParam->msgq)); + + return; +} + +void tacSinkProbeBlockDestructor (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + pSelfParam->shmMsg.type = tacSHMSG_REMOVE_PROBE; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + + /* Send message */ + tacShMsgQSendDataSample(&pSelfParam->shmMsg); + + /* delete internal message queue. Do this as deferred procedure call + * to make sure it is only called when all messages have been send + * (through the same deferred call mechanism) */ + tacDpcPushRequest((tacVOIDFCTPTR) tacSinkDeleteMessageQueue, &(pSelfParam->msgq)); + + return; +} + +/* + * Show Hooks + */ + +void tacSinkDisplayBlockShow (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Print parameter values */ + printf(" Update rate: %d\n",pSelfParam->rate); + + return; +} + +void tacSinkMonitorBlockShow (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Print parameter values */ + printf(" Update rate: %d\n",pSelfParam->rate); + printf(" Number of input signals: %d\n",pSelfParam->inputNb); + printf(" Queued samples: %d\n", msgQNumMsgs(pSelfParam->msgq)); + printf(" Lost samples: %d\n",pSelfParam->lost); + + if (pSelfParam->dbPoint != NULL) + { + printf(" DB Point: %s\n", pSelfParam->dbPoint); + } + + return; +} + +void tacSinkMonitorStateBlockShow (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Print parameter values */ + printf(" Using MonitorState block, not averaging received data\n"); + printf(" Update rate: %d\n",pSelfParam->rate); + printf(" Number of input signals: %d\n",pSelfParam->inputNb); + printf(" Queued samples: %d\n", msgQNumMsgs(pSelfParam->msgq)); + printf(" Lost samples: %d\n",pSelfParam->lost); + + if (pSelfParam->dbPoint != NULL) + { + printf(" DB Point: %s\n", pSelfParam->dbPoint); + } + + return; +} + +void tacSinkProbeBlockShow (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Print parameter values */ + printf(" Update rate: %d\n",pSelfParam->rate); + printf(" Update rate param (sec): %f\n",pSelfParam->rateParam); + printf(" Number of input signals: %d\n",pSelfParam->inputNb); + printf(" Queued samples: %d\n", msgQNumMsgs(pSelfParam->msgq)); + printf(" Lost samples: %d\n",pSelfParam->lost); + + return; +} + +/* + * Installation function + */ + +tacSTDBLOCK_TYPE tacSinkDisplayTypeInfo = { + "Display", + &tacSinkDisplayBlockConstructor, + &tacSinkDisplayBlockGetParameter, + &tacSinkDisplayBlockAlgorithm, + NULL, + NULL, + NULL, + NULL, + &tacSinkDisplayBlockShow, +}; + +tacSTDBLOCK_TYPE tacSinkMonitorTypeInfo = { + "Monitor", + &tacSinkMonitorBlockConstructor, + &tacSinkMonitorBlockGetParameter, + &tacSinkMonitorBlockAlgorithm, + NULL, + NULL, + NULL, + &tacSinkMonitorBlockDestructor, + &tacSinkMonitorBlockShow, +}; + +tacSTDBLOCK_TYPE tacSinkMonitorStateTypeInfo = { + "MonitorState", + &tacSinkMonitorStateBlockConstructor, + &tacSinkMonitorStateBlockGetParameter, + &tacSinkMonitorStateBlockAlgorithm, + NULL, + NULL, + NULL, + &tacSinkMonitorStateBlockDestructor, + &tacSinkMonitorStateBlockShow, +}; + +/* Probe with a maximal sampling rate of 2kHz */ +tacSTDBLOCK_TYPE tacSinkProbeTypeInfo = { + "Probe", + &tacSinkProbeBlockConstructor, + &tacSinkProbeBlockGetParameter, + &tacSinkProbeBlockAlgorithm, + NULL, + &tacSinkProbeBlockReset, + NULL, + &tacSinkProbeBlockDestructor, + &tacSinkProbeBlockShow, +}; + +/* Fast probe is the same as probe but not does have the + * limitation on the max. recording frequency */ +tacSTDBLOCK_TYPE tacSinkFastProbeTypeInfo = { + "FastProbe", + &tacSinkFastProbeBlockConstructor, + &tacSinkProbeBlockGetParameter, + &tacSinkProbeBlockAlgorithm, + NULL, + &tacSinkProbeBlockReset, + NULL, + &tacSinkProbeBlockDestructor, + &tacSinkProbeBlockShow, +}; + +STATUS tacSinkBlockInitAll (void) +{ + /* Install Sink Block Hooks */ + tacStdBlockInstallNewType(&tacSinkDisplayTypeInfo); + tacStdBlockInstallNewType(&tacSinkMonitorTypeInfo); + tacStdBlockInstallNewType(&tacSinkMonitorStateTypeInfo); + tacStdBlockInstallNewType(&tacSinkProbeTypeInfo); + tacStdBlockInstallNewType(&tacSinkFastProbeTypeInfo); + + /* + * Perform other library initialization operations + */ + + return OK; +} + +/* + * Local functions + */ + +/* + * Note: Routines called from within the algorithm must be declared with + * static __inline__ + */ + +STATUS tacSinkCommonBlockConstructor (tacSTDBLOCK* pSelf, + tacERROR* error) +{ + /* Allocate specific arrays (pointers are initialized to NULL by StdBlock) */ + if (tacStdBlockAllocateArrays(pSelf, 0, tacSINK_DEFAULT_INPUT_NUMBER, + tacSINK_DEFAULT_OUTPUT_NUMBER, error) == ERROR) + { + return ERROR; + } + + if (tacStdBlockAllocateArrayBySize(pSelf, tacSTDBLOCK_PARAM_ARRAY, + sizeof(tacSINK_SCOPE_LOCAL_PARAMETER), error) == ERROR) + { + tacStdBlockReleaseArray(pSelf, tacSTDBLOCK_INPUT_ARRAY, error); + tacStdBlockReleaseArray(pSelf, tacSTDBLOCK_OUTPUT_ARRAY, error); + return ERROR; + } + + /* Specify the number of input signals to attach to become resolved */ + tacStdBlockSetInputNumber(pSelf, tacSINK_ONE_INPUT_NUMBER); /* Required */ + + return OK; +} + +STATUS tacSinkSendMonitorMessage(MSG_Q_ID * msgq) +{ + /* Send message using provided function (different for Monitor and Probe blocks) */ + /* Send message using provided function (different for Monitor and Probe blocks) */ + tacSHMSG msg; + + if ( msgQReceive(*msgq, (char*) &msg, sizeof(tacSHMSG), NO_WAIT) == sizeof(tacSHMSG) ) + { + tacShMsgQSendBgInfo (&msg); + } + + return OK; +} + +STATUS tacSinkSendProbeMessage(MSG_Q_ID * msgq) +{ + /* Send message using provided function (different for Monitor and Probe blocks) */ + tacSHMSG msg; + + if ( msgq == NULL ) + { + return ERROR; + } + + if ( msgQReceive(*msgq, (char*) &msg, sizeof(tacSHMSG), NO_WAIT) == sizeof(tacSHMSG) ) + { + tacShMsgQSendDataSample (&msg); + } + return OK; +} + +STATUS tacSinkDeleteMessageQueue (MSG_Q_ID * msgq) +{ + /* Is called when block is destroyed and removes the internal message queue */ + STATUS status; + + status = msgQDelete (*msgq); + *msgq = NULL; + return status; +} + + +/*___oOo___*/ + + + + + + diff --git a/src/arguments.py b/src/arguments.py new file mode 100644 index 0000000..94e4cea --- /dev/null +++ b/src/arguments.py @@ -0,0 +1,26 @@ +import getopt + +def exitUsage(): + print("usage: %s <.tasrc file> -i -o " % sys.argv[0]) + sys.exit(1) + +def readArguments(args): + sourceDirectories = [] + outputFile = "" + try: + options, _ = getopt.getopt(args, "hi:o:") + except getopt.GetoptError: + exitUsage() + for option, arg in options: + if option == "-h": + exitUsage() + elif option == "-o": + outputFile = arg + elif option == "-i": + sourceDirectories.append(arg) + if outputFile == "": + exitUsage() + if len(sourceDirectories) == 0: + print("WARNING: no source directories specified!") + return outputFile, sourceDirectories + diff --git a/src/converter.py b/src/converter.py new file mode 100755 index 0000000..3e44058 --- /dev/null +++ b/src/converter.py @@ -0,0 +1,18 @@ +#!/usr/bin/python3 + +import sys + +import arguments +from tacsrc.tac import readTAC +import grc +import portNaming + +if __name__ == "__main__": + if len(sys.argv) == 1: + params.exitUsage() + inputFile = sys.argv[1] + outputFile, sourceDirectories = arguments.readArguments(sys.argv[2:]) + blocks, connections, blockTypes = readTAC(inputFile) + portNaming.resolvePortNames(blockTypes, sourceDirectories) + grc.write(outputFile, blocks, connections) + diff --git a/src/defaultBlockTypes.py b/src/defaultBlockTypes.py new file mode 100644 index 0000000..a7c7a7a --- /dev/null +++ b/src/defaultBlockTypes.py @@ -0,0 +1,74 @@ +from tacsrc.blockType import BlockType + +class VariablePorts: + def __init__(self, ioDescriptionName, sizeFunction): + self.ioDescriptionName = ioDescriptionName + self.sizeFunction = sizeFunction + + def mapName(self, position, name, index): + return + + def getRealPort(self, originalPort): + return 0 + + def ensureLength(self, length): + return + + def getIODescription(self, block): + return "\\\\n0:%s[%s]" % (self.ioDescriptionName, self.sizeFunction(block)) + + def getRealCount(self): + return 1 + +def inParameters(block): + return block.parameters[1] + +def parameterSize(block): + return len(block.parameters) + +monitor = BlockType("Monitor") +monitor.inputs = VariablePorts("input", inParameters) + +monitorState = BlockType("MonitorState") +monitorState.inputs = VariablePorts("input", inParameters) + +probe = BlockType("Probe") +probe.inputs = VariablePorts("input", inParameters) + +readRfm = BlockType("ReadRfm") +readRfm.outputs = VariablePorts("output", parameterSize) + +rms = BlockType("RMS") +rms.inputs.mapName(0, "input", 0) +rms.outputs.mapName(0, "output", 0) + +constant = BlockType("Constant") +constant.outputs.mapName(0, "CONST", 0) + +manual = BlockType("ManualSwitch") +manual.inputs.mapName(0, "input", 0) +manual.outputs.mapName(0, "output", 0) + +noise = BlockType("NormalNoise") +noise.outputs.mapName(0, "output", 0) + +writeRMNNoTim = BlockType("WriteRmNoTim") +writeRMNNoTim.inputs = VariablePorts("input", parameterSize) + +defaultBlockTypes = { + "Monitor": monitor, + "MonitorState": monitorState, + "Probe": probe, + "ReadRfm": readRfm, + "TIM": BlockType("TIM"), + "WAIT_RFM_INTERRUPT": BlockType("WAIT_RFM_INTERRUPT"), + "RMS": rms, + "Constant": constant, + "ManualSwitch": manual, + "NormalNoise": noise, + "WriteRmNoTim": writeRMNNoTim +} + +def addDefaultBlockTypes(blockTypes): + for key in defaultBlockTypes: + blockTypes[key] = defaultBlockTypes[key] diff --git a/src/grc.py b/src/grc.py new file mode 100644 index 0000000..ed02659 --- /dev/null +++ b/src/grc.py @@ -0,0 +1,94 @@ +GRC_TEMPLATE = ''' +options: + parameters: + title: 'TASRC to GRC converter output' + states: + coordinate: [-100, -100] + +blocks: +%s + +connections: +%s + +metadata: + file_format: 1 +''' + +BLOCK_TEMPLATE = ''' +- name: %s + id: epy_block + parameters: + _source_code: "from gnuradio import gr\\nimport numpy as np\\nclass BLOCK(gr.sync_block):\\n def __init__(self):\\n gr.sync_block.__init__(self,name='%s:%s%s',in_sig=%s,out_sig=%s)\\n def work(self, input_items, output_items):\\n return len(output_items[0])" + states: + coordinate: [%s, %s] +''' + +LINK_TEMPLATE = "- [%s, '%s', %s, '%s']\n" + +def getLongestDependencyRow(blocks, blockDependencies): + currentMax = 0 + for block in blocks: + current = getLongestDependencyRow(blockDependencies[block], blockDependencies) + 1 + if current > currentMax: + currentMax = current + return currentMax + +def getPosition(block, blockDependencies, reverseBlockDependencies, depths): + position = getLongestDependencyRow(blockDependencies[block], blockDependencies) + depths += [0] * (position+1 - len(depths)) + y = depths[position] + depths[position] += 50 # base offset + depths[position] += max( + (3+block.blockType.inputs.getRealCount()+block.blockType.outputs.getRealCount()) * 15, + max(block.blockType.inputs.getRealCount(), block.blockType.outputs.getRealCount()) * 30) + return position * 300, y + +def getBlockDependencies(blocks, links): + blockDependencies = {} + for block in blocks: + blockDependencies[block] = [] + for link in links: + if link.toBlock == block: + blockDependencies[block].append(link.fromBlock) + reverseBlockDependencies = {} + for block in blockDependencies: + for dependency in blockDependencies[block]: + if not dependency in reverseBlockDependencies: + reverseBlockDependencies[dependency] = [] + reverseBlockDependencies[dependency].append(block) + return blockDependencies, reverseBlockDependencies + +def getBlocksContent(blocks, links): + blockDependencies, reverseBlockDependencies = getBlockDependencies(blocks, links) + depths = [] + blocksContent = "" + for block in blocks: + description = block.blockType.getIODescription(block) + inputs = "[%s]" % ", ".join(["np.int8"] * block.blockType.inputs.getRealCount()) + outputs = "[%s]" % ", ".join(["np.int8"] * block.blockType.outputs.getRealCount()) + position = getPosition(block, blockDependencies, reverseBlockDependencies, depths) + blocksContent += BLOCK_TEMPLATE % ( + block.name, + block.name, + block.blockType.name, + description, + inputs, + outputs, + position[0], + position[1]) + return blocksContent + +def getLinksContent(links): + linksContent = "" + for link in links: + fromPort = link.fromBlock.blockType.outputs.getRealPort(link.fromPort) + toPort = link.toBlock.blockType.inputs.getRealPort(link.toPort) + linksContent += LINK_TEMPLATE % (link.fromBlock.name, fromPort, link.toBlock.name, toPort) + return linksContent + +def write(filename, blocks, links): + with open(filename, "w+") as file: + print("writing to file %s" % filename) + file.truncate(0) + file.write(GRC_TEMPLATE % (getBlocksContent(blocks, links), getLinksContent(links))) diff --git a/src/portNaming.py b/src/portNaming.py new file mode 100644 index 0000000..62be549 --- /dev/null +++ b/src/portNaming.py @@ -0,0 +1,104 @@ +import re +import os +import json +from defaultBlockTypes import defaultBlockTypes + +INPUT_FUNCTIONS = [ + "tacStdBlockGetInput", + "tacGraviMatrixGetPointerInput" + ] + +OUTPUT_FUNCTIONS = [ + "tacStdBlockSetOutput", + "tacGraviMatrixSetPointerOutput" + ] + +def getFiles(blockType, sourceDirectories): + files = [] + for sourceDirectory in sourceDirectories: + files += ["%s/%s" % (data[0], file) + for data in os.walk(sourceDirectory) + for file in data[2] if re.match(".*tac%sBlock.c" % blockType.name.replace("Rm", "Rmn"), file) != None] + return files + +def resolvePortNames(blockTypes, sourceDirectories): + missingBlocks = [] + multipleDefinitions = [] + for blockType in blockTypes: + if blockType.name in defaultBlockTypes: + continue + files = getFiles(blockType, sourceDirectories) + if len(files) == 0: + print("WARNING: no source file for block type %s found" % blockType.name) + missingBlocks.append(blockType.name) + continue + if len(files) > 1: + multipleDefinitions.append(blockType.name) + print("WARNING: more than one matching source file for block type %s found, skipping" % blockType.name) + continue + print("reading file %s" % files[0]) + with open(files[0], "r") as file: + content = "\n".join(file.readlines()) + for function in INPUT_FUNCTIONS: + mapInputs(content, function, blockType.inputs) + for function in OUTPUT_FUNCTIONS: + mapOutputs(content, function, blockType.outputs) + for entry in re.findall("\\w+ *= *\\*?\\(?pSelf->input\\[\\d+\\]\\)?", content): + name = re.search("^\\w+", entry).group() + position = int(re.search("(?<=\\[)\\d+(?=\\])", entry).group()) + blockType.inputs.mapName(position, name, 0) + for entry in re.findall("pSelf->output\\[\\d+\\] *= *\\w+", content): + name = re.search("\\w+$", entry).group() + position = int(re.search("(?<=\\[)\\d+(?=\\])", entry).group()) + blockType.outputs.mapName(position, name, 0) + if not os.path.exists("errors.json") or os.stat("errors.json").st_size == 0: + content = {"missing_blocks": [], "multiple_definitions": []} + else: + with open("errors.json", "r") as file: + content = json.load(file) + with open("errors.json", "w+") as file: + for blockTypeName in missingBlocks: + if not blockTypeName in content["missing_blocks"]: + content["missing_blocks"].append(blockTypeName) + for blockTypeName in multipleDefinitions: + if not blockTypeName in content["multiple_definitions"]: + content["multiple_definitions"].append(blockTypeName) + json.dump(content, file, indent=2) + file.close() + +def mapInputs(content, function, ports): + for entry in re.findall("\\w+ *= *%s\\(pSelf *, *\\d+\\);" % function, content): + name = re.search("^\\w+", entry).group() + position = int(re.search("\\d+(?= *\\) *;)", entry).group()) + ports.mapName(position, name, 0) + for entry in re.findall("\\w+->\\w+\\[\\d+\\] *= *%s\\(pSelf *, *\\d+\\);" % function, content): + name = re.search("(?<=\\->)\\w+", entry).group() + position = int(re.search("\\d+(?= *\\) *;)", entry).group()) + index = int(re.search("(?<=\\[)\\d+(?=\\])", entry).group()) + ports.mapName(position, name, index) + for entry in re.findall("\\w+\\[\\d+\\] *= *%s\\(pSelf *, *\\d+\\);" % function, content): + name = re.search("^\\w+", entry).group() + position = int(re.search("\\d+(?= *\\) *;)", entry).group()) + index = int(re.search("(?<=\\[)\\d+(?=\\])", entry).group()) + ports.mapName(position, name, index) + +def mapOutputs(content, function, ports): + for entry in re.findall("%s\\(pSelf *, *\\d+ *, *pSelfParam->\\w+\\);" % function, content): + name = re.search("\\w+(?=\\);$)", entry).group() + position = int(re.search("\\d+(?= *, *pSelfParam->\\w+\\);$)", entry).group()) + ports.mapName(position, name, 0) + for entry in re.findall("%s\\(pSelf *, *\\d+ *, *\\w+\\[\\d+\\]\\);" % function, content): + name = re.search("\\w+(?=\\[\\d+\\]\\);$)", entry).group() + position = int(re.search("\\d+(?= *, *\\w+\\[\\d+\\]\\);$)", entry).group()) + index = int(re.search("(?<=\\[)\\d+(?=\\])", entry).group()) + ports.mapName(position, name, index) + for entry in re.findall("%s\\(pSelf *, *\\d+ *, *pSelfParam->\\w+\\[\\d+\\]\\);" % function, content): + name = re.search("(?<=\\->)\\w+", entry).group() + position = int(re.search("\\d+(?= *, *pSelfParam->\\w+\\[\\d+\\]\\);$)", entry).group()) + index = int(re.search("(?<=\\[)\\d+(?=\\]\\);$)", entry).group()) + ports.mapName(position, name, index) + for entry in re.findall("%s\\(pSelf *, *\\d+ *, *\\w+\\);" % function, content): + name = re.search("\\w+(?= *\\);$)", entry).group() + position = int(re.search("\\d+(?= *, *\\w+\\);$)", entry).group()) + index = 0 + ports.mapName(position, name, index) diff --git a/src/tacsrc/block.py b/src/tacsrc/block.py new file mode 100644 index 0000000..737d9f1 --- /dev/null +++ b/src/tacsrc/block.py @@ -0,0 +1,6 @@ +class Block: + def __init__(self): + self.name = "" + self.blockType = None + self.parameters = [] + diff --git a/src/tacsrc/blockType.py b/src/tacsrc/blockType.py new file mode 100644 index 0000000..8930836 --- /dev/null +++ b/src/tacsrc/blockType.py @@ -0,0 +1,19 @@ +from tacsrc.ports import Ports + +class BlockType: + def __init__(self, name): + self.name = name + self.inputs = Ports() + self.outputs = Ports() + + def getIODescription(self, block): + result = "" + inputDescription = self.inputs.getIODescription(block) + if len(inputDescription) != 0: + result += "\\\\nINPUTS:" + result += inputDescription + outputDescription = self.outputs.getIODescription(block) + if len(outputDescription) != 0: + result += "\\\\nOUTPUTS:" + result += outputDescription + return result diff --git a/src/tacsrc/link.py b/src/tacsrc/link.py new file mode 100644 index 0000000..d89b459 --- /dev/null +++ b/src/tacsrc/link.py @@ -0,0 +1,6 @@ +class Link: + def __init__(self): + self.fromBlock = None + self.fromPort = 0 + self.toBlock = None + self.toPort = 0 diff --git a/src/tacsrc/ports.py b/src/tacsrc/ports.py new file mode 100644 index 0000000..4b26f22 --- /dev/null +++ b/src/tacsrc/ports.py @@ -0,0 +1,47 @@ +class Ports: + def __init__(self): + self.labels = [] + self.labelSizes = {} + + def mapName(self, position, name, index): + self.labels += [0] * (position+1 - len(self.labels)) + self.labels[position] = name + if not name in self.labelSizes: + self.labelSizes[name] = 0 + self.labelSizes[name] = max(self.labelSizes[name], index+1) + + def getRealPort(self, originalPort): + labelsDone = [] + for i in range(min(len(self.labels),originalPort)): + label = self.labels[i] + if label != 0 and label in labelsDone: + continue + labelsDone.append(label) + return len(labelsDone) - 1 + + def getIODescription(self, block): + result = "" + labelsDone = [] + for i in range(len(self.labels)): + label = self.labels[i] + if label != 0 and label in labelsDone: + continue + labelsDone.append(label) + if label == 0: + result += "\\\\n%s: unknown" % i + elif self.labelSizes[label] == 1: + result += "\\\\n%s: %s" % (i, label) + else: + result += "\\\\n%s: %s[%s]" % (i, label, self.labelSizes[label]) + return result + + def ensureLength(self, count): + self.labels += [0] * (count - len(self.labels)) + + def getRealCount(self): + labelsDone = [] + for label in self.labels: + if label != 0 and label in labelsDone: + continue + labelsDone.append(label) + return len(labelsDone) diff --git a/src/tacsrc/tac.py b/src/tacsrc/tac.py new file mode 100644 index 0000000..1428e4b --- /dev/null +++ b/src/tacsrc/tac.py @@ -0,0 +1,98 @@ +from defaultBlockTypes import addDefaultBlockTypes +from tacsrc.block import Block +from tacsrc.blockType import BlockType +from tacsrc.link import Link + +import re + +def addBlockType(blockTypes, blockType): + if not BlockType in blockTypes: + blockTypes[blockTypes] = BlockType(blockType) + +def setBlockType(blockIndex, blockTypeName, blocks, blockTypes): + if not blockTypeName in blockTypes: + blockTypes[blockTypeName] = BlockType(blockTypeName) + blocks += [0] * (blockIndex - len(blocks) + 1) + if blocks[blockIndex] == 0: + blocks[blockIndex] = Block() + blocks[blockIndex].blockType = blockTypes[blockTypeName] + +def setBlockName(blockIndex, blockName, blocks): + blocks += [0] * (blockIndex - len(blocks) + 1) + if blocks[blockIndex] == 0: + blocks[blockIndex] = Block() + blocks[blockIndex].name = blockName + +def setBlockParameters(blockIndex, blockParameters, blocks): + blocks += [0] * (blockIndex - len(blocks) + 1) + if blocks[blockIndex] == 0: + blocks[blockIndex] = Block() + blocks[blockIndex].parameters = blockParameters.split(',') + +def ensureLinks(linkIndex, links): + links += [None] * (linkIndex + 1 - len(links)) + if links[linkIndex] == None: + links[linkIndex] = Link() + +def setLinkSourceBlock(linkIndex, sourceBlock, links): + ensureLinks(linkIndex, links) + links[linkIndex].fromBlock = sourceBlock + +def setLinkSourcePort(linkIndex, sourcePort, links): + ensureLinks(linkIndex, links) + links[linkIndex].fromPort = sourcePort + +def setLinkDestinationBlock(linkIndex, destinationBlock, links): + ensureLinks(linkIndex, links) + links[linkIndex].toBlock = destinationBlock + +def setLinkDestinationPort(linkIndex, destinationPort, links): + ensureLinks(linkIndex, links) + links[linkIndex].toPort = destinationPort + +def readTAC(filename): + blockTypes = {} + addDefaultBlockTypes(blockTypes) + blocks = [] + links = [] + # make sure all blocks have been declared before the links are read + linkLines = [] + print("reading file %s" % filename) + with open(filename, "r") as file: + content = file.readlines() + for line in content: + if len(line) == 0: + continue + if re.match("TAC\\.LINK.*", line): + linkLines.append(line) + if not re.match("TAC\\.BLOCK.*", line): + continue + blockIndex = int(re.search("(?<=TAC\\.BLOCK)\\d+", line).group()) + if re.match("TAC\\.BLOCK\\d+\\.TYPE \\w+", line): + setBlockType(blockIndex, re.search("\\w+$", line).group(), blocks, blockTypes) + elif re.match("TAC\\.BLOCK\\d+\\.NAME \\w+", line): + setBlockName(blockIndex, re.search("\\w+$", line).group(), blocks) + elif re.match("TAC\\.BLOCK\\d+\\.PARAM .+", line): + setBlockParameters(blockIndex, re.search("(?<=\\.PARAM ).*$", line).group(), blocks) + blocksByName = {} + for block in blocks: + blocksByName[block.name] = block + for line in linkLines: + linkIndex = int(re.search("(?<=TAC\\.LINK)\\d+", line).group()) + if re.match("TAC\\.LINK\\d+\\.SOURCE\\.NAME \\w+", line): + sourceBlockName = re.search("\\w+$", line).group() + sourceBlock = blocksByName[sourceBlockName] + setLinkSourceBlock(linkIndex, sourceBlock, links) + elif re.match("TAC\\.LINK\\d+\\.SOURCE\\.PORT \\d+", line): + sourcePort = int(re.search("\\d+$", line).group()) + setLinkSourcePort(linkIndex, sourcePort, links) + elif re.match("TAC\\.LINK\\d+\\.DEST\\.NAME \\w+", line): + destinationBlock = blocksByName[re.search("\\w+$", line).group()] + setLinkDestinationBlock(linkIndex, destinationBlock, links) + elif re.match("TAC\\.LINK\\d+\\.DEST\\.PORT \\d+", line): + destinationPort = int(re.search("\\d+$", line).group()) + setLinkDestinationPort(linkIndex, destinationPort, links) + for link in links: + link.fromBlock.blockType.outputs.ensureLength(link.fromPort) + link.toBlock.blockType.inputs.ensureLength(link.toPort) + return blocks, links, blockTypes.values() diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3624768 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +__pycache__ +out +tacapp.tar.gz +Sources +tacapp +worryingFiles +cc.tar.gz diff --git a/errors.json b/errors.json new file mode 100644 index 0000000..5ec898a --- /dev/null +++ b/errors.json @@ -0,0 +1,4 @@ +{ + "missing_blocks": [], + "multiple_definitions": [] +} \ No newline at end of file diff --git a/hardcodedFiles/tacReadRmnBlock.c b/hardcodedFiles/tacReadRmnBlock.c new file mode 100644 index 0000000..8acbcfa --- /dev/null +++ b/hardcodedFiles/tacReadRmnBlock.c @@ -0,0 +1,568 @@ +/******************************************************************************* +* E.S.O. - VLT project +* +* "@(#) $Id: tacReadRmnBlock.c 305476 2018-01-19 08:56:18Z rfrahm $" +* +* who when what +* ------- -------- ---------------------------------------------- +* gzins 2010-07-27 ported to VLTSW2010 and VxWorks 6.4 +* swehner 2008-10-10 creation +*/ + +/************************************************************************ +* NAME +* tacReadRmnBlock - Implemements the standard functions for the +* tacReadRmn block and tacReadRfm block. +* tacReadRmnBlock - Reads from 1rst generation reflective memory network +* tacReadRfmBlock - Reads from 2nd generation reflective memory network + +* Parameters: +* field - token names for the RMN fields to read (up to 10) +* Inputs: 0 +* Outputs: 1 +* output - 1..10 depending on number of field parameters +* +* +* +* FILES +* +* ENVIRONMENT +* TAC +* +* RETURN VALUES +* +* CAUTIONS +* +* EXAMPLES +* TAC.BLOCK9.TYPE ReadRmn +* TAC.BLOCK9.NAME ReadRmn +* +* SEE ALSO +* +* BUGS +* +*------------------------------------------------------------------------ +*/ + +#define _POSIX_SOURCE 1 +#include "vltPort.h" + +ATTRIBUTE_UNUSED static const char *rcsId="@(#) $Id: tacReadRmnBlock.c 305476 2018-01-19 08:56:18Z rfrahm $"; + +/* + * System Headers + */ + +#include /* taskSpawn, taskDelay, ... */ +#include /* printf ... */ +#include /* malloc ... */ +#include /* malloc ... */ +#include +#include + +/* + * Local Headers + */ + +#include "tacStdBlock.h" +#include "tacRmnBlock.h" +#include "rmassPublic.h" +#include "rmassPrivate.h" + +/* + * Compilation directives + */ + +/* + * Constants + */ + +#define tacREAD_RMN_EXPECTED_PARAM 1 +#define tacREAD_RMN_DEFAULT_INPUT_NUMBER 0 +#define tacREAD_RMN_DEFAULT_OUTPUT_NUMBER tacMAX_DATA_NUMBER + +#define tacREAD_RMN_FIELD_STRING_LEN 256 +#define tacSTRLEN sizeof(double) + +/* + * Types + */ + +/* + * Local function declaration + */ + +/* + * Global variables + */ + +/* + * Function definition + */ + + +STATUS tacReadRmnBlockCheckParameter (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the ADDBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = NULL; + + pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + /* field string is built from block params */ + if ( tacRmnBlockCheckParameter ( pSelf, parameter, 0, error) != OK ) + { + return ERROR; + } + + /* useful information on the screen */ + printf ("ReadRmn %s: [%s]\n", pSelf->name, pSelfParam->fieldString); + + return OK; +} + +STATUS tacReadRfmBlockCheckParameter (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the ADDBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = NULL; + + pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + /* field string is built from block params */ + if ( tacRmnBlockCheckParameter ( pSelf, parameter, 0, error) != OK ) + { + return ERROR; + } + + /* useful information on the screen */ + printf ("ReadRfm %s: [%s]\n", pSelf->name, pSelfParam->fieldString); + + return OK; +} + +/* + * Constructor Hooks - Called when a block of this type is instanciated (CONFIG or ADDBLCK commands) + */ + +STATUS tacReadRmBlockConstructor (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the ADDBLCK command */ + vltLOGICAL isRmn, + tacERROR* error) /* Error structure - not a stack */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = NULL; + + /* Check that the expected number of parameters has been received */ + if (parameter->number < tacREAD_RMN_EXPECTED_PARAM) + { + char errorParam[40]; + + sprintf(errorParam, "Expected at least %d, received %d", tacREAD_RMN_EXPECTED_PARAM, parameter->number); + tacRTC_ERR(tacERR_PARAM_NUMBER, errorParam); + return ERROR; + } + + /* Allocate and initialize block-specific arrays */ + if (tacStdBlockAllocateArrays(pSelf, 0, tacREAD_RMN_DEFAULT_INPUT_NUMBER, tacREAD_RMN_DEFAULT_OUTPUT_NUMBER, error) == ERROR) + { + return ERROR; + } + + if (tacStdBlockAllocateArrayBySize(pSelf, tacSTDBLOCK_PARAM_ARRAY, sizeof(tacRMN_LOCAL_PARAMETER), error) == ERROR) + { + tacStdBlockReleaseArray(pSelf, tacSTDBLOCK_INPUT_ARRAY, error); + tacStdBlockReleaseArray(pSelf, tacSTDBLOCK_OUTPUT_ARRAY, error); + return ERROR; + } + + if ( isRmn ) + { + if ( tacReadRmnBlockCheckParameter (pSelf, parameter, error) == ERROR) + { + return ERROR; + } + } + else + { + if ( tacReadRfmBlockCheckParameter (pSelf, parameter, error) == ERROR) + { + return ERROR; + } + } + + pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + pSelfParam->handleValid = rmassACCESS_BLOCKED; + + /* Attach to RMN */ + if ( rmassReadAttach (&pSelfParam->handle, + pSelfParam->fieldString, + &pSelfParam->val[0], + &pSelfParam->val[1], + &pSelfParam->val[2], + &pSelfParam->val[3], + &pSelfParam->val[4], + &pSelfParam->val[5], + &pSelfParam->val[6], + &pSelfParam->val[7], + &pSelfParam->val[8], + &pSelfParam->val[9]) != SUCCESS ) + { + char errorParam[40]; + + sprintf(errorParam, "Attach to RMN failed."); + tacRTC_ERR(tacERR_INTERNAL, errorParam); + return ERROR; + } + + pSelfParam->handleValid = rmassACCESS_FREE; + + return OK; +} + +STATUS tacReadRmnBlockConstructor (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the ADDBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + if ( tacReadRmBlockConstructor (pSelf, parameter, ccsTRUE, error ) == ERROR ) + { + return ERROR; + } + return OK; +} + +STATUS tacReadRfmBlockConstructor (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the ADDBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + if ( tacReadRmBlockConstructor (pSelf, parameter, ccsFALSE, error ) == ERROR ) + { + return ERROR; + } + return OK; +} + + + +/* + * Destructor Hooks - Called when the block is removed from the algorithm (DELBLCK or new CONFIG commands) + */ + +void tacReadRmnBlockDestructor (tacSTDBLOCK* pSelf) /* Reference to the block instance */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = NULL; + pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + pSelfParam->handleValid = rmassACCESS_BLOCKED; + /* wait until semaphore is acknowledged by realtime algo + * or just procede if realtime is not active */ + while ((*pSelf->shared).active && pSelfParam->handleValid != rmassACCESS_BLOCK_ACKN) + { + taskDelay(1); + } + + rmassDetach (&pSelfParam->handle); + + return; +} + +/* + * Change parameters Hooks - Called when modifying the block parameters (MODBLCK command) + */ + +STATUS tacReadRmnBlockSetParameter (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the MODBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + if ( tacReadRmnBlockCheckParameter (pSelf, parameter, error) == ERROR) + { + return ERROR; + } + + pSelfParam->handleValid = rmassACCESS_BLOCKED; + /* wait until semaphore is acknowledged by realtime algo + * or just procede if realtime is not active */ + while ((*pSelf->shared).active && pSelfParam->handleValid != rmassACCESS_BLOCK_ACKN) + { + taskDelay(1); + } + + /* detach RMN handle */ + if ( rmassDetach (&pSelfParam->handle) != SUCCESS ) + { + char errorParam[40]; + + sprintf(errorParam, "rmassDetach returned error."); + tacRTC_ERR(tacERR_INTERNAL, errorParam); + return ERROR; + } + + if ( rmassReadAttach (&pSelfParam->handle, + pSelfParam->fieldString, + &pSelfParam->val[0], + &pSelfParam->val[1], + &pSelfParam->val[2], + &pSelfParam->val[3], + &pSelfParam->val[4], + &pSelfParam->val[5], + &pSelfParam->val[6], + &pSelfParam->val[7], + &pSelfParam->val[8], + &pSelfParam->val[9]) != SUCCESS ) + { + char errorParam[40]; + + sprintf(errorParam, "Attach to RMN failed."); + tacRTC_ERR(tacERR_INTERNAL, errorParam); + return ERROR; + } + + pSelfParam->handleValid = rmassACCESS_FREE; + + return OK; +} + +STATUS tacReadRfmBlockSetParameter (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the MODBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + if ( tacReadRfmBlockCheckParameter (pSelf, parameter, error) == ERROR) + { + return ERROR; + } + + pSelfParam->handleValid = rmassACCESS_BLOCKED; + /* wait until semaphore is acknowledged by realtime algo + * or just procede if realtime is not active */ + while ((*pSelf->shared).active && pSelfParam->handleValid != rmassACCESS_BLOCK_ACKN) + { + taskDelay(1); + } + + /* detach RMN handle */ + if ( rmassDetach (&pSelfParam->handle) != SUCCESS ) + { + char errorParam[40]; + + sprintf(errorParam, "rmassDetach returned error."); + tacRTC_ERR(tacERR_INTERNAL, errorParam); + return ERROR; + } + + if ( rmassReadAttach (&pSelfParam->handle, + pSelfParam->fieldString, + &pSelfParam->val[0], + &pSelfParam->val[1], + &pSelfParam->val[2], + &pSelfParam->val[3], + &pSelfParam->val[4], + &pSelfParam->val[5], + &pSelfParam->val[6], + &pSelfParam->val[7], + &pSelfParam->val[8], + &pSelfParam->val[9]) != SUCCESS ) + { + char errorParam[40]; + + sprintf(errorParam, "Attach to RFM failed."); + tacRTC_ERR(tacERR_INTERNAL, errorParam); + return ERROR; + } + + pSelfParam->handleValid = rmassACCESS_FREE; + + return OK; +} + +/* + * Algorithm Hooks - Called at each time the TAC algorithm is evaluated (ONLINE state) + */ + +void tacReadRmnBlockAlgorithm (tacSTDBLOCK* pSelf) /* Reference to the block instance */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + int i; + + if ( pSelfParam->handleValid == rmassACCESS_BLOCKED ) + { + pSelfParam->handleValid = rmassACCESS_BLOCK_ACKN; + } + + if ( pSelfParam->handleValid == rmassACCESS_FREE ) + { + /* actual RMN read operation */ + rmassReadAccessRmn (&pSelfParam->handle); + + /* Write to outputs */ + for (i=0; i < pSelfParam->numFields; i++) + { + switch (pSelfParam->type[i]) + { + case rmassTIMESEC: + case rmassUINT32: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).ui); + break; + case rmassTIMEUSEC: + case rmassINT32: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).i); + break; + case rmassFLOAT: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).f); + break; + default: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).d); + break; + } + } + + /* provide zero values at unsatisfied outputs + * I consider this a good thing to do since the block + * is always configured */ + for (i=pSelfParam->numFields; i < tacREAD_RMN_DEFAULT_OUTPUT_NUMBER; i++) + { + tacStdBlockSetOutput(pSelf, i, 0.0); + } + } +} + +void tacReadRfmBlockAlgorithm (tacSTDBLOCK* pSelf) /* Reference to the block instance */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + int i; + + if ( pSelfParam->handleValid == rmassACCESS_BLOCKED ) + { + pSelfParam->handleValid = rmassACCESS_BLOCK_ACKN; + } + + if ( pSelfParam->handleValid == rmassACCESS_FREE ) + { + /* actual RMN read operation */ + rmassReadAccessRfm (&pSelfParam->handle); + + /* Write to outputs */ + for (i=0; i < pSelfParam->numFields; i++) + { + switch (pSelfParam->type[i]) + { + case rmassTIMESEC: + case rmassUINT32: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).ui); + break; + case rmassTIMEUSEC: + case rmassINT32: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).i); + break; + case rmassFLOAT: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).f); + break; + default: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).d); + break; + } + } + + /* provide zero values at unsatisfied outputs + * I consider this a good thing to do since the block + * is always configured */ + for (i=pSelfParam->numFields; i < tacREAD_RMN_DEFAULT_OUTPUT_NUMBER; i++) + { + tacStdBlockSetOutput(pSelf, i, 0.0); + } + } +} + +/* + * Show Hooks - Called when the tacRtcTaskShow routine is executed + */ + +void tacReadRmnBlockShow (tacSTDBLOCK* pSelf) /* Reference to the block instance */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + /* Print parameter values */ + printf(" Attached: %s\n", pSelfParam->fieldString); + + return; +} + + +/***************************************************/ +/* The following code is common to all block types */ +/* Do not modify without any good reasons */ +/***************************************************/ + +/* + * Installation function + */ + +tacSTDBLOCK_TYPE tacReadRmnTypeInfo = { + "ReadRmn", + &tacReadRmnBlockConstructor, + &tacRmBlockGetParameter, + &tacReadRmnBlockAlgorithm, + &tacReadRmnBlockSetParameter, + NULL, + NULL, + &tacReadRmnBlockDestructor, + &tacReadRmnBlockShow +}; + +tacSTDBLOCK_TYPE tacReadRfmTypeInfo = { + "ReadRfm", + &tacReadRfmBlockConstructor, + &tacRmBlockGetParameter, + &tacReadRfmBlockAlgorithm, + &tacReadRmnBlockSetParameter, + NULL, + NULL, + &tacReadRmnBlockDestructor, + &tacReadRmnBlockShow +}; + +STATUS tacReadRmnBlockInitAll (void) +{ + /***************************************************/ + /* The following code is common to all block types */ + /* Do not modify without any good reasons */ + /***************************************************/ + + /* Install ReadRmn1g Block Hooks */ + tacStdBlockInstallNewType(&tacReadRmnTypeInfo); + + /*****************************/ + /* End of common code region */ + /*****************************/ + + /* Perform other library initialization operations */ + + return OK; +} + +STATUS tacReadRfmBlockInitAll (void) +{ + /***************************************************/ + /* The following code is common to all block types */ + /* Do not modify without any good reasons */ + /***************************************************/ + + /* Install ReadRmn1g Block Hooks */ + tacStdBlockInstallNewType(&tacReadRfmTypeInfo); + + /*****************************/ + /* End of common code region */ + /*****************************/ + + /* Perform other library initialization operations */ + + return OK; +} + +/*___oOo___*/ + + + diff --git a/hardcodedFiles/tacSinkBlock.c b/hardcodedFiles/tacSinkBlock.c new file mode 100644 index 0000000..df39833 --- /dev/null +++ b/hardcodedFiles/tacSinkBlock.c @@ -0,0 +1,1256 @@ +/******************************************************************************* +* E.S.O. - VLT project +* +* "@(#) $Id: tacSinkBlock.c 339094 2021-02-10 03:10:02Z jgil $" +* +* who when what +* ------- -------- ---------------------------------------------- +* rdembet 06/08/20 New MonitorState block with no data averaging +* swehner 28/11/09 SPR20090234 Correction in rate adjustment in reset hook +* swehner 27/11/09 Fixed message queue handling +* swehner 10/10/09 New block FastProbe for unlimited rec frequency +* swehner 22/09/09 PPRS 32341 Replaced specialized tacSINK_SHMSG stack +* with standard vxWorks message queue. +* bbauvir 21/09/04 VLTSW20040113 - One sample might be lost +* bbauvir 29/03/04 Monitor block averages over the reporting period +* bbauvir 29/12/02 Probe to the SampTask +* bbauvir 26/12/02 MsgQ access through DPC mechanism +* bbauvir 14/07/02 New MsgQ of TAC version 1.22 +* bbauvir 21/03/01 Created +*/ + +/************************************************************************ +* NAME +* tacSinkBlock - Standard data monitoring blocks +* +* SYNOPSIS +* lcubootAutoCdBoot 1,"tacsink.boot" +* < tacsink.boot +* +* DESCRIPTION +* Block type: Display +* Parameters: +* Inputs: 1 +* Outputs: none +* +* This function block samples the value of its input signal at the +* specified and issues a message containing the time +* and the value of the input on the vxWorks terminal. +* It does not allow modification of the parameter at runtime. +* +* Block type: Monitor +* Parameters: +* +* Inputs: 10max +* Outputs: none +* +* This function block samples the value of its input signals at the +* specified (0.0 to send a message at the system sampling +* period) and issues a message containing the time and the value of +* the inputs on the shared memory. This message is intercepted by the +* background task running on the master CPU. The monitored values are +* written into the online database. The number of inputs of the block +* is specified by parameter. +* This block does not allow modification of the parameters at runtime. +* +* Block type: MonitorState +* Parameters: +* +* Inputs: 10max +* Outputs: none +* +* Same as Monitor block but without the averaging of received data, +* see VLTSW-14260 JIRA ticket. +* +* Block type: Probe +* Parameters: +* +* Inputs: 10max +* Outputs: none +* +* Block type: FastProbe +* Parameters: +* +* Inputs: 10max +* Outputs: none +* +* This function block samples the value of its input signals at the +* specified (0.0 to send a message at the system sampling +* period) and issues a message containing the time and the value of +* the inputs on the shared memory. This message is intercepted by the +* background task running on the master CPU. The number of inputs of +* the block is specified by parameter. +* This message is passed to an external application callback if +* provided. +* This block does not allow modification of the parameters at runtime. +* The normal Probe block has a limited sampling frequency of not more +* than 2kHz. The reason is in particular the bottleneck between master +* and slave CPU which all samples have to pass through a mechanism of +* VME bus shared memory. On one-CPU-systems this limitation does not +* apply so you are free to choose faster sampling. You may of course +* hit other limitations (processor speed, network traffic etc.) +* +* FILES +* +* ENVIRONMENT +* TAC +* +* RETURN VALUES +* +* CAUTIONS +* All these blocks compute an decimation value to use to trigger the +* sampling of the input signals, from the system sampling period. +* They should be created after any synchronization block. +* +* In order to cope with system performances, a minimum +* is defined for each block. The minimum applied periods are 0.1 (10Hz), +* 0.01 (100Hz) and 0.5e-3 (2kHz) for the 'Display', 'Monitor' and +* 'Probe' blocks respectively. +* +* EXAMPLES +* # 5 signals @ 2Hz (monitored in the database) +* TAC.BLOCK9.TYPE Monitor +* TAC.BLOCK9.NAME Monitor +* TAC.BLOCK9.PARAM 0.5, 5 +* +* # 5 signals @ the RT algorithm sampling period (0.0) +* TAC.BLOCK10.TYPE Probe +* TAC.BLOCK10.NAME Probe +* TAC.BLOCK10.PARAM 0.0, 5 +* +* SEE ALSO +* tacServerInstallDataCallback, tacServerRemoveDataCallback +* +* BUGS +* +*------------------------------------------------------------------------ +*/ + +#define _POSIX_SOURCE 1 +#include "vltPort.h" + + +/* + * System Headers + */ + +#include +#include +#include /* logMsg ... */ +#include /* printf ... */ +#include /* malloc ... */ +#include /* memcpy ... */ +#include + +/* + * Local Headers + */ + +#include "tacStdBlock.h" +#include "tacShMsgQ.h" + +/* + * Compilation directives + */ + +/* + * Constants + */ + +#define tacSINK_DEFAULT_EXPECTED_PARAM 2 + +#define tacSINK_DEFAULT_INPUT_NUMBER tacMAX_DATA_NUMBER /* Up to 10 input channels */ +#define tacSINK_DEFAULT_OUTPUT_NUMBER tacMAX_DATA_NUMBER + +#define tacSINK_ONE_EXPECTED_PARAM 1 +#define tacSINK_ONE_INPUT_NUMBER 1 + +#define tacSINK_DISPLAY_MIN_SAMPLING_PERIOD .1 /* 10Hz */ +#define tacSINK_MONITOR_MIN_SAMPLING_PERIOD .01 /* 100Hz */ +#define tacSINK_PROBE_MIN_SAMPLING_PERIOD .5e-3 /* 2kHz */ + +#define tacSINK_DISPLAY_LOG_STRING_SIZE 128 + +#define tacSINK_MONITOR_DEFAULT_DB_POINT "tac:data:monitor" +#define tacSINK_MONITOR_MAX_DB_ADDR_SIZE 64 + +#define tacSINK_MONITOR_QUEUE_SIZE 6 +#define tacSINK_PROBE_QUEUE_SIZE 6 + + +typedef enum { + tacSINK_SAMPLING_PERIOD = 0, + tacSINK_INPUT_NUMBER, + tacSINK_MONITOR_DB_POINT, +}tacSINK_SCOPE_PARAM_INDEX; + +/* + * Types + */ + +typedef struct { + unsigned short rate; + unsigned short counter; + unsigned short inputNb; + unsigned int lost; + double rateParam; + char* dbPoint; + MSG_Q_ID msgq; + tacSHMSG shmMsg; +}tacSINK_SCOPE_LOCAL_PARAMETER; + +/* + * Function declaration + */ + +extern STATUS tacDpcPushRequest(tacVOIDFCTPTR pFunct, void* parameter); + +/* + * Local function declaration + */ + +/* + * Note: Routines called from within the algorithm must be declared with + * static __inline__ + */ + +STATUS tacSinkSendMonitorMessage(MSG_Q_ID * msgqvoid); +STATUS tacSinkSendMonitorStateMessage(MSG_Q_ID * msgqvoid); +STATUS tacSinkSendProbeMessage(MSG_Q_ID * msgq); +STATUS tacSinkDeleteMessageQueue(MSG_Q_ID * msgq); +STATUS tacSinkCommonBlockConstructor(tacSTDBLOCK* pSelf, tacERROR* error); + +/* + * Global variables + */ + +char logStr[tacSINK_DISPLAY_LOG_STRING_SIZE]; /* Logging string used for Display */ + + +/* + * Function definition + */ + +/* + * Constructor Hooks + */ + +STATUS tacSinkDisplayBlockConstructor (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = NULL; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = NULL; + + /* Check that the expected number of parameters has been received */ + if (parameter->number < tacSINK_ONE_EXPECTED_PARAM) + { + char errorParam[40]; + + sprintf(errorParam, "Expected %d, received %d", tacSINK_ONE_EXPECTED_PARAM, parameter->number); + tacRTC_ERR(tacERR_PARAM_NUMBER, errorParam); + return ERROR; + } + + /* Check that the parameters are valid */ + pRealParam = (double*) parameter->buffer; + + /* Passed parameter is the sampling period of the block */ + if (pRealParam[tacSINK_SAMPLING_PERIOD] < (*pSelf->shared).samplingPeriod) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = (*pSelf->shared).samplingPeriod; + } + + if (pRealParam[tacSINK_SAMPLING_PERIOD] < tacSINK_DISPLAY_MIN_SAMPLING_PERIOD) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = tacSINK_DISPLAY_MIN_SAMPLING_PERIOD; + } + + /* Call common constructor */ + if (tacSinkCommonBlockConstructor(pSelf, error) != OK) + { + return ERROR; + } + + /* Store parameters */ + pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; /* We will only store short integers */ + + /* + * Compute the rate at which data has to be processed - divide and take + * the integer part of the result + */ + + pSelfParam->rate = (unsigned short) (pRealParam[tacSINK_SAMPLING_PERIOD] / (*pSelf->shared).samplingPeriod); + pSelfParam->counter = 0; /* Decimation counter */ + + /* + * Perform other block initialization operations + */ + + return OK; +} + +STATUS tacSinkMonitorBlockConstructor (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = NULL; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = NULL; + unsigned short arrayIndex = 0; + + /* Check that the expected number of parameters has been received */ + if (parameter->number < tacSINK_DEFAULT_EXPECTED_PARAM) + { + char errorParam[40]; + + sprintf(errorParam, "Expected %d, received %d", tacSINK_DEFAULT_EXPECTED_PARAM, parameter->number); + tacRTC_ERR(tacERR_PARAM_NUMBER, errorParam); + return ERROR; + } + + /* Check that the parameters are valid */ + pRealParam = (double*) parameter->buffer; + + /* Passed parameter is the sampling period of the block */ + if (pRealParam[tacSINK_SAMPLING_PERIOD] < (*pSelf->shared).samplingPeriod) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = (*pSelf->shared).samplingPeriod; + } + + if (pRealParam[tacSINK_SAMPLING_PERIOD] < tacSINK_MONITOR_MIN_SAMPLING_PERIOD) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = tacSINK_MONITOR_MIN_SAMPLING_PERIOD; + } + + /* Number of inputs is minimum 1 up to tacMSG_MAX_DATA_NUMBER */ + if ((pRealParam[tacSINK_INPUT_NUMBER] < 1) || + (pRealParam[tacSINK_INPUT_NUMBER] > tacMAX_DATA_NUMBER)) + { + tacRTC_ERR(tacERR_PARAM_INVALID, ""); + return ERROR; + } + + /* Call common constructor */ + if (tacSinkCommonBlockConstructor(pSelf, error) != OK) + { + return ERROR; + } + + /* Store parameters */ + pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* + * Compute the rate at which data has to be processed - divide and take + * the integer part of the result + */ + + pSelfParam->rate = (unsigned short) (pRealParam[tacSINK_SAMPLING_PERIOD] / (*pSelf->shared).samplingPeriod); + pSelfParam->counter = 0; /* Decimation counter */ + pSelfParam->inputNb = (unsigned short) pRealParam[tacSINK_INPUT_NUMBER]; + + /* Optional parameter is an application-specific DB point */ + if (parameter->number == tacSINK_DEFAULT_EXPECTED_PARAM + 1) + { + printf("tacSinkMonitorBlockConstructor - DB point %s\n",(char*) &(pRealParam[tacSINK_MONITOR_DB_POINT])); + pSelfParam->dbPoint = (char*) malloc(tacSINK_MONITOR_MAX_DB_ADDR_SIZE); + strcpy(pSelfParam->dbPoint, (char*) &(pRealParam[tacSINK_MONITOR_DB_POINT])); + } + else + { + printf("tacSinkMonitorBlockConstructor - Default DB point\n"); + pSelfParam->dbPoint = NULL; + } + + /* Specify the number of input signals to attach to become resolved */ + tacStdBlockSetInputNumber(pSelf, pSelfParam->inputNb); + + /* + * Perform other block initialization operations + */ + + /* Create the block internal message queue which tosses the messages out of the + * interrupt context. They are buffered in the queue until the DPC tasks + * picks them up and sends them over the shared memory message queue. + * Sorry for that double-queuing, that's because of the M-S architecture */ + + pSelfParam->msgq = msgQCreate(tacSINK_MONITOR_QUEUE_SIZE, sizeof(tacSHMSG), 0); + if ( pSelfParam->msgq == NULL ) + { + char errorParam[40]; + + sprintf(errorParam, "Could not create probe block message queue"); + tacRTC_ERR(tacERR_MALLOC, errorParam); + return ERROR; + } + + /* will count if a message can't be pushed in the queue */ + pSelfParam->lost = 0; + + /* Warn the background task that a new probe block has been created */ + pSelfParam->shmMsg.type = tacSHMSG_ADD_MONITOR; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + + if (pSelfParam->dbPoint == NULL) + { + strcpy((char*) &(pSelfParam->shmMsg.msgBody.monitor.data), tacSINK_MONITOR_DEFAULT_DB_POINT); + } + else + { + strcpy((char*) &(pSelfParam->shmMsg.msgBody.monitor.data), *((char**) &(pSelfParam->dbPoint))); + } + + printf("tacSinkMonitorBlockConstructor - Attach to %s\n",(char*) &(pSelfParam->shmMsg.msgBody.monitor.data)); + + /* Send message */ + tacShMsgQSendBgInfo(&(pSelfParam->shmMsg)); + + /* Initialize the message parameters */ + pSelfParam->shmMsg.type = tacSHMSG_MONITOR_DATA; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + pSelfParam->shmMsg.msgBody.monitor.data.number = pSelfParam->inputNb; + + /* The output port is used to average the inputs over the reporting period */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pSelf->output[arrayIndex] = 0.0; + } + + return OK; +} + +STATUS tacSinkMonitorStateBlockConstructor (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = NULL; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = NULL; + unsigned short arrayIndex = 0; + + /* Check that the expected number of parameters has been received */ + if (parameter->number < tacSINK_DEFAULT_EXPECTED_PARAM) + { + char errorParam[40]; + + sprintf(errorParam, "Expected %d, received %d", tacSINK_DEFAULT_EXPECTED_PARAM, parameter->number); + tacRTC_ERR(tacERR_PARAM_NUMBER, errorParam); + return ERROR; + } + + /* Check that the parameters are valid */ + pRealParam = (double*) parameter->buffer; + + /* Passed parameter is the sampling period of the block */ + if (pRealParam[tacSINK_SAMPLING_PERIOD] < (*pSelf->shared).samplingPeriod) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = (*pSelf->shared).samplingPeriod; + } + + if (pRealParam[tacSINK_SAMPLING_PERIOD] < tacSINK_MONITOR_MIN_SAMPLING_PERIOD) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = tacSINK_MONITOR_MIN_SAMPLING_PERIOD; + } + + /* Number of inputs is minimum 1 up to tacMSG_MAX_DATA_NUMBER */ + if ((pRealParam[tacSINK_INPUT_NUMBER] < 1) || + (pRealParam[tacSINK_INPUT_NUMBER] > tacMAX_DATA_NUMBER)) + { + tacRTC_ERR(tacERR_PARAM_INVALID, ""); + return ERROR; + } + + /* Call common constructor */ + if (tacSinkCommonBlockConstructor(pSelf, error) != OK) + { + return ERROR; + } + + /* Store parameters */ + pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* + * Compute the rate at which data has to be processed - divide and take + * the integer part of the result + */ + + pSelfParam->rate = (unsigned short) (pRealParam[tacSINK_SAMPLING_PERIOD] / (*pSelf->shared).samplingPeriod); + pSelfParam->counter = 0; /* Decimation counter */ + pSelfParam->inputNb = (unsigned short) pRealParam[tacSINK_INPUT_NUMBER]; + + /* Optional parameter is an application-specific DB point */ + if (parameter->number == tacSINK_DEFAULT_EXPECTED_PARAM + 1) + { + printf("tacSinkMonitorStateBlockConstructor - DB point %s\n",(char*) &(pRealParam[tacSINK_MONITOR_DB_POINT])); + pSelfParam->dbPoint = (char*) malloc(tacSINK_MONITOR_MAX_DB_ADDR_SIZE); + strcpy(pSelfParam->dbPoint, (char*) &(pRealParam[tacSINK_MONITOR_DB_POINT])); + } + else + { + printf("tacSinkMonitorStateBlockConstructor - Default DB point\n"); + pSelfParam->dbPoint = NULL; + } + + /* Specify the number of input signals to attach to become resolved */ + tacStdBlockSetInputNumber(pSelf, pSelfParam->inputNb); + + /* + * Perform other block initialization operations + */ + + /* Create the block internal message queue which tosses the messages out of the + * interrupt context. They are buffered in the queue until the DPC tasks + * picks them up and sends them over the shared memory message queue. + * Sorry for that double-queuing, that's because of the M-S architecture */ + + pSelfParam->msgq = msgQCreate(tacSINK_MONITOR_QUEUE_SIZE, sizeof(tacSHMSG), 0); + if ( pSelfParam->msgq == NULL ) + { + char errorParam[40]; + + sprintf(errorParam, "Could not create probe block message queue"); + tacRTC_ERR(tacERR_MALLOC, errorParam); + return ERROR; + } + + /* will count if a message can't be pushed in the queue */ + pSelfParam->lost = 0; + + /* Warn the background task that a new probe block has been created */ + pSelfParam->shmMsg.type = tacSHMSG_ADD_MONITOR; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + + if (pSelfParam->dbPoint == NULL) + { + strcpy((char*) &(pSelfParam->shmMsg.msgBody.monitor.data), tacSINK_MONITOR_DEFAULT_DB_POINT); + } + else + { + strcpy((char*) &(pSelfParam->shmMsg.msgBody.monitor.data), *((char**) &(pSelfParam->dbPoint))); + } + + printf("tacSinkMonitorStateBlockConstructor - Attach to %s\n",(char*) &(pSelfParam->shmMsg.msgBody.monitor.data)); + + /* Send message */ + tacShMsgQSendBgInfo(&(pSelfParam->shmMsg)); + + /* Initialize the message parameters */ + pSelfParam->shmMsg.type = tacSHMSG_MONITOR_DATA; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + pSelfParam->shmMsg.msgBody.monitor.data.number = pSelfParam->inputNb; + + /* Init output port which won't be used to average the inputs over the reporting period */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pSelf->output[arrayIndex] = 0.0; + } + + return OK; +} + +STATUS tacSinkProbeBlockCommonConstructor (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + double minPeriod, + tacERROR* error) +{ + double* pRealParam = NULL; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = NULL; + + /* Check that the expected number of parameters has been received */ + if (parameter->number < tacSINK_DEFAULT_EXPECTED_PARAM) + { + char errorParam[40]; + + sprintf(errorParam, "Expected %d, received %d", tacSINK_DEFAULT_EXPECTED_PARAM, parameter->number); + tacRTC_ERR(tacERR_PARAM_NUMBER, errorParam); + return ERROR; + } + + /* Check that the parameters are valid */ + pRealParam = (double*) parameter->buffer; + + /* Passed parameter is the sampling period of the block */ + if (pRealParam[tacSINK_SAMPLING_PERIOD] < (*pSelf->shared).samplingPeriod) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = (*pSelf->shared).samplingPeriod; + } + + if (pRealParam[tacSINK_SAMPLING_PERIOD] < minPeriod) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = minPeriod; + } + + /* Number of inputs is minimum 1 up to tacMSG_MAX_DATA_NUMBER */ + if ((pRealParam[tacSINK_INPUT_NUMBER] < 1) || + (pRealParam[tacSINK_INPUT_NUMBER] > tacMAX_DATA_NUMBER)) + { + tacRTC_ERR(tacERR_PARAM_INVALID, ""); + return ERROR; + } + + /* Call common constructor */ + if (tacSinkCommonBlockConstructor(pSelf, error) != OK) + { + return ERROR; + } + + /* Store parameters */ + pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* + * Compute the rate at which data has to be processed - divide and take + * the integer part of the result + */ + + pSelfParam->rateParam = pRealParam[tacSINK_SAMPLING_PERIOD]; + pSelfParam->rate = (unsigned short) (pRealParam[tacSINK_SAMPLING_PERIOD] / (*pSelf->shared).samplingPeriod); + pSelfParam->counter = 0; /* Decimation counter */ + pSelfParam->inputNb = (unsigned short) pRealParam[tacSINK_INPUT_NUMBER]; + + /* Specify the number of input signals to attach to become resolved */ + tacStdBlockSetInputNumber(pSelf, pSelfParam->inputNb); + + /* + * Perform other block initialization operations + */ + + /* Create the block internal message queue which gets the messages out of the + * interrupt context. They are buffered in the queue until the DPC tasks + * picks them up and sends them over the shared memory message queue. + * Sorry for that double-queuing, that's because of the M-S architecture */ + + /* There is only one message queue for all probe blocks! */ + pSelfParam->msgq = msgQCreate(tacSINK_PROBE_QUEUE_SIZE, sizeof(tacSHMSG), 0); + if ( pSelfParam->msgq == NULL ) + { + char errorParam[40]; + + sprintf(errorParam, "Could not create probe block message queue"); + tacRTC_ERR(tacERR_MALLOC, errorParam); + return ERROR; + } + + /* will count if a message can't be pushed in the queue */ + pSelfParam->lost = 0; + + /* Warn the background task that a new probe block has been created */ + pSelfParam->shmMsg.type = tacSHMSG_ADD_PROBE; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + + /* Send message */ + tacShMsgQSendDataSample(&pSelfParam->shmMsg); + + /* Initialize the message parameters */ + pSelfParam->shmMsg.type = tacSHMSG_TRANSFER_DATA; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + pSelfParam->shmMsg.msgBody.monitor.data.number = pSelfParam->inputNb; + + return OK; +} + +/* Probe block has a max. sampling frequency of 2kHz */ +STATUS tacSinkProbeBlockConstructor (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + return tacSinkProbeBlockCommonConstructor (pSelf, parameter, tacSINK_PROBE_MIN_SAMPLING_PERIOD, error); +} + +/* Fast probe is the same as probe but not does have the + * limitation on the max. recording frequency */ +STATUS tacSinkFastProbeBlockConstructor (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + return tacSinkProbeBlockCommonConstructor (pSelf, parameter, 0.0, error); +} + +void tacSinkProbeBlockReset (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = + (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* + * Re-Compute the rate at which data has to be processed + */ + if (pSelfParam->rateParam < (*pSelf->shared).samplingPeriod ) + { + pSelfParam->rate = 1; + } + else + { + pSelfParam->rate = (unsigned short) + (pSelfParam->rateParam / (*pSelf->shared).samplingPeriod); + } + + return; +} + +/* + * Report parameters Hooks + */ + +STATUS tacSinkDisplayBlockGetParameter (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = (double*) parameter->buffer; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Send back the expected number of parameters */ + parameter->number = tacSINK_ONE_EXPECTED_PARAM; + + /* Report current parameters */ + pRealParam[tacSINK_SAMPLING_PERIOD] = (double) (pSelfParam->rate * (*pSelf->shared).samplingPeriod); + + return OK; +} + +STATUS tacSinkMonitorBlockGetParameter (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = (double*) parameter->buffer; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Send back the expected number of parameters */ + parameter->number = tacSINK_DEFAULT_EXPECTED_PARAM; + + /* Report current parameters */ + pRealParam[tacSINK_SAMPLING_PERIOD] = (double) (pSelfParam->rate * (*pSelf->shared).samplingPeriod); + pRealParam[tacSINK_INPUT_NUMBER] = (double) pSelfParam->inputNb; + + if (*((char**) &(pSelfParam->dbPoint)) != NULL) + { + parameter->number += 1; + parameter->type[tacSINK_MONITOR_DB_POINT] = tacPARAM_STRING; + strcpy((char*) &(pRealParam[tacSINK_MONITOR_DB_POINT]), *((char**) &(pSelfParam->dbPoint))); + } + + return OK; +} + +STATUS tacSinkMonitorStateBlockGetParameter (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = (double*) parameter->buffer; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Send back the expected number of parameters */ + parameter->number = tacSINK_DEFAULT_EXPECTED_PARAM; + + /* Report current parameters */ + pRealParam[tacSINK_SAMPLING_PERIOD] = (double) (pSelfParam->rate * (*pSelf->shared).samplingPeriod); + pRealParam[tacSINK_INPUT_NUMBER] = (double) pSelfParam->inputNb; + + if (*((char**) &(pSelfParam->dbPoint)) != NULL) + { + parameter->number += 1; + parameter->type[tacSINK_MONITOR_DB_POINT] = tacPARAM_STRING; + strcpy((char*) &(pRealParam[tacSINK_MONITOR_DB_POINT]), *((char**) &(pSelfParam->dbPoint))); + } + + return OK; +} + +STATUS tacSinkProbeBlockGetParameter (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = (double*) parameter->buffer; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Send back the expected number of parameters */ + parameter->number = tacSINK_DEFAULT_EXPECTED_PARAM; + + /* Report current parameters */ + pRealParam[tacSINK_SAMPLING_PERIOD] = (double) (pSelfParam->rate * (*pSelf->shared).samplingPeriod); + pRealParam[tacSINK_INPUT_NUMBER] = (double) pSelfParam->inputNb; + + return OK; +} + +/* + * Change parameters Hooks + */ + +/* + * Algorithm Hooks + */ + +void tacSinkDisplayBlockAlgorithm (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + if ((pSelfParam->counter % pSelfParam->rate) == 0) /* It's time to process data */ + { + sprintf(logStr,"Name: %s Time: %ld.%6ld Value: %g\n", + pSelf->name, + (*pSelf->shared).currentTime.seconds, + (*pSelf->shared).currentTime.microsec, + tacStdBlockGetInput(pSelf,0)); + + tacDpcPushRequest((tacVOIDFCTPTR) &printf, logStr); + + pSelfParam->counter = 0; + } + + pSelfParam->counter++; +} + +void tacSinkMonitorBlockAlgorithm (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + unsigned short arrayIndex = 0; + + /* The output port is used to average the inputs over the reporting period */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pSelf->output[arrayIndex] += tacStdBlockGetInput(pSelf,arrayIndex); + } + + if ((pSelfParam->counter % pSelfParam->rate) == 0) /* It's time to process data */ + { + tacDATA* pData = &(pSelfParam->shmMsg.msgBody.monitor.data); /* We are only interested in message body */ + + /* pData->number = pSelfParam->inputNb; */ + pData->timeStamp = (*pSelf->shared).currentTime; + + /* pData points to the body of the Message */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pData->buffer[arrayIndex] = pSelf->output[arrayIndex] / pSelfParam->rate; + } + + /* Push message into probe block's message que to get the + * data out of the interrupt comtext. */ + if ( msgQSend (pSelfParam->msgq, (char*) &(pSelfParam->shmMsg), sizeof(tacSHMSG), NO_WAIT, 0) != OK ) + { + (pSelfParam->lost)++; + } + + /* Defer procedure call */ + tacDpcPushRequest((tacVOIDFCTPTR) &tacSinkSendMonitorMessage, &pSelfParam->msgq); + + pSelfParam->counter = 0; + + /* The output port is used to average the inputs over the reporting period */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pSelf->output[arrayIndex] = 0.0; + } + } + + pSelfParam->counter++; +} + +void tacSinkMonitorStateBlockAlgorithm (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + unsigned short arrayIndex = 0; + + if ((pSelfParam->counter % pSelfParam->rate) == 0) /* It's time to process data */ + { + tacDATA* pData = &(pSelfParam->shmMsg.msgBody.monitor.data); /* We are only interested in message body */ + + /* pData->number = pSelfParam->inputNb; */ + pData->timeStamp = (*pSelf->shared).currentTime; + + /* pData points to the body of the Message */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pData->buffer[arrayIndex] = tacStdBlockGetInput(pSelf,arrayIndex); + } + + /* Push message into probe block's message que to get the + * data out of the interrupt comtext. */ + if ( msgQSend (pSelfParam->msgq, (char*) &(pSelfParam->shmMsg), sizeof(tacSHMSG), NO_WAIT, 0) != OK ) + { + (pSelfParam->lost)++; + } + + /* Defer procedure call */ + tacDpcPushRequest((tacVOIDFCTPTR) &tacSinkSendMonitorMessage, &pSelfParam->msgq); + + pSelfParam->counter = 0; + } + + pSelfParam->counter++; +} + +void tacSinkProbeBlockAlgorithm (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + unsigned short arrayIndex = 0; + + if ((pSelfParam->counter % pSelfParam->rate) == 0) /* It's time to process data */ + { + tacDATA* pData = &(pSelfParam->shmMsg.msgBody.monitor.data); /* We are only interested in message body */ + + pData->timeStamp = (*pSelf->shared).currentTime; + + /* pData points to the body of the Message */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pData->buffer[arrayIndex] = tacStdBlockGetInput(pSelf,arrayIndex); + } + + /* Push message into probe block's message que to get the + * data out of the interrupt comtext. */ + if ( msgQSend (pSelfParam->msgq, (char*) &(pSelfParam->shmMsg), sizeof(tacSHMSG), NO_WAIT, 0) != OK ) + { + (pSelfParam->lost)++; + } + + /* Defer procedure call: + * tacSinkSendProbeMessage is called outside the interrupt routine + * and will take care to pick up the message from the probe block's + * message queue and send it over the shared memory message queue */ + tacDpcPushRequest((tacVOIDFCTPTR) &tacSinkSendProbeMessage, &pSelfParam->msgq); + + pSelfParam->counter = 0; + } + + pSelfParam->counter++; +} + +/* + * Reset Hooks + */ + +/* + * Stop Hooks + */ + +/* + * Destructor Hooks + */ + +/* + * Note: This destructor is used mainly to send a MONITOR message containing + * 0.0 in order to reset the database array (otherwise going from an + * algorithm with 4 monitored data to one with 3 monitored data leaves + * the 4th value equal to the last ...) + */ + +void tacSinkMonitorBlockDestructor (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + tacDATA* pData = &(pSelfParam->shmMsg.msgBody.monitor.data); + unsigned short arrayIndex = 0; + + /* Reset DB values */ + pSelfParam->shmMsg.type = tacSHMSG_MONITOR_DATA; + pData = &(pSelfParam->shmMsg.msgBody.monitor.data); + + pData->number = pSelfParam->inputNb; + + /* pData points to the body of the Message */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pData->buffer[arrayIndex] = 0.0; + } + + /* Send message */ + tacShMsgQSendBgInfo(&pSelfParam->shmMsg); + + pSelfParam->shmMsg.type = tacSHMSG_REMOVE_MONITOR; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + + /* Send message */ + tacShMsgQSendBgInfo(&pSelfParam->shmMsg); + + free(pSelfParam->dbPoint); + + /* delete internal message queue. Do this as deferred procedure call + * to make sure it is only called when all messages have been send + * (through the same deferred call mechanism) */ + tacDpcPushRequest((tacVOIDFCTPTR) tacSinkDeleteMessageQueue, &(pSelfParam->msgq)); + + return; +} + +void tacSinkMonitorStateBlockDestructor (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + tacDATA* pData = &(pSelfParam->shmMsg.msgBody.monitor.data); + unsigned short arrayIndex = 0; + + /* Reset DB values */ + pSelfParam->shmMsg.type = tacSHMSG_MONITOR_DATA; + pData = &(pSelfParam->shmMsg.msgBody.monitor.data); + + pData->number = pSelfParam->inputNb; + + /* pData points to the body of the Message */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pData->buffer[arrayIndex] = 0.0; + } + + /* Send message */ + tacShMsgQSendBgInfo(&pSelfParam->shmMsg); + + pSelfParam->shmMsg.type = tacSHMSG_REMOVE_MONITOR; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + + /* Send message */ + tacShMsgQSendBgInfo(&pSelfParam->shmMsg); + + free(pSelfParam->dbPoint); + + /* delete internal message queue. Do this as deferred procedure call + * to make sure it is only called when all messages have been send + * (through the same deferred call mechanism) */ + tacDpcPushRequest((tacVOIDFCTPTR) tacSinkDeleteMessageQueue, &(pSelfParam->msgq)); + + return; +} + +void tacSinkProbeBlockDestructor (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + pSelfParam->shmMsg.type = tacSHMSG_REMOVE_PROBE; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + + /* Send message */ + tacShMsgQSendDataSample(&pSelfParam->shmMsg); + + /* delete internal message queue. Do this as deferred procedure call + * to make sure it is only called when all messages have been send + * (through the same deferred call mechanism) */ + tacDpcPushRequest((tacVOIDFCTPTR) tacSinkDeleteMessageQueue, &(pSelfParam->msgq)); + + return; +} + +/* + * Show Hooks + */ + +void tacSinkDisplayBlockShow (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Print parameter values */ + printf(" Update rate: %d\n",pSelfParam->rate); + + return; +} + +void tacSinkMonitorBlockShow (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Print parameter values */ + printf(" Update rate: %d\n",pSelfParam->rate); + printf(" Number of input signals: %d\n",pSelfParam->inputNb); + printf(" Queued samples: %d\n", msgQNumMsgs(pSelfParam->msgq)); + printf(" Lost samples: %d\n",pSelfParam->lost); + + if (pSelfParam->dbPoint != NULL) + { + printf(" DB Point: %s\n", pSelfParam->dbPoint); + } + + return; +} + +void tacSinkMonitorStateBlockShow (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Print parameter values */ + printf(" Using MonitorState block, not averaging received data\n"); + printf(" Update rate: %d\n",pSelfParam->rate); + printf(" Number of input signals: %d\n",pSelfParam->inputNb); + printf(" Queued samples: %d\n", msgQNumMsgs(pSelfParam->msgq)); + printf(" Lost samples: %d\n",pSelfParam->lost); + + if (pSelfParam->dbPoint != NULL) + { + printf(" DB Point: %s\n", pSelfParam->dbPoint); + } + + return; +} + +void tacSinkProbeBlockShow (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Print parameter values */ + printf(" Update rate: %d\n",pSelfParam->rate); + printf(" Update rate param (sec): %f\n",pSelfParam->rateParam); + printf(" Number of input signals: %d\n",pSelfParam->inputNb); + printf(" Queued samples: %d\n", msgQNumMsgs(pSelfParam->msgq)); + printf(" Lost samples: %d\n",pSelfParam->lost); + + return; +} + +/* + * Installation function + */ + +tacSTDBLOCK_TYPE tacSinkDisplayTypeInfo = { + "Display", + &tacSinkDisplayBlockConstructor, + &tacSinkDisplayBlockGetParameter, + &tacSinkDisplayBlockAlgorithm, + NULL, + NULL, + NULL, + NULL, + &tacSinkDisplayBlockShow, +}; + +tacSTDBLOCK_TYPE tacSinkMonitorTypeInfo = { + "Monitor", + &tacSinkMonitorBlockConstructor, + &tacSinkMonitorBlockGetParameter, + &tacSinkMonitorBlockAlgorithm, + NULL, + NULL, + NULL, + &tacSinkMonitorBlockDestructor, + &tacSinkMonitorBlockShow, +}; + +tacSTDBLOCK_TYPE tacSinkMonitorStateTypeInfo = { + "MonitorState", + &tacSinkMonitorStateBlockConstructor, + &tacSinkMonitorStateBlockGetParameter, + &tacSinkMonitorStateBlockAlgorithm, + NULL, + NULL, + NULL, + &tacSinkMonitorStateBlockDestructor, + &tacSinkMonitorStateBlockShow, +}; + +/* Probe with a maximal sampling rate of 2kHz */ +tacSTDBLOCK_TYPE tacSinkProbeTypeInfo = { + "Probe", + &tacSinkProbeBlockConstructor, + &tacSinkProbeBlockGetParameter, + &tacSinkProbeBlockAlgorithm, + NULL, + &tacSinkProbeBlockReset, + NULL, + &tacSinkProbeBlockDestructor, + &tacSinkProbeBlockShow, +}; + +/* Fast probe is the same as probe but not does have the + * limitation on the max. recording frequency */ +tacSTDBLOCK_TYPE tacSinkFastProbeTypeInfo = { + "FastProbe", + &tacSinkFastProbeBlockConstructor, + &tacSinkProbeBlockGetParameter, + &tacSinkProbeBlockAlgorithm, + NULL, + &tacSinkProbeBlockReset, + NULL, + &tacSinkProbeBlockDestructor, + &tacSinkProbeBlockShow, +}; + +STATUS tacSinkBlockInitAll (void) +{ + /* Install Sink Block Hooks */ + tacStdBlockInstallNewType(&tacSinkDisplayTypeInfo); + tacStdBlockInstallNewType(&tacSinkMonitorTypeInfo); + tacStdBlockInstallNewType(&tacSinkMonitorStateTypeInfo); + tacStdBlockInstallNewType(&tacSinkProbeTypeInfo); + tacStdBlockInstallNewType(&tacSinkFastProbeTypeInfo); + + /* + * Perform other library initialization operations + */ + + return OK; +} + +/* + * Local functions + */ + +/* + * Note: Routines called from within the algorithm must be declared with + * static __inline__ + */ + +STATUS tacSinkCommonBlockConstructor (tacSTDBLOCK* pSelf, + tacERROR* error) +{ + /* Allocate specific arrays (pointers are initialized to NULL by StdBlock) */ + if (tacStdBlockAllocateArrays(pSelf, 0, tacSINK_DEFAULT_INPUT_NUMBER, + tacSINK_DEFAULT_OUTPUT_NUMBER, error) == ERROR) + { + return ERROR; + } + + if (tacStdBlockAllocateArrayBySize(pSelf, tacSTDBLOCK_PARAM_ARRAY, + sizeof(tacSINK_SCOPE_LOCAL_PARAMETER), error) == ERROR) + { + tacStdBlockReleaseArray(pSelf, tacSTDBLOCK_INPUT_ARRAY, error); + tacStdBlockReleaseArray(pSelf, tacSTDBLOCK_OUTPUT_ARRAY, error); + return ERROR; + } + + /* Specify the number of input signals to attach to become resolved */ + tacStdBlockSetInputNumber(pSelf, tacSINK_ONE_INPUT_NUMBER); /* Required */ + + return OK; +} + +STATUS tacSinkSendMonitorMessage(MSG_Q_ID * msgq) +{ + /* Send message using provided function (different for Monitor and Probe blocks) */ + /* Send message using provided function (different for Monitor and Probe blocks) */ + tacSHMSG msg; + + if ( msgQReceive(*msgq, (char*) &msg, sizeof(tacSHMSG), NO_WAIT) == sizeof(tacSHMSG) ) + { + tacShMsgQSendBgInfo (&msg); + } + + return OK; +} + +STATUS tacSinkSendProbeMessage(MSG_Q_ID * msgq) +{ + /* Send message using provided function (different for Monitor and Probe blocks) */ + tacSHMSG msg; + + if ( msgq == NULL ) + { + return ERROR; + } + + if ( msgQReceive(*msgq, (char*) &msg, sizeof(tacSHMSG), NO_WAIT) == sizeof(tacSHMSG) ) + { + tacShMsgQSendDataSample (&msg); + } + return OK; +} + +STATUS tacSinkDeleteMessageQueue (MSG_Q_ID * msgq) +{ + /* Is called when block is destroyed and removes the internal message queue */ + STATUS status; + + status = msgQDelete (*msgq); + *msgq = NULL; + return status; +} + + +/*___oOo___*/ + + + + + + diff --git a/src/arguments.py b/src/arguments.py new file mode 100644 index 0000000..94e4cea --- /dev/null +++ b/src/arguments.py @@ -0,0 +1,26 @@ +import getopt + +def exitUsage(): + print("usage: %s <.tasrc file> -i -o " % sys.argv[0]) + sys.exit(1) + +def readArguments(args): + sourceDirectories = [] + outputFile = "" + try: + options, _ = getopt.getopt(args, "hi:o:") + except getopt.GetoptError: + exitUsage() + for option, arg in options: + if option == "-h": + exitUsage() + elif option == "-o": + outputFile = arg + elif option == "-i": + sourceDirectories.append(arg) + if outputFile == "": + exitUsage() + if len(sourceDirectories) == 0: + print("WARNING: no source directories specified!") + return outputFile, sourceDirectories + diff --git a/src/converter.py b/src/converter.py new file mode 100755 index 0000000..3e44058 --- /dev/null +++ b/src/converter.py @@ -0,0 +1,18 @@ +#!/usr/bin/python3 + +import sys + +import arguments +from tacsrc.tac import readTAC +import grc +import portNaming + +if __name__ == "__main__": + if len(sys.argv) == 1: + params.exitUsage() + inputFile = sys.argv[1] + outputFile, sourceDirectories = arguments.readArguments(sys.argv[2:]) + blocks, connections, blockTypes = readTAC(inputFile) + portNaming.resolvePortNames(blockTypes, sourceDirectories) + grc.write(outputFile, blocks, connections) + diff --git a/src/defaultBlockTypes.py b/src/defaultBlockTypes.py new file mode 100644 index 0000000..a7c7a7a --- /dev/null +++ b/src/defaultBlockTypes.py @@ -0,0 +1,74 @@ +from tacsrc.blockType import BlockType + +class VariablePorts: + def __init__(self, ioDescriptionName, sizeFunction): + self.ioDescriptionName = ioDescriptionName + self.sizeFunction = sizeFunction + + def mapName(self, position, name, index): + return + + def getRealPort(self, originalPort): + return 0 + + def ensureLength(self, length): + return + + def getIODescription(self, block): + return "\\\\n0:%s[%s]" % (self.ioDescriptionName, self.sizeFunction(block)) + + def getRealCount(self): + return 1 + +def inParameters(block): + return block.parameters[1] + +def parameterSize(block): + return len(block.parameters) + +monitor = BlockType("Monitor") +monitor.inputs = VariablePorts("input", inParameters) + +monitorState = BlockType("MonitorState") +monitorState.inputs = VariablePorts("input", inParameters) + +probe = BlockType("Probe") +probe.inputs = VariablePorts("input", inParameters) + +readRfm = BlockType("ReadRfm") +readRfm.outputs = VariablePorts("output", parameterSize) + +rms = BlockType("RMS") +rms.inputs.mapName(0, "input", 0) +rms.outputs.mapName(0, "output", 0) + +constant = BlockType("Constant") +constant.outputs.mapName(0, "CONST", 0) + +manual = BlockType("ManualSwitch") +manual.inputs.mapName(0, "input", 0) +manual.outputs.mapName(0, "output", 0) + +noise = BlockType("NormalNoise") +noise.outputs.mapName(0, "output", 0) + +writeRMNNoTim = BlockType("WriteRmNoTim") +writeRMNNoTim.inputs = VariablePorts("input", parameterSize) + +defaultBlockTypes = { + "Monitor": monitor, + "MonitorState": monitorState, + "Probe": probe, + "ReadRfm": readRfm, + "TIM": BlockType("TIM"), + "WAIT_RFM_INTERRUPT": BlockType("WAIT_RFM_INTERRUPT"), + "RMS": rms, + "Constant": constant, + "ManualSwitch": manual, + "NormalNoise": noise, + "WriteRmNoTim": writeRMNNoTim +} + +def addDefaultBlockTypes(blockTypes): + for key in defaultBlockTypes: + blockTypes[key] = defaultBlockTypes[key] diff --git a/src/grc.py b/src/grc.py new file mode 100644 index 0000000..ed02659 --- /dev/null +++ b/src/grc.py @@ -0,0 +1,94 @@ +GRC_TEMPLATE = ''' +options: + parameters: + title: 'TASRC to GRC converter output' + states: + coordinate: [-100, -100] + +blocks: +%s + +connections: +%s + +metadata: + file_format: 1 +''' + +BLOCK_TEMPLATE = ''' +- name: %s + id: epy_block + parameters: + _source_code: "from gnuradio import gr\\nimport numpy as np\\nclass BLOCK(gr.sync_block):\\n def __init__(self):\\n gr.sync_block.__init__(self,name='%s:%s%s',in_sig=%s,out_sig=%s)\\n def work(self, input_items, output_items):\\n return len(output_items[0])" + states: + coordinate: [%s, %s] +''' + +LINK_TEMPLATE = "- [%s, '%s', %s, '%s']\n" + +def getLongestDependencyRow(blocks, blockDependencies): + currentMax = 0 + for block in blocks: + current = getLongestDependencyRow(blockDependencies[block], blockDependencies) + 1 + if current > currentMax: + currentMax = current + return currentMax + +def getPosition(block, blockDependencies, reverseBlockDependencies, depths): + position = getLongestDependencyRow(blockDependencies[block], blockDependencies) + depths += [0] * (position+1 - len(depths)) + y = depths[position] + depths[position] += 50 # base offset + depths[position] += max( + (3+block.blockType.inputs.getRealCount()+block.blockType.outputs.getRealCount()) * 15, + max(block.blockType.inputs.getRealCount(), block.blockType.outputs.getRealCount()) * 30) + return position * 300, y + +def getBlockDependencies(blocks, links): + blockDependencies = {} + for block in blocks: + blockDependencies[block] = [] + for link in links: + if link.toBlock == block: + blockDependencies[block].append(link.fromBlock) + reverseBlockDependencies = {} + for block in blockDependencies: + for dependency in blockDependencies[block]: + if not dependency in reverseBlockDependencies: + reverseBlockDependencies[dependency] = [] + reverseBlockDependencies[dependency].append(block) + return blockDependencies, reverseBlockDependencies + +def getBlocksContent(blocks, links): + blockDependencies, reverseBlockDependencies = getBlockDependencies(blocks, links) + depths = [] + blocksContent = "" + for block in blocks: + description = block.blockType.getIODescription(block) + inputs = "[%s]" % ", ".join(["np.int8"] * block.blockType.inputs.getRealCount()) + outputs = "[%s]" % ", ".join(["np.int8"] * block.blockType.outputs.getRealCount()) + position = getPosition(block, blockDependencies, reverseBlockDependencies, depths) + blocksContent += BLOCK_TEMPLATE % ( + block.name, + block.name, + block.blockType.name, + description, + inputs, + outputs, + position[0], + position[1]) + return blocksContent + +def getLinksContent(links): + linksContent = "" + for link in links: + fromPort = link.fromBlock.blockType.outputs.getRealPort(link.fromPort) + toPort = link.toBlock.blockType.inputs.getRealPort(link.toPort) + linksContent += LINK_TEMPLATE % (link.fromBlock.name, fromPort, link.toBlock.name, toPort) + return linksContent + +def write(filename, blocks, links): + with open(filename, "w+") as file: + print("writing to file %s" % filename) + file.truncate(0) + file.write(GRC_TEMPLATE % (getBlocksContent(blocks, links), getLinksContent(links))) diff --git a/src/portNaming.py b/src/portNaming.py new file mode 100644 index 0000000..62be549 --- /dev/null +++ b/src/portNaming.py @@ -0,0 +1,104 @@ +import re +import os +import json +from defaultBlockTypes import defaultBlockTypes + +INPUT_FUNCTIONS = [ + "tacStdBlockGetInput", + "tacGraviMatrixGetPointerInput" + ] + +OUTPUT_FUNCTIONS = [ + "tacStdBlockSetOutput", + "tacGraviMatrixSetPointerOutput" + ] + +def getFiles(blockType, sourceDirectories): + files = [] + for sourceDirectory in sourceDirectories: + files += ["%s/%s" % (data[0], file) + for data in os.walk(sourceDirectory) + for file in data[2] if re.match(".*tac%sBlock.c" % blockType.name.replace("Rm", "Rmn"), file) != None] + return files + +def resolvePortNames(blockTypes, sourceDirectories): + missingBlocks = [] + multipleDefinitions = [] + for blockType in blockTypes: + if blockType.name in defaultBlockTypes: + continue + files = getFiles(blockType, sourceDirectories) + if len(files) == 0: + print("WARNING: no source file for block type %s found" % blockType.name) + missingBlocks.append(blockType.name) + continue + if len(files) > 1: + multipleDefinitions.append(blockType.name) + print("WARNING: more than one matching source file for block type %s found, skipping" % blockType.name) + continue + print("reading file %s" % files[0]) + with open(files[0], "r") as file: + content = "\n".join(file.readlines()) + for function in INPUT_FUNCTIONS: + mapInputs(content, function, blockType.inputs) + for function in OUTPUT_FUNCTIONS: + mapOutputs(content, function, blockType.outputs) + for entry in re.findall("\\w+ *= *\\*?\\(?pSelf->input\\[\\d+\\]\\)?", content): + name = re.search("^\\w+", entry).group() + position = int(re.search("(?<=\\[)\\d+(?=\\])", entry).group()) + blockType.inputs.mapName(position, name, 0) + for entry in re.findall("pSelf->output\\[\\d+\\] *= *\\w+", content): + name = re.search("\\w+$", entry).group() + position = int(re.search("(?<=\\[)\\d+(?=\\])", entry).group()) + blockType.outputs.mapName(position, name, 0) + if not os.path.exists("errors.json") or os.stat("errors.json").st_size == 0: + content = {"missing_blocks": [], "multiple_definitions": []} + else: + with open("errors.json", "r") as file: + content = json.load(file) + with open("errors.json", "w+") as file: + for blockTypeName in missingBlocks: + if not blockTypeName in content["missing_blocks"]: + content["missing_blocks"].append(blockTypeName) + for blockTypeName in multipleDefinitions: + if not blockTypeName in content["multiple_definitions"]: + content["multiple_definitions"].append(blockTypeName) + json.dump(content, file, indent=2) + file.close() + +def mapInputs(content, function, ports): + for entry in re.findall("\\w+ *= *%s\\(pSelf *, *\\d+\\);" % function, content): + name = re.search("^\\w+", entry).group() + position = int(re.search("\\d+(?= *\\) *;)", entry).group()) + ports.mapName(position, name, 0) + for entry in re.findall("\\w+->\\w+\\[\\d+\\] *= *%s\\(pSelf *, *\\d+\\);" % function, content): + name = re.search("(?<=\\->)\\w+", entry).group() + position = int(re.search("\\d+(?= *\\) *;)", entry).group()) + index = int(re.search("(?<=\\[)\\d+(?=\\])", entry).group()) + ports.mapName(position, name, index) + for entry in re.findall("\\w+\\[\\d+\\] *= *%s\\(pSelf *, *\\d+\\);" % function, content): + name = re.search("^\\w+", entry).group() + position = int(re.search("\\d+(?= *\\) *;)", entry).group()) + index = int(re.search("(?<=\\[)\\d+(?=\\])", entry).group()) + ports.mapName(position, name, index) + +def mapOutputs(content, function, ports): + for entry in re.findall("%s\\(pSelf *, *\\d+ *, *pSelfParam->\\w+\\);" % function, content): + name = re.search("\\w+(?=\\);$)", entry).group() + position = int(re.search("\\d+(?= *, *pSelfParam->\\w+\\);$)", entry).group()) + ports.mapName(position, name, 0) + for entry in re.findall("%s\\(pSelf *, *\\d+ *, *\\w+\\[\\d+\\]\\);" % function, content): + name = re.search("\\w+(?=\\[\\d+\\]\\);$)", entry).group() + position = int(re.search("\\d+(?= *, *\\w+\\[\\d+\\]\\);$)", entry).group()) + index = int(re.search("(?<=\\[)\\d+(?=\\])", entry).group()) + ports.mapName(position, name, index) + for entry in re.findall("%s\\(pSelf *, *\\d+ *, *pSelfParam->\\w+\\[\\d+\\]\\);" % function, content): + name = re.search("(?<=\\->)\\w+", entry).group() + position = int(re.search("\\d+(?= *, *pSelfParam->\\w+\\[\\d+\\]\\);$)", entry).group()) + index = int(re.search("(?<=\\[)\\d+(?=\\]\\);$)", entry).group()) + ports.mapName(position, name, index) + for entry in re.findall("%s\\(pSelf *, *\\d+ *, *\\w+\\);" % function, content): + name = re.search("\\w+(?= *\\);$)", entry).group() + position = int(re.search("\\d+(?= *, *\\w+\\);$)", entry).group()) + index = 0 + ports.mapName(position, name, index) diff --git a/src/tacsrc/block.py b/src/tacsrc/block.py new file mode 100644 index 0000000..737d9f1 --- /dev/null +++ b/src/tacsrc/block.py @@ -0,0 +1,6 @@ +class Block: + def __init__(self): + self.name = "" + self.blockType = None + self.parameters = [] + diff --git a/src/tacsrc/blockType.py b/src/tacsrc/blockType.py new file mode 100644 index 0000000..8930836 --- /dev/null +++ b/src/tacsrc/blockType.py @@ -0,0 +1,19 @@ +from tacsrc.ports import Ports + +class BlockType: + def __init__(self, name): + self.name = name + self.inputs = Ports() + self.outputs = Ports() + + def getIODescription(self, block): + result = "" + inputDescription = self.inputs.getIODescription(block) + if len(inputDescription) != 0: + result += "\\\\nINPUTS:" + result += inputDescription + outputDescription = self.outputs.getIODescription(block) + if len(outputDescription) != 0: + result += "\\\\nOUTPUTS:" + result += outputDescription + return result diff --git a/src/tacsrc/link.py b/src/tacsrc/link.py new file mode 100644 index 0000000..d89b459 --- /dev/null +++ b/src/tacsrc/link.py @@ -0,0 +1,6 @@ +class Link: + def __init__(self): + self.fromBlock = None + self.fromPort = 0 + self.toBlock = None + self.toPort = 0 diff --git a/src/tacsrc/ports.py b/src/tacsrc/ports.py new file mode 100644 index 0000000..4b26f22 --- /dev/null +++ b/src/tacsrc/ports.py @@ -0,0 +1,47 @@ +class Ports: + def __init__(self): + self.labels = [] + self.labelSizes = {} + + def mapName(self, position, name, index): + self.labels += [0] * (position+1 - len(self.labels)) + self.labels[position] = name + if not name in self.labelSizes: + self.labelSizes[name] = 0 + self.labelSizes[name] = max(self.labelSizes[name], index+1) + + def getRealPort(self, originalPort): + labelsDone = [] + for i in range(min(len(self.labels),originalPort)): + label = self.labels[i] + if label != 0 and label in labelsDone: + continue + labelsDone.append(label) + return len(labelsDone) - 1 + + def getIODescription(self, block): + result = "" + labelsDone = [] + for i in range(len(self.labels)): + label = self.labels[i] + if label != 0 and label in labelsDone: + continue + labelsDone.append(label) + if label == 0: + result += "\\\\n%s: unknown" % i + elif self.labelSizes[label] == 1: + result += "\\\\n%s: %s" % (i, label) + else: + result += "\\\\n%s: %s[%s]" % (i, label, self.labelSizes[label]) + return result + + def ensureLength(self, count): + self.labels += [0] * (count - len(self.labels)) + + def getRealCount(self): + labelsDone = [] + for label in self.labels: + if label != 0 and label in labelsDone: + continue + labelsDone.append(label) + return len(labelsDone) diff --git a/src/tacsrc/tac.py b/src/tacsrc/tac.py new file mode 100644 index 0000000..1428e4b --- /dev/null +++ b/src/tacsrc/tac.py @@ -0,0 +1,98 @@ +from defaultBlockTypes import addDefaultBlockTypes +from tacsrc.block import Block +from tacsrc.blockType import BlockType +from tacsrc.link import Link + +import re + +def addBlockType(blockTypes, blockType): + if not BlockType in blockTypes: + blockTypes[blockTypes] = BlockType(blockType) + +def setBlockType(blockIndex, blockTypeName, blocks, blockTypes): + if not blockTypeName in blockTypes: + blockTypes[blockTypeName] = BlockType(blockTypeName) + blocks += [0] * (blockIndex - len(blocks) + 1) + if blocks[blockIndex] == 0: + blocks[blockIndex] = Block() + blocks[blockIndex].blockType = blockTypes[blockTypeName] + +def setBlockName(blockIndex, blockName, blocks): + blocks += [0] * (blockIndex - len(blocks) + 1) + if blocks[blockIndex] == 0: + blocks[blockIndex] = Block() + blocks[blockIndex].name = blockName + +def setBlockParameters(blockIndex, blockParameters, blocks): + blocks += [0] * (blockIndex - len(blocks) + 1) + if blocks[blockIndex] == 0: + blocks[blockIndex] = Block() + blocks[blockIndex].parameters = blockParameters.split(',') + +def ensureLinks(linkIndex, links): + links += [None] * (linkIndex + 1 - len(links)) + if links[linkIndex] == None: + links[linkIndex] = Link() + +def setLinkSourceBlock(linkIndex, sourceBlock, links): + ensureLinks(linkIndex, links) + links[linkIndex].fromBlock = sourceBlock + +def setLinkSourcePort(linkIndex, sourcePort, links): + ensureLinks(linkIndex, links) + links[linkIndex].fromPort = sourcePort + +def setLinkDestinationBlock(linkIndex, destinationBlock, links): + ensureLinks(linkIndex, links) + links[linkIndex].toBlock = destinationBlock + +def setLinkDestinationPort(linkIndex, destinationPort, links): + ensureLinks(linkIndex, links) + links[linkIndex].toPort = destinationPort + +def readTAC(filename): + blockTypes = {} + addDefaultBlockTypes(blockTypes) + blocks = [] + links = [] + # make sure all blocks have been declared before the links are read + linkLines = [] + print("reading file %s" % filename) + with open(filename, "r") as file: + content = file.readlines() + for line in content: + if len(line) == 0: + continue + if re.match("TAC\\.LINK.*", line): + linkLines.append(line) + if not re.match("TAC\\.BLOCK.*", line): + continue + blockIndex = int(re.search("(?<=TAC\\.BLOCK)\\d+", line).group()) + if re.match("TAC\\.BLOCK\\d+\\.TYPE \\w+", line): + setBlockType(blockIndex, re.search("\\w+$", line).group(), blocks, blockTypes) + elif re.match("TAC\\.BLOCK\\d+\\.NAME \\w+", line): + setBlockName(blockIndex, re.search("\\w+$", line).group(), blocks) + elif re.match("TAC\\.BLOCK\\d+\\.PARAM .+", line): + setBlockParameters(blockIndex, re.search("(?<=\\.PARAM ).*$", line).group(), blocks) + blocksByName = {} + for block in blocks: + blocksByName[block.name] = block + for line in linkLines: + linkIndex = int(re.search("(?<=TAC\\.LINK)\\d+", line).group()) + if re.match("TAC\\.LINK\\d+\\.SOURCE\\.NAME \\w+", line): + sourceBlockName = re.search("\\w+$", line).group() + sourceBlock = blocksByName[sourceBlockName] + setLinkSourceBlock(linkIndex, sourceBlock, links) + elif re.match("TAC\\.LINK\\d+\\.SOURCE\\.PORT \\d+", line): + sourcePort = int(re.search("\\d+$", line).group()) + setLinkSourcePort(linkIndex, sourcePort, links) + elif re.match("TAC\\.LINK\\d+\\.DEST\\.NAME \\w+", line): + destinationBlock = blocksByName[re.search("\\w+$", line).group()] + setLinkDestinationBlock(linkIndex, destinationBlock, links) + elif re.match("TAC\\.LINK\\d+\\.DEST\\.PORT \\d+", line): + destinationPort = int(re.search("\\d+$", line).group()) + setLinkDestinationPort(linkIndex, destinationPort, links) + for link in links: + link.fromBlock.blockType.outputs.ensureLength(link.fromPort) + link.toBlock.blockType.inputs.ensureLength(link.toPort) + return blocks, links, blockTypes.values() diff --git a/src/tacsrc/tacsrc.py b/src/tacsrc/tacsrc.py new file mode 100644 index 0000000..ec6fbb1 --- /dev/null +++ b/src/tacsrc/tacsrc.py @@ -0,0 +1,48 @@ +import re +from defaultBlockTypes import addDefaultBlockTypes + +from tacsrc.block import Block +from tacsrc.blockType import BlockType +from tacsrc.link import Link + +def readTASRC(inputFile): + blockTypes = {} + addDefaultBlockTypes(blockTypes) + blocks = {} + links = [] + # make sure all blocks have been declared before the links are read + linklines = [] + with open(inputFile, "r") as file: + content = file.readlines() + for l in content: + # clean up line, putting only a single space in every seperation + line = re.sub("(\\s+|, *)", ' ', l) + parts = line.split(' ') + if len(parts) == 0: + continue + if parts[0] == "TAC_BLOCK": + if not parts[2] in blockTypes: + blockTypes[parts[2]] = BlockType(parts[2]) + blocks[parts[1]] = Block( + parts[1], + blockTypes[parts[2]], + parts[3:-1] + ) + elif parts[0] == "TAC_LINK": + linklines.append(parts) + for parts in linklines: + # parts[1] is the link name and is not used + fromBlock = blocks[parts[2]] + fromPort = int(parts[3]) + toBlock = blocks[parts[4]] + toPort = int(parts[5]) + links.append(Link( + fromBlock, + fromPort, + toBlock, + toPort + )) + fromBlock.blockType.outputs.ensureLength(fromPort) + toBlock.blockType.inputs.ensureLength(toPort) + return blocks.values(), links, blockTypes.values() + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3624768 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +__pycache__ +out +tacapp.tar.gz +Sources +tacapp +worryingFiles +cc.tar.gz diff --git a/errors.json b/errors.json new file mode 100644 index 0000000..5ec898a --- /dev/null +++ b/errors.json @@ -0,0 +1,4 @@ +{ + "missing_blocks": [], + "multiple_definitions": [] +} \ No newline at end of file diff --git a/hardcodedFiles/tacReadRmnBlock.c b/hardcodedFiles/tacReadRmnBlock.c new file mode 100644 index 0000000..8acbcfa --- /dev/null +++ b/hardcodedFiles/tacReadRmnBlock.c @@ -0,0 +1,568 @@ +/******************************************************************************* +* E.S.O. - VLT project +* +* "@(#) $Id: tacReadRmnBlock.c 305476 2018-01-19 08:56:18Z rfrahm $" +* +* who when what +* ------- -------- ---------------------------------------------- +* gzins 2010-07-27 ported to VLTSW2010 and VxWorks 6.4 +* swehner 2008-10-10 creation +*/ + +/************************************************************************ +* NAME +* tacReadRmnBlock - Implemements the standard functions for the +* tacReadRmn block and tacReadRfm block. +* tacReadRmnBlock - Reads from 1rst generation reflective memory network +* tacReadRfmBlock - Reads from 2nd generation reflective memory network + +* Parameters: +* field - token names for the RMN fields to read (up to 10) +* Inputs: 0 +* Outputs: 1 +* output - 1..10 depending on number of field parameters +* +* +* +* FILES +* +* ENVIRONMENT +* TAC +* +* RETURN VALUES +* +* CAUTIONS +* +* EXAMPLES +* TAC.BLOCK9.TYPE ReadRmn +* TAC.BLOCK9.NAME ReadRmn +* +* SEE ALSO +* +* BUGS +* +*------------------------------------------------------------------------ +*/ + +#define _POSIX_SOURCE 1 +#include "vltPort.h" + +ATTRIBUTE_UNUSED static const char *rcsId="@(#) $Id: tacReadRmnBlock.c 305476 2018-01-19 08:56:18Z rfrahm $"; + +/* + * System Headers + */ + +#include /* taskSpawn, taskDelay, ... */ +#include /* printf ... */ +#include /* malloc ... */ +#include /* malloc ... */ +#include +#include + +/* + * Local Headers + */ + +#include "tacStdBlock.h" +#include "tacRmnBlock.h" +#include "rmassPublic.h" +#include "rmassPrivate.h" + +/* + * Compilation directives + */ + +/* + * Constants + */ + +#define tacREAD_RMN_EXPECTED_PARAM 1 +#define tacREAD_RMN_DEFAULT_INPUT_NUMBER 0 +#define tacREAD_RMN_DEFAULT_OUTPUT_NUMBER tacMAX_DATA_NUMBER + +#define tacREAD_RMN_FIELD_STRING_LEN 256 +#define tacSTRLEN sizeof(double) + +/* + * Types + */ + +/* + * Local function declaration + */ + +/* + * Global variables + */ + +/* + * Function definition + */ + + +STATUS tacReadRmnBlockCheckParameter (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the ADDBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = NULL; + + pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + /* field string is built from block params */ + if ( tacRmnBlockCheckParameter ( pSelf, parameter, 0, error) != OK ) + { + return ERROR; + } + + /* useful information on the screen */ + printf ("ReadRmn %s: [%s]\n", pSelf->name, pSelfParam->fieldString); + + return OK; +} + +STATUS tacReadRfmBlockCheckParameter (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the ADDBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = NULL; + + pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + /* field string is built from block params */ + if ( tacRmnBlockCheckParameter ( pSelf, parameter, 0, error) != OK ) + { + return ERROR; + } + + /* useful information on the screen */ + printf ("ReadRfm %s: [%s]\n", pSelf->name, pSelfParam->fieldString); + + return OK; +} + +/* + * Constructor Hooks - Called when a block of this type is instanciated (CONFIG or ADDBLCK commands) + */ + +STATUS tacReadRmBlockConstructor (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the ADDBLCK command */ + vltLOGICAL isRmn, + tacERROR* error) /* Error structure - not a stack */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = NULL; + + /* Check that the expected number of parameters has been received */ + if (parameter->number < tacREAD_RMN_EXPECTED_PARAM) + { + char errorParam[40]; + + sprintf(errorParam, "Expected at least %d, received %d", tacREAD_RMN_EXPECTED_PARAM, parameter->number); + tacRTC_ERR(tacERR_PARAM_NUMBER, errorParam); + return ERROR; + } + + /* Allocate and initialize block-specific arrays */ + if (tacStdBlockAllocateArrays(pSelf, 0, tacREAD_RMN_DEFAULT_INPUT_NUMBER, tacREAD_RMN_DEFAULT_OUTPUT_NUMBER, error) == ERROR) + { + return ERROR; + } + + if (tacStdBlockAllocateArrayBySize(pSelf, tacSTDBLOCK_PARAM_ARRAY, sizeof(tacRMN_LOCAL_PARAMETER), error) == ERROR) + { + tacStdBlockReleaseArray(pSelf, tacSTDBLOCK_INPUT_ARRAY, error); + tacStdBlockReleaseArray(pSelf, tacSTDBLOCK_OUTPUT_ARRAY, error); + return ERROR; + } + + if ( isRmn ) + { + if ( tacReadRmnBlockCheckParameter (pSelf, parameter, error) == ERROR) + { + return ERROR; + } + } + else + { + if ( tacReadRfmBlockCheckParameter (pSelf, parameter, error) == ERROR) + { + return ERROR; + } + } + + pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + pSelfParam->handleValid = rmassACCESS_BLOCKED; + + /* Attach to RMN */ + if ( rmassReadAttach (&pSelfParam->handle, + pSelfParam->fieldString, + &pSelfParam->val[0], + &pSelfParam->val[1], + &pSelfParam->val[2], + &pSelfParam->val[3], + &pSelfParam->val[4], + &pSelfParam->val[5], + &pSelfParam->val[6], + &pSelfParam->val[7], + &pSelfParam->val[8], + &pSelfParam->val[9]) != SUCCESS ) + { + char errorParam[40]; + + sprintf(errorParam, "Attach to RMN failed."); + tacRTC_ERR(tacERR_INTERNAL, errorParam); + return ERROR; + } + + pSelfParam->handleValid = rmassACCESS_FREE; + + return OK; +} + +STATUS tacReadRmnBlockConstructor (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the ADDBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + if ( tacReadRmBlockConstructor (pSelf, parameter, ccsTRUE, error ) == ERROR ) + { + return ERROR; + } + return OK; +} + +STATUS tacReadRfmBlockConstructor (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the ADDBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + if ( tacReadRmBlockConstructor (pSelf, parameter, ccsFALSE, error ) == ERROR ) + { + return ERROR; + } + return OK; +} + + + +/* + * Destructor Hooks - Called when the block is removed from the algorithm (DELBLCK or new CONFIG commands) + */ + +void tacReadRmnBlockDestructor (tacSTDBLOCK* pSelf) /* Reference to the block instance */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = NULL; + pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + pSelfParam->handleValid = rmassACCESS_BLOCKED; + /* wait until semaphore is acknowledged by realtime algo + * or just procede if realtime is not active */ + while ((*pSelf->shared).active && pSelfParam->handleValid != rmassACCESS_BLOCK_ACKN) + { + taskDelay(1); + } + + rmassDetach (&pSelfParam->handle); + + return; +} + +/* + * Change parameters Hooks - Called when modifying the block parameters (MODBLCK command) + */ + +STATUS tacReadRmnBlockSetParameter (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the MODBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + if ( tacReadRmnBlockCheckParameter (pSelf, parameter, error) == ERROR) + { + return ERROR; + } + + pSelfParam->handleValid = rmassACCESS_BLOCKED; + /* wait until semaphore is acknowledged by realtime algo + * or just procede if realtime is not active */ + while ((*pSelf->shared).active && pSelfParam->handleValid != rmassACCESS_BLOCK_ACKN) + { + taskDelay(1); + } + + /* detach RMN handle */ + if ( rmassDetach (&pSelfParam->handle) != SUCCESS ) + { + char errorParam[40]; + + sprintf(errorParam, "rmassDetach returned error."); + tacRTC_ERR(tacERR_INTERNAL, errorParam); + return ERROR; + } + + if ( rmassReadAttach (&pSelfParam->handle, + pSelfParam->fieldString, + &pSelfParam->val[0], + &pSelfParam->val[1], + &pSelfParam->val[2], + &pSelfParam->val[3], + &pSelfParam->val[4], + &pSelfParam->val[5], + &pSelfParam->val[6], + &pSelfParam->val[7], + &pSelfParam->val[8], + &pSelfParam->val[9]) != SUCCESS ) + { + char errorParam[40]; + + sprintf(errorParam, "Attach to RMN failed."); + tacRTC_ERR(tacERR_INTERNAL, errorParam); + return ERROR; + } + + pSelfParam->handleValid = rmassACCESS_FREE; + + return OK; +} + +STATUS tacReadRfmBlockSetParameter (tacSTDBLOCK* pSelf, /* Reference to the block instance */ + tacSTDBLOCK_PARAM* parameter, /* Parameters of the MODBLCK command */ + tacERROR* error) /* Error structure - not a stack */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + if ( tacReadRfmBlockCheckParameter (pSelf, parameter, error) == ERROR) + { + return ERROR; + } + + pSelfParam->handleValid = rmassACCESS_BLOCKED; + /* wait until semaphore is acknowledged by realtime algo + * or just procede if realtime is not active */ + while ((*pSelf->shared).active && pSelfParam->handleValid != rmassACCESS_BLOCK_ACKN) + { + taskDelay(1); + } + + /* detach RMN handle */ + if ( rmassDetach (&pSelfParam->handle) != SUCCESS ) + { + char errorParam[40]; + + sprintf(errorParam, "rmassDetach returned error."); + tacRTC_ERR(tacERR_INTERNAL, errorParam); + return ERROR; + } + + if ( rmassReadAttach (&pSelfParam->handle, + pSelfParam->fieldString, + &pSelfParam->val[0], + &pSelfParam->val[1], + &pSelfParam->val[2], + &pSelfParam->val[3], + &pSelfParam->val[4], + &pSelfParam->val[5], + &pSelfParam->val[6], + &pSelfParam->val[7], + &pSelfParam->val[8], + &pSelfParam->val[9]) != SUCCESS ) + { + char errorParam[40]; + + sprintf(errorParam, "Attach to RFM failed."); + tacRTC_ERR(tacERR_INTERNAL, errorParam); + return ERROR; + } + + pSelfParam->handleValid = rmassACCESS_FREE; + + return OK; +} + +/* + * Algorithm Hooks - Called at each time the TAC algorithm is evaluated (ONLINE state) + */ + +void tacReadRmnBlockAlgorithm (tacSTDBLOCK* pSelf) /* Reference to the block instance */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + int i; + + if ( pSelfParam->handleValid == rmassACCESS_BLOCKED ) + { + pSelfParam->handleValid = rmassACCESS_BLOCK_ACKN; + } + + if ( pSelfParam->handleValid == rmassACCESS_FREE ) + { + /* actual RMN read operation */ + rmassReadAccessRmn (&pSelfParam->handle); + + /* Write to outputs */ + for (i=0; i < pSelfParam->numFields; i++) + { + switch (pSelfParam->type[i]) + { + case rmassTIMESEC: + case rmassUINT32: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).ui); + break; + case rmassTIMEUSEC: + case rmassINT32: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).i); + break; + case rmassFLOAT: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).f); + break; + default: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).d); + break; + } + } + + /* provide zero values at unsatisfied outputs + * I consider this a good thing to do since the block + * is always configured */ + for (i=pSelfParam->numFields; i < tacREAD_RMN_DEFAULT_OUTPUT_NUMBER; i++) + { + tacStdBlockSetOutput(pSelf, i, 0.0); + } + } +} + +void tacReadRfmBlockAlgorithm (tacSTDBLOCK* pSelf) /* Reference to the block instance */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + int i; + + if ( pSelfParam->handleValid == rmassACCESS_BLOCKED ) + { + pSelfParam->handleValid = rmassACCESS_BLOCK_ACKN; + } + + if ( pSelfParam->handleValid == rmassACCESS_FREE ) + { + /* actual RMN read operation */ + rmassReadAccessRfm (&pSelfParam->handle); + + /* Write to outputs */ + for (i=0; i < pSelfParam->numFields; i++) + { + switch (pSelfParam->type[i]) + { + case rmassTIMESEC: + case rmassUINT32: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).ui); + break; + case rmassTIMEUSEC: + case rmassINT32: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).i); + break; + case rmassFLOAT: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).f); + break; + default: + tacStdBlockSetOutput(pSelf, i, (*pSelfParam->val[i]).d); + break; + } + } + + /* provide zero values at unsatisfied outputs + * I consider this a good thing to do since the block + * is always configured */ + for (i=pSelfParam->numFields; i < tacREAD_RMN_DEFAULT_OUTPUT_NUMBER; i++) + { + tacStdBlockSetOutput(pSelf, i, 0.0); + } + } +} + +/* + * Show Hooks - Called when the tacRtcTaskShow routine is executed + */ + +void tacReadRmnBlockShow (tacSTDBLOCK* pSelf) /* Reference to the block instance */ +{ + tacRMN_LOCAL_PARAMETER* pSelfParam = (tacRMN_LOCAL_PARAMETER*) pSelf->parameter; + + /* Print parameter values */ + printf(" Attached: %s\n", pSelfParam->fieldString); + + return; +} + + +/***************************************************/ +/* The following code is common to all block types */ +/* Do not modify without any good reasons */ +/***************************************************/ + +/* + * Installation function + */ + +tacSTDBLOCK_TYPE tacReadRmnTypeInfo = { + "ReadRmn", + &tacReadRmnBlockConstructor, + &tacRmBlockGetParameter, + &tacReadRmnBlockAlgorithm, + &tacReadRmnBlockSetParameter, + NULL, + NULL, + &tacReadRmnBlockDestructor, + &tacReadRmnBlockShow +}; + +tacSTDBLOCK_TYPE tacReadRfmTypeInfo = { + "ReadRfm", + &tacReadRfmBlockConstructor, + &tacRmBlockGetParameter, + &tacReadRfmBlockAlgorithm, + &tacReadRmnBlockSetParameter, + NULL, + NULL, + &tacReadRmnBlockDestructor, + &tacReadRmnBlockShow +}; + +STATUS tacReadRmnBlockInitAll (void) +{ + /***************************************************/ + /* The following code is common to all block types */ + /* Do not modify without any good reasons */ + /***************************************************/ + + /* Install ReadRmn1g Block Hooks */ + tacStdBlockInstallNewType(&tacReadRmnTypeInfo); + + /*****************************/ + /* End of common code region */ + /*****************************/ + + /* Perform other library initialization operations */ + + return OK; +} + +STATUS tacReadRfmBlockInitAll (void) +{ + /***************************************************/ + /* The following code is common to all block types */ + /* Do not modify without any good reasons */ + /***************************************************/ + + /* Install ReadRmn1g Block Hooks */ + tacStdBlockInstallNewType(&tacReadRfmTypeInfo); + + /*****************************/ + /* End of common code region */ + /*****************************/ + + /* Perform other library initialization operations */ + + return OK; +} + +/*___oOo___*/ + + + diff --git a/hardcodedFiles/tacSinkBlock.c b/hardcodedFiles/tacSinkBlock.c new file mode 100644 index 0000000..df39833 --- /dev/null +++ b/hardcodedFiles/tacSinkBlock.c @@ -0,0 +1,1256 @@ +/******************************************************************************* +* E.S.O. - VLT project +* +* "@(#) $Id: tacSinkBlock.c 339094 2021-02-10 03:10:02Z jgil $" +* +* who when what +* ------- -------- ---------------------------------------------- +* rdembet 06/08/20 New MonitorState block with no data averaging +* swehner 28/11/09 SPR20090234 Correction in rate adjustment in reset hook +* swehner 27/11/09 Fixed message queue handling +* swehner 10/10/09 New block FastProbe for unlimited rec frequency +* swehner 22/09/09 PPRS 32341 Replaced specialized tacSINK_SHMSG stack +* with standard vxWorks message queue. +* bbauvir 21/09/04 VLTSW20040113 - One sample might be lost +* bbauvir 29/03/04 Monitor block averages over the reporting period +* bbauvir 29/12/02 Probe to the SampTask +* bbauvir 26/12/02 MsgQ access through DPC mechanism +* bbauvir 14/07/02 New MsgQ of TAC version 1.22 +* bbauvir 21/03/01 Created +*/ + +/************************************************************************ +* NAME +* tacSinkBlock - Standard data monitoring blocks +* +* SYNOPSIS +* lcubootAutoCdBoot 1,"tacsink.boot" +* < tacsink.boot +* +* DESCRIPTION +* Block type: Display +* Parameters: +* Inputs: 1 +* Outputs: none +* +* This function block samples the value of its input signal at the +* specified and issues a message containing the time +* and the value of the input on the vxWorks terminal. +* It does not allow modification of the parameter at runtime. +* +* Block type: Monitor +* Parameters: +* +* Inputs: 10max +* Outputs: none +* +* This function block samples the value of its input signals at the +* specified (0.0 to send a message at the system sampling +* period) and issues a message containing the time and the value of +* the inputs on the shared memory. This message is intercepted by the +* background task running on the master CPU. The monitored values are +* written into the online database. The number of inputs of the block +* is specified by parameter. +* This block does not allow modification of the parameters at runtime. +* +* Block type: MonitorState +* Parameters: +* +* Inputs: 10max +* Outputs: none +* +* Same as Monitor block but without the averaging of received data, +* see VLTSW-14260 JIRA ticket. +* +* Block type: Probe +* Parameters: +* +* Inputs: 10max +* Outputs: none +* +* Block type: FastProbe +* Parameters: +* +* Inputs: 10max +* Outputs: none +* +* This function block samples the value of its input signals at the +* specified (0.0 to send a message at the system sampling +* period) and issues a message containing the time and the value of +* the inputs on the shared memory. This message is intercepted by the +* background task running on the master CPU. The number of inputs of +* the block is specified by parameter. +* This message is passed to an external application callback if +* provided. +* This block does not allow modification of the parameters at runtime. +* The normal Probe block has a limited sampling frequency of not more +* than 2kHz. The reason is in particular the bottleneck between master +* and slave CPU which all samples have to pass through a mechanism of +* VME bus shared memory. On one-CPU-systems this limitation does not +* apply so you are free to choose faster sampling. You may of course +* hit other limitations (processor speed, network traffic etc.) +* +* FILES +* +* ENVIRONMENT +* TAC +* +* RETURN VALUES +* +* CAUTIONS +* All these blocks compute an decimation value to use to trigger the +* sampling of the input signals, from the system sampling period. +* They should be created after any synchronization block. +* +* In order to cope with system performances, a minimum +* is defined for each block. The minimum applied periods are 0.1 (10Hz), +* 0.01 (100Hz) and 0.5e-3 (2kHz) for the 'Display', 'Monitor' and +* 'Probe' blocks respectively. +* +* EXAMPLES +* # 5 signals @ 2Hz (monitored in the database) +* TAC.BLOCK9.TYPE Monitor +* TAC.BLOCK9.NAME Monitor +* TAC.BLOCK9.PARAM 0.5, 5 +* +* # 5 signals @ the RT algorithm sampling period (0.0) +* TAC.BLOCK10.TYPE Probe +* TAC.BLOCK10.NAME Probe +* TAC.BLOCK10.PARAM 0.0, 5 +* +* SEE ALSO +* tacServerInstallDataCallback, tacServerRemoveDataCallback +* +* BUGS +* +*------------------------------------------------------------------------ +*/ + +#define _POSIX_SOURCE 1 +#include "vltPort.h" + + +/* + * System Headers + */ + +#include +#include +#include /* logMsg ... */ +#include /* printf ... */ +#include /* malloc ... */ +#include /* memcpy ... */ +#include + +/* + * Local Headers + */ + +#include "tacStdBlock.h" +#include "tacShMsgQ.h" + +/* + * Compilation directives + */ + +/* + * Constants + */ + +#define tacSINK_DEFAULT_EXPECTED_PARAM 2 + +#define tacSINK_DEFAULT_INPUT_NUMBER tacMAX_DATA_NUMBER /* Up to 10 input channels */ +#define tacSINK_DEFAULT_OUTPUT_NUMBER tacMAX_DATA_NUMBER + +#define tacSINK_ONE_EXPECTED_PARAM 1 +#define tacSINK_ONE_INPUT_NUMBER 1 + +#define tacSINK_DISPLAY_MIN_SAMPLING_PERIOD .1 /* 10Hz */ +#define tacSINK_MONITOR_MIN_SAMPLING_PERIOD .01 /* 100Hz */ +#define tacSINK_PROBE_MIN_SAMPLING_PERIOD .5e-3 /* 2kHz */ + +#define tacSINK_DISPLAY_LOG_STRING_SIZE 128 + +#define tacSINK_MONITOR_DEFAULT_DB_POINT "tac:data:monitor" +#define tacSINK_MONITOR_MAX_DB_ADDR_SIZE 64 + +#define tacSINK_MONITOR_QUEUE_SIZE 6 +#define tacSINK_PROBE_QUEUE_SIZE 6 + + +typedef enum { + tacSINK_SAMPLING_PERIOD = 0, + tacSINK_INPUT_NUMBER, + tacSINK_MONITOR_DB_POINT, +}tacSINK_SCOPE_PARAM_INDEX; + +/* + * Types + */ + +typedef struct { + unsigned short rate; + unsigned short counter; + unsigned short inputNb; + unsigned int lost; + double rateParam; + char* dbPoint; + MSG_Q_ID msgq; + tacSHMSG shmMsg; +}tacSINK_SCOPE_LOCAL_PARAMETER; + +/* + * Function declaration + */ + +extern STATUS tacDpcPushRequest(tacVOIDFCTPTR pFunct, void* parameter); + +/* + * Local function declaration + */ + +/* + * Note: Routines called from within the algorithm must be declared with + * static __inline__ + */ + +STATUS tacSinkSendMonitorMessage(MSG_Q_ID * msgqvoid); +STATUS tacSinkSendMonitorStateMessage(MSG_Q_ID * msgqvoid); +STATUS tacSinkSendProbeMessage(MSG_Q_ID * msgq); +STATUS tacSinkDeleteMessageQueue(MSG_Q_ID * msgq); +STATUS tacSinkCommonBlockConstructor(tacSTDBLOCK* pSelf, tacERROR* error); + +/* + * Global variables + */ + +char logStr[tacSINK_DISPLAY_LOG_STRING_SIZE]; /* Logging string used for Display */ + + +/* + * Function definition + */ + +/* + * Constructor Hooks + */ + +STATUS tacSinkDisplayBlockConstructor (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = NULL; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = NULL; + + /* Check that the expected number of parameters has been received */ + if (parameter->number < tacSINK_ONE_EXPECTED_PARAM) + { + char errorParam[40]; + + sprintf(errorParam, "Expected %d, received %d", tacSINK_ONE_EXPECTED_PARAM, parameter->number); + tacRTC_ERR(tacERR_PARAM_NUMBER, errorParam); + return ERROR; + } + + /* Check that the parameters are valid */ + pRealParam = (double*) parameter->buffer; + + /* Passed parameter is the sampling period of the block */ + if (pRealParam[tacSINK_SAMPLING_PERIOD] < (*pSelf->shared).samplingPeriod) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = (*pSelf->shared).samplingPeriod; + } + + if (pRealParam[tacSINK_SAMPLING_PERIOD] < tacSINK_DISPLAY_MIN_SAMPLING_PERIOD) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = tacSINK_DISPLAY_MIN_SAMPLING_PERIOD; + } + + /* Call common constructor */ + if (tacSinkCommonBlockConstructor(pSelf, error) != OK) + { + return ERROR; + } + + /* Store parameters */ + pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; /* We will only store short integers */ + + /* + * Compute the rate at which data has to be processed - divide and take + * the integer part of the result + */ + + pSelfParam->rate = (unsigned short) (pRealParam[tacSINK_SAMPLING_PERIOD] / (*pSelf->shared).samplingPeriod); + pSelfParam->counter = 0; /* Decimation counter */ + + /* + * Perform other block initialization operations + */ + + return OK; +} + +STATUS tacSinkMonitorBlockConstructor (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = NULL; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = NULL; + unsigned short arrayIndex = 0; + + /* Check that the expected number of parameters has been received */ + if (parameter->number < tacSINK_DEFAULT_EXPECTED_PARAM) + { + char errorParam[40]; + + sprintf(errorParam, "Expected %d, received %d", tacSINK_DEFAULT_EXPECTED_PARAM, parameter->number); + tacRTC_ERR(tacERR_PARAM_NUMBER, errorParam); + return ERROR; + } + + /* Check that the parameters are valid */ + pRealParam = (double*) parameter->buffer; + + /* Passed parameter is the sampling period of the block */ + if (pRealParam[tacSINK_SAMPLING_PERIOD] < (*pSelf->shared).samplingPeriod) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = (*pSelf->shared).samplingPeriod; + } + + if (pRealParam[tacSINK_SAMPLING_PERIOD] < tacSINK_MONITOR_MIN_SAMPLING_PERIOD) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = tacSINK_MONITOR_MIN_SAMPLING_PERIOD; + } + + /* Number of inputs is minimum 1 up to tacMSG_MAX_DATA_NUMBER */ + if ((pRealParam[tacSINK_INPUT_NUMBER] < 1) || + (pRealParam[tacSINK_INPUT_NUMBER] > tacMAX_DATA_NUMBER)) + { + tacRTC_ERR(tacERR_PARAM_INVALID, ""); + return ERROR; + } + + /* Call common constructor */ + if (tacSinkCommonBlockConstructor(pSelf, error) != OK) + { + return ERROR; + } + + /* Store parameters */ + pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* + * Compute the rate at which data has to be processed - divide and take + * the integer part of the result + */ + + pSelfParam->rate = (unsigned short) (pRealParam[tacSINK_SAMPLING_PERIOD] / (*pSelf->shared).samplingPeriod); + pSelfParam->counter = 0; /* Decimation counter */ + pSelfParam->inputNb = (unsigned short) pRealParam[tacSINK_INPUT_NUMBER]; + + /* Optional parameter is an application-specific DB point */ + if (parameter->number == tacSINK_DEFAULT_EXPECTED_PARAM + 1) + { + printf("tacSinkMonitorBlockConstructor - DB point %s\n",(char*) &(pRealParam[tacSINK_MONITOR_DB_POINT])); + pSelfParam->dbPoint = (char*) malloc(tacSINK_MONITOR_MAX_DB_ADDR_SIZE); + strcpy(pSelfParam->dbPoint, (char*) &(pRealParam[tacSINK_MONITOR_DB_POINT])); + } + else + { + printf("tacSinkMonitorBlockConstructor - Default DB point\n"); + pSelfParam->dbPoint = NULL; + } + + /* Specify the number of input signals to attach to become resolved */ + tacStdBlockSetInputNumber(pSelf, pSelfParam->inputNb); + + /* + * Perform other block initialization operations + */ + + /* Create the block internal message queue which tosses the messages out of the + * interrupt context. They are buffered in the queue until the DPC tasks + * picks them up and sends them over the shared memory message queue. + * Sorry for that double-queuing, that's because of the M-S architecture */ + + pSelfParam->msgq = msgQCreate(tacSINK_MONITOR_QUEUE_SIZE, sizeof(tacSHMSG), 0); + if ( pSelfParam->msgq == NULL ) + { + char errorParam[40]; + + sprintf(errorParam, "Could not create probe block message queue"); + tacRTC_ERR(tacERR_MALLOC, errorParam); + return ERROR; + } + + /* will count if a message can't be pushed in the queue */ + pSelfParam->lost = 0; + + /* Warn the background task that a new probe block has been created */ + pSelfParam->shmMsg.type = tacSHMSG_ADD_MONITOR; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + + if (pSelfParam->dbPoint == NULL) + { + strcpy((char*) &(pSelfParam->shmMsg.msgBody.monitor.data), tacSINK_MONITOR_DEFAULT_DB_POINT); + } + else + { + strcpy((char*) &(pSelfParam->shmMsg.msgBody.monitor.data), *((char**) &(pSelfParam->dbPoint))); + } + + printf("tacSinkMonitorBlockConstructor - Attach to %s\n",(char*) &(pSelfParam->shmMsg.msgBody.monitor.data)); + + /* Send message */ + tacShMsgQSendBgInfo(&(pSelfParam->shmMsg)); + + /* Initialize the message parameters */ + pSelfParam->shmMsg.type = tacSHMSG_MONITOR_DATA; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + pSelfParam->shmMsg.msgBody.monitor.data.number = pSelfParam->inputNb; + + /* The output port is used to average the inputs over the reporting period */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pSelf->output[arrayIndex] = 0.0; + } + + return OK; +} + +STATUS tacSinkMonitorStateBlockConstructor (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = NULL; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = NULL; + unsigned short arrayIndex = 0; + + /* Check that the expected number of parameters has been received */ + if (parameter->number < tacSINK_DEFAULT_EXPECTED_PARAM) + { + char errorParam[40]; + + sprintf(errorParam, "Expected %d, received %d", tacSINK_DEFAULT_EXPECTED_PARAM, parameter->number); + tacRTC_ERR(tacERR_PARAM_NUMBER, errorParam); + return ERROR; + } + + /* Check that the parameters are valid */ + pRealParam = (double*) parameter->buffer; + + /* Passed parameter is the sampling period of the block */ + if (pRealParam[tacSINK_SAMPLING_PERIOD] < (*pSelf->shared).samplingPeriod) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = (*pSelf->shared).samplingPeriod; + } + + if (pRealParam[tacSINK_SAMPLING_PERIOD] < tacSINK_MONITOR_MIN_SAMPLING_PERIOD) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = tacSINK_MONITOR_MIN_SAMPLING_PERIOD; + } + + /* Number of inputs is minimum 1 up to tacMSG_MAX_DATA_NUMBER */ + if ((pRealParam[tacSINK_INPUT_NUMBER] < 1) || + (pRealParam[tacSINK_INPUT_NUMBER] > tacMAX_DATA_NUMBER)) + { + tacRTC_ERR(tacERR_PARAM_INVALID, ""); + return ERROR; + } + + /* Call common constructor */ + if (tacSinkCommonBlockConstructor(pSelf, error) != OK) + { + return ERROR; + } + + /* Store parameters */ + pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* + * Compute the rate at which data has to be processed - divide and take + * the integer part of the result + */ + + pSelfParam->rate = (unsigned short) (pRealParam[tacSINK_SAMPLING_PERIOD] / (*pSelf->shared).samplingPeriod); + pSelfParam->counter = 0; /* Decimation counter */ + pSelfParam->inputNb = (unsigned short) pRealParam[tacSINK_INPUT_NUMBER]; + + /* Optional parameter is an application-specific DB point */ + if (parameter->number == tacSINK_DEFAULT_EXPECTED_PARAM + 1) + { + printf("tacSinkMonitorStateBlockConstructor - DB point %s\n",(char*) &(pRealParam[tacSINK_MONITOR_DB_POINT])); + pSelfParam->dbPoint = (char*) malloc(tacSINK_MONITOR_MAX_DB_ADDR_SIZE); + strcpy(pSelfParam->dbPoint, (char*) &(pRealParam[tacSINK_MONITOR_DB_POINT])); + } + else + { + printf("tacSinkMonitorStateBlockConstructor - Default DB point\n"); + pSelfParam->dbPoint = NULL; + } + + /* Specify the number of input signals to attach to become resolved */ + tacStdBlockSetInputNumber(pSelf, pSelfParam->inputNb); + + /* + * Perform other block initialization operations + */ + + /* Create the block internal message queue which tosses the messages out of the + * interrupt context. They are buffered in the queue until the DPC tasks + * picks them up and sends them over the shared memory message queue. + * Sorry for that double-queuing, that's because of the M-S architecture */ + + pSelfParam->msgq = msgQCreate(tacSINK_MONITOR_QUEUE_SIZE, sizeof(tacSHMSG), 0); + if ( pSelfParam->msgq == NULL ) + { + char errorParam[40]; + + sprintf(errorParam, "Could not create probe block message queue"); + tacRTC_ERR(tacERR_MALLOC, errorParam); + return ERROR; + } + + /* will count if a message can't be pushed in the queue */ + pSelfParam->lost = 0; + + /* Warn the background task that a new probe block has been created */ + pSelfParam->shmMsg.type = tacSHMSG_ADD_MONITOR; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + + if (pSelfParam->dbPoint == NULL) + { + strcpy((char*) &(pSelfParam->shmMsg.msgBody.monitor.data), tacSINK_MONITOR_DEFAULT_DB_POINT); + } + else + { + strcpy((char*) &(pSelfParam->shmMsg.msgBody.monitor.data), *((char**) &(pSelfParam->dbPoint))); + } + + printf("tacSinkMonitorStateBlockConstructor - Attach to %s\n",(char*) &(pSelfParam->shmMsg.msgBody.monitor.data)); + + /* Send message */ + tacShMsgQSendBgInfo(&(pSelfParam->shmMsg)); + + /* Initialize the message parameters */ + pSelfParam->shmMsg.type = tacSHMSG_MONITOR_DATA; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + pSelfParam->shmMsg.msgBody.monitor.data.number = pSelfParam->inputNb; + + /* Init output port which won't be used to average the inputs over the reporting period */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pSelf->output[arrayIndex] = 0.0; + } + + return OK; +} + +STATUS tacSinkProbeBlockCommonConstructor (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + double minPeriod, + tacERROR* error) +{ + double* pRealParam = NULL; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = NULL; + + /* Check that the expected number of parameters has been received */ + if (parameter->number < tacSINK_DEFAULT_EXPECTED_PARAM) + { + char errorParam[40]; + + sprintf(errorParam, "Expected %d, received %d", tacSINK_DEFAULT_EXPECTED_PARAM, parameter->number); + tacRTC_ERR(tacERR_PARAM_NUMBER, errorParam); + return ERROR; + } + + /* Check that the parameters are valid */ + pRealParam = (double*) parameter->buffer; + + /* Passed parameter is the sampling period of the block */ + if (pRealParam[tacSINK_SAMPLING_PERIOD] < (*pSelf->shared).samplingPeriod) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = (*pSelf->shared).samplingPeriod; + } + + if (pRealParam[tacSINK_SAMPLING_PERIOD] < minPeriod) + { + pRealParam[tacSINK_SAMPLING_PERIOD] = minPeriod; + } + + /* Number of inputs is minimum 1 up to tacMSG_MAX_DATA_NUMBER */ + if ((pRealParam[tacSINK_INPUT_NUMBER] < 1) || + (pRealParam[tacSINK_INPUT_NUMBER] > tacMAX_DATA_NUMBER)) + { + tacRTC_ERR(tacERR_PARAM_INVALID, ""); + return ERROR; + } + + /* Call common constructor */ + if (tacSinkCommonBlockConstructor(pSelf, error) != OK) + { + return ERROR; + } + + /* Store parameters */ + pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* + * Compute the rate at which data has to be processed - divide and take + * the integer part of the result + */ + + pSelfParam->rateParam = pRealParam[tacSINK_SAMPLING_PERIOD]; + pSelfParam->rate = (unsigned short) (pRealParam[tacSINK_SAMPLING_PERIOD] / (*pSelf->shared).samplingPeriod); + pSelfParam->counter = 0; /* Decimation counter */ + pSelfParam->inputNb = (unsigned short) pRealParam[tacSINK_INPUT_NUMBER]; + + /* Specify the number of input signals to attach to become resolved */ + tacStdBlockSetInputNumber(pSelf, pSelfParam->inputNb); + + /* + * Perform other block initialization operations + */ + + /* Create the block internal message queue which gets the messages out of the + * interrupt context. They are buffered in the queue until the DPC tasks + * picks them up and sends them over the shared memory message queue. + * Sorry for that double-queuing, that's because of the M-S architecture */ + + /* There is only one message queue for all probe blocks! */ + pSelfParam->msgq = msgQCreate(tacSINK_PROBE_QUEUE_SIZE, sizeof(tacSHMSG), 0); + if ( pSelfParam->msgq == NULL ) + { + char errorParam[40]; + + sprintf(errorParam, "Could not create probe block message queue"); + tacRTC_ERR(tacERR_MALLOC, errorParam); + return ERROR; + } + + /* will count if a message can't be pushed in the queue */ + pSelfParam->lost = 0; + + /* Warn the background task that a new probe block has been created */ + pSelfParam->shmMsg.type = tacSHMSG_ADD_PROBE; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + + /* Send message */ + tacShMsgQSendDataSample(&pSelfParam->shmMsg); + + /* Initialize the message parameters */ + pSelfParam->shmMsg.type = tacSHMSG_TRANSFER_DATA; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + pSelfParam->shmMsg.msgBody.monitor.data.number = pSelfParam->inputNb; + + return OK; +} + +/* Probe block has a max. sampling frequency of 2kHz */ +STATUS tacSinkProbeBlockConstructor (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + return tacSinkProbeBlockCommonConstructor (pSelf, parameter, tacSINK_PROBE_MIN_SAMPLING_PERIOD, error); +} + +/* Fast probe is the same as probe but not does have the + * limitation on the max. recording frequency */ +STATUS tacSinkFastProbeBlockConstructor (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + return tacSinkProbeBlockCommonConstructor (pSelf, parameter, 0.0, error); +} + +void tacSinkProbeBlockReset (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = + (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* + * Re-Compute the rate at which data has to be processed + */ + if (pSelfParam->rateParam < (*pSelf->shared).samplingPeriod ) + { + pSelfParam->rate = 1; + } + else + { + pSelfParam->rate = (unsigned short) + (pSelfParam->rateParam / (*pSelf->shared).samplingPeriod); + } + + return; +} + +/* + * Report parameters Hooks + */ + +STATUS tacSinkDisplayBlockGetParameter (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = (double*) parameter->buffer; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Send back the expected number of parameters */ + parameter->number = tacSINK_ONE_EXPECTED_PARAM; + + /* Report current parameters */ + pRealParam[tacSINK_SAMPLING_PERIOD] = (double) (pSelfParam->rate * (*pSelf->shared).samplingPeriod); + + return OK; +} + +STATUS tacSinkMonitorBlockGetParameter (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = (double*) parameter->buffer; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Send back the expected number of parameters */ + parameter->number = tacSINK_DEFAULT_EXPECTED_PARAM; + + /* Report current parameters */ + pRealParam[tacSINK_SAMPLING_PERIOD] = (double) (pSelfParam->rate * (*pSelf->shared).samplingPeriod); + pRealParam[tacSINK_INPUT_NUMBER] = (double) pSelfParam->inputNb; + + if (*((char**) &(pSelfParam->dbPoint)) != NULL) + { + parameter->number += 1; + parameter->type[tacSINK_MONITOR_DB_POINT] = tacPARAM_STRING; + strcpy((char*) &(pRealParam[tacSINK_MONITOR_DB_POINT]), *((char**) &(pSelfParam->dbPoint))); + } + + return OK; +} + +STATUS tacSinkMonitorStateBlockGetParameter (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = (double*) parameter->buffer; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Send back the expected number of parameters */ + parameter->number = tacSINK_DEFAULT_EXPECTED_PARAM; + + /* Report current parameters */ + pRealParam[tacSINK_SAMPLING_PERIOD] = (double) (pSelfParam->rate * (*pSelf->shared).samplingPeriod); + pRealParam[tacSINK_INPUT_NUMBER] = (double) pSelfParam->inputNb; + + if (*((char**) &(pSelfParam->dbPoint)) != NULL) + { + parameter->number += 1; + parameter->type[tacSINK_MONITOR_DB_POINT] = tacPARAM_STRING; + strcpy((char*) &(pRealParam[tacSINK_MONITOR_DB_POINT]), *((char**) &(pSelfParam->dbPoint))); + } + + return OK; +} + +STATUS tacSinkProbeBlockGetParameter (tacSTDBLOCK* pSelf, + tacSTDBLOCK_PARAM* parameter, + tacERROR* error) +{ + double* pRealParam = (double*) parameter->buffer; + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Send back the expected number of parameters */ + parameter->number = tacSINK_DEFAULT_EXPECTED_PARAM; + + /* Report current parameters */ + pRealParam[tacSINK_SAMPLING_PERIOD] = (double) (pSelfParam->rate * (*pSelf->shared).samplingPeriod); + pRealParam[tacSINK_INPUT_NUMBER] = (double) pSelfParam->inputNb; + + return OK; +} + +/* + * Change parameters Hooks + */ + +/* + * Algorithm Hooks + */ + +void tacSinkDisplayBlockAlgorithm (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + if ((pSelfParam->counter % pSelfParam->rate) == 0) /* It's time to process data */ + { + sprintf(logStr,"Name: %s Time: %ld.%6ld Value: %g\n", + pSelf->name, + (*pSelf->shared).currentTime.seconds, + (*pSelf->shared).currentTime.microsec, + tacStdBlockGetInput(pSelf,0)); + + tacDpcPushRequest((tacVOIDFCTPTR) &printf, logStr); + + pSelfParam->counter = 0; + } + + pSelfParam->counter++; +} + +void tacSinkMonitorBlockAlgorithm (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + unsigned short arrayIndex = 0; + + /* The output port is used to average the inputs over the reporting period */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pSelf->output[arrayIndex] += tacStdBlockGetInput(pSelf,arrayIndex); + } + + if ((pSelfParam->counter % pSelfParam->rate) == 0) /* It's time to process data */ + { + tacDATA* pData = &(pSelfParam->shmMsg.msgBody.monitor.data); /* We are only interested in message body */ + + /* pData->number = pSelfParam->inputNb; */ + pData->timeStamp = (*pSelf->shared).currentTime; + + /* pData points to the body of the Message */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pData->buffer[arrayIndex] = pSelf->output[arrayIndex] / pSelfParam->rate; + } + + /* Push message into probe block's message que to get the + * data out of the interrupt comtext. */ + if ( msgQSend (pSelfParam->msgq, (char*) &(pSelfParam->shmMsg), sizeof(tacSHMSG), NO_WAIT, 0) != OK ) + { + (pSelfParam->lost)++; + } + + /* Defer procedure call */ + tacDpcPushRequest((tacVOIDFCTPTR) &tacSinkSendMonitorMessage, &pSelfParam->msgq); + + pSelfParam->counter = 0; + + /* The output port is used to average the inputs over the reporting period */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pSelf->output[arrayIndex] = 0.0; + } + } + + pSelfParam->counter++; +} + +void tacSinkMonitorStateBlockAlgorithm (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + unsigned short arrayIndex = 0; + + if ((pSelfParam->counter % pSelfParam->rate) == 0) /* It's time to process data */ + { + tacDATA* pData = &(pSelfParam->shmMsg.msgBody.monitor.data); /* We are only interested in message body */ + + /* pData->number = pSelfParam->inputNb; */ + pData->timeStamp = (*pSelf->shared).currentTime; + + /* pData points to the body of the Message */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pData->buffer[arrayIndex] = tacStdBlockGetInput(pSelf,arrayIndex); + } + + /* Push message into probe block's message que to get the + * data out of the interrupt comtext. */ + if ( msgQSend (pSelfParam->msgq, (char*) &(pSelfParam->shmMsg), sizeof(tacSHMSG), NO_WAIT, 0) != OK ) + { + (pSelfParam->lost)++; + } + + /* Defer procedure call */ + tacDpcPushRequest((tacVOIDFCTPTR) &tacSinkSendMonitorMessage, &pSelfParam->msgq); + + pSelfParam->counter = 0; + } + + pSelfParam->counter++; +} + +void tacSinkProbeBlockAlgorithm (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + unsigned short arrayIndex = 0; + + if ((pSelfParam->counter % pSelfParam->rate) == 0) /* It's time to process data */ + { + tacDATA* pData = &(pSelfParam->shmMsg.msgBody.monitor.data); /* We are only interested in message body */ + + pData->timeStamp = (*pSelf->shared).currentTime; + + /* pData points to the body of the Message */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pData->buffer[arrayIndex] = tacStdBlockGetInput(pSelf,arrayIndex); + } + + /* Push message into probe block's message que to get the + * data out of the interrupt comtext. */ + if ( msgQSend (pSelfParam->msgq, (char*) &(pSelfParam->shmMsg), sizeof(tacSHMSG), NO_WAIT, 0) != OK ) + { + (pSelfParam->lost)++; + } + + /* Defer procedure call: + * tacSinkSendProbeMessage is called outside the interrupt routine + * and will take care to pick up the message from the probe block's + * message queue and send it over the shared memory message queue */ + tacDpcPushRequest((tacVOIDFCTPTR) &tacSinkSendProbeMessage, &pSelfParam->msgq); + + pSelfParam->counter = 0; + } + + pSelfParam->counter++; +} + +/* + * Reset Hooks + */ + +/* + * Stop Hooks + */ + +/* + * Destructor Hooks + */ + +/* + * Note: This destructor is used mainly to send a MONITOR message containing + * 0.0 in order to reset the database array (otherwise going from an + * algorithm with 4 monitored data to one with 3 monitored data leaves + * the 4th value equal to the last ...) + */ + +void tacSinkMonitorBlockDestructor (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + tacDATA* pData = &(pSelfParam->shmMsg.msgBody.monitor.data); + unsigned short arrayIndex = 0; + + /* Reset DB values */ + pSelfParam->shmMsg.type = tacSHMSG_MONITOR_DATA; + pData = &(pSelfParam->shmMsg.msgBody.monitor.data); + + pData->number = pSelfParam->inputNb; + + /* pData points to the body of the Message */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pData->buffer[arrayIndex] = 0.0; + } + + /* Send message */ + tacShMsgQSendBgInfo(&pSelfParam->shmMsg); + + pSelfParam->shmMsg.type = tacSHMSG_REMOVE_MONITOR; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + + /* Send message */ + tacShMsgQSendBgInfo(&pSelfParam->shmMsg); + + free(pSelfParam->dbPoint); + + /* delete internal message queue. Do this as deferred procedure call + * to make sure it is only called when all messages have been send + * (through the same deferred call mechanism) */ + tacDpcPushRequest((tacVOIDFCTPTR) tacSinkDeleteMessageQueue, &(pSelfParam->msgq)); + + return; +} + +void tacSinkMonitorStateBlockDestructor (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + tacDATA* pData = &(pSelfParam->shmMsg.msgBody.monitor.data); + unsigned short arrayIndex = 0; + + /* Reset DB values */ + pSelfParam->shmMsg.type = tacSHMSG_MONITOR_DATA; + pData = &(pSelfParam->shmMsg.msgBody.monitor.data); + + pData->number = pSelfParam->inputNb; + + /* pData points to the body of the Message */ + for (arrayIndex = 0; arrayIndex < pSelfParam->inputNb; arrayIndex++) + { + pData->buffer[arrayIndex] = 0.0; + } + + /* Send message */ + tacShMsgQSendBgInfo(&pSelfParam->shmMsg); + + pSelfParam->shmMsg.type = tacSHMSG_REMOVE_MONITOR; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + + /* Send message */ + tacShMsgQSendBgInfo(&pSelfParam->shmMsg); + + free(pSelfParam->dbPoint); + + /* delete internal message queue. Do this as deferred procedure call + * to make sure it is only called when all messages have been send + * (through the same deferred call mechanism) */ + tacDpcPushRequest((tacVOIDFCTPTR) tacSinkDeleteMessageQueue, &(pSelfParam->msgq)); + + return; +} + +void tacSinkProbeBlockDestructor (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + pSelfParam->shmMsg.type = tacSHMSG_REMOVE_PROBE; + strcpy(pSelfParam->shmMsg.msgBody.monitor.name, pSelf->name); + + /* Send message */ + tacShMsgQSendDataSample(&pSelfParam->shmMsg); + + /* delete internal message queue. Do this as deferred procedure call + * to make sure it is only called when all messages have been send + * (through the same deferred call mechanism) */ + tacDpcPushRequest((tacVOIDFCTPTR) tacSinkDeleteMessageQueue, &(pSelfParam->msgq)); + + return; +} + +/* + * Show Hooks + */ + +void tacSinkDisplayBlockShow (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Print parameter values */ + printf(" Update rate: %d\n",pSelfParam->rate); + + return; +} + +void tacSinkMonitorBlockShow (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Print parameter values */ + printf(" Update rate: %d\n",pSelfParam->rate); + printf(" Number of input signals: %d\n",pSelfParam->inputNb); + printf(" Queued samples: %d\n", msgQNumMsgs(pSelfParam->msgq)); + printf(" Lost samples: %d\n",pSelfParam->lost); + + if (pSelfParam->dbPoint != NULL) + { + printf(" DB Point: %s\n", pSelfParam->dbPoint); + } + + return; +} + +void tacSinkMonitorStateBlockShow (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Print parameter values */ + printf(" Using MonitorState block, not averaging received data\n"); + printf(" Update rate: %d\n",pSelfParam->rate); + printf(" Number of input signals: %d\n",pSelfParam->inputNb); + printf(" Queued samples: %d\n", msgQNumMsgs(pSelfParam->msgq)); + printf(" Lost samples: %d\n",pSelfParam->lost); + + if (pSelfParam->dbPoint != NULL) + { + printf(" DB Point: %s\n", pSelfParam->dbPoint); + } + + return; +} + +void tacSinkProbeBlockShow (tacSTDBLOCK* pSelf) +{ + tacSINK_SCOPE_LOCAL_PARAMETER* pSelfParam = (tacSINK_SCOPE_LOCAL_PARAMETER*) pSelf->parameter; + + /* Print parameter values */ + printf(" Update rate: %d\n",pSelfParam->rate); + printf(" Update rate param (sec): %f\n",pSelfParam->rateParam); + printf(" Number of input signals: %d\n",pSelfParam->inputNb); + printf(" Queued samples: %d\n", msgQNumMsgs(pSelfParam->msgq)); + printf(" Lost samples: %d\n",pSelfParam->lost); + + return; +} + +/* + * Installation function + */ + +tacSTDBLOCK_TYPE tacSinkDisplayTypeInfo = { + "Display", + &tacSinkDisplayBlockConstructor, + &tacSinkDisplayBlockGetParameter, + &tacSinkDisplayBlockAlgorithm, + NULL, + NULL, + NULL, + NULL, + &tacSinkDisplayBlockShow, +}; + +tacSTDBLOCK_TYPE tacSinkMonitorTypeInfo = { + "Monitor", + &tacSinkMonitorBlockConstructor, + &tacSinkMonitorBlockGetParameter, + &tacSinkMonitorBlockAlgorithm, + NULL, + NULL, + NULL, + &tacSinkMonitorBlockDestructor, + &tacSinkMonitorBlockShow, +}; + +tacSTDBLOCK_TYPE tacSinkMonitorStateTypeInfo = { + "MonitorState", + &tacSinkMonitorStateBlockConstructor, + &tacSinkMonitorStateBlockGetParameter, + &tacSinkMonitorStateBlockAlgorithm, + NULL, + NULL, + NULL, + &tacSinkMonitorStateBlockDestructor, + &tacSinkMonitorStateBlockShow, +}; + +/* Probe with a maximal sampling rate of 2kHz */ +tacSTDBLOCK_TYPE tacSinkProbeTypeInfo = { + "Probe", + &tacSinkProbeBlockConstructor, + &tacSinkProbeBlockGetParameter, + &tacSinkProbeBlockAlgorithm, + NULL, + &tacSinkProbeBlockReset, + NULL, + &tacSinkProbeBlockDestructor, + &tacSinkProbeBlockShow, +}; + +/* Fast probe is the same as probe but not does have the + * limitation on the max. recording frequency */ +tacSTDBLOCK_TYPE tacSinkFastProbeTypeInfo = { + "FastProbe", + &tacSinkFastProbeBlockConstructor, + &tacSinkProbeBlockGetParameter, + &tacSinkProbeBlockAlgorithm, + NULL, + &tacSinkProbeBlockReset, + NULL, + &tacSinkProbeBlockDestructor, + &tacSinkProbeBlockShow, +}; + +STATUS tacSinkBlockInitAll (void) +{ + /* Install Sink Block Hooks */ + tacStdBlockInstallNewType(&tacSinkDisplayTypeInfo); + tacStdBlockInstallNewType(&tacSinkMonitorTypeInfo); + tacStdBlockInstallNewType(&tacSinkMonitorStateTypeInfo); + tacStdBlockInstallNewType(&tacSinkProbeTypeInfo); + tacStdBlockInstallNewType(&tacSinkFastProbeTypeInfo); + + /* + * Perform other library initialization operations + */ + + return OK; +} + +/* + * Local functions + */ + +/* + * Note: Routines called from within the algorithm must be declared with + * static __inline__ + */ + +STATUS tacSinkCommonBlockConstructor (tacSTDBLOCK* pSelf, + tacERROR* error) +{ + /* Allocate specific arrays (pointers are initialized to NULL by StdBlock) */ + if (tacStdBlockAllocateArrays(pSelf, 0, tacSINK_DEFAULT_INPUT_NUMBER, + tacSINK_DEFAULT_OUTPUT_NUMBER, error) == ERROR) + { + return ERROR; + } + + if (tacStdBlockAllocateArrayBySize(pSelf, tacSTDBLOCK_PARAM_ARRAY, + sizeof(tacSINK_SCOPE_LOCAL_PARAMETER), error) == ERROR) + { + tacStdBlockReleaseArray(pSelf, tacSTDBLOCK_INPUT_ARRAY, error); + tacStdBlockReleaseArray(pSelf, tacSTDBLOCK_OUTPUT_ARRAY, error); + return ERROR; + } + + /* Specify the number of input signals to attach to become resolved */ + tacStdBlockSetInputNumber(pSelf, tacSINK_ONE_INPUT_NUMBER); /* Required */ + + return OK; +} + +STATUS tacSinkSendMonitorMessage(MSG_Q_ID * msgq) +{ + /* Send message using provided function (different for Monitor and Probe blocks) */ + /* Send message using provided function (different for Monitor and Probe blocks) */ + tacSHMSG msg; + + if ( msgQReceive(*msgq, (char*) &msg, sizeof(tacSHMSG), NO_WAIT) == sizeof(tacSHMSG) ) + { + tacShMsgQSendBgInfo (&msg); + } + + return OK; +} + +STATUS tacSinkSendProbeMessage(MSG_Q_ID * msgq) +{ + /* Send message using provided function (different for Monitor and Probe blocks) */ + tacSHMSG msg; + + if ( msgq == NULL ) + { + return ERROR; + } + + if ( msgQReceive(*msgq, (char*) &msg, sizeof(tacSHMSG), NO_WAIT) == sizeof(tacSHMSG) ) + { + tacShMsgQSendDataSample (&msg); + } + return OK; +} + +STATUS tacSinkDeleteMessageQueue (MSG_Q_ID * msgq) +{ + /* Is called when block is destroyed and removes the internal message queue */ + STATUS status; + + status = msgQDelete (*msgq); + *msgq = NULL; + return status; +} + + +/*___oOo___*/ + + + + + + diff --git a/src/arguments.py b/src/arguments.py new file mode 100644 index 0000000..94e4cea --- /dev/null +++ b/src/arguments.py @@ -0,0 +1,26 @@ +import getopt + +def exitUsage(): + print("usage: %s <.tasrc file> -i -o " % sys.argv[0]) + sys.exit(1) + +def readArguments(args): + sourceDirectories = [] + outputFile = "" + try: + options, _ = getopt.getopt(args, "hi:o:") + except getopt.GetoptError: + exitUsage() + for option, arg in options: + if option == "-h": + exitUsage() + elif option == "-o": + outputFile = arg + elif option == "-i": + sourceDirectories.append(arg) + if outputFile == "": + exitUsage() + if len(sourceDirectories) == 0: + print("WARNING: no source directories specified!") + return outputFile, sourceDirectories + diff --git a/src/converter.py b/src/converter.py new file mode 100755 index 0000000..3e44058 --- /dev/null +++ b/src/converter.py @@ -0,0 +1,18 @@ +#!/usr/bin/python3 + +import sys + +import arguments +from tacsrc.tac import readTAC +import grc +import portNaming + +if __name__ == "__main__": + if len(sys.argv) == 1: + params.exitUsage() + inputFile = sys.argv[1] + outputFile, sourceDirectories = arguments.readArguments(sys.argv[2:]) + blocks, connections, blockTypes = readTAC(inputFile) + portNaming.resolvePortNames(blockTypes, sourceDirectories) + grc.write(outputFile, blocks, connections) + diff --git a/src/defaultBlockTypes.py b/src/defaultBlockTypes.py new file mode 100644 index 0000000..a7c7a7a --- /dev/null +++ b/src/defaultBlockTypes.py @@ -0,0 +1,74 @@ +from tacsrc.blockType import BlockType + +class VariablePorts: + def __init__(self, ioDescriptionName, sizeFunction): + self.ioDescriptionName = ioDescriptionName + self.sizeFunction = sizeFunction + + def mapName(self, position, name, index): + return + + def getRealPort(self, originalPort): + return 0 + + def ensureLength(self, length): + return + + def getIODescription(self, block): + return "\\\\n0:%s[%s]" % (self.ioDescriptionName, self.sizeFunction(block)) + + def getRealCount(self): + return 1 + +def inParameters(block): + return block.parameters[1] + +def parameterSize(block): + return len(block.parameters) + +monitor = BlockType("Monitor") +monitor.inputs = VariablePorts("input", inParameters) + +monitorState = BlockType("MonitorState") +monitorState.inputs = VariablePorts("input", inParameters) + +probe = BlockType("Probe") +probe.inputs = VariablePorts("input", inParameters) + +readRfm = BlockType("ReadRfm") +readRfm.outputs = VariablePorts("output", parameterSize) + +rms = BlockType("RMS") +rms.inputs.mapName(0, "input", 0) +rms.outputs.mapName(0, "output", 0) + +constant = BlockType("Constant") +constant.outputs.mapName(0, "CONST", 0) + +manual = BlockType("ManualSwitch") +manual.inputs.mapName(0, "input", 0) +manual.outputs.mapName(0, "output", 0) + +noise = BlockType("NormalNoise") +noise.outputs.mapName(0, "output", 0) + +writeRMNNoTim = BlockType("WriteRmNoTim") +writeRMNNoTim.inputs = VariablePorts("input", parameterSize) + +defaultBlockTypes = { + "Monitor": monitor, + "MonitorState": monitorState, + "Probe": probe, + "ReadRfm": readRfm, + "TIM": BlockType("TIM"), + "WAIT_RFM_INTERRUPT": BlockType("WAIT_RFM_INTERRUPT"), + "RMS": rms, + "Constant": constant, + "ManualSwitch": manual, + "NormalNoise": noise, + "WriteRmNoTim": writeRMNNoTim +} + +def addDefaultBlockTypes(blockTypes): + for key in defaultBlockTypes: + blockTypes[key] = defaultBlockTypes[key] diff --git a/src/grc.py b/src/grc.py new file mode 100644 index 0000000..ed02659 --- /dev/null +++ b/src/grc.py @@ -0,0 +1,94 @@ +GRC_TEMPLATE = ''' +options: + parameters: + title: 'TASRC to GRC converter output' + states: + coordinate: [-100, -100] + +blocks: +%s + +connections: +%s + +metadata: + file_format: 1 +''' + +BLOCK_TEMPLATE = ''' +- name: %s + id: epy_block + parameters: + _source_code: "from gnuradio import gr\\nimport numpy as np\\nclass BLOCK(gr.sync_block):\\n def __init__(self):\\n gr.sync_block.__init__(self,name='%s:%s%s',in_sig=%s,out_sig=%s)\\n def work(self, input_items, output_items):\\n return len(output_items[0])" + states: + coordinate: [%s, %s] +''' + +LINK_TEMPLATE = "- [%s, '%s', %s, '%s']\n" + +def getLongestDependencyRow(blocks, blockDependencies): + currentMax = 0 + for block in blocks: + current = getLongestDependencyRow(blockDependencies[block], blockDependencies) + 1 + if current > currentMax: + currentMax = current + return currentMax + +def getPosition(block, blockDependencies, reverseBlockDependencies, depths): + position = getLongestDependencyRow(blockDependencies[block], blockDependencies) + depths += [0] * (position+1 - len(depths)) + y = depths[position] + depths[position] += 50 # base offset + depths[position] += max( + (3+block.blockType.inputs.getRealCount()+block.blockType.outputs.getRealCount()) * 15, + max(block.blockType.inputs.getRealCount(), block.blockType.outputs.getRealCount()) * 30) + return position * 300, y + +def getBlockDependencies(blocks, links): + blockDependencies = {} + for block in blocks: + blockDependencies[block] = [] + for link in links: + if link.toBlock == block: + blockDependencies[block].append(link.fromBlock) + reverseBlockDependencies = {} + for block in blockDependencies: + for dependency in blockDependencies[block]: + if not dependency in reverseBlockDependencies: + reverseBlockDependencies[dependency] = [] + reverseBlockDependencies[dependency].append(block) + return blockDependencies, reverseBlockDependencies + +def getBlocksContent(blocks, links): + blockDependencies, reverseBlockDependencies = getBlockDependencies(blocks, links) + depths = [] + blocksContent = "" + for block in blocks: + description = block.blockType.getIODescription(block) + inputs = "[%s]" % ", ".join(["np.int8"] * block.blockType.inputs.getRealCount()) + outputs = "[%s]" % ", ".join(["np.int8"] * block.blockType.outputs.getRealCount()) + position = getPosition(block, blockDependencies, reverseBlockDependencies, depths) + blocksContent += BLOCK_TEMPLATE % ( + block.name, + block.name, + block.blockType.name, + description, + inputs, + outputs, + position[0], + position[1]) + return blocksContent + +def getLinksContent(links): + linksContent = "" + for link in links: + fromPort = link.fromBlock.blockType.outputs.getRealPort(link.fromPort) + toPort = link.toBlock.blockType.inputs.getRealPort(link.toPort) + linksContent += LINK_TEMPLATE % (link.fromBlock.name, fromPort, link.toBlock.name, toPort) + return linksContent + +def write(filename, blocks, links): + with open(filename, "w+") as file: + print("writing to file %s" % filename) + file.truncate(0) + file.write(GRC_TEMPLATE % (getBlocksContent(blocks, links), getLinksContent(links))) diff --git a/src/portNaming.py b/src/portNaming.py new file mode 100644 index 0000000..62be549 --- /dev/null +++ b/src/portNaming.py @@ -0,0 +1,104 @@ +import re +import os +import json +from defaultBlockTypes import defaultBlockTypes + +INPUT_FUNCTIONS = [ + "tacStdBlockGetInput", + "tacGraviMatrixGetPointerInput" + ] + +OUTPUT_FUNCTIONS = [ + "tacStdBlockSetOutput", + "tacGraviMatrixSetPointerOutput" + ] + +def getFiles(blockType, sourceDirectories): + files = [] + for sourceDirectory in sourceDirectories: + files += ["%s/%s" % (data[0], file) + for data in os.walk(sourceDirectory) + for file in data[2] if re.match(".*tac%sBlock.c" % blockType.name.replace("Rm", "Rmn"), file) != None] + return files + +def resolvePortNames(blockTypes, sourceDirectories): + missingBlocks = [] + multipleDefinitions = [] + for blockType in blockTypes: + if blockType.name in defaultBlockTypes: + continue + files = getFiles(blockType, sourceDirectories) + if len(files) == 0: + print("WARNING: no source file for block type %s found" % blockType.name) + missingBlocks.append(blockType.name) + continue + if len(files) > 1: + multipleDefinitions.append(blockType.name) + print("WARNING: more than one matching source file for block type %s found, skipping" % blockType.name) + continue + print("reading file %s" % files[0]) + with open(files[0], "r") as file: + content = "\n".join(file.readlines()) + for function in INPUT_FUNCTIONS: + mapInputs(content, function, blockType.inputs) + for function in OUTPUT_FUNCTIONS: + mapOutputs(content, function, blockType.outputs) + for entry in re.findall("\\w+ *= *\\*?\\(?pSelf->input\\[\\d+\\]\\)?", content): + name = re.search("^\\w+", entry).group() + position = int(re.search("(?<=\\[)\\d+(?=\\])", entry).group()) + blockType.inputs.mapName(position, name, 0) + for entry in re.findall("pSelf->output\\[\\d+\\] *= *\\w+", content): + name = re.search("\\w+$", entry).group() + position = int(re.search("(?<=\\[)\\d+(?=\\])", entry).group()) + blockType.outputs.mapName(position, name, 0) + if not os.path.exists("errors.json") or os.stat("errors.json").st_size == 0: + content = {"missing_blocks": [], "multiple_definitions": []} + else: + with open("errors.json", "r") as file: + content = json.load(file) + with open("errors.json", "w+") as file: + for blockTypeName in missingBlocks: + if not blockTypeName in content["missing_blocks"]: + content["missing_blocks"].append(blockTypeName) + for blockTypeName in multipleDefinitions: + if not blockTypeName in content["multiple_definitions"]: + content["multiple_definitions"].append(blockTypeName) + json.dump(content, file, indent=2) + file.close() + +def mapInputs(content, function, ports): + for entry in re.findall("\\w+ *= *%s\\(pSelf *, *\\d+\\);" % function, content): + name = re.search("^\\w+", entry).group() + position = int(re.search("\\d+(?= *\\) *;)", entry).group()) + ports.mapName(position, name, 0) + for entry in re.findall("\\w+->\\w+\\[\\d+\\] *= *%s\\(pSelf *, *\\d+\\);" % function, content): + name = re.search("(?<=\\->)\\w+", entry).group() + position = int(re.search("\\d+(?= *\\) *;)", entry).group()) + index = int(re.search("(?<=\\[)\\d+(?=\\])", entry).group()) + ports.mapName(position, name, index) + for entry in re.findall("\\w+\\[\\d+\\] *= *%s\\(pSelf *, *\\d+\\);" % function, content): + name = re.search("^\\w+", entry).group() + position = int(re.search("\\d+(?= *\\) *;)", entry).group()) + index = int(re.search("(?<=\\[)\\d+(?=\\])", entry).group()) + ports.mapName(position, name, index) + +def mapOutputs(content, function, ports): + for entry in re.findall("%s\\(pSelf *, *\\d+ *, *pSelfParam->\\w+\\);" % function, content): + name = re.search("\\w+(?=\\);$)", entry).group() + position = int(re.search("\\d+(?= *, *pSelfParam->\\w+\\);$)", entry).group()) + ports.mapName(position, name, 0) + for entry in re.findall("%s\\(pSelf *, *\\d+ *, *\\w+\\[\\d+\\]\\);" % function, content): + name = re.search("\\w+(?=\\[\\d+\\]\\);$)", entry).group() + position = int(re.search("\\d+(?= *, *\\w+\\[\\d+\\]\\);$)", entry).group()) + index = int(re.search("(?<=\\[)\\d+(?=\\])", entry).group()) + ports.mapName(position, name, index) + for entry in re.findall("%s\\(pSelf *, *\\d+ *, *pSelfParam->\\w+\\[\\d+\\]\\);" % function, content): + name = re.search("(?<=\\->)\\w+", entry).group() + position = int(re.search("\\d+(?= *, *pSelfParam->\\w+\\[\\d+\\]\\);$)", entry).group()) + index = int(re.search("(?<=\\[)\\d+(?=\\]\\);$)", entry).group()) + ports.mapName(position, name, index) + for entry in re.findall("%s\\(pSelf *, *\\d+ *, *\\w+\\);" % function, content): + name = re.search("\\w+(?= *\\);$)", entry).group() + position = int(re.search("\\d+(?= *, *\\w+\\);$)", entry).group()) + index = 0 + ports.mapName(position, name, index) diff --git a/src/tacsrc/block.py b/src/tacsrc/block.py new file mode 100644 index 0000000..737d9f1 --- /dev/null +++ b/src/tacsrc/block.py @@ -0,0 +1,6 @@ +class Block: + def __init__(self): + self.name = "" + self.blockType = None + self.parameters = [] + diff --git a/src/tacsrc/blockType.py b/src/tacsrc/blockType.py new file mode 100644 index 0000000..8930836 --- /dev/null +++ b/src/tacsrc/blockType.py @@ -0,0 +1,19 @@ +from tacsrc.ports import Ports + +class BlockType: + def __init__(self, name): + self.name = name + self.inputs = Ports() + self.outputs = Ports() + + def getIODescription(self, block): + result = "" + inputDescription = self.inputs.getIODescription(block) + if len(inputDescription) != 0: + result += "\\\\nINPUTS:" + result += inputDescription + outputDescription = self.outputs.getIODescription(block) + if len(outputDescription) != 0: + result += "\\\\nOUTPUTS:" + result += outputDescription + return result diff --git a/src/tacsrc/link.py b/src/tacsrc/link.py new file mode 100644 index 0000000..d89b459 --- /dev/null +++ b/src/tacsrc/link.py @@ -0,0 +1,6 @@ +class Link: + def __init__(self): + self.fromBlock = None + self.fromPort = 0 + self.toBlock = None + self.toPort = 0 diff --git a/src/tacsrc/ports.py b/src/tacsrc/ports.py new file mode 100644 index 0000000..4b26f22 --- /dev/null +++ b/src/tacsrc/ports.py @@ -0,0 +1,47 @@ +class Ports: + def __init__(self): + self.labels = [] + self.labelSizes = {} + + def mapName(self, position, name, index): + self.labels += [0] * (position+1 - len(self.labels)) + self.labels[position] = name + if not name in self.labelSizes: + self.labelSizes[name] = 0 + self.labelSizes[name] = max(self.labelSizes[name], index+1) + + def getRealPort(self, originalPort): + labelsDone = [] + for i in range(min(len(self.labels),originalPort)): + label = self.labels[i] + if label != 0 and label in labelsDone: + continue + labelsDone.append(label) + return len(labelsDone) - 1 + + def getIODescription(self, block): + result = "" + labelsDone = [] + for i in range(len(self.labels)): + label = self.labels[i] + if label != 0 and label in labelsDone: + continue + labelsDone.append(label) + if label == 0: + result += "\\\\n%s: unknown" % i + elif self.labelSizes[label] == 1: + result += "\\\\n%s: %s" % (i, label) + else: + result += "\\\\n%s: %s[%s]" % (i, label, self.labelSizes[label]) + return result + + def ensureLength(self, count): + self.labels += [0] * (count - len(self.labels)) + + def getRealCount(self): + labelsDone = [] + for label in self.labels: + if label != 0 and label in labelsDone: + continue + labelsDone.append(label) + return len(labelsDone) diff --git a/src/tacsrc/tac.py b/src/tacsrc/tac.py new file mode 100644 index 0000000..1428e4b --- /dev/null +++ b/src/tacsrc/tac.py @@ -0,0 +1,98 @@ +from defaultBlockTypes import addDefaultBlockTypes +from tacsrc.block import Block +from tacsrc.blockType import BlockType +from tacsrc.link import Link + +import re + +def addBlockType(blockTypes, blockType): + if not BlockType in blockTypes: + blockTypes[blockTypes] = BlockType(blockType) + +def setBlockType(blockIndex, blockTypeName, blocks, blockTypes): + if not blockTypeName in blockTypes: + blockTypes[blockTypeName] = BlockType(blockTypeName) + blocks += [0] * (blockIndex - len(blocks) + 1) + if blocks[blockIndex] == 0: + blocks[blockIndex] = Block() + blocks[blockIndex].blockType = blockTypes[blockTypeName] + +def setBlockName(blockIndex, blockName, blocks): + blocks += [0] * (blockIndex - len(blocks) + 1) + if blocks[blockIndex] == 0: + blocks[blockIndex] = Block() + blocks[blockIndex].name = blockName + +def setBlockParameters(blockIndex, blockParameters, blocks): + blocks += [0] * (blockIndex - len(blocks) + 1) + if blocks[blockIndex] == 0: + blocks[blockIndex] = Block() + blocks[blockIndex].parameters = blockParameters.split(',') + +def ensureLinks(linkIndex, links): + links += [None] * (linkIndex + 1 - len(links)) + if links[linkIndex] == None: + links[linkIndex] = Link() + +def setLinkSourceBlock(linkIndex, sourceBlock, links): + ensureLinks(linkIndex, links) + links[linkIndex].fromBlock = sourceBlock + +def setLinkSourcePort(linkIndex, sourcePort, links): + ensureLinks(linkIndex, links) + links[linkIndex].fromPort = sourcePort + +def setLinkDestinationBlock(linkIndex, destinationBlock, links): + ensureLinks(linkIndex, links) + links[linkIndex].toBlock = destinationBlock + +def setLinkDestinationPort(linkIndex, destinationPort, links): + ensureLinks(linkIndex, links) + links[linkIndex].toPort = destinationPort + +def readTAC(filename): + blockTypes = {} + addDefaultBlockTypes(blockTypes) + blocks = [] + links = [] + # make sure all blocks have been declared before the links are read + linkLines = [] + print("reading file %s" % filename) + with open(filename, "r") as file: + content = file.readlines() + for line in content: + if len(line) == 0: + continue + if re.match("TAC\\.LINK.*", line): + linkLines.append(line) + if not re.match("TAC\\.BLOCK.*", line): + continue + blockIndex = int(re.search("(?<=TAC\\.BLOCK)\\d+", line).group()) + if re.match("TAC\\.BLOCK\\d+\\.TYPE \\w+", line): + setBlockType(blockIndex, re.search("\\w+$", line).group(), blocks, blockTypes) + elif re.match("TAC\\.BLOCK\\d+\\.NAME \\w+", line): + setBlockName(blockIndex, re.search("\\w+$", line).group(), blocks) + elif re.match("TAC\\.BLOCK\\d+\\.PARAM .+", line): + setBlockParameters(blockIndex, re.search("(?<=\\.PARAM ).*$", line).group(), blocks) + blocksByName = {} + for block in blocks: + blocksByName[block.name] = block + for line in linkLines: + linkIndex = int(re.search("(?<=TAC\\.LINK)\\d+", line).group()) + if re.match("TAC\\.LINK\\d+\\.SOURCE\\.NAME \\w+", line): + sourceBlockName = re.search("\\w+$", line).group() + sourceBlock = blocksByName[sourceBlockName] + setLinkSourceBlock(linkIndex, sourceBlock, links) + elif re.match("TAC\\.LINK\\d+\\.SOURCE\\.PORT \\d+", line): + sourcePort = int(re.search("\\d+$", line).group()) + setLinkSourcePort(linkIndex, sourcePort, links) + elif re.match("TAC\\.LINK\\d+\\.DEST\\.NAME \\w+", line): + destinationBlock = blocksByName[re.search("\\w+$", line).group()] + setLinkDestinationBlock(linkIndex, destinationBlock, links) + elif re.match("TAC\\.LINK\\d+\\.DEST\\.PORT \\d+", line): + destinationPort = int(re.search("\\d+$", line).group()) + setLinkDestinationPort(linkIndex, destinationPort, links) + for link in links: + link.fromBlock.blockType.outputs.ensureLength(link.fromPort) + link.toBlock.blockType.inputs.ensureLength(link.toPort) + return blocks, links, blockTypes.values() diff --git a/src/tacsrc/tacsrc.py b/src/tacsrc/tacsrc.py new file mode 100644 index 0000000..ec6fbb1 --- /dev/null +++ b/src/tacsrc/tacsrc.py @@ -0,0 +1,48 @@ +import re +from defaultBlockTypes import addDefaultBlockTypes + +from tacsrc.block import Block +from tacsrc.blockType import BlockType +from tacsrc.link import Link + +def readTASRC(inputFile): + blockTypes = {} + addDefaultBlockTypes(blockTypes) + blocks = {} + links = [] + # make sure all blocks have been declared before the links are read + linklines = [] + with open(inputFile, "r") as file: + content = file.readlines() + for l in content: + # clean up line, putting only a single space in every seperation + line = re.sub("(\\s+|, *)", ' ', l) + parts = line.split(' ') + if len(parts) == 0: + continue + if parts[0] == "TAC_BLOCK": + if not parts[2] in blockTypes: + blockTypes[parts[2]] = BlockType(parts[2]) + blocks[parts[1]] = Block( + parts[1], + blockTypes[parts[2]], + parts[3:-1] + ) + elif parts[0] == "TAC_LINK": + linklines.append(parts) + for parts in linklines: + # parts[1] is the link name and is not used + fromBlock = blocks[parts[2]] + fromPort = int(parts[3]) + toBlock = blocks[parts[4]] + toPort = int(parts[5]) + links.append(Link( + fromBlock, + fromPort, + toBlock, + toPort + )) + fromBlock.blockType.outputs.ensureLength(fromPort) + toBlock.blockType.inputs.ensureLength(toPort) + return blocks.values(), links, blockTypes.values() + diff --git a/test.sh b/test.sh new file mode 100755 index 0000000..c7c3876 --- /dev/null +++ b/test.sh @@ -0,0 +1,9 @@ +#/usr/bin/sh + +rm errors.json +mkdir out +rm out/*.grc + +for f in tacapp/*; do + src/converter.py $f -o out/$(basename $f).grc -i Sources; +done