Merge remote-tracking branch 'origin/develop' into develop-nr
Conflicts: ci-scripts/Jenkinsfile-gitlab ci-scripts/buildOnVM.sh ci-scripts/checkCodingFormattingRules.sh ci-scripts/createVM.sh ci-scripts/destroyAllRunningVM.sh ci-scripts/reportBuildLocally.sh cmake_targets/CMakeLists.txt cmake_targets/build_oai cmake_targets/tools/build_helper common/utils/LOG/log.h openair1/PHY/LTE_ESTIMATION/lte_sync_timefreq.c openair1/PHY/TOOLS/file_output.c openair1/PHY/TOOLS/lte_dfts.c openair1/PHY/TOOLS/tools_defs.h openair1/PHY/defs_eNB.h openair1/PHY/impl_defs_lte.h openair1/SCHED_UE/phy_procedures_lte_ue.c openair2/COMMON/platform_constants.h openair2/COMMON/platform_types.h openair2/LAYER2/MAC/eNB_scheduler.c openair2/LAYER2/MAC/main.c openair2/RRC/LTE/L2_interface.c openair2/RRC/LTE/MESSAGES/asn1_msg.c openair2/RRC/LTE/MESSAGES/asn1_msg_NB_IoT.c openair2/RRC/LTE/rrc_UE.c openair2/RRC/LTE/rrc_eNB.c openair2/RRC/LTE/rrc_eNB_S1AP.c openair2/UTIL/LOG/log.c openair3/S1AP/s1ap_common.h openair3/S1AP/s1ap_eNB.c openair3/S1AP/s1ap_eNB_context_management_procedures.c openair3/S1AP/s1ap_eNB_decoder.c openair3/S1AP/s1ap_eNB_decoder.h openair3/S1AP/s1ap_eNB_handlers.c openair3/S1AP/s1ap_eNB_nas_procedures.c openair3/S1AP/s1ap_eNB_overload.c openair3/S1AP/s1ap_eNB_trace.c openair3/TEST/EPC_TEST/play_scenario_decode.c openair3/TEST/EPC_TEST/play_scenario_s1ap.c openair3/TEST/EPC_TEST/play_scenario_s1ap_compare_ie.c targets/COMMON/openairinterface5g_limits.h targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.50PRB.usrpb210.conf targets/RT/USER/lte-ran.c targets/RT/USER/lte-ru.c targets/RT/USER/lte-ue.c targets/SIMU/USER/oaisim_functions.c
This commit is contained in:
@@ -29,18 +29,50 @@
|
||||
* \note
|
||||
* \warning
|
||||
*/
|
||||
#define _GNU_SOURCE
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include "config_userapi.h"
|
||||
|
||||
|
||||
void parse_stringlist(paramdef_t *cfgoptions, char *val)
|
||||
{
|
||||
char *atoken;
|
||||
char *tokctx;
|
||||
char *tmpval=strdup(val);
|
||||
int numelt=0;
|
||||
|
||||
cfgoptions->numelt=0;
|
||||
|
||||
atoken=strtok_r(tmpval, ",",&tokctx);
|
||||
while(atoken != NULL) {
|
||||
numelt++ ;
|
||||
atoken=strtok_r(NULL, ",",&tokctx);
|
||||
}
|
||||
free(tmpval);
|
||||
config_check_valptr(cfgoptions,(char **)&(cfgoptions->strlistptr), sizeof(char *) * numelt);
|
||||
cfgoptions->numelt=numelt;
|
||||
|
||||
atoken=strtok_r(val, ",",&tokctx);
|
||||
for( int i=0; i<cfgoptions->numelt && atoken != NULL ; i++) {
|
||||
config_check_valptr(cfgoptions,&(cfgoptions->strlistptr[i]),strlen(atoken)+1);
|
||||
sprintf(cfgoptions->strlistptr[i],"%s",atoken);
|
||||
printf_params("[LIBCONFIG] %s[%i]: %s\n", cfgoptions->optname,i,cfgoptions->strlistptr[i]);
|
||||
atoken=strtok_r(NULL, ",",&tokctx);
|
||||
}
|
||||
cfgoptions->numelt=numelt;
|
||||
}
|
||||
|
||||
int processoption(paramdef_t *cfgoptions, char *value)
|
||||
{
|
||||
char *tmpval = value;
|
||||
int optisset=0;
|
||||
char defbool[2]="1";
|
||||
|
||||
|
||||
if ( value == NULL) {
|
||||
if( (cfgoptions->paramflags &PARAMFLAG_BOOL) == 0 ) { /* not a boolean, argument required */
|
||||
fprintf(stderr,"[CONFIG] command line, option %s requires an argument\n",cfgoptions->optname);
|
||||
@@ -63,6 +95,7 @@ char defbool[2]="1";
|
||||
break;
|
||||
|
||||
case TYPE_STRINGLIST:
|
||||
parse_stringlist(cfgoptions,tmpval);
|
||||
break;
|
||||
case TYPE_UINT32:
|
||||
case TYPE_INT32:
|
||||
@@ -103,15 +136,15 @@ char defbool[2]="1";
|
||||
if (optisset == 1) {
|
||||
cfgoptions->paramflags = cfgoptions->paramflags | PARAMFLAG_PARAMSET;
|
||||
}
|
||||
|
||||
return optisset;
|
||||
}
|
||||
|
||||
int config_process_cmdline(paramdef_t *cfgoptions,int numoptions, char *prefix)
|
||||
{
|
||||
char **p = config_get_if()->argv;
|
||||
|
||||
|
||||
int c = config_get_if()->argc;
|
||||
int j;
|
||||
int i,j;
|
||||
char *pp;
|
||||
char *cfgpath;
|
||||
|
||||
@@ -122,42 +155,74 @@ char *cfgpath;
|
||||
return -1;
|
||||
}
|
||||
|
||||
j=0;
|
||||
p++;
|
||||
c--;
|
||||
while (c > 0 && *p != NULL) {
|
||||
if (strcmp(*p, "-h") == 0 || strcmp(*p, "--help") == 0 ) {
|
||||
config_printhelp(cfgoptions,numoptions);
|
||||
j = 0;
|
||||
i = 0;
|
||||
while (c > 0 ) {
|
||||
char *oneargv = strdup(config_get_if()->argv[i]); /* we use strtok_r which modifies its string paramater, and we don't want argv to be modified */
|
||||
/* first check help options, either --help, -h or --help_<section> */
|
||||
if (strncmp(oneargv, "-h",2) == 0 || strncmp(oneargv, "--help",6) == 0 ) {
|
||||
char *tokctx;
|
||||
pp=strtok_r(oneargv, "_",&tokctx);
|
||||
if (pp == NULL || strcasecmp(pp,config_get_if()->argv[i] ) == 0 ) {
|
||||
if( prefix == NULL) {
|
||||
config_printhelp(cfgoptions,numoptions);
|
||||
if ( ! ( CONFIG_ISFLAGSET(CONFIG_NOEXITONHELP)))
|
||||
exit_fun("[CONFIG] Exiting after displaying help\n");
|
||||
}
|
||||
} else {
|
||||
pp=strtok_r(NULL, " ",&tokctx);
|
||||
if ( prefix != NULL && pp != NULL && strncasecmp(prefix,pp,strlen(pp)) == 0 ) {
|
||||
printf ("Help for %s section:\n",prefix);
|
||||
config_printhelp(cfgoptions,numoptions);
|
||||
if ( ! (CONFIG_ISFLAGSET(CONFIG_NOEXITONHELP))) {
|
||||
fprintf(stderr,"[CONFIG] %s %i section %s:", __FILE__, __LINE__, prefix);
|
||||
exit_fun(" Exiting after displaying help\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (*p[0] == '-') {
|
||||
for(int i=0;i<numoptions;i++) {
|
||||
if ( ( cfgoptions[i].paramflags & PARAMFLAG_DISABLECMDLINE) != 0) {
|
||||
/* now, check for non help options */
|
||||
if (oneargv[0] == '-') {
|
||||
for(int n=0;n<numoptions;n++) {
|
||||
if ( ( cfgoptions[n].paramflags & PARAMFLAG_DISABLECMDLINE) != 0) {
|
||||
continue;
|
||||
}
|
||||
if (prefix != NULL) {
|
||||
sprintf(cfgpath,"%s.%s",prefix,cfgoptions[i].optname);
|
||||
sprintf(cfgpath,"%s.%s",prefix,cfgoptions[n].optname);
|
||||
} else {
|
||||
sprintf(cfgpath,"%s",cfgoptions[i].optname);
|
||||
sprintf(cfgpath,"%s",cfgoptions[n].optname);
|
||||
}
|
||||
|
||||
if ( ((strlen(*p) == 2) && (strcmp(*p + 1,cfgpath) == 0)) ||
|
||||
((strlen(*p) > 2) && (strcmp(*p + 2,cfgpath ) == 0 )) ) {
|
||||
pp = *(p+1);
|
||||
if ( ( pp != NULL ) && (c>1) && (pp[0]!= '-') ) {
|
||||
|
||||
j += processoption(&(cfgoptions[i]), pp);
|
||||
} else {
|
||||
j += processoption(&(cfgoptions[i]), NULL);
|
||||
}
|
||||
if ( ((strlen(oneargv) == 2) && (strcmp(oneargv + 1,cfgpath) == 0)) || /* short option, one "-" */
|
||||
((strlen(oneargv) > 2) && (strcmp(oneargv + 2,cfgpath ) == 0 )) ) {
|
||||
char *valptr=NULL;
|
||||
int ret;
|
||||
if (c > 0) {
|
||||
pp = config_get_if()->argv[i+1];
|
||||
if (pp != NULL ) {
|
||||
ret = strlen(pp);
|
||||
if (ret > 0 ) {
|
||||
if (pp[0] != '-')
|
||||
valptr=pp;
|
||||
else if ( ret > 1 && pp[0] == '-' && isdigit(pp[1]) )
|
||||
valptr=pp;
|
||||
}
|
||||
}
|
||||
}
|
||||
j += processoption(&(cfgoptions[n]), valptr);
|
||||
if ( valptr != NULL ) {
|
||||
i++;
|
||||
c--;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} /* for */
|
||||
} /* if (*p[0] == '-') */
|
||||
p++;
|
||||
} /* for n... */
|
||||
} /* if (oneargv[0] == '-') */
|
||||
free(oneargv);
|
||||
i++;
|
||||
c--;
|
||||
} /* fin du while */
|
||||
printf_cmdl("[CONFIG] %s %i options set from command line\n",((prefix == NULL) ? "":prefix),j);
|
||||
printf_cmdl("[CONFIG] %s %i options set from command line\n",((prefix == NULL) ? "(root)":prefix),j);
|
||||
free(cfgpath);
|
||||
return j;
|
||||
} /* parse_cmdline*/
|
||||
|
||||
@@ -97,7 +97,77 @@ int st;
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* from here: interface implementtion of the configuration module */
|
||||
int nooptfunc(void) {
|
||||
return 0;
|
||||
};
|
||||
|
||||
int config_cmdlineonly_getlist(paramlist_def_t *ParamList,
|
||||
paramdef_t *params, int numparams, char *prefix)
|
||||
{
|
||||
ParamList->numelt = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int config_cmdlineonly_get(paramdef_t *cfgoptions,int numoptions, char *prefix )
|
||||
{
|
||||
int defval;
|
||||
int fatalerror=0;
|
||||
int numdefvals=0;
|
||||
|
||||
|
||||
for(int i=0;i<numoptions;i++) {
|
||||
defval=0;
|
||||
switch(cfgoptions[i].type) {
|
||||
case TYPE_STRING:
|
||||
defval=config_setdefault_string(&(cfgoptions[i]), prefix);
|
||||
break;
|
||||
case TYPE_STRINGLIST:
|
||||
defval=config_setdefault_stringlist(&(cfgoptions[i]), prefix);
|
||||
break;
|
||||
case TYPE_UINT8:
|
||||
case TYPE_INT8:
|
||||
case TYPE_UINT16:
|
||||
case TYPE_INT16:
|
||||
case TYPE_UINT32:
|
||||
case TYPE_INT32:
|
||||
case TYPE_MASK:
|
||||
defval=config_setdefault_int(&(cfgoptions[i]), prefix);
|
||||
break;
|
||||
case TYPE_UINT64:
|
||||
case TYPE_INT64:
|
||||
defval=config_setdefault_int64(&(cfgoptions[i]), prefix);
|
||||
break;
|
||||
case TYPE_UINTARRAY:
|
||||
case TYPE_INTARRAY:
|
||||
defval=config_setdefault_intlist(&(cfgoptions[i]), prefix);
|
||||
break;
|
||||
case TYPE_DOUBLE:
|
||||
defval=config_setdefault_double(&(cfgoptions[i]), prefix);
|
||||
break;
|
||||
case TYPE_IPV4ADDR:
|
||||
defval=config_setdefault_ipv4addr(&(cfgoptions[i]), prefix);
|
||||
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr,"[CONFIG] %s.%s type %i not supported\n",prefix, cfgoptions[i].optname,cfgoptions[i].type);
|
||||
fatalerror=1;
|
||||
break;
|
||||
} /* switch on param type */
|
||||
if (defval == 1) {
|
||||
numdefvals++;
|
||||
cfgoptions[i].paramflags = cfgoptions[i].paramflags | PARAMFLAG_PARAMSETDEF;
|
||||
}
|
||||
} /* for loop on options */
|
||||
printf("[CONFIG] %s: %i/%i parameters successfully set \n",
|
||||
((prefix == NULL)?"(root)":prefix),
|
||||
numdefvals,numoptions );
|
||||
if (fatalerror == 1) {
|
||||
fprintf(stderr,"[CONFIG] fatal errors found when assigning %s parameters \n",
|
||||
prefix);
|
||||
}
|
||||
return numdefvals;
|
||||
}
|
||||
|
||||
configmodule_interface_t *load_configmodule(int argc, char **argv)
|
||||
{
|
||||
@@ -110,17 +180,19 @@ uint32_t tmpflags=0;
|
||||
int i;
|
||||
|
||||
/* first parse the command line to look for the -O option */
|
||||
opterr=0;
|
||||
for (i = 0;i<argc;i++) {
|
||||
if (strlen(argv[i]) < 2) continue;
|
||||
if ( argv[i][1] == 'O' && i < (argc -1)) {
|
||||
cfgparam = argv[i+1];
|
||||
}
|
||||
if ( argv[i][1] == 'h' ) {
|
||||
if ( strstr(argv[i], "help_config") != NULL ) {
|
||||
config_printhelp(Config_Params,CONFIG_PARAMLENGTH(Config_Params));
|
||||
exit(0);
|
||||
}
|
||||
if ( (strcmp(argv[i]+1, "h") == 0) || (strstr(argv[i]+1, "help_") != NULL ) ) {
|
||||
tmpflags = CONFIG_HELP;
|
||||
}
|
||||
}
|
||||
optind=1;
|
||||
|
||||
/* look for the OAI_CONFIGMODULE environement variable */
|
||||
if ( cfgparam == NULL ) {
|
||||
@@ -129,21 +201,25 @@ int i;
|
||||
|
||||
/* default */
|
||||
if (cfgparam == NULL) {
|
||||
tmpflags = tmpflags | CONFIG_NOOOPT;
|
||||
cfgparam = DEFAULT_CFGMODE ":" DEFAULT_CFGFILENAME;
|
||||
}
|
||||
tmpflags = tmpflags | CONFIG_NOOOPT;
|
||||
if (strstr(argv[0],"uesoftmodem") == NULL) {
|
||||
cfgparam = CONFIG_LIBCONFIGFILE ":" DEFAULT_CFGFILENAME;
|
||||
} else {
|
||||
cfgparam = CONFIG_CMDLINEONLY ":dbgl0" ;
|
||||
}
|
||||
}
|
||||
|
||||
/* parse the config parameters to set the config source */
|
||||
i = sscanf(cfgparam,"%m[^':']:%ms",&cfgmode,&modeparams);
|
||||
if (i< 0) {
|
||||
fprintf(stderr,"[CONFIG] %s, %d, sscanf error parsing config source %s: %s\n", __FILE__, __LINE__,cfgparam, strerror(errno));
|
||||
cfgmode=strdup(DEFAULT_CFGMODE);
|
||||
modeparams = strdup(DEFAULT_CFGFILENAME);
|
||||
exit(-1);
|
||||
}
|
||||
else if ( i == 1 ) {
|
||||
/* -O argument doesn't contain ":" separator, assume -O <conf file> option, default cfgmode to libconfig
|
||||
with one parameter, the path to the configuration file */
|
||||
modeparams=cfgmode;
|
||||
cfgmode=strdup(DEFAULT_CFGMODE);
|
||||
cfgmode=strdup(CONFIG_LIBCONFIGFILE);
|
||||
}
|
||||
|
||||
cfgptr = malloc(sizeof(configmodule_interface_t));
|
||||
@@ -153,7 +229,6 @@ int i;
|
||||
cfgptr->argc = argc;
|
||||
cfgptr->argv = argv;
|
||||
cfgptr->cfgmode=strdup(cfgmode);
|
||||
|
||||
cfgptr->num_cfgP=0;
|
||||
atoken=strtok_r(modeparams,":",&strtokctx);
|
||||
while ( cfgptr->num_cfgP< CONFIG_MAX_OOPT_PARAMS && atoken != NULL) {
|
||||
@@ -176,24 +251,33 @@ int i;
|
||||
for (i=0;i<cfgptr->num_cfgP; i++) {
|
||||
printf("%s ",cfgptr->cfgP[i]);
|
||||
}
|
||||
printf("\n");
|
||||
printf(", debug flags: 0x%08x\n",cfgptr->rtflags);
|
||||
|
||||
|
||||
i=load_config_sharedlib(cfgptr);
|
||||
if (i< 0) {
|
||||
fprintf(stderr,"[CONFIG] %s %d config module %s couldn't be loaded\n", __FILE__, __LINE__,cfgmode);
|
||||
cfgptr->rtflags = cfgptr->rtflags | CONFIG_HELP | CONFIG_ABORT;
|
||||
if (strstr(cfgparam,CONFIG_CMDLINEONLY) == NULL) {
|
||||
i=load_config_sharedlib(cfgptr);
|
||||
if (i == 0) {
|
||||
printf("[CONFIG] config module %s loaded\n",cfgmode);
|
||||
Config_Params[CONFIGPARAM_DEBUGFLAGS_IDX].uptr=&(cfgptr->rtflags);
|
||||
config_get(Config_Params,CONFIG_PARAMLENGTH(Config_Params), CONFIG_SECTIONNAME );
|
||||
} else {
|
||||
fprintf(stderr,"[CONFIG] %s %d config module \"%s\" couldn't be loaded\n", __FILE__, __LINE__,cfgmode);
|
||||
cfgptr->rtflags = cfgptr->rtflags | CONFIG_HELP | CONFIG_ABORT;
|
||||
}
|
||||
} else {
|
||||
printf("[CONFIG] config module %s loaded\n",cfgmode);
|
||||
Config_Params[CONFIGPARAM_DEBUGFLAGS_IDX].uptr=&(cfgptr->rtflags);
|
||||
config_get(Config_Params,CONFIG_PARAMLENGTH(Config_Params), CONFIG_SECTIONNAME );
|
||||
cfgptr->init = (configmodule_initfunc_t)nooptfunc;
|
||||
cfgptr->get = config_cmdlineonly_get;
|
||||
cfgptr->getlist = config_cmdlineonly_getlist;
|
||||
cfgptr->end = (configmodule_endfunc_t)nooptfunc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (modeparams != NULL) free(modeparams);
|
||||
if (cfgmode != NULL) free(cfgmode);
|
||||
if (CONFIG_ISFLAGSET(CONFIG_ABORT)) config_printhelp(Config_Params,CONFIG_PARAMLENGTH(Config_Params));
|
||||
if (CONFIG_ISFLAGSET(CONFIG_ABORT)) {
|
||||
config_printhelp(Config_Params,CONFIG_PARAMLENGTH(Config_Params));
|
||||
// exit(-1);
|
||||
}
|
||||
return cfgptr;
|
||||
}
|
||||
|
||||
|
||||
@@ -41,17 +41,19 @@
|
||||
#define CONFIG_MAX_ALLOCATEDPTRS 1024 // maximum number of parameters that can be dynamicaly allocated in the config module
|
||||
|
||||
/* default values for configuration module parameters */
|
||||
#define DEFAULT_CFGMODE "libconfig" // use libconfig file
|
||||
#define DEFAULT_CFGFILENAME "oai.conf" // default config file
|
||||
#define CONFIG_LIBCONFIGFILE "libconfig" // use libconfig file
|
||||
#define CONFIG_CMDLINEONLY "cmdline" // use only command line options
|
||||
#define DEFAULT_CFGFILENAME "oai.conf" // default config file
|
||||
|
||||
/* rtflags bit position definitions */
|
||||
#define CONFIG_PRINTPARAMS 1 // print parameters values while processing
|
||||
#define CONFIG_DEBUGPTR 1<<1 // print memory allocation/free debug messages
|
||||
#define CONFIG_DEBUGCMDLINE 1<<2 // print command line processing messages
|
||||
#define CONFIG_NOABORTONCHKF 1<<3 // disable abort execution when parameter checking function fails
|
||||
#define CONFIG_HELP 1<<20 // print help message
|
||||
#define CONFIG_ABORT 1<<21 // config failed,abort execution
|
||||
#define CONFIG_NOOOPT 1<<22 // no -O option found when parsing command line
|
||||
#define CONFIG_PRINTPARAMS 1 // print parameters values while processing
|
||||
#define CONFIG_DEBUGPTR (1<<1) // print memory allocation/free debug messages
|
||||
#define CONFIG_DEBUGCMDLINE (1<<2) // print command line processing messages
|
||||
#define CONFIG_NOABORTONCHKF (1<<3) // disable abort execution when parameter checking function fails
|
||||
#define CONFIG_NOEXITONHELP (1<<19) // do not exit after printing help
|
||||
#define CONFIG_HELP (1<<20) // print help message
|
||||
#define CONFIG_ABORT (1<<21) // config failed,abort execution
|
||||
#define CONFIG_NOOOPT (1<<22) // no -O option found when parsing command line
|
||||
typedef int(*configmodule_initfunc_t)(char *cfgP[],int numP);
|
||||
typedef int(*configmodule_getfunc_t)(paramdef_t *,int numparams, char *prefix);
|
||||
typedef int(*configmodule_getlistfunc_t)(paramlist_def_t *, paramdef_t *,int numparams, char *prefix);
|
||||
@@ -75,7 +77,7 @@ typedef struct configmodule_interface
|
||||
#ifdef CONFIG_LOADCONFIG_MAIN
|
||||
configmodule_interface_t *cfgptr=NULL;
|
||||
|
||||
static char config_helpstr [] = "\n lte-softmodem -O [config mode]<:dbg[debugflags]> \n \
|
||||
static char config_helpstr [] = "\n lte-softmodem -O [config mode]<:dbgl[debugflags]> \n \
|
||||
debugflags can also be defined in the config_libconfig section of the config file\n \
|
||||
debugflags: mask, 1->print parameters, 2->print memory allocations debug messages\n \
|
||||
4->print command line processing debug messages\n ";
|
||||
@@ -97,9 +99,9 @@ extern configmodule_interface_t *cfgptr;
|
||||
#endif
|
||||
|
||||
|
||||
#define printf_params(...) if ( (cfgptr->rtflags & CONFIG_PRINTPARAMS) != 0 ) { printf ( __VA_ARGS__ ); }
|
||||
#define printf_ptrs(...) if ( (cfgptr->rtflags & CONFIG_DEBUGPTR) != 0 ) { printf ( __VA_ARGS__ ); }
|
||||
#define printf_cmdl(...) if ( (cfgptr->rtflags & CONFIG_DEBUGCMDLINE) != 0 ) { printf ( __VA_ARGS__ ); }
|
||||
#define printf_params(...) if ( (cfgptr->rtflags & (CONFIG_PRINTPARAMS)) != 0 ) { printf ( __VA_ARGS__ ); }
|
||||
#define printf_ptrs(...) if ( (cfgptr->rtflags & (CONFIG_DEBUGPTR)) != 0 ) { printf ( __VA_ARGS__ ); }
|
||||
#define printf_cmdl(...) if ( (cfgptr->rtflags & (CONFIG_DEBUGCMDLINE)) != 0 ) { printf ( __VA_ARGS__ ); }
|
||||
|
||||
extern configmodule_interface_t *load_configmodule(int argc, char **argv);
|
||||
extern void end_configmodule(void);
|
||||
|
||||
@@ -148,7 +148,10 @@ typedef struct paramdef
|
||||
#define TYPE_MASK 10
|
||||
#define TYPE_DOUBLE 16
|
||||
#define TYPE_IPV4ADDR 20
|
||||
#define TYPE_LASTSCALAR 25
|
||||
|
||||
#define PARAM_ISLISTORARRAY(P) (P->type > TYPE_LASTSCALAR )
|
||||
#define PARAM_ISSCALAR(P) (P->type < TYPE_LASTSCALAR )
|
||||
|
||||
#define TYPE_STRINGLIST 50
|
||||
#define TYPE_INTARRAY 51
|
||||
|
||||
@@ -35,6 +35,8 @@
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <dlfcn.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "config_userapi.h"
|
||||
extern void exit_fun(const char* s); // lte-softmodem clean exit function
|
||||
|
||||
@@ -50,10 +52,30 @@ configmodule_interface_t *config_get_if(void)
|
||||
|
||||
char * config_check_valptr(paramdef_t *cfgoptions, char **ptr, int length)
|
||||
{
|
||||
|
||||
if (ptr == NULL ) {
|
||||
ptr = malloc(sizeof(char *));
|
||||
if (ptr != NULL) {
|
||||
*ptr=NULL;
|
||||
cfgoptions->strptr=ptr;
|
||||
if ( (cfgoptions->paramflags & PARAMFLAG_NOFREE) == 0) {
|
||||
config_get_if()->ptrs[config_get_if()->numptrs] = (char *)ptr;
|
||||
config_get_if()->numptrs++;
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "[CONFIG] %s %d option %s, cannot allocate pointer: %s \n",
|
||||
__FILE__, __LINE__, cfgoptions->optname, strerror(errno));
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
printf_ptrs("[CONFIG] %s ptr: 0x%08lx requested size: %i\n",cfgoptions->optname,(uintptr_t)(ptr),length);
|
||||
if(cfgoptions->numelt > 0) { /* already allocated */
|
||||
return *ptr;
|
||||
if(cfgoptions->numelt > 0 && PARAM_ISSCALAR(cfgoptions) ) { /* already allocated */
|
||||
if (*ptr != NULL) {
|
||||
return *ptr;
|
||||
} else {
|
||||
fprintf(stderr,"[CONFIG] %s %d option %s, definition error: value pointer is NULL, declared as %i bytes allocated\n",
|
||||
__FILE__, __LINE__,cfgoptions->optname, cfgoptions->numelt);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
if (*ptr == NULL) {
|
||||
@@ -75,7 +97,7 @@ char * config_check_valptr(paramdef_t *cfgoptions, char **ptr, int length)
|
||||
void config_assign_int(paramdef_t *cfgoptions, char *fullname, int val)
|
||||
{
|
||||
int tmpval=val;
|
||||
if ( ((cfgoptions->paramflags &PARAMFLAG_BOOL) != 0) && tmpval >1) {
|
||||
if ( ((cfgoptions->paramflags &PARAMFLAG_BOOL) != 0) && tmpval >0) {
|
||||
tmpval =1;
|
||||
}
|
||||
switch (cfgoptions->type) {
|
||||
@@ -160,7 +182,7 @@ int st=0;
|
||||
}
|
||||
}
|
||||
if (st != 0) {
|
||||
fprintf(stderr,"[CONFIG] config_execcheck: %i parameters with wrong value\n", -st);
|
||||
fprintf(stderr,"[CONFIG] config_execcheck: section %s %i parameters with wrong value\n", prefix, -st);
|
||||
if ( CONFIG_ISFLAGSET(CONFIG_NOABORTONCHKF) == 0) {
|
||||
exit_fun("exit because configuration failed\n");
|
||||
}
|
||||
@@ -173,7 +195,7 @@ int config_get(paramdef_t *params,int numparams, char *prefix)
|
||||
int ret= -1;
|
||||
|
||||
if (CONFIG_ISFLAGSET(CONFIG_ABORT)) {
|
||||
fprintf(stderr,"[CONFIG] config_get skipped, config module not properly initialized\n");
|
||||
fprintf(stderr,"[CONFIG] config_get, section %s skipped, config module not properly initialized\n",prefix);
|
||||
return ret;
|
||||
}
|
||||
configmodule_interface_t *cfgif = config_get_if();
|
||||
@@ -283,3 +305,115 @@ int config_checkstr_assign_integer(paramdef_t *param)
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int config_setdefault_string(paramdef_t *cfgoptions, char *prefix)
|
||||
{
|
||||
int status = 0;
|
||||
if( cfgoptions->defstrval != NULL) {
|
||||
status=1;
|
||||
|
||||
if (cfgoptions->numelt == 0 ) {
|
||||
config_check_valptr(cfgoptions, (char **)(cfgoptions->strptr), sizeof(char *));
|
||||
config_check_valptr(cfgoptions, cfgoptions->strptr, strlen(cfgoptions->defstrval)+1);
|
||||
sprintf(*(cfgoptions->strptr), "%s",cfgoptions->defstrval);
|
||||
printf_params("[CONFIG] %s.%s set to default value \"%s\"\n", ((prefix == NULL) ? "" : prefix), cfgoptions->optname, *(cfgoptions->strptr));
|
||||
} else {
|
||||
sprintf((char *)*(cfgoptions->strptr), "%s",cfgoptions->defstrval);
|
||||
printf_params("[CONFIG] %s.%s set to default value \"%s\"\n", ((prefix == NULL) ? "" : prefix), cfgoptions->optname, (char *)*(cfgoptions->strptr));
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
int config_setdefault_stringlist(paramdef_t *cfgoptions, char *prefix)
|
||||
{
|
||||
int status = 0;
|
||||
if( cfgoptions->defstrlistval != NULL) {
|
||||
cfgoptions->strlistptr=cfgoptions->defstrlistval;
|
||||
status=1;
|
||||
for(int j=0; j<cfgoptions->numelt; j++)
|
||||
printf_params("[CONFIG] %s.%s[%i] set to default value %s\n", ((prefix == NULL) ? "" : prefix), cfgoptions->optname,j, cfgoptions->strlistptr[j]);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
int config_setdefault_int(paramdef_t *cfgoptions, char *prefix)
|
||||
{
|
||||
int status = 0;
|
||||
config_check_valptr(cfgoptions, (char **)(&(cfgoptions->iptr)),sizeof(int32_t));
|
||||
if( ((cfgoptions->paramflags & PARAMFLAG_MANDATORY) == 0)) {
|
||||
config_assign_int(cfgoptions,cfgoptions->optname,cfgoptions->defintval);
|
||||
status=1;
|
||||
printf_params("[CONFIG] %s.%s set to default value\n", ((prefix == NULL) ? "" : prefix), cfgoptions->optname);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
int config_setdefault_int64(paramdef_t *cfgoptions, char *prefix)
|
||||
{
|
||||
int status = 0;
|
||||
config_check_valptr(cfgoptions, (char **)&(cfgoptions->i64ptr),sizeof(long long));
|
||||
if( ((cfgoptions->paramflags & PARAMFLAG_MANDATORY) == 0)) {
|
||||
*(cfgoptions->u64ptr)=cfgoptions->defuintval;
|
||||
status=1;
|
||||
printf_params("[CONFIG] %s.%s set to default value %llu\n", ((prefix == NULL) ? "" : prefix), cfgoptions->optname, (long long unsigned)(*(cfgoptions->u64ptr)));
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
int config_setdefault_intlist(paramdef_t *cfgoptions, char *prefix)
|
||||
{
|
||||
int status = 0;
|
||||
if( cfgoptions->defintarrayval != NULL) {
|
||||
config_check_valptr(cfgoptions,(char **)&(cfgoptions->iptr), sizeof(int32_t*));
|
||||
cfgoptions->iptr=cfgoptions->defintarrayval;
|
||||
status=1;
|
||||
for (int j=0; j<cfgoptions->numelt ; j++) {
|
||||
printf_params("[CONFIG] %s[%i] set to default value %i\n",cfgoptions->optname ,j,(int)cfgoptions->iptr[j]);
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
int config_setdefault_double(paramdef_t *cfgoptions, char *prefix)
|
||||
{
|
||||
int status = 0;
|
||||
config_check_valptr(cfgoptions, (char **)&(cfgoptions->dblptr),sizeof(double));
|
||||
if( ((cfgoptions->paramflags & PARAMFLAG_MANDATORY) == 0)) {
|
||||
*(cfgoptions->u64ptr)=cfgoptions->defdblval;
|
||||
status=1;
|
||||
printf_params("[CONFIG] %s set to default value %lf\n",cfgoptions->optname , *(cfgoptions->dblptr));
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
int config_assign_ipv4addr(paramdef_t *cfgoptions, char *ipv4addr)
|
||||
{
|
||||
config_check_valptr(cfgoptions,(char **)&(cfgoptions->uptr), sizeof(int));
|
||||
int rst=inet_pton(AF_INET, ipv4addr ,cfgoptions->uptr );
|
||||
if (rst == 1 && *(cfgoptions->uptr) > 0) {
|
||||
printf_params("[CONFIG] %s: %s\n",cfgoptions->optname, ipv4addr);
|
||||
return 1;
|
||||
} else {
|
||||
if ( strncmp(ipv4addr,ANY_IPV4ADDR_STRING,sizeof(ANY_IPV4ADDR_STRING)) == 0) {
|
||||
printf_params("[CONFIG] %s:%s (INADDR_ANY) \n",cfgoptions->optname,ipv4addr);
|
||||
*cfgoptions->uptr=INADDR_ANY;
|
||||
return 1;
|
||||
} else {
|
||||
fprintf(stderr,"[CONFIG] %s not valid for %s \n", ipv4addr, cfgoptions->optname);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int config_setdefault_ipv4addr(paramdef_t *cfgoptions, char *prefix)
|
||||
{
|
||||
int status = 0;
|
||||
|
||||
if (cfgoptions->defstrval != NULL) {
|
||||
status = config_assign_ipv4addr(cfgoptions, cfgoptions->defstrval);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -38,10 +38,15 @@
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
/* get rid of "exit_fun undeclared" warning */
|
||||
extern void exit_fun(const char* s);
|
||||
|
||||
#define CONFIG_GETSOURCE ( (config_get_if()==NULL) ? NULL : config_get_if()->cfgmode )
|
||||
#define CONFIG_GETNUMP ( (config_get_if()==NULL) ? 0 : config_get_if()->num_cfgP )
|
||||
#define CONFIG_GETP(P) ( (config_get_if()==NULL) ? NULL : config_get_if()->cfgP[P] )
|
||||
#define CONFIG_ISFLAGSET(P) ( (config_get_if()==NULL) ? 0 : !!(config_get_if()->rtflags & P))
|
||||
#define CONFIG_SETRTFLAG(P) if (config_get_if()) { config_get_if()->rtflags |= P; }
|
||||
#define CONFIG_CLEARRTFLAG(P) if (config_get_if()) { config_get_if()->rtflags &= (~P); }
|
||||
#define CONFIG_ISPARAMFLAGSET(P,F) ( !!(P.paramflags & F))
|
||||
/* utility functions, to be used by configuration module and/or configuration libraries */
|
||||
extern configmodule_interface_t *config_get_if(void);
|
||||
@@ -50,6 +55,7 @@ extern void config_printhelp(paramdef_t *,int numparams);
|
||||
extern int config_process_cmdline(paramdef_t *params,int numparams, char *prefix);
|
||||
extern void config_assign_processedint(paramdef_t *cfgoption, int val);
|
||||
extern void config_assign_int(paramdef_t *cfgoptions, char *fullname, int val);
|
||||
extern int config_assign_ipv4addr(paramdef_t *cfgoptions, char *ipv4addr);
|
||||
|
||||
/* apis to get parameters, to be used by oai modules, at configuration time */
|
||||
extern int config_get(paramdef_t *params,int numparams, char *prefix);
|
||||
@@ -66,6 +72,15 @@ extern int config_check_intrange(paramdef_t *param);
|
||||
extern int config_check_strval(paramdef_t *param);
|
||||
extern int config_checkstr_assign_integer(paramdef_t *param);
|
||||
|
||||
/* functions to set a parameter to its default value */
|
||||
extern int config_setdefault_string(paramdef_t *cfgoptions, char *prefix);
|
||||
extern int config_setdefault_stringlist(paramdef_t *cfgoptions, char *prefix);
|
||||
extern int config_setdefault_int(paramdef_t *cfgoptions, char *prefix);
|
||||
extern int config_setdefault_int64(paramdef_t *cfgoptions, char *prefix);
|
||||
extern int config_setdefault_intlist(paramdef_t *cfgoptions, char *prefix);
|
||||
extern int config_setdefault_double(paramdef_t *cfgoptions, char *prefix);
|
||||
extern int config_setdefault_ipv4addr(paramdef_t *cfgoptions, char *prefix);
|
||||
|
||||
#define CONFIG_GETCONFFILE (config_get_if()->cfgP[0])
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -129,8 +129,6 @@ int config_libconfig_get(paramdef_t *cfgoptions,int numoptions, char *prefix )
|
||||
switch(cfgoptions[i].type)
|
||||
{
|
||||
case TYPE_STRING:
|
||||
|
||||
printf("call config_lookup_string for '%s' %p\n", cfgpath, &(libconfig_privdata.cfg)); fflush(stdout);
|
||||
if ( config_lookup_string(&(libconfig_privdata.cfg),cfgpath, (const char **)&str)) {
|
||||
if ( cfgoptions[i].numelt > 0 && str != NULL && strlen(str) >= cfgoptions[i].numelt ) {
|
||||
fprintf(stderr,"[LIBCONFIG] %s: %s exceeds maximum length of %i bytes, value truncated\n",
|
||||
@@ -138,7 +136,7 @@ printf("call config_lookup_string for '%s' %p\n", cfgpath, &(libconfig_privdata.
|
||||
str[strlen(str)-1] = 0;
|
||||
}
|
||||
if (cfgoptions[i].numelt == 0 ) {
|
||||
config_check_valptr(&(cfgoptions[i]), (char **)(&(cfgoptions[i].strptr)), sizeof(char *));
|
||||
// config_check_valptr(&(cfgoptions[i]), (char **)(&(cfgoptions[i].strptr)), sizeof(char *));
|
||||
config_check_valptr(&(cfgoptions[i]), cfgoptions[i].strptr, strlen(str)+1);
|
||||
sprintf( *(cfgoptions[i].strptr) , "%s", str);
|
||||
printf_params("[LIBCONFIG] %s: \"%s\"\n", cfgpath,*(cfgoptions[i].strptr) );
|
||||
@@ -147,21 +145,7 @@ printf("call config_lookup_string for '%s' %p\n", cfgpath, &(libconfig_privdata.
|
||||
printf_params("[LIBCONFIG] %s: \"%s\"\n", cfgpath,(char *)cfgoptions[i].strptr );
|
||||
}
|
||||
} else {
|
||||
if( cfgoptions[i].defstrval != NULL) {
|
||||
defval=1;
|
||||
|
||||
if (cfgoptions[i].numelt == 0 ) {
|
||||
config_check_valptr(&(cfgoptions[i]), (char **)(&(cfgoptions[i].strptr)), sizeof(char *));
|
||||
config_check_valptr(&(cfgoptions[i]), cfgoptions[i].strptr, strlen(cfgoptions[i].defstrval)+1);
|
||||
sprintf(*(cfgoptions[i].strptr), "%s",cfgoptions[i].defstrval);
|
||||
printf_params("[LIBCONFIG] %s set to default value \"%s\"\n", cfgpath, *(cfgoptions[i].strptr));
|
||||
} else {
|
||||
sprintf((char *)*(cfgoptions[i].strptr), "%s",cfgoptions[i].defstrval);
|
||||
printf_params("[LIBCONFIG] %s set to default value \"%s\"\n", cfgpath, (char *)*(cfgoptions[i].strptr));
|
||||
}
|
||||
} else {
|
||||
notfound=1;
|
||||
}
|
||||
defval=config_setdefault_string(&(cfgoptions[i]),prefix);
|
||||
}
|
||||
break;
|
||||
case TYPE_STRINGLIST:
|
||||
@@ -169,14 +153,7 @@ printf("call config_lookup_string for '%s' %p\n", cfgpath, &(libconfig_privdata.
|
||||
if ( setting != NULL) {
|
||||
read_strlist(&cfgoptions[i],setting,cfgpath);
|
||||
} else {
|
||||
if( cfgoptions[i].defstrlistval != NULL) {
|
||||
cfgoptions[i].strlistptr=cfgoptions[i].defstrlistval;
|
||||
defval=1;
|
||||
for(int j=0; j<cfgoptions[i].numelt; j++)
|
||||
printf_params("[LIBCONFIG] %s%i set to default value %s\n", cfgpath,j, cfgoptions[i].strlistptr[j]);
|
||||
} else {
|
||||
notfound=1;
|
||||
}
|
||||
defval=config_setdefault_stringlist(&(cfgoptions[i]),prefix);
|
||||
}
|
||||
break;
|
||||
case TYPE_UINT8:
|
||||
@@ -186,23 +163,17 @@ printf("call config_lookup_string for '%s' %p\n", cfgpath, &(libconfig_privdata.
|
||||
case TYPE_UINT32:
|
||||
case TYPE_INT32:
|
||||
case TYPE_MASK:
|
||||
config_check_valptr(&(cfgoptions[i]), (char **)(&(cfgoptions[i].iptr)),sizeof(int32_t));
|
||||
if ( config_lookup_int(&(libconfig_privdata.cfg),cfgpath, &u)) {
|
||||
config_check_valptr(&(cfgoptions[i]), (char **)(&(cfgoptions[i].iptr)),sizeof(int32_t));
|
||||
config_assign_int(&(cfgoptions[i]),cfgpath,u);
|
||||
} else {
|
||||
if( ((cfgoptions[i].paramflags & PARAMFLAG_MANDATORY) == 0)) {
|
||||
config_assign_int(&(cfgoptions[i]),cfgpath,cfgoptions[i].defintval);
|
||||
defval=1;
|
||||
printf_params("[LIBCONFIG] %s set to default value\n", cfgpath);
|
||||
} else {
|
||||
notfound=1;
|
||||
}
|
||||
defval=config_setdefault_int(&(cfgoptions[i]),prefix);
|
||||
}
|
||||
break;
|
||||
case TYPE_UINT64:
|
||||
case TYPE_INT64:
|
||||
config_check_valptr(&(cfgoptions[i]), (char **)&(cfgoptions[i].i64ptr),sizeof(long long));
|
||||
if ( config_lookup_int64(&(libconfig_privdata.cfg),cfgpath, &llu)) {
|
||||
config_check_valptr(&(cfgoptions[i]), (char **)&(cfgoptions[i].i64ptr),sizeof(long long));
|
||||
if(cfgoptions[i].type==TYPE_UINT64) {
|
||||
*(cfgoptions[i].u64ptr) = (uint64_t)llu;
|
||||
printf_params("[LIBCONFIG] %s: %llu\n", cfgpath,(long long unsigned)(*(cfgoptions[i].u64ptr)) );
|
||||
@@ -211,13 +182,7 @@ printf("call config_lookup_string for '%s' %p\n", cfgpath, &(libconfig_privdata.
|
||||
printf_params("[LIBCONFIG] %s: %lli\n", cfgpath,(long long unsigned)(*(cfgoptions[i].i64ptr)) );
|
||||
}
|
||||
} else {
|
||||
if( ((cfgoptions[i].paramflags & PARAMFLAG_MANDATORY) == 0)) {
|
||||
*(cfgoptions[i].u64ptr)=cfgoptions[i].defuintval;
|
||||
defval=1;
|
||||
printf_params("[LIBCONFIG] %s set to default value %llu\n", cfgpath, (long long unsigned)(*(cfgoptions[i].u64ptr)));
|
||||
} else {
|
||||
notfound=1;
|
||||
}
|
||||
defval=config_setdefault_int64(&(cfgoptions[i]),prefix);
|
||||
}
|
||||
break;
|
||||
case TYPE_UINTARRAY:
|
||||
@@ -226,57 +191,28 @@ printf("call config_lookup_string for '%s' %p\n", cfgpath, &(libconfig_privdata.
|
||||
if ( setting != NULL) {
|
||||
read_intarray(&cfgoptions[i],setting,cfgpath);
|
||||
} else {
|
||||
if( cfgoptions[i].defintarrayval != NULL) {
|
||||
config_check_valptr(&(cfgoptions[i]),(char **)&(cfgoptions[i].iptr), sizeof(int32_t*));
|
||||
cfgoptions[i].iptr=cfgoptions[i].defintarrayval;
|
||||
defval=1;
|
||||
for (int j=0; j<cfgoptions[i].numelt ; j++) {
|
||||
printf_params("[LIBCONFIG] %s[%i] set to default value %i\n", cfgpath,j,(int)cfgoptions[i].iptr[j]);
|
||||
}
|
||||
} else {
|
||||
notfound=1;
|
||||
}
|
||||
defval=config_setdefault_intlist(&(cfgoptions[i]),prefix);
|
||||
}
|
||||
break;
|
||||
case TYPE_DOUBLE:
|
||||
config_check_valptr(&(cfgoptions[i]), (char **)&(cfgoptions[i].dblptr),sizeof(double));
|
||||
if ( config_lookup_float(&(libconfig_privdata.cfg),cfgpath, &dbl)) {
|
||||
config_check_valptr(&(cfgoptions[i]), (char **)&(cfgoptions[i].dblptr),sizeof(double));
|
||||
*(cfgoptions[i].dblptr) = dbl;
|
||||
printf_params("[LIBCONFIG] %s: %lf\n", cfgpath,*(cfgoptions[i].dblptr) );
|
||||
} else {
|
||||
if( ((cfgoptions[i].paramflags & PARAMFLAG_MANDATORY) == 0)) {
|
||||
*(cfgoptions[i].u64ptr)=cfgoptions[i].defdblval;
|
||||
defval=1;
|
||||
printf_params("[LIBCONFIG] %s set to default value %lf\n", cfgpath, *(cfgoptions[i].dblptr));
|
||||
} else {
|
||||
notfound=1;
|
||||
}
|
||||
defval=config_setdefault_double(&(cfgoptions[i]),prefix);
|
||||
}
|
||||
break;
|
||||
case TYPE_IPV4ADDR:
|
||||
config_check_valptr(&(cfgoptions[i]),(char **)&(cfgoptions[i].uptr), sizeof(int));
|
||||
if ( !config_lookup_string(&(libconfig_privdata.cfg),cfgpath, (const char **)&str)) {
|
||||
str=cfgoptions[i].defstrval;
|
||||
defval=1;
|
||||
printf_params("[LIBCONFIG] %s set to default value %s\n", cfgpath, str);
|
||||
}
|
||||
if (str != NULL) {
|
||||
rst=inet_pton(AF_INET, str,cfgoptions[i].uptr );
|
||||
if (rst == 1 && *(cfgoptions[i].uptr) > 0) {
|
||||
printf_params("[LIBCONFIG] %s: %s\n", cfgpath,str );
|
||||
} else {
|
||||
if ( strncmp(str,ANY_IPV4ADDR_STRING,sizeof(ANY_IPV4ADDR_STRING)) == 0) {
|
||||
printf_params("[LIBCONFIG] %s:%s (INADDR_ANY) \n",cfgpath,str);
|
||||
*cfgoptions[i].uptr=INADDR_ANY;
|
||||
} else {
|
||||
fprintf(stderr,"[LIBCONFIG] %s not valid for %s \n", str, cfgpath);
|
||||
fatalerror=1;
|
||||
}
|
||||
defval=config_setdefault_ipv4addr(&(cfgoptions[i]),prefix);
|
||||
} else {
|
||||
rst=config_assign_ipv4addr(cfgoptions, str);
|
||||
if (rst < 0) {
|
||||
fprintf(stderr,"[LIBCONFIG] %s not valid for %s \n", str, cfgpath);
|
||||
fatalerror=1;
|
||||
}
|
||||
} else {
|
||||
notfound=1;
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
case TYPE_LIST:
|
||||
setting = config_setting_lookup (config_root_setting(&(libconfig_privdata.cfg)),cfgpath );
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
VCD Plugin v0.1
|
||||
|
||||
The VCD plugin outputs signals to a .vcd file which is readable by gtkwave (http://en.wikipedia.org/wiki/GTKWave).
|
||||
Signals may have two types:
|
||||
- Variables to dump the state of a variable (range 0..2^64 - 1).
|
||||
- Functions to log function usage (implies two call to VCD API: IN and OUT)
|
||||
|
||||
This module is always built in, but is only used when -V oaisim option is added.
|
||||
The VCD file generated is called openair_vcd_dump.vcd and is located in the execution folder.
|
||||
|
||||
Usage:
|
||||
1) To dump function usage:
|
||||
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(FUNCTION_NAME, VCD_FUNCTION_IN); at start of function
|
||||
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(FUNCTION_NAME, VCD_FUNCTION_OUT); at end of function
|
||||
FUNCTION_NAME should be defined in the enum in vcd_signal_dumper.h and the function name should be addded at the right place in the vcd_signal_dumper.c file.
|
||||
|
||||
2) To dump a variable:
|
||||
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VARIABLE_NAME, value); where VARIABLE_NAME is defined as described above for functions and value is the state of the variable at log time.
|
||||
|
||||
TODO list:
|
||||
- Add support for signed variables
|
||||
- Create more than two module (for now: one for variable, one for functions)
|
||||
- Integrate date in filename
|
||||
- Use a more accurate clock (if necessary) or use a host specific clock (for other systems than Linux)
|
||||
|
||||
Useful link:
|
||||
http://www.beyondttl.com/vcd.php
|
||||
@@ -0,0 +1,707 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
/*! \file log.c
|
||||
* \brief log implementaion
|
||||
* \author Navid Nikaein
|
||||
* \date 2009 - 2014
|
||||
* \version 0.5
|
||||
* @ingroup util
|
||||
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE /* required for pthread_getname_np */
|
||||
//#define LOG_TEST 1
|
||||
|
||||
#define COMPONENT_LOG
|
||||
#define COMPONENT_LOG_IF
|
||||
#include <ctype.h>
|
||||
#define LOG_MAIN
|
||||
#include "log.h"
|
||||
#include "vcd_signal_dumper.h"
|
||||
#include "assertions.h"
|
||||
|
||||
#if defined(ENABLE_ITTI)
|
||||
# include "intertask_interface.h"
|
||||
#endif
|
||||
|
||||
# include <pthread.h>
|
||||
# include <string.h>
|
||||
#include <linux/prctl.h>
|
||||
#include "common/config/config_userapi.h"
|
||||
// main log variables
|
||||
|
||||
|
||||
|
||||
|
||||
mapping log_level_names[] = {
|
||||
{"error", OAILOG_ERR},
|
||||
{"file", OAILOG_FILE},
|
||||
{"warn", OAILOG_WARNING},
|
||||
{"info", OAILOG_INFO},
|
||||
{"debug", OAILOG_DEBUG},
|
||||
{"trace", OAILOG_TRACE},
|
||||
{NULL, -1}
|
||||
};
|
||||
|
||||
mapping log_options[] = {
|
||||
{"nocolor", FLAG_NOCOLOR },
|
||||
{"level", FLAG_LEVEL },
|
||||
{"thread", FLAG_THREAD },
|
||||
{NULL,-1}
|
||||
};
|
||||
|
||||
|
||||
mapping log_maskmap[] = {
|
||||
{"prach", DEBUG_PRACH},
|
||||
{"RU", DEBUG_RU},
|
||||
{"LTEESTIM", DEBUG_LTEESTIM},
|
||||
{"ctrlsocket", DEBUG_CTRLSOCKET},
|
||||
{"UE_PHYPROC", DEBUG_UE_PHYPROC},
|
||||
{"UE_TIMING", UE_TIMING},
|
||||
{NULL,-1}
|
||||
};
|
||||
|
||||
char *log_level_highlight_start[] = {LOG_RED, LOG_GREEN, LOG_ORANGE, "", LOG_BLUE, LOG_CYBL}; /*!< \brief Optional start-format strings for highlighting */
|
||||
char *log_level_highlight_end[] = {LOG_RESET,LOG_RESET,LOG_RESET,LOG_RESET, LOG_RESET,LOG_RESET}; /*!< \brief Optional end-format strings for highlighting */
|
||||
|
||||
|
||||
int write_file_matlab(const char *fname,const char *vname,void *data,int length,int dec,char format)
|
||||
{
|
||||
|
||||
FILE *fp=NULL;
|
||||
int i;
|
||||
|
||||
if (data == NULL)
|
||||
return -1;
|
||||
//printf("Writing %d elements of type %d to %s\n",length,format,fname);
|
||||
|
||||
|
||||
if (format == 10 || format ==11 || format == 12 || format == 13 || format == 14) {
|
||||
fp = fopen(fname,"a+");
|
||||
} else if (format != 10 && format !=11 && format != 12 && format != 13 && format != 14) {
|
||||
fp = fopen(fname,"w+");
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (fp== NULL) {
|
||||
printf("[OPENAIR][FILE OUTPUT] Cannot open file %s\n",fname);
|
||||
return(-1);
|
||||
}
|
||||
|
||||
if (format != 10 && format !=11 && format != 12 && format != 13 && format != 14)
|
||||
fprintf(fp,"%s = [",vname);
|
||||
|
||||
|
||||
switch (format) {
|
||||
case 0: // real 16-bit
|
||||
|
||||
for (i=0; i<length; i+=dec) {
|
||||
fprintf(fp,"%d\n",((short *)data)[i]);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 1: // complex 16-bit
|
||||
case 13:
|
||||
case 14:
|
||||
case 15:
|
||||
|
||||
for (i=0; i<length<<1; i+=(2*dec)) {
|
||||
fprintf(fp,"%d + j*(%d)\n",((short *)data)[i],((short *)data)[i+1]);
|
||||
|
||||
}
|
||||
|
||||
|
||||
break;
|
||||
|
||||
case 2: // real 32-bit
|
||||
for (i=0; i<length; i+=dec) {
|
||||
fprintf(fp,"%d\n",((int *)data)[i]);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 3: // complex 32-bit
|
||||
for (i=0; i<length<<1; i+=(2*dec)) {
|
||||
fprintf(fp,"%d + j*(%d)\n",((int *)data)[i],((int *)data)[i+1]);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 4: // real 8-bit
|
||||
for (i=0; i<length; i+=dec) {
|
||||
fprintf(fp,"%d\n",((char *)data)[i]);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 5: // complex 8-bit
|
||||
for (i=0; i<length<<1; i+=(2*dec)) {
|
||||
fprintf(fp,"%d + j*(%d)\n",((char *)data)[i],((char *)data)[i+1]);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 6: // real 64-bit
|
||||
for (i=0; i<length; i+=dec) {
|
||||
fprintf(fp,"%lld\n",((long long*)data)[i]);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 7: // real double
|
||||
for (i=0; i<length; i+=dec) {
|
||||
fprintf(fp,"%g\n",((double *)data)[i]);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 8: // complex double
|
||||
for (i=0; i<length<<1; i+=2*dec) {
|
||||
fprintf(fp,"%g + j*(%g)\n",((double *)data)[i], ((double *)data)[i+1]);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 9: // real unsigned 8-bit
|
||||
for (i=0; i<length; i+=dec) {
|
||||
fprintf(fp,"%d\n",((unsigned char *)data)[i]);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
|
||||
case 10 : // case eren 16 bit complex :
|
||||
|
||||
for (i=0; i<length<<1; i+=(2*dec)) {
|
||||
|
||||
if((i < 2*(length-1)) && (i > 0))
|
||||
fprintf(fp,"%d + j*(%d),",((short *)data)[i],((short *)data)[i+1]);
|
||||
else if (i == 2*(length-1))
|
||||
fprintf(fp,"%d + j*(%d);",((short *)data)[i],((short *)data)[i+1]);
|
||||
else if (i == 0)
|
||||
fprintf(fp,"\n%d + j*(%d),",((short *)data)[i],((short *)data)[i+1]);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 11 : //case eren 16 bit real for channel magnitudes:
|
||||
for (i=0; i<length; i+=dec) {
|
||||
|
||||
if((i <(length-1))&& (i > 0))
|
||||
fprintf(fp,"%d,",((short *)data)[i]);
|
||||
else if (i == (length-1))
|
||||
fprintf(fp,"%d;",((short *)data)[i]);
|
||||
else if (i == 0)
|
||||
fprintf(fp,"\n%d,",((short *)data)[i]);
|
||||
}
|
||||
|
||||
printf("\n eren: length :%d",length);
|
||||
break;
|
||||
|
||||
case 12 : // case eren for log2_maxh real unsigned 8 bit
|
||||
fprintf(fp,"%d \n",((unsigned char *)&data)[0]);
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
if (format != 10 && format !=11 && format !=12 && format != 13 && format != 15) {
|
||||
fprintf(fp,"];\n");
|
||||
fclose(fp);
|
||||
return(0);
|
||||
} else if (format == 10 || format ==11 || format == 12 || format == 13 || format == 15) {
|
||||
fclose(fp);
|
||||
return(0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* get log parameters from configuration file */
|
||||
void log_getconfig(log_t *g_log) {
|
||||
char *gloglevel = NULL;
|
||||
int level;
|
||||
|
||||
|
||||
paramdef_t logparams_defaults[] = LOG_GLOBALPARAMS_DESC;
|
||||
paramdef_t logparams_level[MAX_LOG_PREDEF_COMPONENTS];
|
||||
paramdef_t logparams_logfile[MAX_LOG_PREDEF_COMPONENTS];
|
||||
paramdef_t logparams_debug[sizeof(log_maskmap)/sizeof(mapping)];
|
||||
paramdef_t logparams_matlab[sizeof(log_maskmap)/sizeof(mapping)];
|
||||
|
||||
int ret = config_get( logparams_defaults,sizeof(logparams_defaults)/sizeof(paramdef_t),CONFIG_STRING_LOG_PREFIX);
|
||||
if (ret <0) {
|
||||
fprintf(stderr,"[LOG] init aborted, configuration couldn't be performed");
|
||||
return;
|
||||
}
|
||||
|
||||
for(int i=0; i<logparams_defaults[LOG_OPTIONS_IDX].numelt ; i++) {
|
||||
for(int j=0; log_options[j].name != NULL ; j++) {
|
||||
if (strcmp(logparams_defaults[LOG_OPTIONS_IDX].strlistptr[i],log_options[j].name) == 0) {
|
||||
g_log->flag = g_log->flag | log_options[j].value;
|
||||
break;
|
||||
} else if (log_options[j+1].name == NULL){
|
||||
fprintf(stderr,"Unknown log option: %s\n",logparams_defaults[LOG_OPTIONS_IDX].strlistptr[i]);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* build the parameter array for setting per component log level and infile options */
|
||||
memset(logparams_level, 0, sizeof(paramdef_t)*MAX_LOG_PREDEF_COMPONENTS);
|
||||
memset(logparams_logfile, 0, sizeof(paramdef_t)*MAX_LOG_PREDEF_COMPONENTS);
|
||||
for (int i=MIN_LOG_COMPONENTS; i < MAX_LOG_PREDEF_COMPONENTS; i++) {
|
||||
if(g_log->log_component[i].name == NULL) {
|
||||
g_log->log_component[i].name = malloc(16);
|
||||
sprintf((char *)g_log->log_component[i].name,"comp%i?",i);
|
||||
logparams_logfile[i].paramflags = PARAMFLAG_DONOTREAD;
|
||||
logparams_level[i].paramflags = PARAMFLAG_DONOTREAD;
|
||||
}
|
||||
sprintf(logparams_level[i].optname, LOG_CONFIG_LEVEL_FORMAT, g_log->log_component[i].name);
|
||||
sprintf(logparams_logfile[i].optname, LOG_CONFIG_LOGFILE_FORMAT, g_log->log_component[i].name);
|
||||
/* workaround: all log options in existing configuration files use lower case component names
|
||||
where component names include uppercase char in log.h.... */
|
||||
for (int j=0 ; j<strlen(logparams_level[i].optname); j++)
|
||||
logparams_level[i].optname[j] = tolower(logparams_level[i].optname[j]);
|
||||
for (int j=0 ; j<strlen(logparams_level[i].optname); j++)
|
||||
logparams_logfile[i].optname[j] = tolower(logparams_logfile[i].optname[j]);
|
||||
/* */
|
||||
logparams_level[i].defstrval = gloglevel;
|
||||
logparams_logfile[i].defuintval = 0;
|
||||
logparams_logfile[i].numelt = 0;
|
||||
logparams_level[i].numelt = 0;
|
||||
logparams_level[i].type = TYPE_STRING;
|
||||
logparams_logfile[i].type = TYPE_UINT;
|
||||
|
||||
logparams_logfile[i].paramflags = logparams_logfile[i].paramflags|PARAMFLAG_BOOL;
|
||||
}
|
||||
/* read the per component parameters */
|
||||
config_get( logparams_level, MAX_LOG_PREDEF_COMPONENTS,CONFIG_STRING_LOG_PREFIX);
|
||||
config_get( logparams_logfile, MAX_LOG_PREDEF_COMPONENTS,CONFIG_STRING_LOG_PREFIX);
|
||||
/* now set the log levels and infile option, according to what we read */
|
||||
for (int i=MIN_LOG_COMPONENTS; i < MAX_LOG_PREDEF_COMPONENTS; i++) {
|
||||
level = map_str_to_int(log_level_names, *(logparams_level[i].strptr));
|
||||
set_log(i, level,1);
|
||||
if (*(logparams_logfile[i].uptr) == 1)
|
||||
set_component_filelog(i);
|
||||
}
|
||||
|
||||
/* build then read the debug and matlab parameter array */
|
||||
for (int i=0;log_maskmap[i].name != NULL ; i++) {
|
||||
sprintf(logparams_debug[i].optname, LOG_CONFIG_DEBUG_FORMAT, log_maskmap[i].name);
|
||||
sprintf(logparams_matlab[i].optname, LOG_CONFIG_MATLAB_FORMAT, log_maskmap[i].name);
|
||||
logparams_debug[i].defuintval = 0;
|
||||
logparams_debug[i].type = TYPE_UINT;
|
||||
logparams_debug[i].paramflags = PARAMFLAG_BOOL;
|
||||
logparams_debug[i].uptr = NULL;
|
||||
logparams_debug[i].chkPptr = NULL;
|
||||
logparams_debug[i].numelt = 0;
|
||||
logparams_matlab[i].defuintval = 0;
|
||||
logparams_matlab[i].type = TYPE_UINT;
|
||||
logparams_matlab[i].paramflags = PARAMFLAG_BOOL;
|
||||
logparams_matlab[i].uptr = NULL;
|
||||
logparams_matlab[i].chkPptr = NULL;
|
||||
logparams_matlab[i].numelt = 0;
|
||||
}
|
||||
config_get( logparams_debug,(sizeof(log_maskmap)/sizeof(mapping)) - 1 ,CONFIG_STRING_LOG_PREFIX);
|
||||
config_get( logparams_matlab,(sizeof(log_maskmap)/sizeof(mapping)) - 1 ,CONFIG_STRING_LOG_PREFIX);
|
||||
/* set the debug mask according to the debug parameters values */
|
||||
for (int i=0; log_maskmap[i].name != NULL ; i++) {
|
||||
if (*(logparams_debug[i].uptr) )
|
||||
g_log->debug_mask = g_log->debug_mask | log_maskmap[i].value;
|
||||
if (*(logparams_matlab[i].uptr) )
|
||||
g_log->matlab_mask = g_log->matlab_mask | log_maskmap[i].value;
|
||||
}
|
||||
}
|
||||
|
||||
int register_log_component(char *name, char *fext, int compidx)
|
||||
{
|
||||
int computed_compidx=compidx;
|
||||
|
||||
if (strlen(fext) > 3) {
|
||||
fext[3]=0; /* limit log file extension to 3 chars */
|
||||
}
|
||||
if (compidx < 0) { /* this is not a pre-defined component */
|
||||
for (int i = MAX_LOG_PREDEF_COMPONENTS; i< MAX_LOG_COMPONENTS; i++) {
|
||||
if (g_log->log_component[i].name == NULL) {
|
||||
computed_compidx=i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (computed_compidx >= 0 && computed_compidx <MAX_LOG_COMPONENTS) {
|
||||
g_log->log_component[computed_compidx].name = strdup(name);
|
||||
g_log->log_component[computed_compidx].level = LOG_ERR;
|
||||
g_log->log_component[computed_compidx].interval = 1;
|
||||
g_log->log_component[computed_compidx].stream = NULL;
|
||||
g_log->log_component[computed_compidx].filelog = 0;
|
||||
g_log->log_component[computed_compidx].filelog_name = malloc(strlen(name)+16);/* /tmp/<name>.%s rounded to ^2 */
|
||||
sprintf(g_log->log_component[computed_compidx].filelog_name,"/tmp/%s.%s",name,fext);
|
||||
} else {
|
||||
fprintf(stderr,"{LOG} %s %d Couldn't register componemt %s\n",__FILE__,__LINE__,name);
|
||||
}
|
||||
return computed_compidx;
|
||||
}
|
||||
|
||||
int logInit (void)
|
||||
{
|
||||
int i;
|
||||
g_log = calloc(1, sizeof(log_t));
|
||||
|
||||
if (g_log == NULL) {
|
||||
perror ("cannot allocated memory for log generation module \n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
memset(g_log,0,sizeof(log_t));
|
||||
|
||||
|
||||
|
||||
register_log_component("PHY","log",PHY);
|
||||
register_log_component("MAC","log",MAC);
|
||||
register_log_component("OPT","log",OPT);
|
||||
register_log_component("RLC","log",RLC);
|
||||
register_log_component("PDCP","log",PDCP);
|
||||
register_log_component("RRC","log",RRC);
|
||||
register_log_component("OMG","csv",OMG);
|
||||
register_log_component("OTG","log",OTG);
|
||||
register_log_component("OTG_LATENCY","dat",OTG_LATENCY);
|
||||
register_log_component("OTG_LATENCY_BG","dat",OTG_LATENCY_BG);
|
||||
register_log_component("OTG_GP","dat",OTG_GP);
|
||||
register_log_component("OTG_GP_BG","dat",OTG_GP_BG);
|
||||
register_log_component("OTG_JITTER","dat",OTG_JITTER);
|
||||
register_log_component("OCG","",OCG);
|
||||
register_log_component("PERF","",PERF);
|
||||
register_log_component("OIP","",OIP);
|
||||
register_log_component("CLI","",CLI);
|
||||
register_log_component("MSC","log",MSC);
|
||||
register_log_component("OCM","log",OCM);
|
||||
register_log_component("HW","",HW);
|
||||
register_log_component("OSA","",OSA);
|
||||
register_log_component("eRAL","",RAL_ENB);
|
||||
register_log_component("mRAL","",RAL_UE);
|
||||
register_log_component("ENB_APP","log",ENB_APP);
|
||||
register_log_component("FLEXRAN_AGENT","log",FLEXRAN_AGENT);
|
||||
register_log_component("TMR","",TMR);
|
||||
register_log_component("USIM","txt",USIM);
|
||||
register_log_component("SIM","txt",SIM);
|
||||
|
||||
/* following log component are used for the localization*/
|
||||
register_log_component("LOCALIZE","log",LOCALIZE);
|
||||
register_log_component("NAS","log",NAS);
|
||||
register_log_component("UDP","",UDP_);
|
||||
|
||||
|
||||
register_log_component("GTPV1U","",GTPU);
|
||||
|
||||
|
||||
register_log_component("S1AP","",S1AP);
|
||||
|
||||
|
||||
register_log_component("SCTP","",SCTP);
|
||||
register_log_component("RRH","",RRH);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
g_log->level2string[OAILOG_ERR] = "E"; // ERROR
|
||||
g_log->level2string[OAILOG_WARNING] = "W"; // WARNING
|
||||
g_log->level2string[OAILOG_INFO] = "I"; //INFO
|
||||
g_log->level2string[OAILOG_DEBUG] = "D"; // DEBUG
|
||||
g_log->level2string[OAILOG_FILE] = "F"; // file
|
||||
g_log->level2string[OAILOG_TRACE] = "T"; // TRACE
|
||||
|
||||
|
||||
g_log->onlinelog = 1; //online log file
|
||||
g_log->filelog = 0;
|
||||
|
||||
|
||||
|
||||
g_log->filelog_name = "/tmp/openair.log";
|
||||
|
||||
log_getconfig(g_log);
|
||||
|
||||
|
||||
// could put a loop here to check for all comps
|
||||
for (i=MIN_LOG_COMPONENTS; i < MAX_LOG_COMPONENTS; i++) {
|
||||
if (g_log->log_component[i].filelog == 1 ) {
|
||||
g_log->log_component[i].stream = fopen(g_log->log_component[i].filelog_name,"w");
|
||||
g_log->log_component[i].fwrite = vfprintf;
|
||||
} else if (g_log->log_component[i].filelog == 1 ) {
|
||||
g_log->log_component[i].stream = fopen(g_log->filelog_name,"w");
|
||||
g_log->log_component[i].fwrite = vfprintf;
|
||||
} else if (g_log->onlinelog == 1 ) {
|
||||
g_log->log_component[i].stream = stdout;
|
||||
g_log->log_component[i].fwrite = vfprintf;
|
||||
}
|
||||
}
|
||||
|
||||
// set all unused component items to 0, they are for non predefined components
|
||||
for (i=MAX_LOG_PREDEF_COMPONENTS; i < MAX_LOG_COMPONENTS; i++) {
|
||||
memset(&(g_log->log_component[i]),0,sizeof(log_component_t));
|
||||
}
|
||||
printf("log init done\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
char *log_getthreadname(char *threadname, int bufsize) {
|
||||
|
||||
int rt = pthread_getname_np(pthread_self(), threadname,bufsize) ;
|
||||
if (rt == 0)
|
||||
{
|
||||
return threadname;
|
||||
} else {
|
||||
return "thread?";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void logRecord_mt(const char *file, const char *func, int line, int comp, int level, const char* format, ... )
|
||||
{
|
||||
|
||||
char threadname[PR_SET_NAME];
|
||||
char log_buffer[MAX_LOG_TOTAL];
|
||||
va_list args;
|
||||
|
||||
va_start(args, format);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
snprintf(log_buffer, MAX_LOG_TOTAL , "%s%s[%s]%s %s %s",
|
||||
log_level_highlight_end[level],
|
||||
( (g_log->flag & FLAG_NOCOLOR)?"":log_level_highlight_start[level]),
|
||||
g_log->log_component[comp].name,
|
||||
( (g_log->flag & FLAG_LEVEL)?g_log->level2string[level]:""),
|
||||
( (g_log->flag & FLAG_THREAD)?log_getthreadname(threadname,PR_SET_NAME+1):""),
|
||||
format);
|
||||
|
||||
g_log->log_component[comp].fwrite(g_log->log_component[comp].stream,log_buffer, args);
|
||||
va_end(args);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
int set_log(int component, int level, int interval)
|
||||
{
|
||||
/* Checking parameters */
|
||||
DevCheck((component >= MIN_LOG_COMPONENTS) && (component < MAX_LOG_COMPONENTS),
|
||||
component, MIN_LOG_COMPONENTS, MAX_LOG_COMPONENTS);
|
||||
DevCheck((level < NUM_LOG_LEVEL) && (level >= OAILOG_ERR), level, NUM_LOG_LEVEL,
|
||||
OAILOG_ERR);
|
||||
DevCheck((interval >= 0) && (interval <= 0xFF), interval, 0, 0xFF);
|
||||
|
||||
g_log->log_component[component].level = level;
|
||||
|
||||
|
||||
g_log->log_component[component].interval = interval;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void set_glog(int level)
|
||||
{
|
||||
for (int c=0; c< MAX_LOG_COMPONENTS; c++ ) {
|
||||
g_log->log_component[c].level = level;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void set_glog_onlinelog(int enable)
|
||||
{
|
||||
g_log->onlinelog = enable;
|
||||
}
|
||||
void set_glog_filelog(int enable)
|
||||
{
|
||||
g_log->filelog = enable;
|
||||
}
|
||||
|
||||
void set_component_filelog(int comp)
|
||||
{
|
||||
if (g_log->log_component[comp].filelog == 0) {
|
||||
g_log->log_component[comp].filelog = 1;
|
||||
|
||||
if (g_log->log_component[comp].stream == NULL) {
|
||||
g_log->log_component[comp].stream = fopen(g_log->log_component[comp].filelog_name,"w");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* for the two functions below, the passed array must have a final entry
|
||||
* with string value NULL
|
||||
*/
|
||||
/* map a string to an int. Takes a mapping array and a string as arg */
|
||||
int map_str_to_int(mapping *map, const char *str)
|
||||
{
|
||||
while (1) {
|
||||
if (map->name == NULL) {
|
||||
return(-1);
|
||||
}
|
||||
|
||||
if (!strcmp(map->name, str)) {
|
||||
return(map->value);
|
||||
}
|
||||
|
||||
map++;
|
||||
}
|
||||
}
|
||||
|
||||
/* map an int to a string. Takes a mapping array and a value */
|
||||
char *map_int_to_str(mapping *map, int val)
|
||||
{
|
||||
while (1) {
|
||||
if (map->name == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (map->value == val) {
|
||||
return map->name;
|
||||
}
|
||||
|
||||
map++;
|
||||
}
|
||||
}
|
||||
|
||||
int is_newline( char *str, int size)
|
||||
{
|
||||
int i;
|
||||
|
||||
for ( i = 0; i < size; i++ ) {
|
||||
if ( str[i] == '\n' ) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* if we get all the way to here, there must not have been a newline! */
|
||||
return 0;
|
||||
}
|
||||
|
||||
void logClean (void)
|
||||
{
|
||||
int i;
|
||||
LOG_I(PHY,"\n");
|
||||
|
||||
|
||||
|
||||
|
||||
for (i=MIN_LOG_COMPONENTS; i < MAX_LOG_COMPONENTS; i++) {
|
||||
if (g_log->log_component[i].stream != NULL) {
|
||||
fclose(g_log->log_component[i].stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef LOG_TEST
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
|
||||
logInit();
|
||||
|
||||
|
||||
test_log();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int test_log(void)
|
||||
{
|
||||
LOG_ENTER(MAC); // because the default level is DEBUG
|
||||
LOG_I(EMU, "1 Starting OAI logs version %s Build date: %s on %s\n",
|
||||
BUILD_VERSION, BUILD_DATE, BUILD_HOST);
|
||||
LOG_D(MAC, "1 debug MAC \n");
|
||||
LOG_W(MAC, "1 warning MAC \n");
|
||||
|
||||
set_log(EMU, OAILOG_INFO, FLAG_ONLINE);
|
||||
set_log(MAC, OAILOG_WARNING, 0);
|
||||
|
||||
LOG_I(EMU, "2 Starting OAI logs version %s Build date: %s on %s\n",
|
||||
BUILD_VERSION, BUILD_DATE, BUILD_HOST);
|
||||
LOG_E(MAC, "2 error MAC\n");
|
||||
LOG_D(MAC, "2 debug MAC \n");
|
||||
LOG_W(MAC, "2 warning MAC \n");
|
||||
LOG_I(MAC, "2 info MAC \n");
|
||||
|
||||
|
||||
set_log(MAC, OAILOG_NOTICE, 1);
|
||||
|
||||
LOG_ENTER(MAC);
|
||||
LOG_I(EMU, "3 Starting OAI logs version %s Build date: %s on %s\n",
|
||||
BUILD_VERSION, BUILD_DATE, BUILD_HOST);
|
||||
LOG_D(MAC, "3 debug MAC \n");
|
||||
LOG_W(MAC, "3 warning MAC \n");
|
||||
LOG_I(MAC, "3 info MAC \n");
|
||||
|
||||
set_log(MAC, LOG_DEBUG,1);
|
||||
set_log(EMU, LOG_DEBUG,1);
|
||||
|
||||
LOG_ENTER(MAC);
|
||||
LOG_I(EMU, "4 Starting OAI logs version %s Build date: %s on %s\n",
|
||||
BUILD_VERSION, BUILD_DATE, BUILD_HOST);
|
||||
LOG_D(MAC, "4 debug MAC \n");
|
||||
LOG_W(MAC, "4 warning MAC \n");
|
||||
LOG_I(MAC, "4 info MAC \n");
|
||||
|
||||
|
||||
set_log(MAC, LOG_DEBUG,0);
|
||||
set_log(EMU, LOG_DEBUG,0);
|
||||
|
||||
LOG_I(LOG, "5 Starting OAI logs version %s Build date: %s on %s\n",
|
||||
BUILD_VERSION, BUILD_DATE, BUILD_HOST);
|
||||
LOG_D(MAC, "5 debug MAC \n");
|
||||
LOG_W(MAC, "5 warning MAC \n");
|
||||
LOG_I(MAC, "5 info MAC \n");
|
||||
|
||||
|
||||
set_log(MAC, LOG_TRACE,0X07F);
|
||||
set_log(EMU, LOG_TRACE,0X07F);
|
||||
|
||||
LOG_ENTER(MAC);
|
||||
LOG_I(LOG, "6 Starting OAI logs version %s Build date: %s on %s\n",
|
||||
BUILD_VERSION, BUILD_DATE, BUILD_HOST);
|
||||
LOG_D(MAC, "6 debug MAC \n");
|
||||
LOG_W(MAC, "6 warning MAC \n");
|
||||
LOG_I(MAC, "6 info MAC \n");
|
||||
LOG_EXIT(MAC);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,492 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
/*! \file log.h
|
||||
* \brief openair log generator (OLG) for
|
||||
* \author Navid Nikaein
|
||||
* \date 2009 - 2014
|
||||
* \version 0.5
|
||||
* @ingroup util
|
||||
|
||||
*/
|
||||
|
||||
#ifndef __LOG_H__
|
||||
# define __LOG_H__
|
||||
|
||||
/*--- INCLUDES ---------------------------------------------------------------*/
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <syslog.h>
|
||||
#include <assert.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdarg.h>
|
||||
#include <time.h>
|
||||
#include <stdint.h>
|
||||
#ifndef __STDC_FORMAT_MACROS
|
||||
#define __STDC_FORMAT_MACROS
|
||||
#endif
|
||||
#include <inttypes.h>
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
#include <pthread.h>
|
||||
#include "T.h"
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** @defgroup _LOG LOG Generator
|
||||
* @{*/
|
||||
/* @}*/
|
||||
|
||||
/** @defgroup _macro Macro Definition
|
||||
* @ingroup _LOG
|
||||
* @brief these macros are used in the code of LOG
|
||||
* @{*/
|
||||
/* @}*/
|
||||
|
||||
/** @defgroup _max_length Maximum Length of LOG
|
||||
* @ingroup _macro
|
||||
* @brief the macros that describe the maximum length of LOG
|
||||
* @{*/
|
||||
|
||||
#define MAX_LOG_TOTAL 1500 /*!< \brief the maximum length of a log */
|
||||
/* @}*/
|
||||
|
||||
/** @defgroup _log_level Message levels defined by LOG
|
||||
* @ingroup _macro
|
||||
* @brief LOG defines 9 levels of messages for users. Importance of these levels decrease gradually from 0 to 8
|
||||
* @{*/
|
||||
|
||||
# define OAILOG_ERR 0 /*!< \brief critical error conditions, impact on "must have" fuctinalities */
|
||||
# define OAILOG_FILE 1 /*!< \brief important informational messages, but everything OK */
|
||||
# define OAILOG_WARNING 2 /*!< \brief warning conditions, shouldn't happen but doesn't impact "must have" functionalities */
|
||||
# define OAILOG_INFO 3 /*!< \brief informational messages most people don't need, shouldn't impact real-time behavior */
|
||||
# define OAILOG_DEBUG 4 /*!< \brief first level debug-level messages, for developers , may impact real-time behavior */
|
||||
# define OAILOG_TRACE 5 /*!< \brief second level debug-level messages, for developers ,likely impact real-time behavior*/
|
||||
|
||||
#define NUM_LOG_LEVEL 6 /*!< \brief the number of message levels users have with LOG */
|
||||
/* @}*/
|
||||
|
||||
|
||||
/** @defgroup _log_format Defined log format
|
||||
* @ingroup _macro
|
||||
* @brief Macro of log formats defined by LOG
|
||||
* @{*/
|
||||
|
||||
/* .log_format = 0x13 uncolored standard messages
|
||||
* .log_format = 0x93 colored standard messages */
|
||||
/* keep white space in first position; switching it to 0 allows colors to be disabled*/
|
||||
#define LOG_RED "\033[1;31m" /*!< \brief VT100 sequence for bold red foreground */
|
||||
#define LOG_GREEN "\033[32m" /*!< \brief VT100 sequence for green foreground */
|
||||
#define LOG_ORANGE "\033[93m" /*!< \brief VT100 sequence for orange foreground */
|
||||
#define LOG_BLUE "\033[34m" /*!< \brief VT100 sequence for blue foreground */
|
||||
#define LOG_CYBL "\033[40;36m" /*!< \brief VT100 sequence for cyan foreground on black background */
|
||||
#define LOG_RESET "\033[0m" /*!< \brief VT100 sequence for reset (black) foreground */
|
||||
/* @}*/
|
||||
|
||||
|
||||
/** @defgroup _syslog_conf Macros for write in syslog.conf
|
||||
* @ingroup _macro
|
||||
* @brief Macros used to write lines (local/remote) in syslog.conf
|
||||
* @{*/
|
||||
|
||||
|
||||
#define FLAG_NOCOLOR 0x0001 /*!< \brief use colors in log messages, depending on level */
|
||||
#define FLAG_THREAD 0x0008 /*!< \brief display thread name in log messages */
|
||||
#define FLAG_LEVEL 0x0010 /*!< \brief display log level in log messages */
|
||||
#define FLAG_FUNCT 0x0020
|
||||
#define FLAG_FILE_LINE 0x0040
|
||||
#define FLAG_TIME 0x0100
|
||||
|
||||
#define SET_LOG_OPTION(O) g_log->flag = (g_log->flag | O)
|
||||
#define CLEAR_LOG_OPTION(O) g_log->flag = (g_log->flag & (~O))
|
||||
|
||||
/** @defgroup macros to identify a debug entity
|
||||
* @ingroup each macro is a bit mask where the unique bit set identifies an entity to be debugged
|
||||
* it allows to dynamically activate or not blocks of code
|
||||
* @brief
|
||||
* @{*/
|
||||
#define DEBUG_PRACH (1<<0)
|
||||
#define DEBUG_RU (1<<1)
|
||||
#define DEBUG_UE_PHYPROC (1<<2)
|
||||
#define DEBUG_LTEESTIM (1<<3)
|
||||
#define DEBUG_CTRLSOCKET (1<<10)
|
||||
#define UE_TIMING (1<<20)
|
||||
|
||||
#define SET_LOG_DEBUG(O) g_log->debug_mask = (g_log->debug_mask | O)
|
||||
#define CLEAR_LOG_DEBUG(O) g_log->debug_mask = (g_log->debug_mask & (~O))
|
||||
|
||||
#define SET_LOG_MATLAB(O) g_log->matlab_mask = (g_log->matlab_mask | O)
|
||||
#define CLEAR_LOG_MATLAB(O) g_log->matlab_mask = (g_log->matlab_mask & (~O))
|
||||
|
||||
|
||||
|
||||
typedef enum {
|
||||
MIN_LOG_COMPONENTS = 0,
|
||||
PHY = MIN_LOG_COMPONENTS,
|
||||
MAC,
|
||||
SIM,
|
||||
OCG,
|
||||
OMG,
|
||||
OPT,
|
||||
OTG,
|
||||
OTG_LATENCY,
|
||||
OTG_LATENCY_BG,
|
||||
OTG_GP,
|
||||
OTG_GP_BG,
|
||||
OTG_JITTER,
|
||||
RLC,
|
||||
PDCP,
|
||||
RRC,
|
||||
NAS,
|
||||
PERF,
|
||||
OIP,
|
||||
CLI,
|
||||
MSC,
|
||||
OCM,
|
||||
UDP_,
|
||||
GTPU,
|
||||
SPGW,
|
||||
S1AP,
|
||||
SCTP,
|
||||
HW,
|
||||
OSA,
|
||||
RAL_ENB,
|
||||
RAL_UE,
|
||||
ENB_APP,
|
||||
FLEXRAN_AGENT,
|
||||
TMR,
|
||||
USIM,
|
||||
LOCALIZE,
|
||||
RRH,
|
||||
X2AP,
|
||||
GNB_APP,
|
||||
NR_RRC,
|
||||
NR_MAC,
|
||||
NR_PHY,
|
||||
MAX_LOG_COMPONENTS,
|
||||
LOADER,
|
||||
MAX_LOG_PREDEF_COMPONENTS,
|
||||
}
|
||||
comp_name_t;
|
||||
|
||||
#define MAX_LOG_DYNALLOC_COMPONENTS 20
|
||||
#define MAX_LOG_COMPONENTS (MAX_LOG_PREDEF_COMPONENTS + MAX_LOG_DYNALLOC_COMPONENTS)
|
||||
|
||||
|
||||
typedef struct {
|
||||
char *name; /*!< \brief string name of item */
|
||||
int value; /*!< \brief integer value of mapping */
|
||||
} mapping;
|
||||
|
||||
typedef int(*log_write_func_t)(FILE *stream, const char *format, va_list ap );
|
||||
|
||||
typedef struct {
|
||||
const char *name;
|
||||
int level;
|
||||
int flag;
|
||||
int interval;
|
||||
int filelog;
|
||||
char *filelog_name;
|
||||
FILE *stream;
|
||||
log_write_func_t fwrite;
|
||||
/* SR: make the log buffer component relative */
|
||||
char log_buffer[MAX_LOG_TOTAL];
|
||||
} log_component_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
log_component_t log_component[MAX_LOG_COMPONENTS];
|
||||
char* level2string[NUM_LOG_LEVEL];
|
||||
int onlinelog;
|
||||
int flag;
|
||||
int filelog;
|
||||
char* filelog_name;
|
||||
uint64_t debug_mask;
|
||||
uint64_t matlab_mask;
|
||||
} log_t;
|
||||
|
||||
|
||||
#if defined(ENABLE_ITTI)
|
||||
typedef enum log_instance_type_e {
|
||||
LOG_INSTANCE_UNKNOWN,
|
||||
LOG_INSTANCE_ENB,
|
||||
LOG_INSTANCE_UE,
|
||||
} log_instance_type_t;
|
||||
|
||||
void log_set_instance_type (log_instance_type_t instance);
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef LOG_MAIN
|
||||
log_t *g_log;
|
||||
#else
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
extern log_t *g_log;
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
/*--- INCLUDES ---------------------------------------------------------------*/
|
||||
# include "log_if.h"
|
||||
/*----------------------------------------------------------------------------*/
|
||||
int logInit (void);
|
||||
void logRecord_mt(const char *file, const char *func, int line,int comp, int level, const char *format, ...) __attribute__ ((format (printf, 6, 7)));
|
||||
|
||||
int set_log(int component, int level, int interval);
|
||||
void set_glog(int level);
|
||||
|
||||
void set_glog_onlinelog(int enable);
|
||||
void set_glog_filelog(int enable);
|
||||
void set_component_filelog(int comp);
|
||||
|
||||
int map_str_to_int(mapping *map, const char *str);
|
||||
char *map_int_to_str(mapping *map, int val);
|
||||
void logClean (void);
|
||||
int is_newline( char *str, int size);
|
||||
|
||||
int register_log_component(char *name, char *fext, int compidx);
|
||||
|
||||
/* @}*/
|
||||
|
||||
/*!\fn int32_t write_file_matlab(const char *fname, const char *vname, void *data, int length, int dec, char format);
|
||||
\brief Write output file from signal data
|
||||
@param fname output file name
|
||||
@param vname output vector name (for MATLAB/OCTAVE)
|
||||
@param data point to data
|
||||
@param length length of data vector to output
|
||||
@param dec decimation level
|
||||
@param format data format (0 = real 16-bit, 1 = complex 16-bit,2 real 32-bit, 3 complex 32-bit,4 = real 8-bit, 5 = complex 8-bit)
|
||||
*/
|
||||
int32_t write_file_matlab(const char *fname, const char *vname, void *data, int length, int dec, char format);
|
||||
|
||||
/*----------------macro definitions for reading log configuration from the config module */
|
||||
#define CONFIG_STRING_LOG_PREFIX "log_config"
|
||||
|
||||
#define LOG_CONFIG_STRING_GLOBAL_LOG_LEVEL "global_log_level"
|
||||
#define LOG_CONFIG_STRING_GLOBAL_LOG_ONLINE "global_log_online"
|
||||
#define LOG_CONFIG_STRING_GLOBAL_LOG_INFILE "global_log_infile"
|
||||
#define LOG_CONFIG_STRING_GLOBAL_LOG_OPTIONS "global_log_options"
|
||||
|
||||
#define LOG_CONFIG_LEVEL_FORMAT "%s_log_level"
|
||||
#define LOG_CONFIG_LOGFILE_FORMAT "%s_log_infile"
|
||||
#define LOG_CONFIG_DEBUG_FORMAT "%s_debug"
|
||||
#define LOG_CONFIG_MATLAB_FORMAT "%s_matlab"
|
||||
|
||||
#define LOG_CONFIG_HELP_OPTIONS " list of comma separated options to enable log module behavior. Available options: \n"\
|
||||
" nocolor: disable color usage in log messages\n"\
|
||||
" level: add log level indication in log messages\n"\
|
||||
" thread: add threads names in log messages\n"
|
||||
|
||||
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
|
||||
/* LOG globalconfiguration parameters */
|
||||
/* optname help paramflags XXXptr defXXXval type numelt */
|
||||
/*------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
|
||||
#define LOG_GLOBALPARAMS_DESC { \
|
||||
{LOG_CONFIG_STRING_GLOBAL_LOG_LEVEL, "Default log level for all componemts\n", 0, strptr:(char **)&gloglevel, defstrval:log_level_names[2].name, TYPE_STRING, 0}, \
|
||||
{LOG_CONFIG_STRING_GLOBAL_LOG_ONLINE, "Default console output option, for all components\n", 0, iptr:&(g_log->onlinelog), defintval:1, TYPE_INT, 0}, \
|
||||
{LOG_CONFIG_STRING_GLOBAL_LOG_OPTIONS, LOG_CONFIG_HELP_OPTIONS, 0, strlistptr:NULL, defstrlistval:NULL, TYPE_STRINGLIST,0} \
|
||||
}
|
||||
|
||||
#define LOG_OPTIONS_IDX 2
|
||||
/*----------------------------------------------------------------------------------*/
|
||||
/** @defgroup _debugging debugging macros
|
||||
* @ingroup _macro
|
||||
* @brief Macro used to call logIt function with different message levels
|
||||
* @{*/
|
||||
|
||||
// debugging macros(g_log->log_component[component].interval?logRecord_mt(__FILE__, __FUNCTION__, __LINE__, component, level, format, ##args):(void)0)
|
||||
# if T_TRACER
|
||||
/* per component, level dependant macros */
|
||||
# define LOG_I(c, x...) do { if (T_stdout) { if( g_log->log_component[c].level >= OAILOG_INFO ) logRecord_mt(__FILE__, __FUNCTION__, __LINE__,c, OAILOG_INFO, x) ;} else { T(T_LEGACY_ ## c ## _INFO, T_PRINTF(x)) ;}} while (0)
|
||||
# define LOG_W(c, x...) do { if (T_stdout) { if( g_log->log_component[c].level >= OAILOG_WARNING) logRecord_mt(__FILE__, __FUNCTION__, __LINE__,c, OAILOG_WARNING, x) ;} else { T(T_LEGACY_ ## c ## _WARNING, T_PRINTF(x)) ;}} while (0)
|
||||
# define LOG_E(c, x...) do { if (T_stdout) { if( g_log->log_component[c].level >= OAILOG_ERR ) logRecord_mt(__FILE__, __FUNCTION__, __LINE__,c, OAILOG_ERR, x) ;} else { T(T_LEGACY_ ## c ## _ERROR, T_PRINTF(x)) ;}} while (0)
|
||||
# define LOG_D(c, x...) do { if (T_stdout) { if( g_log->log_component[c].level >= OAILOG_DEBUG ) logRecord_mt(__FILE__, __FUNCTION__, __LINE__,c, OAILOG_DEBUG, x) ;} else { T(T_LEGACY_ ## c ## _DEBUG, T_PRINTF(x)) ;}} while (0)
|
||||
# define LOG_T(c, x...) do { if (T_stdout) { if( g_log->log_component[c].level >= OAILOG_TRACE ) logRecord_mt(__FILE__, __FUNCTION__, __LINE__,c, OAILOG_TRACE, x) ;} else { T(T_LEGACY_ ## c ## _TRACE, T_PRINTF(x)) ;}} while (0)
|
||||
# define LOG_F(c, x...) do { if (T_stdout) { if( g_log->log_component[c].level >= OAILOG_FILE ) logRecord_mt(__FILE__, __FUNCTION__, __LINE__,c, OAILOG_FILE, x) ;}} while (0) /* */
|
||||
# define nfapi_log(FILE, FNC, LN, COMP, LVL, F...) do { if (T_stdout) { logRecord_mt(__FILE__, __FUNCTION__, __LINE__,COMP, LVL, F) ;}} while (0) /* */
|
||||
/* bitmask dependant macros, to isolate debugging code */
|
||||
# define LOG_DEBUG_BEGIN(D) if (g_log->debug_mask & D) {
|
||||
# define LOG_DEBUG_END }
|
||||
/* bitmask dependant macros, to generate matlab files */
|
||||
# define LOG_M_BEGIN(D) if (g_log->matlab_mask & D) {
|
||||
# define LOG_M_END }
|
||||
# define LOG_M(file, vector, data, len, dec, format) do { write_file_matlab(file, vector, data, len, dec, format);} while(0)/* */
|
||||
/* define variable only used in LOG macro's */
|
||||
# define LOG_VAR(A,B) A B
|
||||
# else /* T_TRACER: remove all debugging and tracing messages, except errors */
|
||||
# define LOG_I(c, x...) /* */
|
||||
# define LOG_W(c, x...) /* */
|
||||
# define LOG_E(c, x...) /* */
|
||||
# define LOG_D(c, x...) /* */
|
||||
# define LOG_T(c, x...) /* */
|
||||
# define LOG_F(c, x...) /* */
|
||||
# define nfapi_log(FILE, FNC, LN, COMP, LVL, FMT...)
|
||||
# define LOG_DEBUG_BEGIN(D) if (0) {
|
||||
# define LOG_DEBUG_END }
|
||||
# define LOG_M_BEGIN(D) if (0) {
|
||||
# define LOG_M_END }
|
||||
# define LOG_M(file, vector, data, len, dec, format)
|
||||
# define LOG_VAR(A,B)
|
||||
# endif /* T_TRACER */
|
||||
/* avoid warnings for variables only used in LOG macro's but set outside debug section */
|
||||
#define LOG_USEDINLOG_VAR(A,B) __attribute__((unused)) A B
|
||||
|
||||
/* unfiltered macros, usefull for simulators or messages at init time, before log is configured */
|
||||
#define LOG_UM(file, vector, data, len, dec, format) do { write_file_matlab(file, vector, data, len, dec, format);} while(0)
|
||||
|
||||
#define LOG_UI(c, x...) do {logRecord_mt(__FILE__, __FUNCTION__, __LINE__,c, OAILOG_INFO, x) ; } while(0)
|
||||
/* @}*/
|
||||
|
||||
|
||||
/** @defgroup _useful_functions useful functions in LOG
|
||||
* @ingroup _macro
|
||||
* @brief Macro of some useful functions defined by LOG
|
||||
* @{*/
|
||||
#define LOG_ENTER(c) do {LOG_T(c, "Entering\n");}while(0) /*!< \brief Macro to log a message with severity DEBUG when entering a function */
|
||||
#define LOG_EXIT(c) do {LOG_T(c,"Exiting\n"); return;}while(0) /*!< \brief Macro to log a message with severity TRACE when exiting a function */
|
||||
#define LOG_RETURN(c,x) do {uint32_t __rv;__rv=(unsigned int)(x);LOG_T(c,"Returning %08x\n", __rv);return((typeof(x))__rv);}while(0) /*!< \brief Macro to log a function exit, including integer value, then to return a value to the calling function */
|
||||
/* @}*/
|
||||
|
||||
static __inline__ uint64_t rdtsc(void) {
|
||||
uint32_t a, d;
|
||||
__asm__ volatile ("rdtsc" : "=a" (a), "=d" (d));
|
||||
return (((uint64_t)d)<<32) | ((uint64_t)a);
|
||||
}
|
||||
|
||||
#define DEBUG_REALTIME 1
|
||||
#if DEBUG_REALTIME
|
||||
|
||||
extern double cpuf;
|
||||
|
||||
static inline uint64_t checkTCPU(int timeout, char * file, int line) {
|
||||
static __thread uint64_t lastCPUTime=0;
|
||||
static __thread uint64_t last=0;
|
||||
uint64_t cur=rdtsc();
|
||||
struct timespec CPUt;
|
||||
clock_gettime(CLOCK_THREAD_CPUTIME_ID, &CPUt);
|
||||
uint64_t CPUTime=CPUt.tv_sec*1000*1000+CPUt.tv_nsec/1000;
|
||||
double microCycles=(double)(cpuf*1000);
|
||||
int duration=(int)((cur-last)/microCycles);
|
||||
if ( last!=0 && duration > timeout ) {
|
||||
//struct timespec ts;
|
||||
//clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
printf("%s:%d lte-ue delay %d (exceed %d), CPU for this period: %lld\n", file, line,
|
||||
duration, timeout, (long long)CPUTime-lastCPUTime );
|
||||
}
|
||||
last=cur;
|
||||
lastCPUTime=CPUTime;
|
||||
return cur;
|
||||
}
|
||||
|
||||
static inline unsigned long long checkT(int timeout, char * file, int line) {
|
||||
static __thread unsigned long long last=0;
|
||||
unsigned long long cur=rdtsc();
|
||||
int microCycles=(int)(cpuf*1000);
|
||||
int duration=(int)((cur-last)/microCycles);
|
||||
if ( last!=0 && duration > timeout )
|
||||
printf("%s:%d lte-ue delay %d (exceed %d)\n", file, line,
|
||||
duration, timeout);
|
||||
last=cur;
|
||||
return cur;
|
||||
}
|
||||
|
||||
typedef struct m {
|
||||
uint64_t iterations;
|
||||
uint64_t sum;
|
||||
uint64_t maxArray[11];
|
||||
} Meas;
|
||||
|
||||
static inline void printMeas(char * txt, Meas *M, int period) {
|
||||
if (M->iterations%period == 0 ) {
|
||||
char txt2[512];
|
||||
sprintf(txt2,"%s avg=%" PRIu64 " iterations=%" PRIu64 " max=%"
|
||||
PRIu64 ":%" PRIu64 ":%" PRIu64 ":%" PRIu64 ":%" PRIu64 ":%" PRIu64 ":%" PRIu64 ":%" PRIu64 ":%" PRIu64 ":%" PRIu64 "\n",
|
||||
txt,
|
||||
M->sum/M->iterations,
|
||||
M->iterations,
|
||||
M->maxArray[1],M->maxArray[2], M->maxArray[3],M->maxArray[4], M->maxArray[5],
|
||||
M->maxArray[6],M->maxArray[7], M->maxArray[8],M->maxArray[9],M->maxArray[10]);
|
||||
#if DISABLE_LOG_X
|
||||
printf("%s",txt2);
|
||||
#else
|
||||
LOG_W(PHY, "%s",txt2);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static inline int cmpint(const void* a, const void* b) {
|
||||
uint64_t* aa=(uint64_t*)a;
|
||||
uint64_t* bb=(uint64_t*)b;
|
||||
return (int)(*aa-*bb);
|
||||
}
|
||||
|
||||
static inline void updateTimes(uint64_t start, Meas *M, int period, char * txt) {
|
||||
if (start!=0) {
|
||||
uint64_t end=rdtsc();
|
||||
long long diff=(end-start)/(cpuf*1000);
|
||||
M->maxArray[0]=diff;
|
||||
M->sum+=diff;
|
||||
M->iterations++;
|
||||
qsort(M->maxArray, 11, sizeof(uint64_t), cmpint);
|
||||
printMeas(txt,M,period);
|
||||
}
|
||||
}
|
||||
|
||||
#define check(a) do { checkT(a,__FILE__,__LINE__); } while (0)
|
||||
#define checkcpu(a) do { checkTCPU(a,__FILE__,__LINE__); } while (0)
|
||||
#define initRefTimes(a) static __thread Meas a= {0}
|
||||
#define pickTime(a) uint64_t a=rdtsc()
|
||||
#define readTime(a) a
|
||||
#define initStaticTime(a) static __thread uint64_t a={0}
|
||||
#define pickStaticTime(a) do { a=rdtsc(); } while (0)
|
||||
|
||||
#else
|
||||
#define check(a) do {} while (0)
|
||||
#define checkcpu(a) do {} while (0)
|
||||
#define initRefTimes(a) do {} while (0)
|
||||
#define initStaticTime(a) do {} while (0)
|
||||
#define pickTime(a) do {} while (0)
|
||||
#define readTime(a) 0
|
||||
#define pickStaticTime(a) do {} while (0)
|
||||
#define updateTimes(a,b,c,d) do {} while (0)
|
||||
#define printMeas(a,b,c) do {} while (0)
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -19,16 +19,12 @@
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
#ifndef INTERTASK_INTERFACE_DUMP_H_
|
||||
#define INTERTASK_INTERFACE_DUMP_H_
|
||||
#include"log.h"
|
||||
|
||||
int itti_dump_queue_message(task_id_t sender_task, message_number_t message_number, MessageDef *message_p, const char *message_name,
|
||||
const uint32_t message_size);
|
||||
extern log_t *g_log;
|
||||
|
||||
int itti_dump_init(const char * const messages_definition_xml, const char * const dump_file_name);
|
||||
|
||||
void itti_dump_exit(void);
|
||||
extern mapping log_level_names[];
|
||||
extern mapping log_options[];
|
||||
extern mapping log_maskmap[];
|
||||
|
||||
void itti_dump_thread_use_ring_buffer(void);
|
||||
|
||||
#endif /* INTERTASK_INTERFACE_DUMP_H_ */
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
/*! \file log_if.h
|
||||
* \brief log interface
|
||||
* \author Navid Nikaein
|
||||
* \date 2009 - 2014
|
||||
* \version 0.3
|
||||
* \warning This component can be runned only in user-space
|
||||
* @ingroup routing
|
||||
*/
|
||||
|
||||
// LTS: kept this file for compatibility
|
||||
// this file was probably a trial to separate internal functions and external ones
|
||||
// but it has never been finished, most source code include directly log.h (not log_if.h)
|
||||
#include "log.h"
|
||||
@@ -0,0 +1,823 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
/*! \file vcd_signal_dumper.c
|
||||
* \brief Dump functions calls and variables to VCD file. Use GTKWave to display this file.
|
||||
* \author S. Roux
|
||||
* \maintainer: navid nikaein
|
||||
* \date 2012 - 2104
|
||||
* \version 0.1
|
||||
* \company Eurecom
|
||||
* \email: navid.nikaein@eurecom.fr
|
||||
* \note
|
||||
* \warning
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <error.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "assertions.h"
|
||||
#include "signals.h"
|
||||
|
||||
#include "vcd_signal_dumper.h"
|
||||
|
||||
#define VCDSIGNALDUMPER_VERSION_MAJOR 0
|
||||
#define VCDSIGNALDUMPER_VERSION_MINOR 1
|
||||
|
||||
// Global variable. If the VCD option is set at execution time, output VCD trace. Otherwise this module has no effect.
|
||||
int ouput_vcd = 0;
|
||||
|
||||
struct vcd_module_s {
|
||||
const char *name;
|
||||
int number_of_signals;
|
||||
const char **signals_names;
|
||||
vcd_signal_type signal_type;
|
||||
int signal_size;
|
||||
} vcd_module_s;
|
||||
|
||||
const char* eurecomVariablesNames[] = {
|
||||
"frame_number_TX0_eNB",
|
||||
"frame_number_TX1_eNB",
|
||||
"frame_number_RX0_eNB",
|
||||
"frame_number_RX1_eNB",
|
||||
"subframe_number_TX0_eNB",
|
||||
"subframe_number_TX1_eNB",
|
||||
"subframe_number_RX0_eNB",
|
||||
"subframe_number_RX1_eNB",
|
||||
"frame_number_TX0_RU",
|
||||
"frame_number_TX1_RU",
|
||||
"frame_number_RX0_RU",
|
||||
"frame_number_RX1_RU",
|
||||
"subframe_number_TX0_RU",
|
||||
"subframe_number_TX1_RU",
|
||||
"subframe_number_RX0_RU",
|
||||
"subframe_number_RX1_RU",
|
||||
"runtime_TX_eNB",
|
||||
"runtime_RX_eNB",
|
||||
"frame_number_TX0_UE",
|
||||
"frame_number_TX1_UE",
|
||||
"frame_number_RX0_UE",
|
||||
"frame_number_RX1_UE",
|
||||
"subframe_TX0_UE",
|
||||
"subframe_TX1_UE",
|
||||
"subframe_RX0_UE",
|
||||
"subframe_RX1_UE",
|
||||
"ue_rx_offset",
|
||||
"diff2",
|
||||
"hw_subframe",
|
||||
"hw_frame",
|
||||
"hw_subframe_rx",
|
||||
"hw_frame_rx",
|
||||
"txcnt",
|
||||
"rxcnt",
|
||||
"trx_ts",
|
||||
"trx_tst",
|
||||
"trx_ts_ue",
|
||||
"trx_tst_ue",
|
||||
"trx_write_flags",
|
||||
"tx_ts",
|
||||
"rx_ts",
|
||||
"hw_cnt_rx",
|
||||
"lhw_cnt_rx",
|
||||
"hw_cnt_tx",
|
||||
"lhw_cnt_tx",
|
||||
"pck_rx",
|
||||
"pck_tx",
|
||||
"rx_seq_num",
|
||||
"rx_seq_num_prv",
|
||||
"tx_seq_num",
|
||||
"cnt",
|
||||
"dummy_dump",
|
||||
"itti_send_msg",
|
||||
"itti_poll_msg",
|
||||
"itti_recv_msg",
|
||||
"itti_alloc_msg",
|
||||
"mp_alloc",
|
||||
"mp_free",
|
||||
"ue_inst_cnt_rx",
|
||||
"ue_inst_cnt_tx",
|
||||
"dci_info",
|
||||
"ue0_BSR",
|
||||
"ue0_BO",
|
||||
"ue0_scheduled",
|
||||
"ue0_timing_advance",
|
||||
"ue0_SR_ENERGY",
|
||||
"ue0_SR_THRES",
|
||||
"ue0_rssi0",
|
||||
"ue0_rssi1",
|
||||
"ue0_rssi2",
|
||||
"ue0_rssi3",
|
||||
"ue0_rssi4",
|
||||
"ue0_rssi5",
|
||||
"ue0_rssi6",
|
||||
"ue0_rssi7",
|
||||
"ue0_res0",
|
||||
"ue0_res1",
|
||||
"ue0_res2",
|
||||
"ue0_res3",
|
||||
"ue0_res4",
|
||||
"ue0_res5",
|
||||
"ue0_res6",
|
||||
"ue0_res7",
|
||||
"ue0_MCS0",
|
||||
"ue0_MCS1",
|
||||
"ue0_MCS2",
|
||||
"ue0_MCS3",
|
||||
"ue0_MCS4",
|
||||
"ue0_MCS5",
|
||||
"ue0_MCS6",
|
||||
"ue0_MCS7",
|
||||
"ue0_RB0",
|
||||
"ue0_RB1",
|
||||
"ue0_RB2",
|
||||
"ue0_RB3",
|
||||
"ue0_RB4",
|
||||
"ue0_RB5",
|
||||
"ue0_RB6",
|
||||
"ue0_RB7",
|
||||
"ue0_ROUND0",
|
||||
"ue0_ROUND1",
|
||||
"ue0_ROUND2",
|
||||
"ue0_ROUND3",
|
||||
"ue0_ROUND4",
|
||||
"ue0_ROUND5",
|
||||
"ue0_ROUND6",
|
||||
"ue0_ROUND7",
|
||||
"ue0_SFN0",
|
||||
"ue0_SFN1",
|
||||
"ue0_SFN2",
|
||||
"ue0_SFN3",
|
||||
"ue0_SFN4",
|
||||
"ue0_SFN5",
|
||||
"ue0_SFN6",
|
||||
"ue0_SFN7",
|
||||
"send_if4_symbol",
|
||||
"recv_if4_symbol",
|
||||
"send_if5_pkt_id",
|
||||
"recv_if5_pkt_id",
|
||||
"ue_pdcp_flush_size",
|
||||
"ue_pdcp_flush_err",
|
||||
"ue0_trx_read_ns",
|
||||
"ue0_trx_write_ns",
|
||||
"ue0_trx_read_ns_missing",
|
||||
"ue0_trx_write_ns_missing",
|
||||
"enb_thread_rxtx_CPUID",
|
||||
"ru_thread_CPUID",
|
||||
"ru_thread_tx_CPUID"
|
||||
};
|
||||
|
||||
const char* eurecomFunctionsNames[] = {
|
||||
/* softmodem signals */
|
||||
"rt_sleep",
|
||||
"trx_read",
|
||||
"trx_write",
|
||||
"trx_read_ue",
|
||||
"trx_write_ue",
|
||||
"trx_read_if",
|
||||
"trx_write_if",
|
||||
"eNB_thread_rxtx0",
|
||||
"eNB_thread_rxtx1",
|
||||
"ue_thread_synch",
|
||||
"ue_thread_rxtx0",
|
||||
"ue_thread_rxtx1",
|
||||
"trx_read_sf9",
|
||||
"trx_write_sf9",
|
||||
"ue_signal_cond_rxtx0",
|
||||
"ue_signal_cond_rxtx1",
|
||||
"ue_wait_cond_rxtx0",
|
||||
"ue_wait_cond_rxtx1",
|
||||
"ue_lock_mutex_rxtx_for_cond_wait0",
|
||||
"ue_lock_mutex_rxtx_for_cond_wait1",
|
||||
"ue_lock_mutex_rxtx_for_cnt_decrement0",
|
||||
"ue_lock_mutex_rxtx_for_cnt_decrement1",
|
||||
"ue_lock_mutex_rxtx_for_cnt_increment0",
|
||||
"ue_lock_mutex_rxtx_for_cnt_increment1",
|
||||
/* simulation signals */
|
||||
"do_DL_sig",
|
||||
"do_UL_sig",
|
||||
"UE_trx_read",
|
||||
/* RRH signals */
|
||||
"eNB_tx",
|
||||
"eNB_rx",
|
||||
"eNB_trx",
|
||||
"eNB_tm",
|
||||
"eNB_rx_sleep",
|
||||
"eNB_tx_sleep",
|
||||
"eNB_proc_sleep",
|
||||
"trx_read_rf",
|
||||
"trx_write_rf",
|
||||
|
||||
/* PHY signals */
|
||||
"ue_synch",
|
||||
"ue_slot_fep",
|
||||
"ue_rrc_measurements",
|
||||
"ue_gain_control",
|
||||
"ue_adjust_synch",
|
||||
"lte_ue_measurement_procedures",
|
||||
"lte_ue_pdcch_procedures",
|
||||
"lte_ue_pbch_procedures",
|
||||
"phy_procedures_eNb_tx0",
|
||||
"phy_procedures_eNb_tx1",
|
||||
"phy_procedures_ru_feprx0",
|
||||
"phy_procedures_ru_feprx1",
|
||||
"phy_procedures_ru_feptx_ofdm0",
|
||||
"phy_procedures_ru_feptx_ofdm1",
|
||||
"phy_procedures_ru_feptx_prec0",
|
||||
"phy_procedures_ru_feptx_prec1",
|
||||
"phy_procedures_eNb_rx_uespec0",
|
||||
"phy_procedures_eNb_rx_uespec1",
|
||||
"phy_procedures_ue_tx",
|
||||
"phy_procedures_ue_rx",
|
||||
"phy_procedures_ue_tx_ulsch_uespec",
|
||||
"phy_procedures_ue_tx_pucch",
|
||||
"phy_procedures_ue_tx_ulsch_common",
|
||||
"phy_procedures_ue_tx_prach",
|
||||
"phy_procedures_ue_tx_ulsch_rar",
|
||||
"phy_procedures_eNB_lte",
|
||||
"phy_procedures_UE_lte",
|
||||
"pdsch_thread",
|
||||
"dlsch_thread0",
|
||||
"dlsch_thread1",
|
||||
"dlsch_thread2",
|
||||
"dlsch_thread3",
|
||||
"dlsch_thread4",
|
||||
"dlsch_thread5",
|
||||
"dlsch_thread6",
|
||||
"dlsch_thread7",
|
||||
"dlsch_decoding0",
|
||||
"dlsch_decoding1",
|
||||
"dlsch_decoding2",
|
||||
"dlsch_decoding3",
|
||||
"dlsch_decoding4",
|
||||
"dlsch_decoding5",
|
||||
"dlsch_decoding6",
|
||||
"dlsch_decoding7",
|
||||
"rx_pdcch",
|
||||
"dci_decoding",
|
||||
"rx_phich",
|
||||
"pdsch_procedures",
|
||||
"pdsch_procedures_si",
|
||||
"pdsch_procedures_p",
|
||||
"pdsch_procedures_ra",
|
||||
"phy_ue_config_sib2",
|
||||
"macxface_phy_config_sib1_eNB",
|
||||
"macxface_phy_config_sib2_eNB",
|
||||
"macxface_phy_config_dedicated_eNB",
|
||||
"phy_ue_compute_prach",
|
||||
"phy_enb_ulsch_msg3",
|
||||
"phy_enb_ulsch_decoding0",
|
||||
"phy_enb_ulsch_decoding1",
|
||||
"phy_enb_ulsch_decoding2",
|
||||
"phy_enb_ulsch_decoding3",
|
||||
"phy_enb_ulsch_decoding4",
|
||||
"phy_enb_ulsch_decoding5",
|
||||
"phy_enb_ulsch_decoding6",
|
||||
"phy_enb_ulsch_decoding7",
|
||||
"phy_enb_sfgen",
|
||||
"phy_enb_prach_rx",
|
||||
"phy_ru_prach_rx",
|
||||
"phy_enb_pdcch_tx",
|
||||
"phy_enb_rs_tx",
|
||||
"phy_ue_generate_prach",
|
||||
"phy_ue_ulsch_modulation",
|
||||
"phy_ue_ulsch_encoding",
|
||||
#if 1 // add for debugging losing PDSCH immediately before and after reporting CQI
|
||||
"phy_ue_ulsch_encoding_fill_cqi",
|
||||
#endif
|
||||
"phy_ue_ulsch_scrambling",
|
||||
"phy_eNB_dlsch_modulation",
|
||||
"phy_eNB_dlsch_encoding",
|
||||
"phy_eNB_dlsch_encoding_w",
|
||||
"phy_eNB_dlsch_scrambling",
|
||||
"phy_eNB_beam_precoding",
|
||||
"phy_eNB_ofdm_mod_l",
|
||||
|
||||
/* MAC signals */
|
||||
"macxface_macphy_init",
|
||||
"macxface_macphy_exit",
|
||||
"macxface_eNB_dlsch_ulsch_scheduler",
|
||||
"macxface_fill_rar",
|
||||
"macxface_terminate_ra_proc",
|
||||
"macxface_initiate_ra_proc",
|
||||
"macxface_cancel_ra_proc",
|
||||
"macxface_get_dci_sdu",
|
||||
"macxface_get_dlsch_sdu",
|
||||
"macxface_rx_sdu",
|
||||
"macxface_mrbch_phy_sync_failure",
|
||||
"macxface_SR_indication",
|
||||
"mac_dlsch_preprocessor",
|
||||
"mac_schedule_dlsch",
|
||||
"mac_fill_dlsch_dci",
|
||||
|
||||
"macxface_out_of_sync_ind",
|
||||
"macxface_ue_decode_si",
|
||||
"macxface_ue_decode_pcch",
|
||||
"macxface_ue_decode_ccch",
|
||||
"macxface_ue_decode_bcch",
|
||||
"macxface_ue_send_sdu",
|
||||
"macxface_ue_get_sdu",
|
||||
"macxface_ue_get_rach",
|
||||
"macxface_ue_process_rar",
|
||||
"macxface_ue_scheduler",
|
||||
"macxface_ue_get_sr",
|
||||
|
||||
"ue_send_mch_sdu",
|
||||
|
||||
/*RLC signals */
|
||||
"rlc_data_req",
|
||||
// "rlc_data_ind", // this calls "pdcp_data_ind",
|
||||
"mac_rlc_status_ind",
|
||||
"mac_rlc_data_req",
|
||||
"mac_rlc_data_ind",
|
||||
"rlc_um_try_reassembly",
|
||||
"rlc_um_check_timer_dar_time_out",
|
||||
"rlc_um_receive_process_dar",
|
||||
|
||||
/* PDCP signals */
|
||||
"pdcp_run",
|
||||
"pdcp_data_req",
|
||||
"pdcp_data_ind",
|
||||
"pdcp_apply_security",
|
||||
"pdcp_validate_security",
|
||||
"pdcp_fifo_read",
|
||||
"pdcp_fifo_read_buffer",
|
||||
"pdcp_fifo_flush",
|
||||
"pdcp_fifo_flush_buffer",
|
||||
/* RRC signals */
|
||||
"rrc_rx_tx",
|
||||
"rrc_mac_config_req",
|
||||
"rrc_ue_decode_sib1",
|
||||
"rrc_ue_decode_si",
|
||||
/* GTPV1U signals */
|
||||
"gtpv1u_enb_task",
|
||||
"gtpv1u_process_udp_req",
|
||||
"gtpv1u_process_tunnel_data_req",
|
||||
/* UDP signals */
|
||||
"udp_enb_task",
|
||||
/* MISC signals */
|
||||
"emu_transport",
|
||||
"log_record",
|
||||
"itti_enqueue_message",
|
||||
"itti_dump_enqueue_message",
|
||||
"itti_dump_enqueue_message_malloc",
|
||||
"itti_relay_thread",
|
||||
"test",
|
||||
|
||||
/* IF4/IF5 signals */
|
||||
"send_if4",
|
||||
"recv_if4",
|
||||
"send_if5",
|
||||
"recv_if5",
|
||||
|
||||
"compress_if",
|
||||
"decompress_if",
|
||||
|
||||
"nfapi_subframe",
|
||||
"generate_pcfich",
|
||||
"generate_dci0",
|
||||
"generate_dlsch",
|
||||
"generate_phich",
|
||||
"pdcch_scrambling",
|
||||
"pdcch_modulation",
|
||||
"pdcch_interleaving",
|
||||
"pdcch_tx",
|
||||
|
||||
};
|
||||
|
||||
struct vcd_module_s vcd_modules[] = {
|
||||
{ "variables", VCD_SIGNAL_DUMPER_VARIABLES_END, eurecomVariablesNames, VCD_WIRE, 64 },
|
||||
{ "functions", VCD_SIGNAL_DUMPER_FUNCTIONS_END, eurecomFunctionsNames, VCD_WIRE, 1 },
|
||||
// { "ue_procedures_functions", VCD_SIGNAL_DUMPER_UE_PROCEDURES_FUNCTIONS_END, eurecomUEFunctionsNames, VCD_WIRE, 1 },
|
||||
};
|
||||
|
||||
FILE *vcd_fd = NULL;
|
||||
static inline unsigned long long int vcd_get_time(void);
|
||||
|
||||
#if defined(ENABLE_USE_CPU_EXECUTION_TIME)
|
||||
struct timespec g_time_start;
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(ENABLE_VCD_FIFO)
|
||||
|
||||
# define VCD_POLL_DELAY (500) // Poll delay in micro-seconds
|
||||
# define VCD_MAX_WAIT_DELAY (200 * 1000) // Maximum data ready wait delay in micro-seconds
|
||||
# define VCD_FIFO_NB_ELEMENTS (1 << 24) // Must be a power of 2
|
||||
# define VCD_FIFO_MASK (VCD_FIFO_NB_ELEMENTS - 1)
|
||||
|
||||
typedef struct vcd_queue_user_data_s {
|
||||
uint32_t log_id;
|
||||
vcd_signal_dumper_modules module;
|
||||
union data_u {
|
||||
struct function_s {
|
||||
vcd_signal_dump_functions function_name;
|
||||
vcd_signal_dump_in_out in_out;
|
||||
} function;
|
||||
struct variable_s {
|
||||
vcd_signal_dump_variables variable_name;
|
||||
unsigned long value;
|
||||
} variable;
|
||||
} data;
|
||||
|
||||
long long unsigned int time;
|
||||
} vcd_queue_user_data_t;
|
||||
|
||||
typedef struct vcd_fifo_s {
|
||||
vcd_queue_user_data_t user_data[VCD_FIFO_NB_ELEMENTS];
|
||||
|
||||
volatile uint32_t write_index;
|
||||
volatile uint32_t read_index;
|
||||
} vcd_fifo_t;
|
||||
|
||||
vcd_fifo_t vcd_fifo;
|
||||
|
||||
pthread_t vcd_dumper_thread;
|
||||
#endif
|
||||
|
||||
#define BYTE_SIZE 8
|
||||
#define NIBBLE_SIZE 4
|
||||
static void uint64_to_binary(uint64_t value, char *binary)
|
||||
{
|
||||
static const char * const nibbles_start[] = {
|
||||
"", "1", "10", "11",
|
||||
"100", "101", "110", "111",
|
||||
"1000", "1001", "1010", "1011",
|
||||
"1100", "1101", "1110", "1111",
|
||||
};
|
||||
static const char * const nibbles[] = {
|
||||
"0000", "0001", "0010", "0011",
|
||||
"0100", "0101", "0110", "0111",
|
||||
"1000", "1001", "1010", "1011",
|
||||
"1100", "1101", "1110", "1111",
|
||||
};
|
||||
int nibble;
|
||||
int nibble_value;
|
||||
int nibble_size;
|
||||
int zero = 1;
|
||||
|
||||
for (nibble = 0; nibble < (sizeof (uint64_t) * (BYTE_SIZE / NIBBLE_SIZE)); nibble++) {
|
||||
nibble_value = value >> ((sizeof (uint64_t) * BYTE_SIZE) - NIBBLE_SIZE);
|
||||
|
||||
if (zero) {
|
||||
if (nibble_value > 0) {
|
||||
zero = 0;
|
||||
nibble_size = strlen(nibbles_start[nibble_value]);
|
||||
memcpy (binary, nibbles_start[nibble_value], nibble_size);
|
||||
binary += nibble_size;
|
||||
}
|
||||
} else {
|
||||
memcpy (binary, nibbles[nibble_value], NIBBLE_SIZE);
|
||||
binary += NIBBLE_SIZE;
|
||||
}
|
||||
|
||||
value <<= NIBBLE_SIZE;
|
||||
}
|
||||
|
||||
/* Add a '0' if the value was null */
|
||||
if (zero) {
|
||||
binary[0] = '0';
|
||||
binary ++;
|
||||
}
|
||||
|
||||
/* Add a null value at the end of the string */
|
||||
binary[0] = '\0';
|
||||
}
|
||||
|
||||
#if defined(ENABLE_VCD_FIFO)
|
||||
inline static uint32_t vcd_get_write_index(void)
|
||||
{
|
||||
uint32_t write_index;
|
||||
uint32_t read_index;
|
||||
|
||||
/* Get current write index and increment it (atomic operation) */
|
||||
write_index = __sync_fetch_and_add(&vcd_fifo.write_index, 1);
|
||||
/* Wrap index */
|
||||
write_index &= VCD_FIFO_MASK;
|
||||
|
||||
/* Check FIFO overflow (increase VCD_FIFO_NB_ELEMENTS if this assert is triggered) */
|
||||
DevCheck((read_index = vcd_fifo.read_index, ((write_index + 1) & VCD_FIFO_MASK) != read_index), write_index, read_index, VCD_FIFO_NB_ELEMENTS);
|
||||
|
||||
return write_index;
|
||||
}
|
||||
|
||||
void *vcd_dumper_thread_rt(void *args)
|
||||
{
|
||||
vcd_queue_user_data_t *data;
|
||||
char binary_string[(sizeof (uint64_t) * BYTE_SIZE) + 1];
|
||||
struct sched_param sched_param;
|
||||
uint32_t data_ready_wait;
|
||||
|
||||
# if defined(ENABLE_ITTI)
|
||||
signal_mask();
|
||||
# endif
|
||||
|
||||
sched_param.sched_priority = sched_get_priority_min(SCHED_FIFO) + 1;
|
||||
sched_setscheduler(0, SCHED_FIFO, &sched_param);
|
||||
|
||||
while(1) {
|
||||
if (vcd_fifo.read_index == (vcd_fifo.write_index & VCD_FIFO_MASK)) {
|
||||
/* No element -> sleep a while */
|
||||
usleep(VCD_POLL_DELAY);
|
||||
} else {
|
||||
data = &vcd_fifo.user_data[vcd_fifo.read_index];
|
||||
data_ready_wait = 0;
|
||||
|
||||
while (data->module == VCD_SIGNAL_DUMPER_MODULE_FREE) {
|
||||
/* Check wait delay (increase VCD_MAX_WAIT_DELAY if this assert is triggered and that no thread is locked) */
|
||||
DevCheck(data_ready_wait < VCD_MAX_WAIT_DELAY, data_ready_wait, VCD_MAX_WAIT_DELAY, 0);
|
||||
|
||||
/* data is not yet ready, wait for it to be completed */
|
||||
data_ready_wait += VCD_POLL_DELAY;
|
||||
usleep(VCD_POLL_DELAY);
|
||||
}
|
||||
|
||||
switch (data->module) {
|
||||
case VCD_SIGNAL_DUMPER_MODULE_VARIABLES:
|
||||
if (vcd_fd != NULL) {
|
||||
int variable_name;
|
||||
variable_name = (int)data->data.variable.variable_name;
|
||||
fprintf(vcd_fd, "#%llu\n", data->time);
|
||||
/* Set variable to value */
|
||||
uint64_to_binary(data->data.variable.value, binary_string);
|
||||
fprintf(vcd_fd, "b%s %s_w\n", binary_string,
|
||||
eurecomVariablesNames[variable_name]);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case VCD_SIGNAL_DUMPER_MODULE_FUNCTIONS:
|
||||
if (vcd_fd != NULL) {
|
||||
int function_name;
|
||||
|
||||
function_name = (int)data->data.function.function_name;
|
||||
fprintf(vcd_fd, "#%llu\n", data->time);
|
||||
|
||||
/* Check if we are entering or leaving the function ( 0 = leaving, 1 = entering) */
|
||||
if (data->data.function.in_out == VCD_FUNCTION_IN)
|
||||
/* Set event to 1 */
|
||||
fprintf(vcd_fd, "1%s_w\n", eurecomFunctionsNames[function_name]);
|
||||
else
|
||||
fprintf(vcd_fd, "0%s_w\n", eurecomFunctionsNames[function_name]);
|
||||
|
||||
fflush(vcd_fd);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
DevParam(data->module, 0, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
data->module = VCD_SIGNAL_DUMPER_MODULE_FREE;
|
||||
vcd_fifo.read_index = (vcd_fifo.read_index + 1) & VCD_FIFO_MASK;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
void vcd_signal_dumper_init(char *filename)
|
||||
{
|
||||
if (ouput_vcd) {
|
||||
// char filename[] = "/tmp/openair_vcd_dump.vcd";
|
||||
|
||||
if ((vcd_fd = fopen(filename, "w+")) == NULL) {
|
||||
perror("vcd_signal_dumper_init: cannot open file");
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined(ENABLE_USE_CPU_EXECUTION_TIME)
|
||||
clock_gettime(CLOCK_MONOTONIC, &g_time_start);
|
||||
#endif
|
||||
|
||||
vcd_signal_dumper_create_header();
|
||||
|
||||
#if defined(ENABLE_VCD_FIFO)
|
||||
vcd_fifo.write_index = 0;
|
||||
vcd_fifo.read_index = 0;
|
||||
|
||||
fprintf(stderr, "[VCD] Creating dumper thread\n");
|
||||
|
||||
if (pthread_create(&vcd_dumper_thread, NULL, vcd_dumper_thread_rt, NULL) < 0) {
|
||||
fprintf(stderr, "vcd_signal_dumper_init: Failed to create thread: %s\n",
|
||||
strerror(errno));
|
||||
ouput_vcd = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void vcd_signal_dumper_close(void)
|
||||
{
|
||||
if (ouput_vcd) {
|
||||
#if defined(ENABLE_VCD_FIFO)
|
||||
|
||||
#else
|
||||
|
||||
if (vcd_fd != NULL) {
|
||||
fclose(vcd_fd);
|
||||
vcd_fd = NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static inline void vcd_signal_dumper_print_time_since_start(void)
|
||||
{
|
||||
if (vcd_fd != NULL) {
|
||||
#if defined(ENABLE_USE_CPU_EXECUTION_TIME)
|
||||
struct timespec time;
|
||||
long long unsigned int nanosecondsSinceStart;
|
||||
long long unsigned int secondsSinceStart;
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC, &time);
|
||||
|
||||
/* Get current execution time in nanoseconds */
|
||||
nanosecondsSinceStart = (long long unsigned int)((time.tv_nsec - g_time_start.tv_nsec));
|
||||
secondsSinceStart = (long long unsigned int)time.tv_sec - (long long unsigned int)g_time_start.tv_sec;
|
||||
/* Write time in nanoseconds */
|
||||
fprintf(vcd_fd, "#%llu\n", nanosecondsSinceStart + (secondsSinceStart * 1000000000UL));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static inline unsigned long long int vcd_get_time(void)
|
||||
{
|
||||
#if defined(ENABLE_USE_CPU_EXECUTION_TIME)
|
||||
struct timespec time;
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC, &time);
|
||||
|
||||
return (long long unsigned int)((time.tv_nsec - g_time_start.tv_nsec)) +
|
||||
((long long unsigned int)time.tv_sec - (long long unsigned int)g_time_start.tv_sec) * 1000000000UL;
|
||||
#endif
|
||||
}
|
||||
|
||||
void vcd_signal_dumper_create_header(void)
|
||||
{
|
||||
if (ouput_vcd) {
|
||||
struct tm *pDate;
|
||||
time_t intps;
|
||||
|
||||
intps = time(NULL);
|
||||
pDate = localtime(&intps);
|
||||
|
||||
if (vcd_fd != NULL) {
|
||||
int i, j;
|
||||
fprintf(vcd_fd, "$date\n\t%s$end\n", asctime(pDate));
|
||||
// Display version
|
||||
fprintf(vcd_fd, "$version\n\tVCD plugin ver%d.%d\n$end\n", VCDSIGNALDUMPER_VERSION_MAJOR, VCDSIGNALDUMPER_VERSION_MINOR);
|
||||
// Init timescale, here = 1ns
|
||||
fprintf(vcd_fd, "$timescale 1 ns $end\n");
|
||||
|
||||
/* Initialize each module definition */
|
||||
for(i = 0; i < sizeof(vcd_modules) / sizeof(struct vcd_module_s); i++) {
|
||||
struct vcd_module_s *module;
|
||||
module = &vcd_modules[i];
|
||||
fprintf(vcd_fd, "$scope module %s $end\n", module->name);
|
||||
|
||||
/* Declare each signal as defined in array */
|
||||
for (j = 0; j < module->number_of_signals; j++) {
|
||||
const char *signal_name;
|
||||
signal_name = module->signals_names[j];
|
||||
|
||||
if (VCD_WIRE == module->signal_type) {
|
||||
fprintf(vcd_fd, "$var wire %d %s_w %s $end\n", module->signal_size, signal_name, signal_name);
|
||||
} else if (VCD_REAL == module->signal_type) {
|
||||
fprintf(vcd_fd, "$var real %d %s_r %s $end\n", module->signal_size, signal_name, signal_name);
|
||||
} else {
|
||||
// Handle error here
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(vcd_fd, "$upscope $end\n");
|
||||
}
|
||||
|
||||
/* Init variables and functions to 0 */
|
||||
fprintf(vcd_fd, "$dumpvars\n");
|
||||
|
||||
for(i = 0; i < sizeof(vcd_modules) / sizeof(struct vcd_module_s); i++) {
|
||||
struct vcd_module_s *module;
|
||||
module = &vcd_modules[i];
|
||||
|
||||
/* Declare each signal as defined in array */
|
||||
for (j = 0; j < module->number_of_signals; j++) {
|
||||
const char *signal_name;
|
||||
signal_name = module->signals_names[j];
|
||||
|
||||
if (VCD_WIRE == module->signal_type) {
|
||||
if (module->signal_size > 1) {
|
||||
fprintf(vcd_fd, "b0 %s_w $end\n", signal_name);
|
||||
} else {
|
||||
fprintf(vcd_fd, "0%s_w $end\n", signal_name);
|
||||
}
|
||||
} else if (VCD_REAL == module->signal_type) {
|
||||
fprintf(vcd_fd, "r0 %s_r $end\n", signal_name);
|
||||
} else {
|
||||
// Handle error here
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(vcd_fd, "$end\n");
|
||||
fprintf(vcd_fd, "$enddefinitions $end\n\n");
|
||||
//fflush(vcd_fd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void vcd_signal_dumper_dump_variable_by_name(vcd_signal_dump_variables variable_name,
|
||||
unsigned long value)
|
||||
{
|
||||
DevCheck((0 <= variable_name) && (variable_name < VCD_SIGNAL_DUMPER_VARIABLES_END),
|
||||
variable_name, VCD_SIGNAL_DUMPER_VARIABLES_END, 0);
|
||||
|
||||
if (ouput_vcd) {
|
||||
#if defined(ENABLE_VCD_FIFO)
|
||||
uint32_t write_index = vcd_get_write_index();
|
||||
|
||||
vcd_fifo.user_data[write_index].time = vcd_get_time();
|
||||
vcd_fifo.user_data[write_index].data.variable.variable_name = variable_name;
|
||||
vcd_fifo.user_data[write_index].data.variable.value = value;
|
||||
vcd_fifo.user_data[write_index].module = VCD_SIGNAL_DUMPER_MODULE_VARIABLES; // Set when all other fields are set to validate the user_data
|
||||
#else
|
||||
char binary_string[(sizeof (uint64_t) * BYTE_SIZE) + 1];
|
||||
|
||||
if (vcd_fd != NULL) {
|
||||
vcd_signal_dumper_print_time_since_start();
|
||||
|
||||
/* Set variable to value */
|
||||
uint64_to_binary(value, binary_string);
|
||||
fprintf(vcd_fd, "b%s %s_w\n", binary_string, eurecomVariablesNames[variable_name]);
|
||||
//fflush(vcd_fd);
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void vcd_signal_dumper_dump_function_by_name(vcd_signal_dump_functions function_name,
|
||||
vcd_signal_dump_in_out in_out)
|
||||
{
|
||||
DevCheck((0 <= function_name) && (function_name < VCD_SIGNAL_DUMPER_FUNCTIONS_END),
|
||||
function_name, VCD_SIGNAL_DUMPER_FUNCTIONS_END, 0);
|
||||
|
||||
if (ouput_vcd) {
|
||||
#if defined(ENABLE_VCD_FIFO)
|
||||
uint32_t write_index = vcd_get_write_index();
|
||||
|
||||
vcd_fifo.user_data[write_index].time = vcd_get_time();
|
||||
vcd_fifo.user_data[write_index].data.function.function_name = function_name;
|
||||
vcd_fifo.user_data[write_index].data.function.in_out = in_out;
|
||||
vcd_fifo.user_data[write_index].module = VCD_SIGNAL_DUMPER_MODULE_FUNCTIONS; // Set when all other fields are set to validate the user_data
|
||||
#else
|
||||
|
||||
if (vcd_fd != NULL) {
|
||||
vcd_signal_dumper_print_time_since_start();
|
||||
|
||||
/* Check if we are entering or leaving the function ( 0 = leaving, 1 = entering) */
|
||||
if (in_out == VCD_FUNCTION_IN)
|
||||
/* Set event to 1 */
|
||||
fprintf(vcd_fd, "1%s_w\n", eurecomFunctionsNames[function_name]);
|
||||
else
|
||||
fprintf(vcd_fd, "0%s_w\n", eurecomFunctionsNames[function_name]);
|
||||
|
||||
//fflush(vcd_fd);
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,460 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
/*! \file vcd_signal_dumper.h
|
||||
* \brief Output functions call to VCD file which is readable by gtkwave.
|
||||
* \author ROUX Sebastien
|
||||
* \author S. Roux
|
||||
* \maintainer: navid nikaein
|
||||
* \date 2012 - 2104
|
||||
* \version 0.1
|
||||
* \company Eurecom
|
||||
* \email: navid.nikaein@eurecom.fr
|
||||
* \note
|
||||
* \warning
|
||||
*/
|
||||
|
||||
#ifndef VCD_SIGNAL_DUMPER_H_
|
||||
#define VCD_SIGNAL_DUMPER_H_
|
||||
|
||||
//#define ENABLE_USE_CPU_EXECUTION_TIME
|
||||
|
||||
/* WARNING: if you edit the enums below, update also string definitions in vcd_signal_dumper.c */
|
||||
typedef enum {
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX0_ENB=0,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX1_ENB,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_RX0_ENB,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_RX1_ENB,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_TX0_ENB,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_TX1_ENB,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_RX0_ENB,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_RX1_ENB,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX0_RU,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX1_RU,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_RX0_RU,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_RX1_RU,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_TX0_RU,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_TX1_RU,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_RX0_RU,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_RX1_RU,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_RUNTIME_TX_ENB,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_RUNTIME_RX_ENB,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX0_UE,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX1_UE,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_RX0_UE,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_RX1_UE,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_TX0_UE,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_TX1_UE,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_RX0_UE,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_RX1_UE,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_UE_RX_OFFSET,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_DIFF,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_HW_SUBFRAME,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_HW_FRAME,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_HW_SUBFRAME_RX,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_HW_FRAME_RX,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_TXCNT,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_RXCNT,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_TRX_TS,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_TRX_TS_UE,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST_UE,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_TRX_WRITE_FLAGS,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_TX_TS,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_RX_TS,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_RX_HWCNT,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_RX_LHWCNT,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_TX_HWCNT,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_TX_LHWCNT,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_RX_PCK,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_TX_PCK,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_RX_SEQ_NUM,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_RX_SEQ_NUM_PRV,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_TX_SEQ_NUM,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_CNT,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_DUMMY_DUMP,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_ITTI_SEND_MSG,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_ITTI_POLL_MSG,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_ITTI_RECV_MSG,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_ITTI_ALLOC_MSG,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_MP_ALLOC,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_MP_FREE,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_UE_INST_CNT_RX,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_UE_INST_CNT_TX,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_DCI_INFO,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_UE0_BSR,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_UE0_BO,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_UE0_SCHEDULED,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_UE0_TIMING_ADVANCE,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_UE0_SR_ENERGY,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_UE0_SR_THRES,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_UE0_RSSI0,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_UE0_RSSI1,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_UE0_RSSI2,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_UE0_RSSI3,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_UE0_RSSI4,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_UE0_RSSI5,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_UE0_RSSI6,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_UE0_RSSI7,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_UE0_RES0,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_UE0_RES1,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_UE0_RES2,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_UE0_RES3,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_UE0_RES4,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_UE0_RES5,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_UE0_RES6,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_UE0_RES7,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_UE0_MCS0,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_UE0_MCS1,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_UE0_MCS2,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_UE0_MCS3,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_UE0_MCS4,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_UE0_MCS5,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_UE0_MCS6,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_UE0_MCS7,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_UE0_RB0,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_UE0_RB1,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_UE0_RB2,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_UE0_RB3,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_UE0_RB4,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_UE0_RB5,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_UE0_RB6,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_UE0_RB7,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_UE0_ROUND0,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_UE0_ROUND1,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_UE0_ROUND2,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_UE0_ROUND3,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_UE0_ROUND4,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_UE0_ROUND5,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_UE0_ROUND6,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_UE0_ROUND7,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_UE0_SFN0,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_UE0_SFN1,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_UE0_SFN2,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_UE0_SFN3,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_UE0_SFN4,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_UE0_SFN5,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_UE0_SFN6,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_UE0_SFN7,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_SEND_IF4_SYMBOL,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_RECV_IF4_SYMBOL,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_SEND_IF5_PKT_ID,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_RECV_IF5_PKT_ID,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_UE_PDCP_FLUSH_SIZE,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_UE_PDCP_FLUSH_ERR,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_UE0_TRX_READ_NS,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_UE0_TRX_WRITE_NS,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_UE0_TRX_READ_NS_MISSING,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_UE0_TRX_WRITE_NS_MISSING,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_CPUID_ENB_THREAD_RXTX,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_CPUID_RU_THREAD,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_CPUID_RU_THREAD_TX,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_END
|
||||
} vcd_signal_dump_variables;
|
||||
|
||||
typedef enum {
|
||||
/* softmodem signals */
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_RT_SLEEP=0,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ_UE,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE_UE,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ_IF,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE_IF,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_PROC_RXTX0,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_PROC_RXTX1,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_UE_THREAD_SYNCH,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_UE_THREAD_RXTX0,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_UE_THREAD_RXTX1,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ_SF9,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE_SF9,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SIGNAL_COND_RXTX0,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SIGNAL_COND_RXTX1,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_UE_WAIT_COND_RXTX0,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_UE_WAIT_COND_RXTX1,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_UE_LOCK_MUTEX_RXTX_FOR_COND_WAIT0,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_UE_LOCK_MUTEX_RXTX_FOR_COND_WAIT1,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_UE_LOCK_MUTEX_RXTX_FOR_CNT_DECREMENT0,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_UE_LOCK_MUTEX_RXTX_FOR_CNT_DECREMENT1,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_UE_LOCK_MUTEX_RXTX_FOR_CNT_INCREMENT0,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_UE_LOCK_MUTEX_RXTX_FOR_CNT_INCREMENT1,
|
||||
/* SIMULATION signals */
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_SIM_DO_DL_SIGNAL,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_SIM_DO_UL_SIGNAL,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_SIM_UE_TRX_READ,
|
||||
/* RRH signals */
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_TX,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_RX,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_TRX,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_TM,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_RX_SLEEP,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_TX_SLEEP,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_PROC_SLEEP,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ_RF,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE_RF,
|
||||
|
||||
/* PHY signals */
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SYNCH,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SLOT_FEP,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_UE_RRC_MEASUREMENTS,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_UE_GAIN_CONTROL,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_UE_ADJUST_SYNCH,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_UE_MEASUREMENT_PROCEDURES,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_UE_PDCCH_PROCEDURES,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_UE_PBCH_PROCEDURES,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_ENB_TX,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_ENB_TX1,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPRX,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPRX1,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPTX_OFDM,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPTX_OFDM1,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPTX_PREC,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPTX_PREC1,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_ENB_RX_UESPEC,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_ENB_RX_UESPEC1,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_TX,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_RX,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_TX_ULSCH_UESPEC,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_TX_PUCCH,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_TX_ULSCH_COMMON,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_TX_PRACH,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_TX_ULSCH_RAR,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_ENB_LTE,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_LTE,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_PDSCH_THREAD,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_THREAD0,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_THREAD1,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_THREAD2,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_THREAD3,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_THREAD4,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_THREAD5,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_THREAD6,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_THREAD7,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_DECODING0,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_DECODING1,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_DECODING2,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_DECODING3,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_DECODING4,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_DECODING5,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_DECODING6,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_DECODING7,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_RX_PDCCH,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_DCI_DECODING,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_RX_PHICH,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_PDSCH_PROC,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_PDSCH_PROC_SI,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_PDSCH_PROC_P,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_PDSCH_PROC_RA,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_UE_CONFIG_SIB2,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_CONFIG_SIB1_ENB,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_CONFIG_SIB2_ENB,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_CONFIG_DEDICATED_ENB,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_UE_COMPUTE_PRACH,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_ULSCH_MSG3,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_ULSCH_DECODING0,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_ULSCH_DECODING1,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_ULSCH_DECODING2,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_ULSCH_DECODING3,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_ULSCH_DECODING4,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_ULSCH_DECODING5,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_ULSCH_DECODING6,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_ULSCH_DECODING7,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_SFGEN,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_PRACH_RX,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_RU_PRACH_RX,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_PDCCH_TX,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_RS_TX,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_UE_GENERATE_PRACH,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_UE_ULSCH_MODULATION,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_UE_ULSCH_ENCODING,
|
||||
#if 1 // add for debugging losing PDSCH immediately before and after reporting CQI
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_UE_ULSCH_ENCODING_FILL_CQI,
|
||||
#endif
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_UE_ULSCH_SCRAMBLING,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_DLSCH_MODULATION,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_DLSCH_ENCODING,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_DLSCH_ENCODING_W,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_DLSCH_SCRAMBLING,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_BEAM_PRECODING,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_OFDM_MODULATION,
|
||||
|
||||
/* MAC signals */
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_MACPHY_INIT,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_MACPHY_EXIT,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_DLSCH_ULSCH_SCHEDULER,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_FILL_RAR,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_TERMINATE_RA_PROC,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_INITIATE_RA_PROC,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_CANCEL_RA_PROC,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_GET_DCI_SDU,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_GET_DLSCH_SDU,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_RX_SDU,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_MRBCH_PHY_SYNC_FAILURE,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_SR_INDICATION,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_PREPROCESSOR,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_SCHEDULE_DLSCH, // schedule_ue_spec
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_FILL_DLSCH_DCI,
|
||||
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_OUT_OF_SYNC_IND,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_UE_DECODE_SI,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_UE_DECODE_PCCH,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_UE_DECODE_CCCH,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_UE_DECODE_BCCH,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SEND_SDU,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_UE_GET_SDU,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_UE_GET_RACH,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_UE_PROCESS_RAR,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SCHEDULER,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_UE_GET_SR,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SEND_MCH_SDU,
|
||||
|
||||
/* RLC signals */
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_RLC_DATA_REQ,
|
||||
// VCD_SIGNAL_DUMPER_FUNCTIONS_RLC_DATA_IND,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_MAC_RLC_STATUS_IND,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_MAC_RLC_DATA_REQ,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_MAC_RLC_DATA_IND,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_RLC_UM_TRY_REASSEMBLY,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_RLC_UM_CHECK_TIMER_DAR_TIME_OUT,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_RLC_UM_RECEIVE_PROCESS_DAR,
|
||||
|
||||
/* PDCP signals */
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_RUN,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_DATA_REQ,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_DATA_IND,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_APPLY_SECURITY,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_VALIDATE_SECURITY,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_FIFO_READ,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_FIFO_READ_BUFFER,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_FIFO_FLUSH,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_FIFO_FLUSH_BUFFER,
|
||||
|
||||
/* RRC signals */
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_RX_TX,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_MAC_CONFIG,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_UE_DECODE_SIB1,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_UE_DECODE_SI,
|
||||
|
||||
/* GTPV1U signals */
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_GTPV1U_ENB_TASK,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_GTPV1U_PROCESS_UDP_REQ,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_GTPV1U_PROCESS_TUNNEL_DATA_REQ,
|
||||
|
||||
/* UDP signals */
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_UDP_ENB_TASK,
|
||||
|
||||
/* MISC signals */
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_EMU_TRANSPORT,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_LOG_RECORD,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_ITTI_ENQUEUE_MESSAGE,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_ITTI_DUMP_ENQUEUE_MESSAGE,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_ITTI_DUMP_ENQUEUE_MESSAGE_MALLOC,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_ITTI_RELAY_THREAD,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_TEST,
|
||||
|
||||
/* IF4/IF5 signals */
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_SEND_IF4,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_RECV_IF4,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_SEND_IF5,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_RECV_IF5,
|
||||
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_COMPR_IF,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_DECOMPR_IF,
|
||||
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_NFAPI,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_GENERATE_PCFICH,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_GENERATE_DCI0,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_GENERATE_DLSCH,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_GENERATE_PHICH,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_PDCCH_SCRAMBLING,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_PDCCH_MODULATION,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_PDCCH_INTERLEAVING,
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_PDCCH_TX,
|
||||
|
||||
VCD_SIGNAL_DUMPER_FUNCTIONS_END
|
||||
} vcd_signal_dump_functions;
|
||||
|
||||
typedef enum {
|
||||
VCD_SIGNAL_DUMPER_MODULE_FREE = 0,
|
||||
|
||||
VCD_SIGNAL_DUMPER_MODULE_VARIABLES,
|
||||
VCD_SIGNAL_DUMPER_MODULE_FUNCTIONS,
|
||||
// VCD_SIGNAL_DUMPER_MODULE_UE_PROCEDURES_FUNCTIONS,
|
||||
} vcd_signal_dumper_modules;
|
||||
|
||||
typedef enum {
|
||||
VCD_FUNCTION_OUT,
|
||||
VCD_FUNCTION_IN,
|
||||
VCD_FUNCTION_LAST,
|
||||
} vcd_signal_dump_in_out;
|
||||
|
||||
typedef enum {
|
||||
VCD_REAL, // REAL = variable
|
||||
VCD_WIRE, // WIRE = Function
|
||||
} vcd_signal_type;
|
||||
|
||||
/*!
|
||||
* \brief Init function for the vcd dumper.
|
||||
* @param None
|
||||
*/
|
||||
void vcd_signal_dumper_init(char* filename);
|
||||
/*!
|
||||
* \brief Close file descriptor.
|
||||
* @param None
|
||||
*/
|
||||
void vcd_signal_dumper_close(void);
|
||||
/*!
|
||||
* \brief Create header for VCD file.
|
||||
* @param None
|
||||
*/
|
||||
void vcd_signal_dumper_create_header(void);
|
||||
/*!
|
||||
* \brief Dump state of a variable
|
||||
* @param Name of the variable to dump (see the corresponding enum)
|
||||
* @param Value of the variable to dump (type: unsigned long)
|
||||
*/
|
||||
void vcd_signal_dumper_dump_variable_by_name(vcd_signal_dump_variables variable_name,
|
||||
unsigned long value);
|
||||
/*!
|
||||
* \brief Dump function usage
|
||||
* @param Name Function name to dump (see the corresponding enum)
|
||||
* @param State: either VCD_FUNCTION_START or VCD_FUNCTION_END
|
||||
*/
|
||||
void vcd_signal_dumper_dump_function_by_name(vcd_signal_dump_functions function_name,
|
||||
vcd_signal_dump_in_out function_in_out);
|
||||
|
||||
extern int ouput_vcd;
|
||||
|
||||
#if T_TRACER
|
||||
|
||||
#include "T.h"
|
||||
|
||||
#define VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(var, val) T_VCD_VARIABLE(var, val)
|
||||
#define VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(var, val) T_VCD_FUNCTION(var, val)
|
||||
#else
|
||||
|
||||
#define VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(var, val)
|
||||
#define VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(var, val)
|
||||
|
||||
#endif /* T_TRACER */
|
||||
|
||||
#endif /* !defined (VCD_SIGNAL_DUMPER_H_) */
|
||||
|
||||
@@ -15,4 +15,5 @@ tracer/to_vcd
|
||||
tracer/extract_input_subframe
|
||||
tracer/extract_output_subframe
|
||||
tracer/extract
|
||||
tracer/multi
|
||||
tracee/tracee
|
||||
|
||||
+12
-3
@@ -13,11 +13,20 @@ $(GENIDS): $(GENIDS_OBJS)
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
T_messages.txt.h: T_messages.txt
|
||||
xxd -i T_messages.txt > T_messages.txt.h
|
||||
xxd -i T_messages.txt T_messages.txt.h
|
||||
|
||||
T_IDs.h: $(GENIDS) T_messages.txt
|
||||
./$(GENIDS) T_messages.txt T_IDs.h
|
||||
|
||||
check_vcd:
|
||||
gcc -Wall -I. -I.. -I../itti -Itracer -o _check_vcd check_vcd.c tracer/database.c tracer/utils.c -lm -pthread
|
||||
./_check_vcd || (rm -f ./_check_vcd ./T_IDs.h ./T_messages.txt.h && false)
|
||||
rm -f ./_check_vcd
|
||||
|
||||
.PHONY: check_vcd
|
||||
|
||||
clean:
|
||||
rm -f *.o $(GENIDS) core T_IDs.h T_messages.txt.h
|
||||
cd tracer && make clean
|
||||
rm -f *.o $(GENIDS) core T_IDs.h T_messages.txt.h _check_vcd
|
||||
|
||||
cleanall: clean
|
||||
cd tracer && $(MAKE) clean
|
||||
|
||||
+50
-13
@@ -9,6 +9,8 @@
|
||||
#include <fcntl.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include "common/config/config_userapi.h"
|
||||
|
||||
#define QUIT(x) do { \
|
||||
printf("T tracer: QUIT: %s\n", x); \
|
||||
exit(1); \
|
||||
@@ -17,6 +19,7 @@
|
||||
/* array used to activate/disactivate a log */
|
||||
static int T_IDs[T_NUMBER_OF_IDS];
|
||||
int *T_active = T_IDs;
|
||||
int T_stdout;
|
||||
|
||||
static int T_socket;
|
||||
|
||||
@@ -28,6 +31,12 @@ volatile int _T_freelist_head;
|
||||
volatile int *T_freelist_head = &_T_freelist_head;
|
||||
T_cache_t *T_cache;
|
||||
|
||||
#if BASIC_SIMULATOR
|
||||
/* global variables used by T_GET_SLOT, see in T.h */
|
||||
volatile uint64_t T_next_id;
|
||||
volatile uint64_t T_active_id;
|
||||
#endif
|
||||
|
||||
static void get_message(int s)
|
||||
{
|
||||
char t;
|
||||
@@ -88,7 +97,7 @@ static void new_thread(void *(*f)(void *), void *data)
|
||||
|
||||
/* defined in local_tracer.c */
|
||||
void T_local_tracer_main(int remote_port, int wait_for_tracer,
|
||||
int local_socket);
|
||||
int local_socket, void *shm_array);
|
||||
|
||||
/* We monitor the tracee and the local tracer processes.
|
||||
* When one dies we forcefully kill the other.
|
||||
@@ -111,18 +120,31 @@ void T_init(int remote_port, int wait_for_tracer, int dont_fork)
|
||||
{
|
||||
int socket_pair[2];
|
||||
int s;
|
||||
int T_shm_fd;
|
||||
int child1, child2;
|
||||
int i;
|
||||
|
||||
if (socketpair(AF_UNIX, SOCK_STREAM, 0, socket_pair))
|
||||
{ perror("socketpair"); abort(); }
|
||||
|
||||
/* setup shared memory */
|
||||
T_cache = mmap(NULL, T_CACHE_SIZE * sizeof(T_cache_t),
|
||||
PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
|
||||
if (T_cache == MAP_FAILED)
|
||||
{ perror("mmap"); abort(); }
|
||||
|
||||
/* let's garbage the memory to catch some potential problems
|
||||
* (think multiprocessor sync issues, barriers, etc.)
|
||||
*/
|
||||
memset(T_cache, 0x55, T_CACHE_SIZE * sizeof(T_cache_t));
|
||||
for (i = 0; i < T_CACHE_SIZE; i++) T_cache[i].busy = 0;
|
||||
|
||||
/* child1 runs the local tracer and child2 (or main) runs the tracee */
|
||||
|
||||
child1 = fork(); if (child1 == -1) abort();
|
||||
if (child1 == 0) {
|
||||
close(socket_pair[1]);
|
||||
T_local_tracer_main(remote_port, wait_for_tracer, socket_pair[0]);
|
||||
T_local_tracer_main(remote_port, wait_for_tracer, socket_pair[0],
|
||||
T_cache);
|
||||
exit(0);
|
||||
}
|
||||
close(socket_pair[0]);
|
||||
@@ -131,6 +153,7 @@ void T_init(int remote_port, int wait_for_tracer, int dont_fork)
|
||||
child2 = fork(); if (child2 == -1) abort();
|
||||
if (child2 != 0) {
|
||||
close(socket_pair[1]);
|
||||
munmap(T_cache, T_CACHE_SIZE * sizeof(T_cache_t));
|
||||
monitor_and_kill(child1, child2);
|
||||
}
|
||||
}
|
||||
@@ -141,15 +164,29 @@ void T_init(int remote_port, int wait_for_tracer, int dont_fork)
|
||||
|
||||
T_socket = s;
|
||||
|
||||
/* setup shared memory */
|
||||
T_shm_fd = shm_open(T_SHM_FILENAME, O_RDWR /*| O_SYNC*/, 0666);
|
||||
shm_unlink(T_SHM_FILENAME);
|
||||
if (T_shm_fd == -1) { perror(T_SHM_FILENAME); abort(); }
|
||||
T_cache = mmap(NULL, T_CACHE_SIZE * sizeof(T_cache_t),
|
||||
PROT_READ | PROT_WRITE, MAP_SHARED, T_shm_fd, 0);
|
||||
if (T_cache == NULL)
|
||||
{ perror(T_SHM_FILENAME); abort(); }
|
||||
close(T_shm_fd);
|
||||
|
||||
new_thread(T_receive_thread, NULL);
|
||||
}
|
||||
|
||||
void T_Config_Init(void)
|
||||
{
|
||||
int T_port; /* by default we wait for the tracer */
|
||||
int T_nowait; /* default port to listen to to wait for the tracer */
|
||||
int T_dont_fork; /* default is to fork, see 'T_init' to understand */
|
||||
|
||||
paramdef_t ttraceparams[] = CMDLINE_TTRACEPARAMS_DESC;
|
||||
|
||||
/* for a cleaner config file, TTracer params should be defined in a
|
||||
* specific section...
|
||||
*/
|
||||
config_get(ttraceparams,
|
||||
sizeof(ttraceparams) / sizeof(paramdef_t),
|
||||
TTRACER_CONFIG_PREFIX);
|
||||
|
||||
/* compatibility: look for TTracer command line options in root section */
|
||||
config_process_cmdline(ttraceparams,
|
||||
sizeof(ttraceparams) / sizeof(paramdef_t),
|
||||
NULL);
|
||||
|
||||
if (T_stdout == 0)
|
||||
T_init(T_port, 1-T_nowait, T_dont_fork);
|
||||
}
|
||||
|
||||
+63
-50
@@ -14,6 +14,7 @@
|
||||
/* T message IDs */
|
||||
#include "T_IDs.h"
|
||||
|
||||
#define T_ACTIVE_STDOUT 2
|
||||
/* known type - this is where you add new types */
|
||||
|
||||
#define T_INT(x) int, (x)
|
||||
@@ -94,12 +95,12 @@ struct T_header;
|
||||
#define T_ID(x) ((struct T_header *)(uintptr_t)(x))
|
||||
|
||||
/* T macro tricks */
|
||||
|
||||
extern int T_stdout;
|
||||
#define TN(...) TN_N(__VA_ARGS__,33,32,31,30,29,28,27,26,25,24,23,22,21,\
|
||||
20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0)(__VA_ARGS__)
|
||||
#define TN_N(n0,n1,n2,n3,n4,n5,n6,n7,n8,n9,n10,n11,n12,n13,n14,n15,n16,n17,\
|
||||
n18,n19,n20,n21,n22,n23,n24,n25,n26,n27,n28,n29,n30,n31,n32,n,...) T##n
|
||||
#define T(...) TN(__VA_ARGS__)
|
||||
#define T(...) do { if (T_stdout == 0) TN(__VA_ARGS__); } while (0)
|
||||
|
||||
/* type used to send arbitrary buffer data */
|
||||
typedef struct {
|
||||
@@ -109,16 +110,52 @@ typedef struct {
|
||||
|
||||
extern volatile int *T_freelist_head;
|
||||
extern T_cache_t *T_cache;
|
||||
extern int *T_active;
|
||||
/* When running the basic simulator, we may fill the T cache too fast.
|
||||
* Let's serialize write accesses to the T cache. For that, we use a
|
||||
* 'ticket' mechanism. To acquire a T slot the caller needs to own the
|
||||
* current active ticket. We also wait for the slot to be free if
|
||||
* it is already in use.
|
||||
*/
|
||||
#if BASIC_SIMULATOR
|
||||
# define T_GET_SLOT \
|
||||
do { \
|
||||
extern volatile uint64_t T_next_id; \
|
||||
extern volatile uint64_t T_active_id; \
|
||||
uint64_t id; \
|
||||
/* get a ticket */ \
|
||||
id = __sync_fetch_and_add(&T_next_id, 1); \
|
||||
/* wait for our turn */ \
|
||||
while (id != __sync_fetch_and_add(&T_active_id, 0)) /* busy wait */; \
|
||||
/* this is our turn, try to acquire the slot until it's free */ \
|
||||
do { \
|
||||
T_LOCAL_busy = __sync_fetch_and_or(&T_cache[T_LOCAL_slot].busy, 0x01); \
|
||||
if (T_LOCAL_busy & 0x01) usleep(100); \
|
||||
} while (T_LOCAL_busy & 0x01); \
|
||||
/* check that there are still some tickets */ \
|
||||
if (__sync_fetch_and_add(&T_active_id, 0) == 0xffffffffffffffff) { \
|
||||
printf("T: reached the end of times, bye...\n"); \
|
||||
abort(); \
|
||||
} \
|
||||
/* free our ticket, which signals the next waiter that it's its turn */ \
|
||||
(void)__sync_fetch_and_add(&T_active_id, 1); \
|
||||
} while (0)
|
||||
#else
|
||||
# define T_GET_SLOT \
|
||||
T_LOCAL_busy = __sync_fetch_and_or(&T_cache[T_LOCAL_slot].busy, 0x01);
|
||||
#endif
|
||||
|
||||
/* used at header of Tn, allocates buffer */
|
||||
#define T_LOCAL_DATA \
|
||||
char *T_LOCAL_buf; \
|
||||
int T_LOCAL_size = 0; \
|
||||
int T_LOCAL_slot; \
|
||||
int T_LOCAL_busy; \
|
||||
T_LOCAL_slot = __sync_fetch_and_add(T_freelist_head, 1) \
|
||||
& (T_CACHE_SIZE - 1); \
|
||||
(void)__sync_fetch_and_and(T_freelist_head, T_CACHE_SIZE - 1); \
|
||||
if (T_cache[T_LOCAL_slot].busy) { \
|
||||
T_GET_SLOT; \
|
||||
if (T_LOCAL_busy & 0x01) { \
|
||||
printf("%s:%d:%s: T cache is full - consider increasing its size\n", \
|
||||
__FILE__, __LINE__, __FUNCTION__); \
|
||||
abort(); \
|
||||
@@ -130,7 +167,7 @@ extern T_cache_t *T_cache;
|
||||
#define T_COMMIT() \
|
||||
T_cache[T_LOCAL_slot].length = T_LOCAL_size; \
|
||||
__sync_synchronize(); \
|
||||
T_cache[T_LOCAL_slot].busy = 1; \
|
||||
(void)__sync_fetch_and_or(&T_cache[T_LOCAL_slot].busy, 0x02);
|
||||
|
||||
#define T_CHECK_SIZE(len, argnum) \
|
||||
if (T_LOCAL_size + (len) > T_BUFFER_MAX) { \
|
||||
@@ -140,50 +177,6 @@ extern T_cache_t *T_cache;
|
||||
abort(); \
|
||||
}
|
||||
|
||||
#if 0
|
||||
#define T_PUT(type, var, argnum) \
|
||||
do { \
|
||||
if (T_LOCAL_size + sizeof(var) > T_BUFFER_MAX) { \
|
||||
printf("%s:%d:%s: cannot put argument %d in T macro, not enough space" \
|
||||
", consider increasing T_BUFFER_MAX (%d)\n", \
|
||||
__FILE__, __LINE__, __FUNCTION__, argnum, T_BUFFER_MAX); \
|
||||
abort(); \
|
||||
} \
|
||||
memcpy(T_LOCAL_buf + T_LOCAL_size, &var, sizeof(var)); \
|
||||
T_LOCAL_size += sizeof(var); \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
#define T_PROCESS(x, argnum) \
|
||||
do { \
|
||||
T_PUT(typeof(x), x, argnum); \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
#define T_PROCESS(x, argnum) \
|
||||
do { \
|
||||
if (__builtin_types_compatible_p(typeof(x), int)) \
|
||||
{ T_PUT(int, (intptr_t)(x), argnum); printf("int\n"); } \
|
||||
else if (__builtin_types_compatible_p(typeof(x), short)) \
|
||||
{ T_PUT(short, (intptr_t)(x), argnum); printf("short\n"); } \
|
||||
else if (__builtin_types_compatible_p(typeof(x), float)) \
|
||||
{ T_PUT(float, (x), argnum); printf("float\n"); } \
|
||||
else if (__builtin_types_compatible_p(typeof(x), char *)) \
|
||||
{ T_PUT(char *, (char *)(intptr_t)(x), argnum); printf("char *\n"); } \
|
||||
else if (__builtin_types_compatible_p(typeof(x), float *)) \
|
||||
{ T_PUT(float *, (float *)(intptr_t)(x), argnum); printf("float *\n"); } \
|
||||
else if (__builtin_types_compatible_p(typeof(x), void *)) \
|
||||
{ T_PUT(void *, (void *)(intptr_t)(x), argnum); printf("void *\n"); } \
|
||||
else { \
|
||||
printf("%s:%d:%s: unsupported type for argument %d in T macro\n", \
|
||||
__FILE__, __LINE__, __FUNCTION__, argnum); \
|
||||
abort(); \
|
||||
} \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
/* we have 4 versions of T_HEADER:
|
||||
* - bad quality C++ version with time
|
||||
* - good quality C version with time
|
||||
@@ -597,10 +590,30 @@ extern T_cache_t *T_cache;
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
extern int *T_active;
|
||||
|
||||
#define CONFIG_HLP_TPORT "tracer port\n"
|
||||
#define CONFIG_HLP_NOTWAIT "don't wait for tracer, start immediately\n"
|
||||
#define CONFIG_HLP_TNOFORK "to ease debugging with gdb\n"
|
||||
#define CONFIG_HLP_STDOUT "print log messges on console\n"
|
||||
|
||||
|
||||
#define TTRACER_CONFIG_PREFIX "TTracer"
|
||||
/*------------------------------------------------------------------------------------------------------------------------------------------*/
|
||||
/* configuration parameters for TTRACE utility */
|
||||
/* optname helpstr paramflags XXXptr defXXXval type numelt */
|
||||
/*------------------------------------------------------------------------------------------------------------------------------------------*/
|
||||
#define CMDLINE_TTRACEPARAMS_DESC { \
|
||||
{"T_port", CONFIG_HLP_TPORT, 0, iptr:&T_port, defintval:2021, TYPE_INT, 0}, \
|
||||
{"T_nowait", CONFIG_HLP_NOTWAIT, PARAMFLAG_BOOL, iptr:&T_nowait, defintval:0, TYPE_INT, 0}, \
|
||||
{"T_dont_fork", CONFIG_HLP_TNOFORK, PARAMFLAG_BOOL, iptr:&T_dont_fork, defintval:0, TYPE_INT, 0}, \
|
||||
{"T_stdout", CONFIG_HLP_STDOUT, PARAMFLAG_BOOL, iptr:&T_stdout, defintval:1, TYPE_INT, 0}, \
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* log on stdout */
|
||||
void T_init(int remote_port, int wait_for_tracer, int dont_fork);
|
||||
|
||||
void T_Config_Init(void);
|
||||
#else /* T_TRACER */
|
||||
|
||||
/* if T_TRACER is not defined or is 0, the T is deactivated */
|
||||
|
||||
+18
-6
@@ -8,10 +8,20 @@
|
||||
#define T_MAX_ARGS 16
|
||||
|
||||
/* maximum size of a message - increase if needed */
|
||||
#define T_BUFFER_MAX (1024*64)
|
||||
#if BASIC_SIMULATOR
|
||||
/* let's have 100 RBs functional for the basic simulator */
|
||||
# define T_BUFFER_MAX (1024*64*2)
|
||||
#else
|
||||
# define T_BUFFER_MAX (1024*64)
|
||||
#endif
|
||||
|
||||
/* size of the local cache for messages (must be pow(2,something)) */
|
||||
#define T_CACHE_SIZE (8192 * 2)
|
||||
#if BASIC_SIMULATOR
|
||||
/* we don't need much space for the basic simulator */
|
||||
# define T_CACHE_SIZE 1024
|
||||
#else
|
||||
# define T_CACHE_SIZE (8192 * 2)
|
||||
#endif
|
||||
|
||||
/* maximum number of bytes a message can contain */
|
||||
#ifdef T_SEND_TIME
|
||||
@@ -21,18 +31,20 @@
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
/* 'busy' is a bit field
|
||||
* bit 0: 1 means that slot is acquired by writer
|
||||
* bit 1: 1 means that slot is ready for consumption
|
||||
*/
|
||||
volatile int busy;
|
||||
char buffer[T_BUFFER_MAX];
|
||||
int length;
|
||||
} T_cache_t;
|
||||
|
||||
#define T_SHM_FILENAME "/T_shm_segment"
|
||||
|
||||
/* number of VCD functions (to be kept up to date! see in T_messages.txt) */
|
||||
#define VCD_NUM_FUNCTIONS 187
|
||||
#define VCD_NUM_FUNCTIONS 190
|
||||
|
||||
/* number of VCD variables (to be kept up to date! see in T_messages.txt) */
|
||||
#define VCD_NUM_VARIABLES 131
|
||||
#define VCD_NUM_VARIABLES 128
|
||||
|
||||
/* first VCD function (to be kept up to date! see in T_messages.txt) */
|
||||
#define VCD_FIRST_FUNCTION ((uintptr_t)T_VCD_FUNCTION_RT_SLEEP)
|
||||
|
||||
+355
-36
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,249 @@
|
||||
/*
|
||||
* To disable the checks done by this program, see below at the beginning
|
||||
* of the function 'main'.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "database.h"
|
||||
|
||||
#define T_TRACER 1
|
||||
#include "T.h"
|
||||
|
||||
/* VCD specific defines and includes
|
||||
* If the codebase changes, it may need to be updated
|
||||
*/
|
||||
#define ENB_MODE
|
||||
#define ENABLE_USE_CPU_EXECUTION_TIME
|
||||
#include "../LOG/vcd_signal_dumper.c"
|
||||
|
||||
void err(char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
|
||||
void err(char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
|
||||
printf("\x1b[31m");
|
||||
printf("error: ");
|
||||
vprintf(fmt, ap);
|
||||
printf("\n"
|
||||
"\x1b[33m\n"
|
||||
"You probably added a VCD trace (variable or function) but you did not\n"
|
||||
"update T_messages.txt and/or T_defs.h in common/utils/T/\n"
|
||||
"\n"
|
||||
"Be sure to add the new trace to T_messages.txt, at the right place in the\n"
|
||||
"file. Do not forget to define VCD_NAME with an identical value as found\n"
|
||||
"in the array eurecomVariablesNames or eurecomFunctionsNames.\n"
|
||||
"\n"
|
||||
"Be sure to update VCD_NUM_FUNCTIONS, VCD_NUM_VARIABLES, VCD_FIRST_FUNCTION\n"
|
||||
"and VCD_FIRST_VARIABLE in T_defs.h\n"
|
||||
"\n"
|
||||
"The same procedure has to be followed when you delete a VCD trace.\n"
|
||||
"Delete it in T_messages.txt as well and update T_defs.h\n"
|
||||
"\n"
|
||||
"You can disable those VCD checks at development time.\n"
|
||||
"To disable the VCD checks see the file common/utils/T/check_vcd.c\n"
|
||||
"Do not push any modification that disables the VCD checks to the\n"
|
||||
"main repository.\n");
|
||||
|
||||
printf("\x1b[m\n");
|
||||
|
||||
va_end(ap);
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
/* to disable the checks done by this program, uncomment the following
|
||||
* line, ie. remove the leading '//'
|
||||
*/
|
||||
//return 0;
|
||||
|
||||
void *database = parse_database("T_messages.txt");
|
||||
int number_of_events;
|
||||
int first_var = -1;
|
||||
int last_var;
|
||||
int first_fun = -1;
|
||||
int last_fun;
|
||||
char *prefix;
|
||||
int prefix_len;
|
||||
char *name;
|
||||
char *vcd_name;
|
||||
int i;
|
||||
FILE *in;
|
||||
char *l = NULL;
|
||||
size_t lsize;
|
||||
|
||||
if (database == NULL) err("something wrong with T_messages.txt");
|
||||
|
||||
/* check the value of VCD_NUM_FUNCTIONS */
|
||||
if (VCD_NUM_FUNCTIONS != sizeof(eurecomFunctionsNames) / sizeof(char *))
|
||||
err("VCD_NUM_FUNCTIONS (%d) must be equal to %zd",
|
||||
VCD_NUM_FUNCTIONS,
|
||||
sizeof(eurecomFunctionsNames) / sizeof(char *));
|
||||
|
||||
/* check the value of VCD_NUM_VARIABLES */
|
||||
if (VCD_NUM_VARIABLES != sizeof(eurecomVariablesNames) / sizeof(char *))
|
||||
err("VCD_NUM_VARIABLES (%d) must be equal to %zd",
|
||||
VCD_NUM_VARIABLES,
|
||||
sizeof(eurecomVariablesNames) / sizeof(char *));
|
||||
|
||||
number_of_events = number_of_ids(database);
|
||||
if (number_of_events == 0) err("no event defined in T_messages.txt");
|
||||
|
||||
/* T_messages.txt ends with VCD VARIABLES followed by VCD FUNCTIONS
|
||||
* followed by nothing.
|
||||
* Let's check.
|
||||
*/
|
||||
|
||||
/* check VCD VARIABLES traces in T_messages.txt */
|
||||
prefix = "VCD_VARIABLE_";
|
||||
prefix_len = strlen(prefix);
|
||||
|
||||
for (i = 0; i < number_of_events; i++) {
|
||||
name = event_name_from_id(database, i);
|
||||
if (strncmp(name, prefix, prefix_len)) continue;
|
||||
first_var = i;
|
||||
break;
|
||||
}
|
||||
if (first_var == -1)
|
||||
err("no VCD_VARIABLE_ found in T_messages.txt");
|
||||
for (; i < number_of_events; i++) {
|
||||
name = event_name_from_id(database, i);
|
||||
if (strncmp(name, prefix, prefix_len)) break;
|
||||
}
|
||||
last_var = i-1;
|
||||
|
||||
/* check VCD FUNCTIONS traces in T_messages.txt */
|
||||
if (i == number_of_events)
|
||||
err("no VCD_FUNCTION_ found in T_messages.txt");
|
||||
|
||||
prefix = "VCD_FUNCTION_";
|
||||
prefix_len = strlen(prefix);
|
||||
|
||||
first_fun = i;
|
||||
|
||||
name = event_name_from_id(database, i);
|
||||
if (strncmp(name, prefix, prefix_len))
|
||||
err("last VCD_VARIABLE_ not followed by a VCD_FUNCTION_ in T_messages.txt");
|
||||
|
||||
for (; i < number_of_events; i++) {
|
||||
name = event_name_from_id(database, i);
|
||||
if (strncmp(name, prefix, prefix_len)) break;
|
||||
}
|
||||
|
||||
if (i != number_of_events)
|
||||
err("T_messages.txt does not end with a VCD_FUNCTION_ trace");
|
||||
|
||||
last_fun = i-1;
|
||||
|
||||
if (first_var != (unsigned)VCD_FIRST_VARIABLE)
|
||||
err("VCD_FIRST_VARIABLE is not correct in T_defs.h");
|
||||
if (first_fun != (unsigned)VCD_FIRST_FUNCTION)
|
||||
err("VCD_FIRST_FUNCTION is not correct in T_defs.h");
|
||||
if (last_var-first_var+1 != VCD_NUM_VARIABLES)
|
||||
err("VCD_NUM_VARIABLES is not correct in T_defs.h");
|
||||
if (last_fun-first_fun+1 != VCD_NUM_FUNCTIONS)
|
||||
err("VCD_NUM_FUNCTIONS is not correct in T_defs.h");
|
||||
|
||||
/* check that VCD_NAME is identical to
|
||||
* eurecomVariablesNames[x]/eurecomFunctionsNames[x]
|
||||
*/
|
||||
prefix = "VCD_VARIABLE_";
|
||||
prefix_len = strlen(prefix);
|
||||
|
||||
for (i = 0; i < number_of_events; i++) {
|
||||
name = event_name_from_id(database, i);
|
||||
if (strncmp(name, prefix, prefix_len)) continue;
|
||||
vcd_name = event_vcd_name_from_id(database, i);
|
||||
if (vcd_name == NULL)
|
||||
err("%s has no VCD_NAME in T_messages.txt", name);
|
||||
if (strcmp(vcd_name, eurecomVariablesNames[i - first_var]))
|
||||
err("%s has a wrong VCD_NAME in T_messages.txt", name);
|
||||
}
|
||||
|
||||
prefix = "VCD_FUNCTION_";
|
||||
prefix_len = strlen(prefix);
|
||||
|
||||
for (i = 0; i < number_of_events; i++) {
|
||||
name = event_name_from_id(database, i);
|
||||
if (strncmp(name, prefix, prefix_len)) continue;
|
||||
vcd_name = event_vcd_name_from_id(database, i);
|
||||
if (vcd_name == NULL)
|
||||
err("%s has no VCD_NAME in T_messages.txt", name);
|
||||
if (strcmp(vcd_name, eurecomFunctionsNames[i - first_fun]))
|
||||
err("%s has a wrong VCD_NAME in T_messages.txt", name);
|
||||
}
|
||||
|
||||
/* check IDs - these checks are difficult because we parse
|
||||
* common/utils/LOG/vcd_signal_dumper.h which is expected to
|
||||
* be formatted as is:
|
||||
* - define vcd_signal_dump_variables then vcd_signal_dump_functions
|
||||
* - one VCD_XXXX per line starting with two spaces
|
||||
* followed by ',' or '=' with no space in between
|
||||
* - no #ifdef / #if is taken into account
|
||||
* - we require VCD_SIGNAL_DUMPER_VARIABLES_END and
|
||||
* VCD_SIGNAL_DUMPER_FUNCTIONS_END at the end of each array,
|
||||
* each on a line of its own with two spaces before and nothing after.
|
||||
*
|
||||
* If these checks fail, consider formatting
|
||||
* common/utils/LOG/vcd_signal_dumper.h as expected here, if
|
||||
* it makes sense of course. Otherwise, change the code below.
|
||||
*
|
||||
* In common/utils/LOG/vcd_signal_dumper.h a valid name is
|
||||
* either VCD_SIGNAL_DUMPER_VARIABLES_ABC or
|
||||
* VCD_SIGNAL_DUMPER_FUNCTIONS_XYZ
|
||||
* and in T_messages.txt the corresponding name has to be
|
||||
* VCD_VARIABLE_ABC or VCD_FUNCTION_XYZ
|
||||
*/
|
||||
i = first_var;
|
||||
in = fopen("../LOG/vcd_signal_dumper.h", "r");
|
||||
if (in == NULL) err("could not open ../LOG/vcd_signal_dumper.h");
|
||||
while (1) {
|
||||
char *x = " VCD_SIGNAL_DUMPER_VARIABLES_";
|
||||
ssize_t r;
|
||||
free(l);
|
||||
l = NULL;
|
||||
lsize = 0;
|
||||
r = getline(&l, &lsize, in);
|
||||
if (r == -1) break;
|
||||
if (!strcmp(l, " VCD_SIGNAL_DUMPER_VARIABLES_END\n")) break;
|
||||
/* remove ',' or '=' if found */
|
||||
{ char *s=l; while (*s) { if (*s==','||*s=='=') { *s=0; break; } s++; } }
|
||||
if (strncmp(l, x, strlen(x))) continue;
|
||||
if (!(i >= first_var && i <= last_var))
|
||||
err("T_messages.txt is not correct with respect to VCD VARIABLES");
|
||||
name = event_name_from_id(database, i);
|
||||
if (strcmp(l+strlen(x), name+strlen("VCD_VARIABLE_")))
|
||||
err("%s is not correct in T_messages.txt", name);
|
||||
i++;
|
||||
}
|
||||
if (i != last_var + 1) err("VCD VARIABLES wrong in T_messages.txt");
|
||||
while (1) {
|
||||
char *x = " VCD_SIGNAL_DUMPER_FUNCTIONS_";
|
||||
ssize_t r;
|
||||
free(l);
|
||||
l = NULL;
|
||||
lsize = 0;
|
||||
r = getline(&l, &lsize, in);
|
||||
if (r == -1) break;
|
||||
if (!strcmp(l, " VCD_SIGNAL_DUMPER_FUNCTIONS_END\n")) break;
|
||||
/* remove ',' or '=' if found */
|
||||
{ char *s=l; while (*s) { if (*s==','||*s=='=') { *s=0; break; } s++; } }
|
||||
if (strncmp(l, x, strlen(x))) continue;
|
||||
if (!(i >= first_fun && i <= last_fun))
|
||||
err("T_messages.txt is not correct with respect to VCD FUNCTIONS");
|
||||
name = event_name_from_id(database, i);
|
||||
if (strcmp(l+strlen(x), name+strlen("VCD_FUNCTION_")))
|
||||
err("%s is not correct in T_messages.txt", name);
|
||||
i++;
|
||||
}
|
||||
fclose(in);
|
||||
if (i != last_fun + 1) err("VCD FUNCTIONS wrong in T_messages.txt");
|
||||
|
||||
return 0;
|
||||
}
|
||||
+11
-10
@@ -14,21 +14,21 @@ int cmp(const void *p1, const void *p2)
|
||||
}
|
||||
|
||||
/* return 1 if s was not already known, 0 if it was */
|
||||
int new_unique_id(char *s)
|
||||
int new_unique_id(char *s, char *input_file)
|
||||
{
|
||||
if (unique_ids_size)
|
||||
if (bsearch(&s, unique_ids, unique_ids_size, sizeof(char *), cmp) != NULL) {
|
||||
printf("FATAL: ID %s is not unique\n", s);
|
||||
printf("error: ID %s is not unique in %s\n", s, input_file);
|
||||
return 0;
|
||||
}
|
||||
if (unique_ids_size == unique_ids_maxsize) {
|
||||
unique_ids_maxsize += 256;
|
||||
unique_ids = realloc(unique_ids, unique_ids_maxsize * sizeof(char *));
|
||||
if (unique_ids == NULL) { printf("out of memory\n"); abort(); }
|
||||
if (unique_ids == NULL) { printf("erorr: out of memory\n"); abort(); }
|
||||
}
|
||||
unique_ids[unique_ids_size] = strdup(s);
|
||||
if (unique_ids[unique_ids_size] == NULL)
|
||||
{ printf("out of memory\n"); abort(); }
|
||||
{ printf("erorr: out of memory\n"); abort(); }
|
||||
unique_ids_size++;
|
||||
qsort(unique_ids, unique_ids_size, sizeof(char *), cmp);
|
||||
return 1;
|
||||
@@ -43,7 +43,8 @@ void putname(int c)
|
||||
if (bufname_size == bufname_maxsize) {
|
||||
bufname_maxsize += 256;
|
||||
bufname = realloc(bufname, bufname_maxsize);
|
||||
if (bufname == NULL) { printf("memory allocation error\n"); exit(1); }
|
||||
if (bufname == NULL)
|
||||
{ printf("erorr: memory allocation error\n"); exit(1); }
|
||||
}
|
||||
bufname[bufname_size] = c;
|
||||
bufname_size++;
|
||||
@@ -58,7 +59,8 @@ void putvalue(int c)
|
||||
if (bufvalue_size == bufvalue_maxsize) {
|
||||
bufvalue_maxsize += 256;
|
||||
bufvalue = realloc(bufvalue, bufvalue_maxsize);
|
||||
if (bufvalue == NULL) { printf("memory allocation error\n"); exit(1); }
|
||||
if (bufvalue == NULL)
|
||||
{ printf("error: memory allocation error\n"); exit(1); }
|
||||
}
|
||||
bufvalue[bufvalue_size] = c;
|
||||
bufvalue_size++;
|
||||
@@ -119,7 +121,7 @@ int main(int n, char **v)
|
||||
char *in_name;
|
||||
char *out_name;
|
||||
|
||||
if (n != 3) { printf("gimme <source> <dest>\n"); exit(1); }
|
||||
if (n != 3) { printf("error: gimme <source> <dest>\n"); exit(1); }
|
||||
|
||||
n = 0;
|
||||
|
||||
@@ -134,14 +136,13 @@ int main(int n, char **v)
|
||||
while (1) {
|
||||
get_line(in, &name, &value);
|
||||
if (name == NULL) break;
|
||||
printf("name '%s' value '%s'\n", name, value);
|
||||
if (isspace(value[strlen(value)-1])) {
|
||||
printf("bad value '%s' (no space at the end please!)\n", value);
|
||||
printf("error: bad value '%s' (no space at the end please!)\n", value);
|
||||
unlink(out_name);
|
||||
exit(1);
|
||||
}
|
||||
if (!strcmp(name, "ID")) {
|
||||
if (!new_unique_id(value)) { unlink(out_name); exit(1); }
|
||||
if (!new_unique_id(value, in_name)) { unlink(out_name); exit(1); }
|
||||
fprintf(out, "#define T_%s T_ID(%d)\n", value, n);
|
||||
n++;
|
||||
}
|
||||
|
||||
@@ -300,6 +300,20 @@ static void forward(void *_forwarder, char *buf, int size)
|
||||
if (f->tail != NULL) f->tail->next = new;
|
||||
f->tail = new;
|
||||
|
||||
#if BASIC_SIMULATOR
|
||||
/* When runnng the basic simulator, the tracer may be too slow.
|
||||
* Let's not take too much memory in the tracee and
|
||||
* wait if there is too much data to send. 200MB is
|
||||
* arbitrary.
|
||||
*/
|
||||
while (f->memusage > 200 * 1024 * 1024) {
|
||||
if (pthread_cond_signal(&f->cond)) abort();
|
||||
if (pthread_mutex_unlock(&f->lock)) abort();
|
||||
usleep(1000);
|
||||
if (pthread_mutex_lock(&f->lock)) abort();
|
||||
}
|
||||
#endif /* BASIC_SIMULATOR */
|
||||
|
||||
f->memusage += size+4;
|
||||
/* warn every 100MB */
|
||||
if (f->memusage > f->last_warning_memusage &&
|
||||
@@ -323,31 +337,11 @@ static void forward(void *_forwarder, char *buf, int size)
|
||||
|
||||
static void wait_message(void)
|
||||
{
|
||||
while (T_local_cache[T_busylist_head].busy == 0) usleep(1000);
|
||||
}
|
||||
|
||||
static void init_shm(void)
|
||||
{
|
||||
int i;
|
||||
int s = shm_open(T_SHM_FILENAME, O_RDWR | O_CREAT /*| O_SYNC*/, 0666);
|
||||
if (s == -1) { perror(T_SHM_FILENAME); abort(); }
|
||||
if (ftruncate(s, T_CACHE_SIZE * sizeof(T_cache_t)))
|
||||
{ perror(T_SHM_FILENAME); abort(); }
|
||||
T_local_cache = mmap(NULL, T_CACHE_SIZE * sizeof(T_cache_t),
|
||||
PROT_READ | PROT_WRITE, MAP_SHARED, s, 0);
|
||||
if (T_local_cache == NULL)
|
||||
{ perror(T_SHM_FILENAME); abort(); }
|
||||
close(s);
|
||||
|
||||
/* let's garbage the memory to catch some potential problems
|
||||
* (think multiprocessor sync issues, barriers, etc.)
|
||||
*/
|
||||
memset(T_local_cache, 0x55, T_CACHE_SIZE * sizeof(T_cache_t));
|
||||
for (i = 0; i < T_CACHE_SIZE; i++) T_local_cache[i].busy = 0;
|
||||
while ((T_local_cache[T_busylist_head].busy & 0x02) == 0) usleep(1000);
|
||||
}
|
||||
|
||||
void T_local_tracer_main(int remote_port, int wait_for_tracer,
|
||||
int local_socket)
|
||||
int local_socket, void *shm_array)
|
||||
{
|
||||
int s;
|
||||
int port = remote_port;
|
||||
@@ -355,9 +349,13 @@ void T_local_tracer_main(int remote_port, int wait_for_tracer,
|
||||
void *f;
|
||||
|
||||
/* write on a socket fails if the other end is closed and we get SIGPIPE */
|
||||
if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) abort();
|
||||
if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
|
||||
printf("local tracer received SIGPIPE\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
T_local_cache = shm_array;
|
||||
|
||||
init_shm();
|
||||
s = local_socket;
|
||||
|
||||
if (dont_wait) {
|
||||
|
||||
@@ -7,7 +7,7 @@ LIBS=-lm
|
||||
XLIBS=-lX11 -lpng -lXft
|
||||
|
||||
all: record replay extract_config textlog enb ue vcd macpdu2wireshark \
|
||||
extract_input_subframe extract_output_subframe to_vcd extract
|
||||
extract_input_subframe extract_output_subframe to_vcd extract multi
|
||||
|
||||
record: utils.o record.o database.o config.o
|
||||
$(CC) $(CFLAGS) -o record $^ $(LIBS)
|
||||
@@ -57,19 +57,22 @@ macpdu2wireshark: macpdu2wireshark.o database.o utils.o handler.o event.o \
|
||||
config.o
|
||||
$(CC) $(CFLAGS) -o $@ $^ $(LIBS)
|
||||
|
||||
multi: multi.o utils.o database.o config.o
|
||||
$(CC) $(CFLAGS) -o multi $^ $(LIBS)
|
||||
|
||||
.PHONY: all gui/gui.a view/view.a logger/logger.a filter/filter.a
|
||||
|
||||
gui/gui.a:
|
||||
cd gui && make
|
||||
cd gui && $(MAKE)
|
||||
|
||||
view/view.a:
|
||||
cd view && make
|
||||
cd view && $(MAKE)
|
||||
|
||||
logger/logger.a:
|
||||
cd logger && make
|
||||
cd logger && $(MAKE)
|
||||
|
||||
filter/filter.a:
|
||||
cd filter && make
|
||||
cd filter && $(MAKE)
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
@@ -77,9 +80,9 @@ filter/filter.a:
|
||||
clean:
|
||||
rm -f *.o core tracer_remote textlog enb ue vcd record replay
|
||||
rm -f extract_config macpdu2wireshark extract_input_subframe
|
||||
rm -f extract_output_subframe to_vcd extract
|
||||
cd gui && make clean
|
||||
cd view && make clean
|
||||
cd logger && make clean
|
||||
cd filter && make clean
|
||||
cd hacks && make clean
|
||||
rm -f extract_output_subframe to_vcd extract multi
|
||||
cd gui && $(MAKE) clean
|
||||
cd view && $(MAKE) clean
|
||||
cd logger && $(MAKE) clean
|
||||
cd filter && $(MAKE) clean
|
||||
cd hacks && $(MAKE) clean
|
||||
|
||||
@@ -60,3 +60,9 @@ void verify_config(void)
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
void get_local_config(char **txt, int *len)
|
||||
{
|
||||
*txt = local;
|
||||
*len = local_size;
|
||||
}
|
||||
|
||||
@@ -5,5 +5,6 @@ void clear_remote_config(void);
|
||||
void append_received_config_chunk(char *buf, int length);
|
||||
void load_config_file(char *filename);
|
||||
void verify_config(void);
|
||||
void get_local_config(char **txt, int *len);
|
||||
|
||||
#endif /* _CONFIG_H_ */
|
||||
|
||||
@@ -13,6 +13,7 @@ typedef struct {
|
||||
char **arg_type;
|
||||
char **arg_name;
|
||||
int asize;
|
||||
char *vcd_name;
|
||||
int id;
|
||||
} id;
|
||||
|
||||
@@ -138,6 +139,7 @@ id *add_id(database *r, char *idname, int i)
|
||||
r->i[r->isize].arg_type = NULL;
|
||||
r->i[r->isize].arg_name = NULL;
|
||||
r->i[r->isize].asize = 0;
|
||||
r->i[r->isize].vcd_name = NULL;
|
||||
r->i[r->isize].id = i;
|
||||
r->isize++;
|
||||
qsort(r->i, r->isize, sizeof(id), id_cmp);
|
||||
@@ -224,6 +226,12 @@ void add_desc(id *i, char *desc)
|
||||
i->desc = strdup(desc); if (i->desc == NULL) abort();
|
||||
}
|
||||
|
||||
void add_vcd_name(id *i, char *vcd_name)
|
||||
{
|
||||
if (i == NULL) {printf("ERROR: VCD_NAME line before ID line\n");exit(1);}
|
||||
i->vcd_name = strdup(vcd_name); if (i->vcd_name == NULL) abort();
|
||||
}
|
||||
|
||||
char *format_get_next_token(char **cur)
|
||||
{
|
||||
char *start;
|
||||
@@ -320,6 +328,7 @@ void *parse_database(char *filename)
|
||||
if (!strcmp(name, "GROUP")) add_groups(r, last_id, value);
|
||||
if (!strcmp(name, "DESC")) add_desc(last_id, value);
|
||||
if (!strcmp(name, "FORMAT")) add_format(last_id, value);
|
||||
if (!strcmp(name, "VCD_NAME")) add_vcd_name(last_id, value);
|
||||
}
|
||||
|
||||
fclose(in);
|
||||
@@ -424,6 +433,12 @@ char *event_name_from_id(void *_database, int id)
|
||||
return d->i[d->id_to_pos[id]].name;
|
||||
}
|
||||
|
||||
char *event_vcd_name_from_id(void *_database, int id)
|
||||
{
|
||||
database *d = _database;
|
||||
return d->i[d->id_to_pos[id]].vcd_name;
|
||||
}
|
||||
|
||||
int event_id_from_name(void *_database, char *name)
|
||||
{
|
||||
database *d = _database;
|
||||
|
||||
@@ -8,6 +8,7 @@ void list_ids(void *database);
|
||||
void list_groups(void *database);
|
||||
void on_off(void *d, char *item, int *a, int onoff);
|
||||
char *event_name_from_id(void *database, int id);
|
||||
char *event_vcd_name_from_id(void *_database, int id);
|
||||
int event_id_from_name(void *database, char *name);
|
||||
int number_of_ids(void *database);
|
||||
int database_get_ids(void *database, char ***ids);
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
#include "gui/gui.h"
|
||||
#include "filter/filter.h"
|
||||
#include "utils.h"
|
||||
#include "../T_defs.h"
|
||||
#include "event_selector.h"
|
||||
#include "openair_logo.h"
|
||||
#include "config.h"
|
||||
@@ -875,8 +874,11 @@ int main(int n, char **v)
|
||||
if (pthread_mutex_init(&enb_data.lock, NULL)) abort();
|
||||
setup_event_selector(g, database, is_on, is_on_changed, &enb_data);
|
||||
|
||||
OBUF ebuf = { osize: 0, omaxsize: 0, obuf: NULL };
|
||||
|
||||
restart:
|
||||
clear_remote_config();
|
||||
if (enb_data.socket != -1) close(enb_data.socket);
|
||||
enb_data.socket = connect_to(ip, port);
|
||||
|
||||
/* send the first message - activate selected traces */
|
||||
@@ -884,9 +886,8 @@ restart:
|
||||
|
||||
/* read messages */
|
||||
while (1) {
|
||||
char v[T_BUFFER_MAX];
|
||||
event e;
|
||||
e = get_event(enb_data.socket, v, database);
|
||||
e = get_event(enb_data.socket, &ebuf, database);
|
||||
if (e.type == -1) goto restart;
|
||||
if (pthread_mutex_lock(&enb_data.lock)) abort();
|
||||
handle_event(h, e);
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
event get_event(int socket, char *event_buffer, void *database)
|
||||
event get_event(int socket, OBUF *event_buffer, void *database)
|
||||
{
|
||||
#ifdef T_SEND_TIME
|
||||
struct timespec t;
|
||||
@@ -29,17 +29,23 @@ again:
|
||||
#endif
|
||||
if (fullread(socket, &type, sizeof(int)) == -1) goto read_error;
|
||||
length -= sizeof(int);
|
||||
if (fullread(socket, event_buffer, length) == -1) goto read_error;
|
||||
if (event_buffer->omaxsize < length) {
|
||||
event_buffer->omaxsize = (length + 65535) & ~65535;
|
||||
event_buffer->obuf = realloc(event_buffer->obuf, event_buffer->omaxsize);
|
||||
if (event_buffer->obuf == NULL) { printf("out of memory\n"); exit(1); }
|
||||
}
|
||||
if (fullread(socket, event_buffer->obuf, length) == -1) goto read_error;
|
||||
event_buffer->osize = length;
|
||||
|
||||
if (type == -1) append_received_config_chunk(event_buffer, length);
|
||||
if (type == -1) append_received_config_chunk(event_buffer->obuf, length);
|
||||
if (type == -2) verify_config();
|
||||
|
||||
if (type == -1 || type == -2) goto again;
|
||||
|
||||
#ifdef T_SEND_TIME
|
||||
return new_event(t, type, length, event_buffer, database);
|
||||
return new_event(t, type, length, event_buffer->obuf, database);
|
||||
#else
|
||||
return new_event(type, length, event_buffer, database);
|
||||
return new_event(type, length, event_buffer->obuf, database);
|
||||
#endif
|
||||
|
||||
read_error:
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#ifndef _EVENT_H_
|
||||
#define _EVENT_H_
|
||||
|
||||
#include "utils.h"
|
||||
#include "../T_defs.h"
|
||||
#ifdef T_SEND_TIME
|
||||
#include <time.h>
|
||||
@@ -37,7 +38,7 @@ typedef struct {
|
||||
int ecount;
|
||||
} event;
|
||||
|
||||
event get_event(int s, char *v, void *d);
|
||||
event get_event(int s, OBUF *v, void *d);
|
||||
|
||||
#ifdef T_SEND_TIME
|
||||
event new_event(struct timespec sending_time, int type,
|
||||
|
||||
@@ -99,10 +99,11 @@ int main(int n, char **v)
|
||||
|
||||
found = 0;
|
||||
|
||||
OBUF ebuf = { osize: 0, omaxsize: 0, obuf: NULL };
|
||||
|
||||
while (1) {
|
||||
char v[T_BUFFER_MAX];
|
||||
event e;
|
||||
e = get_event(fd, v, database);
|
||||
e = get_event(fd, &ebuf, database);
|
||||
if (e.type == -1) break;
|
||||
if (e.type != input_event_id) continue;
|
||||
for (i = 0; i < filter_count; i++)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "utils.h"
|
||||
#include "../T_defs.h"
|
||||
|
||||
void usage(void)
|
||||
@@ -35,14 +36,22 @@ int main(int n, char **v)
|
||||
in = fopen(input_filename, "r");
|
||||
if (in == NULL) { perror(input_filename); abort(); }
|
||||
|
||||
OBUF ebuf = { osize: 0, omaxsize: 0, obuf: NULL };
|
||||
|
||||
while (1) {
|
||||
int type;
|
||||
int32_t length;
|
||||
char v[T_BUFFER_MAX];
|
||||
char *v;
|
||||
int vpos = 0;
|
||||
|
||||
/* read event from file */
|
||||
if (fread(&length, 4, 1, in) != 1) break;
|
||||
if (ebuf.omaxsize < length) {
|
||||
ebuf.omaxsize = (length + 65535) & ~65535;
|
||||
ebuf.obuf = realloc(ebuf.obuf, ebuf.omaxsize);
|
||||
if (ebuf.obuf == NULL) { printf("out of memory\n"); exit(1); }
|
||||
}
|
||||
v = ebuf.obuf;
|
||||
memcpy(v+vpos, &length, 4);
|
||||
vpos += 4;
|
||||
#ifdef T_SEND_TIME
|
||||
|
||||
@@ -104,11 +104,12 @@ err:
|
||||
fd = open(file, O_RDONLY);
|
||||
if (fd == -1) { perror(file); exit(1); }
|
||||
|
||||
OBUF ebuf = { osize: 0, omaxsize: 0, obuf: NULL };
|
||||
|
||||
/* get wanted frame/subframe */
|
||||
while (1) {
|
||||
char v[T_BUFFER_MAX];
|
||||
event e;
|
||||
e = get_event(fd, v, database);
|
||||
e = get_event(fd, &ebuf, database);
|
||||
if (e.type == -1) break;
|
||||
if (e.type != input_event_id) continue;
|
||||
if (verbose)
|
||||
@@ -116,12 +117,7 @@ err:
|
||||
e.e[frame_arg].i, e.e[subframe_arg].i, e.e[buffer_arg].bsize);
|
||||
if (!(frame == e.e[frame_arg].i && subframe == e.e[subframe_arg].i))
|
||||
continue;
|
||||
#if 0
|
||||
for (i = 0; i < e.e[buffer_arg].bsize/2; i++) {
|
||||
short *x = e.e[buffer_arg].b;
|
||||
x[i] *= 14;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (fwrite(e.e[buffer_arg].b, e.e[buffer_arg].bsize, 1, out) != 1)
|
||||
{ perror(output_file); exit(1); }
|
||||
processed_subframes++;
|
||||
|
||||
@@ -100,10 +100,12 @@ err:
|
||||
int last_frame = -1;
|
||||
int last_subframe = -1;
|
||||
int subframe_written = 0;
|
||||
|
||||
OBUF ebuf = { osize: 0, omaxsize: 0, obuf: NULL };
|
||||
|
||||
while (1) {
|
||||
char v[T_BUFFER_MAX];
|
||||
event e;
|
||||
e = get_event(fd, v, database);
|
||||
e = get_event(fd, &ebuf, database);
|
||||
if (e.type == -1) break;
|
||||
if (e.type != output_event_id) continue;
|
||||
if (verbose)
|
||||
@@ -122,12 +124,6 @@ err:
|
||||
}
|
||||
last_frame = frame;
|
||||
last_subframe = subframe;
|
||||
#if 0
|
||||
for (i = 0; i < e.e[buffer_arg].bsize/2; i++) {
|
||||
short *x = e.e[buffer_arg].b;
|
||||
x[i] *= 14;
|
||||
}
|
||||
#endif
|
||||
if (verbose)
|
||||
printf("save output frame %d subframe %d size %d\n",
|
||||
e.e[frame_arg].i, e.e[subframe_arg].i, e.e[buffer_arg].bsize);
|
||||
|
||||
@@ -22,13 +22,7 @@ int main(void)
|
||||
widget_add_child(g, c1, c2, 0);
|
||||
|
||||
plot = new_xy_plot(g, 100, 100, "xy plot test", 30);
|
||||
#if 0
|
||||
c2 = new_container(g, HORIZONTAL);
|
||||
widget_add_child(g, c2, plot, -1);
|
||||
widget_add_child(g, c1, c2, -1);
|
||||
#else
|
||||
widget_add_child(g, c1, plot, -1);
|
||||
#endif
|
||||
|
||||
tlcol = new_color(g, "#ddf");
|
||||
tl = new_textlist(g, 300, 10, tlcol);
|
||||
|
||||
@@ -124,20 +124,6 @@ x_window *x_create_window(x_connection *_x, int width, int height,
|
||||
|
||||
XMapWindow(x->d, ret->w);
|
||||
|
||||
#if 0
|
||||
/* wait for window to be mapped */
|
||||
LOGD("wait for map\n");
|
||||
while (1) {
|
||||
XEvent ev;
|
||||
//XWindowEvent(x->d, ret->w, StructureNotifyMask, &ev);
|
||||
XWindowEvent(x->d, ret->w, ExposureMask, &ev);
|
||||
LOGD("got ev %d\n", ev.type);
|
||||
//if (ev.type == MapNotify) break;
|
||||
if (ev.type == Expose) break;
|
||||
}
|
||||
LOGD("XXX create connection %p window %p (win id %d pixmap %d) w h %d %d\n", x, ret, (int)ret->w, (int)ret->p, width, height);
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -265,14 +251,6 @@ void x_events(gui *_gui)
|
||||
ev.xbutton.button, 1);
|
||||
}
|
||||
break;
|
||||
#if 0
|
||||
case MapNotify:
|
||||
if ((w = find_x_window(g, ev.xmap.window)) != NULL) {
|
||||
struct x_window *xw = w->x;
|
||||
xw->repaint = 1;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
default: if (gui_logd) WARN("TODO: X event type %d\n", ev.type); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,165 +7,6 @@
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#if 0
|
||||
/* this version behaves differently when you resize the XY plot. Say
|
||||
* you increase the size. The old (smaller) view is put at the center
|
||||
* of the new view. Everything inside keeps the same size/aspect ratio.
|
||||
* The other version below resizes the old view so that it fully occupies
|
||||
* the new view. It may introduce aspect ratio changes, but usage seems
|
||||
* to suggest it's a better behaviour.
|
||||
*/
|
||||
static void paint(gui *_gui, widget *_this)
|
||||
{
|
||||
struct gui *g = _gui;
|
||||
struct xy_plot_widget *this = _this;
|
||||
int wanted_plot_width, allocated_plot_width;
|
||||
int wanted_plot_height, allocated_plot_height;
|
||||
float pxsize;
|
||||
float ticdist;
|
||||
float tic;
|
||||
float ticstep;
|
||||
int k, kmin, kmax;
|
||||
float allocated_xmin, allocated_xmax;
|
||||
float allocated_ymin, allocated_ymax;
|
||||
float center;
|
||||
int i;
|
||||
int n;
|
||||
|
||||
# define FLIP(v) (-(v) + allocated_plot_height-1)
|
||||
|
||||
LOGD("PAINT xy plot xywh %d %d %d %d\n", this->common.x, this->common.y, this->common.width, this->common.height);
|
||||
|
||||
//x_draw_rectangle(g->x, g->xwin, 1, this->common.x, this->common.y, this->common.width, this->common.height);
|
||||
|
||||
wanted_plot_width = this->wanted_width;
|
||||
allocated_plot_width = this->common.width - this->vrule_width;
|
||||
wanted_plot_height = this->wanted_height;
|
||||
allocated_plot_height = this->common.height - this->label_height * 2;
|
||||
|
||||
/* plot zone */
|
||||
/* TODO: refine height - height of hrule text may be != from label */
|
||||
x_draw_rectangle(g->x, g->xwin, 1,
|
||||
this->common.x + this->vrule_width,
|
||||
this->common.y,
|
||||
this->common.width - this->vrule_width -1, /* -1 to see right border */
|
||||
this->common.height - this->label_height * 2);
|
||||
|
||||
/* horizontal tics */
|
||||
pxsize = (this->xmax - this->xmin) / wanted_plot_width;
|
||||
ticdist = 100;
|
||||
tic = floor(log10(ticdist * pxsize));
|
||||
ticstep = powf(10, tic);
|
||||
center = (this->xmax + this->xmin) / 2;
|
||||
allocated_xmin = center - ((this->xmax - this->xmin) *
|
||||
allocated_plot_width / wanted_plot_width) / 2;
|
||||
allocated_xmax = center + ((this->xmax - this->xmin) *
|
||||
allocated_plot_width / wanted_plot_width) / 2;
|
||||
/* adjust tic if too tight */
|
||||
LOGD("pre x ticstep %g\n", ticstep);
|
||||
while (1) {
|
||||
if (ticstep / (allocated_xmax - allocated_xmin)
|
||||
* (allocated_plot_width - 1) > 40) break;
|
||||
ticstep *= 2;
|
||||
}
|
||||
LOGD("post x ticstep %g\n", ticstep);
|
||||
LOGD("xmin/max %g %g width wanted allocated %d %d alloc xmin/max %g %g ticstep %g\n", this->xmin, this->xmax, wanted_plot_width, allocated_plot_width, allocated_xmin, allocated_xmax, ticstep);
|
||||
kmin = ceil(allocated_xmin / ticstep);
|
||||
kmax = floor(allocated_xmax / ticstep);
|
||||
for (k = kmin; k <= kmax; k++) {
|
||||
/*
|
||||
(k * ticstep - allocated_xmin) / (allocated_max - allocated_xmin) =
|
||||
(x - 0) / (allocated_plot_width-1 - 0)
|
||||
*/
|
||||
char v[64];
|
||||
int vwidth, dummy;
|
||||
int x = (k * ticstep - allocated_xmin) /
|
||||
(allocated_xmax - allocated_xmin) *
|
||||
(allocated_plot_width - 1);
|
||||
x_draw_line(g->x, g->xwin, FOREGROUND_COLOR,
|
||||
this->common.x + this->vrule_width + x,
|
||||
this->common.y + this->common.height - this->label_height * 2,
|
||||
this->common.x + this->vrule_width + x,
|
||||
this->common.y + this->common.height - this->label_height * 2 - 5);
|
||||
sprintf(v, "%g", k * ticstep);
|
||||
x_text_get_dimensions(g->x, DEFAULT_FONT, v, &vwidth, &dummy, &dummy);
|
||||
x_draw_string(g->x, g->xwin, DEFAULT_FONT, FOREGROUND_COLOR,
|
||||
this->common.x + this->vrule_width + x - vwidth/2,
|
||||
this->common.y + this->common.height - this->label_height * 2 +
|
||||
this->label_baseline,
|
||||
v);
|
||||
LOGD("tic k %d val %g x %d\n", k, k * ticstep, x);
|
||||
}
|
||||
|
||||
/* vertical tics */
|
||||
pxsize = (this->ymax - this->ymin) / wanted_plot_height;
|
||||
ticdist = 30;
|
||||
tic = floor(log10(ticdist * pxsize));
|
||||
ticstep = powf(10, tic);
|
||||
center = (this->ymax + this->ymin) / 2;
|
||||
allocated_ymin = center - ((this->ymax - this->ymin) *
|
||||
allocated_plot_height / wanted_plot_height) / 2;
|
||||
allocated_ymax = center + ((this->ymax - this->ymin) *
|
||||
allocated_plot_height / wanted_plot_height) / 2;
|
||||
/* adjust tic if too tight */
|
||||
LOGD("pre y ticstep %g\n", ticstep);
|
||||
while (1) {
|
||||
if (ticstep / (allocated_ymax - allocated_ymin)
|
||||
* (allocated_plot_height - 1) > 20) break;
|
||||
ticstep *= 2;
|
||||
}
|
||||
LOGD("post y ticstep %g\n", ticstep);
|
||||
LOGD("ymin/max %g %g height wanted allocated %d %d alloc ymin/max %g %g ticstep %g\n", this->ymin, this->ymax, wanted_plot_height, allocated_plot_height, allocated_ymin, allocated_ymax, ticstep);
|
||||
kmin = ceil(allocated_ymin / ticstep);
|
||||
kmax = floor(allocated_ymax / ticstep);
|
||||
for (k = kmin; k <= kmax; k++) {
|
||||
char v[64];
|
||||
int vwidth, dummy;
|
||||
int y = (k * ticstep - allocated_ymin) /
|
||||
(allocated_ymax - allocated_ymin) *
|
||||
(allocated_plot_height - 1);
|
||||
sprintf(v, "%g", k * ticstep);
|
||||
x_text_get_dimensions(g->x, DEFAULT_FONT, v, &vwidth, &dummy, &dummy);
|
||||
x_draw_line(g->x, g->xwin, FOREGROUND_COLOR,
|
||||
this->common.x + this->vrule_width,
|
||||
this->common.y + FLIP(y),
|
||||
this->common.x + this->vrule_width + 5,
|
||||
this->common.y + FLIP(y));
|
||||
x_draw_string(g->x, g->xwin, DEFAULT_FONT, FOREGROUND_COLOR,
|
||||
this->common.x + this->vrule_width - vwidth - 2,
|
||||
this->common.y + FLIP(y) - this->label_height/2+this->label_baseline,
|
||||
v);
|
||||
}
|
||||
|
||||
/* label at bottom, in the middle */
|
||||
x_draw_string(g->x, g->xwin, DEFAULT_FONT, FOREGROUND_COLOR,
|
||||
this->common.x + (this->common.width - this->label_width) / 2,
|
||||
this->common.y + this->common.height - this->label_height
|
||||
+ this->label_baseline,
|
||||
this->label);
|
||||
|
||||
for (n = 0; n < this->nplots; n++) {
|
||||
/* points */
|
||||
float ax, bx, ay, by;
|
||||
ax = (allocated_plot_width-1) / (allocated_xmax - allocated_xmin);
|
||||
bx = -ax * allocated_xmin;
|
||||
ay = (allocated_plot_height-1) / (allocated_ymax - allocated_ymin);
|
||||
by = -ay * allocated_ymin;
|
||||
for (i = 0; i < this->plots[n].npoints; i++) {
|
||||
int x, y;
|
||||
x = ax * this->plots[n].x[i] + bx;
|
||||
y = ay * this->plots[n].y[i] + by;
|
||||
if (x >= 0 && x < allocated_plot_width &&
|
||||
y >= 0 && y < allocated_plot_height)
|
||||
x_add_point(g->x,
|
||||
this->common.x + this->vrule_width + x,
|
||||
this->common.y + FLIP(y));
|
||||
}
|
||||
x_plot_points(g->x, g->xwin, this->plots[n].color);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void paint(gui *_gui, widget *_this)
|
||||
{
|
||||
struct gui *g = _gui;
|
||||
|
||||
@@ -73,17 +73,22 @@ int main(int n, char **v)
|
||||
socket_send(socket, is_on, number_of_events * sizeof(int)) == -1)
|
||||
abort();
|
||||
|
||||
OBUF ebuf = { osize: 0, omaxsize: 0, obuf: NULL };
|
||||
|
||||
char dump[10][T_BUFFER_MAX];
|
||||
event dump_ev[10];
|
||||
FILE *z = fopen("/tmp/dd", "w"); if (z == NULL) abort();
|
||||
while (1) {
|
||||
char v[T_BUFFER_MAX];
|
||||
char *v;
|
||||
event e;
|
||||
e = get_event(socket, v, database);
|
||||
e = get_event(socket, &ebuf, database);
|
||||
v = ebuf.obuf;
|
||||
if (e.type == -1) break;
|
||||
if (e.type == ev_input) {
|
||||
int sf = e.e[2].i;
|
||||
memcpy(dump[sf], v, T_BUFFER_MAX);
|
||||
if (ebuf.osize > T_BUFFER_MAX)
|
||||
{ printf("event size too big\n"); exit(1); }
|
||||
memcpy(dump[sf], ebuf.obuf, ebuf.osize);
|
||||
dump_ev[sf] = e;
|
||||
printf("input %d/%d\n", e.e[1].i, sf);
|
||||
if (fwrite(dump_ev[sf].e[4].b, dump_ev[sf].e[4].bsize, 1, z) != 1) abort();
|
||||
|
||||
@@ -84,11 +84,12 @@ int main(int n, char **v)
|
||||
socket_send(socket, is_on, number_of_events * sizeof(int)) == -1)
|
||||
abort();
|
||||
|
||||
OBUF ebuf = { osize: 0, omaxsize: 0, obuf: NULL };
|
||||
|
||||
while (1) {
|
||||
char v[T_BUFFER_MAX];
|
||||
event e;
|
||||
int on_off;
|
||||
e = get_event(socket, v, database);
|
||||
e = get_event(socket, &ebuf, database);
|
||||
if (e.type == -1) break;
|
||||
if (e.type != ev_fun)
|
||||
{ printf("unhandled event %d\n", e.type); continue; }
|
||||
|
||||
@@ -20,42 +20,6 @@ struct iqlog {
|
||||
int max_length;
|
||||
};
|
||||
|
||||
#if 0
|
||||
/* this function passes all received IQ samples to the views */
|
||||
static void _event(void *p, event e)
|
||||
{
|
||||
struct iqlog *l = p;
|
||||
int i;
|
||||
void *buffer;
|
||||
int bsize;
|
||||
int nsamples;
|
||||
|
||||
if (l->common.filter != NULL && filter_eval(l->common.filter, e) == 0)
|
||||
return;
|
||||
|
||||
buffer = e.e[l->buffer_arg].b;
|
||||
bsize = e.e[l->buffer_arg].bsize;
|
||||
|
||||
nsamples = bsize / (2*sizeof(int16_t));
|
||||
|
||||
if (nsamples > l->max_length) {
|
||||
l->i = realloc(l->i, nsamples * sizeof(float));
|
||||
if (l->i == NULL) abort();
|
||||
l->q = realloc(l->q, nsamples * sizeof(float));
|
||||
if (l->q == NULL) abort();
|
||||
l->max_length = nsamples;
|
||||
}
|
||||
|
||||
for (i = 0; i < nsamples; i++) {
|
||||
l->i[i] = ((int16_t *)buffer)[i*2];
|
||||
l->q[i] = ((int16_t *)buffer)[i*2+1];
|
||||
}
|
||||
|
||||
for (i = 0; i < l->common.vsize; i++)
|
||||
l->common.v[i]->append(l->common.v[i], l->i, l->q, nsamples);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void _event(void *p, event e)
|
||||
{
|
||||
struct iqlog *l = p;
|
||||
|
||||
@@ -246,11 +246,12 @@ int main(int n, char **v)
|
||||
|
||||
new_thread(receiver, &d);
|
||||
|
||||
OBUF ebuf = { osize: 0, omaxsize: 0, obuf: NULL };
|
||||
|
||||
/* read messages */
|
||||
while (1) {
|
||||
char v[T_BUFFER_MAX];
|
||||
event e;
|
||||
e = get_event(in, v, database);
|
||||
e = get_event(in, &ebuf, database);
|
||||
if (e.type == -1) break;
|
||||
if (!(e.type == ul_id || e.type == dl_id)) continue;
|
||||
handle_event(h, e);
|
||||
|
||||
@@ -0,0 +1,385 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <poll.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
#include "database.h"
|
||||
#include "utils.h"
|
||||
#include "../T.h"
|
||||
#include "config.h"
|
||||
|
||||
#define DEFAULT_LOCAL_PORT 2022
|
||||
|
||||
typedef struct {
|
||||
int id; /* increases at each new tracer's connection */
|
||||
int s; /* socket */
|
||||
int *is_on; /* local vision of is_on for this tracer */
|
||||
int poll_id; /* -1: invalid, otherwise index in fds array */
|
||||
} ti_t;
|
||||
|
||||
typedef struct {
|
||||
ti_t *ti; /* data for tracers */
|
||||
int ti_size;
|
||||
int ti_maxsize;
|
||||
} multi_t;
|
||||
|
||||
void set_is_on(int *is_on, int pos, int val)
|
||||
{
|
||||
if (val) is_on[pos]++; else is_on[pos]--;
|
||||
/* TODO: remove check? */
|
||||
if (is_on[pos] < 0) { printf("%s:%d:nonono\n",__FILE__,__LINE__); abort(); }
|
||||
}
|
||||
|
||||
int send_messages_txt(int s, char *T_messages_txt, int T_messages_txt_len)
|
||||
{
|
||||
char buf[T_BUFFER_MAX];
|
||||
char *T_LOCAL_buf = buf;
|
||||
int32_t T_LOCAL_size;
|
||||
unsigned char *src;
|
||||
int src_len;
|
||||
|
||||
/* trace T_message.txt
|
||||
* Send several messages -1 with content followed by message -2.
|
||||
*/
|
||||
src = (unsigned char *)T_messages_txt;
|
||||
src_len = T_messages_txt_len;
|
||||
while (src_len) {
|
||||
int send_size = src_len;
|
||||
if (send_size > T_PAYLOAD_MAXSIZE - sizeof(int))
|
||||
send_size = T_PAYLOAD_MAXSIZE - sizeof(int);
|
||||
/* TODO: be careful, we use internal T stuff, to rewrite? */
|
||||
T_LOCAL_size = 0;
|
||||
T_HEADER(T_ID(-1));
|
||||
T_PUT_buffer(1, ((T_buffer){addr:(src), length:(send_size)}));
|
||||
if (socket_send(s, &T_LOCAL_size, 4) == -1) return -1;
|
||||
if (socket_send(s, buf, T_LOCAL_size) == -1) return -1;
|
||||
src += send_size;
|
||||
src_len -= send_size;
|
||||
}
|
||||
T_LOCAL_size = 0;
|
||||
T_HEADER(T_ID(-2));
|
||||
if (socket_send(s, &T_LOCAL_size, 4) == -1) return -1;
|
||||
return socket_send(s, buf, T_LOCAL_size);
|
||||
}
|
||||
|
||||
void new_tracer(multi_t *m, int s, int is_on_size, char *t, int t_size, int id)
|
||||
{
|
||||
if (send_messages_txt(s, t, t_size) == -1) {
|
||||
printf("error sending T_messages.txt to new tracer %d => remove tracer\n",
|
||||
id);
|
||||
return;
|
||||
}
|
||||
if (m->ti_size == m->ti_maxsize) {
|
||||
m->ti_maxsize += 64;
|
||||
m->ti = realloc(m->ti, m->ti_maxsize * sizeof(ti_t));
|
||||
if (m->ti == NULL) abort();
|
||||
}
|
||||
m->ti[m->ti_size].id = id;
|
||||
m->ti[m->ti_size].s = s;
|
||||
m->ti[m->ti_size].is_on = calloc(is_on_size, sizeof(int));
|
||||
if (m->ti[m->ti_size].is_on == NULL) abort();
|
||||
m->ti[m->ti_size].poll_id = -1;
|
||||
m->ti_size++;
|
||||
}
|
||||
|
||||
void remove_tracer(multi_t *m, int t)
|
||||
{
|
||||
free(m->ti[t].is_on);
|
||||
shutdown(m->ti[t].s, SHUT_RDWR);
|
||||
close(m->ti[t].s);
|
||||
m->ti_size--;
|
||||
memmove(&m->ti[t], &m->ti[t+1], (m->ti_size - t) * sizeof(ti_t));
|
||||
}
|
||||
|
||||
int send_is_on(int socket, int number_of_events, int *is_on)
|
||||
{
|
||||
int i;
|
||||
char mt = 1;
|
||||
if (socket_send(socket, &mt, 1) == -1 ||
|
||||
socket_send(socket, &number_of_events, sizeof(int)) == -1) return -1;
|
||||
for (i = 0; i < number_of_events; i++) {
|
||||
int v = is_on[i] ? 1 : 0;
|
||||
if (socket_send(socket, &v, sizeof(int)) == -1) return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int read_tracee(int s, OBUF *ebuf, int *_type, int32_t *_length)
|
||||
{
|
||||
int type;
|
||||
int32_t length;
|
||||
char *v;
|
||||
int vpos = 0;
|
||||
|
||||
if (fullread(s, &length, 4) == -1) return -1;
|
||||
if (ebuf->omaxsize < length) {
|
||||
ebuf->omaxsize = (length + 65535) & ~65535;
|
||||
ebuf->obuf = realloc(ebuf->obuf, ebuf->omaxsize);
|
||||
if (ebuf->obuf == NULL) { printf("out of memory\n"); exit(1); }
|
||||
}
|
||||
v = ebuf->obuf;
|
||||
memcpy(v+vpos, &length, 4);
|
||||
vpos += 4;
|
||||
#ifdef T_SEND_TIME
|
||||
if (fullread(s,v+vpos,sizeof(struct timespec))==-1) return -1;
|
||||
vpos += sizeof(struct timespec);
|
||||
length -= sizeof(struct timespec);
|
||||
#endif
|
||||
if (fullread(s, &type, sizeof(int)) == -1) return -1;
|
||||
memcpy(v+vpos, &type, sizeof(int));
|
||||
vpos += sizeof(int);
|
||||
length -= sizeof(int);
|
||||
if (fullread(s, v+vpos, length) == -1) return -1;
|
||||
vpos += length;
|
||||
|
||||
ebuf->osize = vpos;
|
||||
|
||||
*_type = type;
|
||||
*_length = length;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void forward_event(multi_t *m, int number_of_events, OBUF *ebuf, int type)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (type < 0 || type >= number_of_events)
|
||||
{ printf("error: bad type of event to forward %d\n", type); abort(); }
|
||||
|
||||
for (i = 0; i < m->ti_size; i++) {
|
||||
if (!m->ti[i].is_on[type]) continue;
|
||||
if (socket_send(m->ti[i].s, ebuf->obuf, ebuf->osize) == -1)
|
||||
printf("warning: error forwarding event to tracer %d\n", m->ti[i].id);
|
||||
}
|
||||
}
|
||||
|
||||
int connect_to_tracee(char *ip, int port, int number_of_events, int *is_on)
|
||||
{
|
||||
int s;
|
||||
|
||||
printf("connecting to %s:%d\n", ip, port);
|
||||
|
||||
s = try_connect_to(ip, port);
|
||||
if (s == -1) return -1;
|
||||
|
||||
if (send_is_on(s, number_of_events, is_on) == -1) {
|
||||
shutdown(s, SHUT_RDWR);
|
||||
close(s);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
void usage(void)
|
||||
{
|
||||
printf(
|
||||
"options:\n"
|
||||
" -d <database file> this option is mandatory\n"
|
||||
" -ip <host> connect to given IP address (default %s)\n"
|
||||
" -p <port> connect to given port (default %d)\n"
|
||||
" -lp <port> listen on local port (default %d)\n",
|
||||
DEFAULT_REMOTE_IP,
|
||||
DEFAULT_REMOTE_PORT,
|
||||
DEFAULT_LOCAL_PORT
|
||||
);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main(int n, char **v)
|
||||
{
|
||||
char *database_filename = NULL;
|
||||
void *database;
|
||||
char *ip = DEFAULT_REMOTE_IP;
|
||||
int port = DEFAULT_REMOTE_PORT;
|
||||
int local_port = DEFAULT_LOCAL_PORT;
|
||||
int *is_on;
|
||||
int number_of_events;
|
||||
int i, j;
|
||||
char *T_messages_txt;
|
||||
int T_messages_txt_len;
|
||||
int l; /* listen socket for tracers' connections */
|
||||
int s = -1; /* socket connected to tracee. -1 if not connected */
|
||||
multi_t m;
|
||||
int is_on_changed;
|
||||
int current_nfd;
|
||||
struct pollfd *fds = NULL;
|
||||
int next_id = 0;
|
||||
|
||||
memset(&m, 0, sizeof(m));
|
||||
|
||||
/* write on a socket fails if the other end is closed and we get SIGPIPE */
|
||||
if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) abort();
|
||||
|
||||
for (i = 1; i < n; i++) {
|
||||
if (!strcmp(v[i], "-h") || !strcmp(v[i], "--help")) usage();
|
||||
if (!strcmp(v[i], "-d"))
|
||||
{ if (i > n-2) usage(); database_filename = v[++i]; continue; }
|
||||
if (!strcmp(v[i], "-ip")) { if (i > n-2) usage(); ip = v[++i]; continue; }
|
||||
if (!strcmp(v[i], "-p"))
|
||||
{ if (i > n-2) usage(); port = atoi(v[++i]); continue; }
|
||||
if (!strcmp(v[i], "-lp"))
|
||||
{ if (i > n-2) usage(); local_port = atoi(v[++i]); continue; }
|
||||
usage();
|
||||
}
|
||||
|
||||
if (database_filename == NULL) {
|
||||
printf("ERROR: provide a database file (-d)\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
database = parse_database(database_filename);
|
||||
|
||||
load_config_file(database_filename);
|
||||
get_local_config(&T_messages_txt, &T_messages_txt_len);
|
||||
|
||||
number_of_events = number_of_ids(database);
|
||||
is_on = calloc(number_of_events, sizeof(int));
|
||||
if (is_on == NULL) abort();
|
||||
|
||||
/* create listener socket */
|
||||
l = create_listen_socket("0.0.0.0", local_port);
|
||||
|
||||
OBUF ebuf = { osize: 0, omaxsize: 0, obuf: NULL };
|
||||
|
||||
current_nfd = 0;
|
||||
|
||||
while (1) {
|
||||
int nfd;
|
||||
int timeout;
|
||||
|
||||
if (s == -1) s = connect_to_tracee(ip, port, number_of_events, is_on);
|
||||
|
||||
/* poll on s (if there), l, and all tracers' sockets */
|
||||
nfd = 1 + (s != -1) + m.ti_size;
|
||||
if (nfd != current_nfd) {
|
||||
current_nfd = nfd;
|
||||
free(fds);
|
||||
fds = calloc(nfd, sizeof(struct pollfd));
|
||||
if (fds == NULL) { perror("calloc"); exit(1); }
|
||||
}
|
||||
i = 0;
|
||||
fds[i].fd = l;
|
||||
fds[i].events = POLLIN;
|
||||
i++;
|
||||
if (s != -1) {
|
||||
fds[i].fd = s;
|
||||
fds[i].events = POLLIN;
|
||||
i++;
|
||||
}
|
||||
for (j = 0; j < m.ti_size; j++) {
|
||||
m.ti[j].poll_id = i;
|
||||
fds[i].fd = m.ti[j].s;
|
||||
fds[i].events = POLLIN;
|
||||
i++;
|
||||
}
|
||||
if (s == -1) timeout = 1000; else timeout = -1;
|
||||
if (poll(fds, nfd, timeout) == -1) { perror("poll"); exit(1); }
|
||||
|
||||
if (fds[0].revents & ~POLLIN) {
|
||||
printf("TODO: error on listen socket?\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* new tracer connecting? */
|
||||
if (fds[0].revents & POLLIN) {
|
||||
int t;
|
||||
printf("tracer %d connecting\n", next_id);
|
||||
t = socket_accept(l);
|
||||
if (t == -1) perror("accept");
|
||||
else new_tracer(&m, t, number_of_events,
|
||||
T_messages_txt, T_messages_txt_len, next_id);
|
||||
next_id++;
|
||||
}
|
||||
|
||||
if (s != -1 && fds[1].revents & ~POLLIN) {
|
||||
printf("TODO: error on tracee socket?\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* data from tracee */
|
||||
if (s != -1 && fds[1].revents & POLLIN) {
|
||||
int type;
|
||||
int32_t length;
|
||||
if (read_tracee(s, &ebuf, &type, &length) == -1) {
|
||||
clear_remote_config();
|
||||
shutdown(s, SHUT_RDWR);
|
||||
close(s);
|
||||
s = -1;
|
||||
} else {
|
||||
if (type == -1)
|
||||
append_received_config_chunk(ebuf.obuf+ebuf.osize-length, length);
|
||||
else if (type == -2) verify_config();
|
||||
else forward_event(&m, number_of_events, &ebuf, type);
|
||||
}
|
||||
}
|
||||
|
||||
/* status of each tracer */
|
||||
is_on_changed = 0;
|
||||
for (j = 0; j < m.ti_size; j++) {
|
||||
int l;
|
||||
int s;
|
||||
int *t_is_on;
|
||||
if (m.ti[j].poll_id == -1) continue;
|
||||
i = m.ti[j].poll_id;
|
||||
s = m.ti[j].s;
|
||||
t_is_on = m.ti[j].is_on;
|
||||
if (fds[i].revents & (POLLHUP | POLLERR)) goto tracer_error;
|
||||
/* error? */
|
||||
if (fds[i].revents & ~POLLIN) {
|
||||
printf("TODO: error with tracer?\n");
|
||||
exit(1);
|
||||
}
|
||||
/* data in */
|
||||
if (fds[i].revents & POLLIN) {
|
||||
char t;
|
||||
int len;
|
||||
int v;
|
||||
if (fullread(s, &t, 1) != 1) goto tracer_error;
|
||||
switch (t) {
|
||||
case 0:
|
||||
is_on_changed = 1;
|
||||
if (fullread(s, &len, sizeof(int)) == -1) goto tracer_error;
|
||||
for (l = 0; l < len; l++) {
|
||||
if (fullread(s, &v, sizeof(int)) == -1) goto tracer_error;
|
||||
if (v < 0 || v >= number_of_events) goto tracer_error;
|
||||
t_is_on[v] = 1 - t_is_on[v];
|
||||
set_is_on(is_on, v, t_is_on[v]);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
is_on_changed = 1;
|
||||
if (fullread(s, &len, sizeof(int)) == -1) goto tracer_error;
|
||||
if (len < 0 || len > number_of_events) goto tracer_error;
|
||||
for (l = 0; l < len; l++) {
|
||||
if (fullread(s, &v, sizeof(int)) == -1) goto tracer_error;
|
||||
if (v < 0 || v > 1) goto tracer_error;
|
||||
if (t_is_on[l] != v) set_is_on(is_on, l, v);
|
||||
t_is_on[l] = v;
|
||||
}
|
||||
break;
|
||||
case 2: break;
|
||||
default: printf("error: unhandled message type %d\n", t); //abort();
|
||||
}
|
||||
}
|
||||
continue;
|
||||
tracer_error:
|
||||
printf("remove tracer %d\n", m.ti[j].id);
|
||||
for (l = 0; l < number_of_events; l++)
|
||||
if (m.ti[j].is_on[l]) { is_on_changed = 1; set_is_on(is_on, l, 0); }
|
||||
remove_tracer(&m, j);
|
||||
j--;
|
||||
}
|
||||
if (is_on_changed && s != -1)
|
||||
if (send_is_on(s, number_of_events, is_on) == -1) {
|
||||
clear_remote_config();
|
||||
shutdown(s, SHUT_RDWR);
|
||||
close(s);
|
||||
s = -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -56,176 +56,6 @@
|
||||
#define SC_RNTI 9
|
||||
#define G_RNTI 10
|
||||
|
||||
#if 0
|
||||
typedef enum mac_lte_oob_event {
|
||||
ltemac_send_preamble,
|
||||
ltemac_send_sr,
|
||||
ltemac_sr_failure
|
||||
} mac_lte_oob_event;
|
||||
|
||||
typedef enum mac_lte_dl_retx {
|
||||
dl_retx_no,
|
||||
dl_retx_yes,
|
||||
dl_retx_unknown
|
||||
} mac_lte_dl_retx;
|
||||
|
||||
typedef enum mac_lte_crc_status {
|
||||
crc_fail = 0,
|
||||
crc_success = 1,
|
||||
crc_high_code_rate = 2,
|
||||
crc_pdsch_lost = 3,
|
||||
crc_duplicate_nonzero_rv = 4,
|
||||
crc_false_dci = 5
|
||||
} mac_lte_crc_status;
|
||||
|
||||
typedef enum mac_lte_carrier_id {
|
||||
carrier_id_primary,
|
||||
carrier_id_secondary_1,
|
||||
carrier_id_secondary_2,
|
||||
carrier_id_secondary_3,
|
||||
carrier_id_secondary_4
|
||||
} mac_lte_carrier_id;
|
||||
|
||||
typedef enum mac_lte_ce_mode {
|
||||
no_ce_mode = 0,
|
||||
ce_mode_a = 1,
|
||||
ce_mode_b = 2
|
||||
} mac_lte_ce_mode;
|
||||
|
||||
typedef enum mac_lte_nb_mode {
|
||||
no_nb_mode = 0,
|
||||
nb_mode = 1
|
||||
} mac_lte_nb_mode;
|
||||
|
||||
/* Context info attached to each LTE MAC frame */
|
||||
typedef struct mac_lte_info
|
||||
{
|
||||
/* Needed for decode */
|
||||
guint8 radioType;
|
||||
guint8 direction;
|
||||
guint8 rntiType;
|
||||
|
||||
/* Extra info to display */
|
||||
guint16 rnti;
|
||||
guint16 ueid;
|
||||
|
||||
/* Timing info */
|
||||
guint16 sysframeNumber;
|
||||
guint16 subframeNumber;
|
||||
|
||||
/* Optional field. More interesting for TDD (FDD is always -4 subframeNumber) */
|
||||
gboolean subframeNumberOfGrantPresent;
|
||||
guint16 subframeNumberOfGrant;
|
||||
|
||||
/* Flag set only if doing PHY-level data test - i.e. there may not be a
|
||||
well-formed MAC PDU so just show as raw data */
|
||||
gboolean isPredefinedData;
|
||||
|
||||
/* Length of DL PDU or UL grant size in bytes */
|
||||
guint16 length;
|
||||
|
||||
/* 0=newTx, 1=first-retx, etc */
|
||||
guint8 reTxCount;
|
||||
guint8 isPHICHNACK; /* FALSE=PDCCH retx grant, TRUE=PHICH NACK */
|
||||
|
||||
/* UL only. Indicates if the R10 extendedBSR-Sizes parameter is set */
|
||||
gboolean isExtendedBSRSizes;
|
||||
|
||||
/* UL only. Indicates if the R10 simultaneousPUCCH-PUSCH parameter is set for PCell */
|
||||
gboolean isSimultPUCCHPUSCHPCell;
|
||||
|
||||
/* UL only. Indicates if the R10 extendedBSR-Sizes parameter is set for PSCell */
|
||||
gboolean isSimultPUCCHPUSCHPSCell;
|
||||
|
||||
/* Status of CRC check. For UE it is DL only. For eNodeB it is UL
|
||||
only. For an analyzer, it is present for both DL and UL. */
|
||||
gboolean crcStatusValid;
|
||||
mac_lte_crc_status crcStatus;
|
||||
|
||||
/* Carrier ID */
|
||||
mac_lte_carrier_id carrierId;
|
||||
|
||||
/* DL only. Is this known to be a retransmission? */
|
||||
mac_lte_dl_retx dl_retx;
|
||||
|
||||
/* DL only. CE mode to be used for RAR decoding */
|
||||
mac_lte_ce_mode ceMode;
|
||||
|
||||
/* DL and UL. NB-IoT mode of the UE */
|
||||
mac_lte_nb_mode nbMode;
|
||||
|
||||
/* More Physical layer info (see direction above for which side of union to use) */
|
||||
union {
|
||||
struct mac_lte_ul_phy_info
|
||||
{
|
||||
guint8 present; /* Remaining UL fields are present and should be displayed */
|
||||
guint8 modulation_type;
|
||||
guint8 tbs_index;
|
||||
guint8 resource_block_length;
|
||||
guint8 resource_block_start;
|
||||
guint8 harq_id;
|
||||
gboolean ndi;
|
||||
} ul_info;
|
||||
struct mac_lte_dl_phy_info
|
||||
{
|
||||
guint8 present; /* Remaining DL fields are present and should be displayed */
|
||||
guint8 dci_format;
|
||||
guint8 resource_allocation_type;
|
||||
guint8 aggregation_level;
|
||||
guint8 mcs_index;
|
||||
guint8 redundancy_version_index;
|
||||
guint8 resource_block_length;
|
||||
guint8 harq_id;
|
||||
gboolean ndi;
|
||||
guint8 transport_block; /* 0..1 */
|
||||
} dl_info;
|
||||
} detailed_phy_info;
|
||||
|
||||
/* Relating to out-of-band events */
|
||||
/* N.B. dissector will only look to these fields if length is 0... */
|
||||
mac_lte_oob_event oob_event;
|
||||
guint8 rapid;
|
||||
guint8 rach_attempt_number;
|
||||
#define MAX_SRs 20
|
||||
guint16 number_of_srs;
|
||||
guint16 oob_ueid[MAX_SRs];
|
||||
guint16 oob_rnti[MAX_SRs];
|
||||
} mac_lte_info;
|
||||
|
||||
|
||||
typedef struct mac_lte_tap_info {
|
||||
/* Info from context */
|
||||
guint16 rnti;
|
||||
guint16 ueid;
|
||||
guint8 rntiType;
|
||||
guint8 isPredefinedData;
|
||||
gboolean crcStatusValid;
|
||||
mac_lte_crc_status crcStatus;
|
||||
guint8 direction;
|
||||
|
||||
guint8 isPHYRetx;
|
||||
guint16 ueInTTI;
|
||||
|
||||
nstime_t mac_lte_time;
|
||||
|
||||
/* Number of bytes (which part is used depends upon context settings) */
|
||||
guint32 single_number_of_bytes;
|
||||
guint32 bytes_for_lcid[11];
|
||||
guint32 sdus_for_lcid[11];
|
||||
guint8 number_of_rars;
|
||||
guint8 number_of_paging_ids;
|
||||
|
||||
/* Number of padding bytes includes padding subheaders and trailing padding */
|
||||
guint16 padding_bytes;
|
||||
guint16 raw_length;
|
||||
} mac_lte_tap_info;
|
||||
|
||||
|
||||
/* Accessor function to check if a frame was considered to be ReTx */
|
||||
int is_mac_lte_frame_retx(packet_info *pinfo, guint8 direction);
|
||||
|
||||
#endif
|
||||
|
||||
/*****************************************************************/
|
||||
/* UDP framing format */
|
||||
/* ----------------------- */
|
||||
@@ -309,82 +139,3 @@ int is_mac_lte_frame_retx(packet_info *pinfo, guint8 direction);
|
||||
continues until the end of the frame) */
|
||||
#define MAC_LTE_PAYLOAD_TAG 0x01
|
||||
|
||||
|
||||
#if 0
|
||||
|
||||
/* Type to store parameters for configuring LCID->RLC channel settings for DRB */
|
||||
/* Some are optional, and may not be seen (e.g. on reestablishment) */
|
||||
typedef struct drb_mapping_t
|
||||
{
|
||||
guint16 ueid; /* Mandatory */
|
||||
guint8 drbid; /* Mandatory */
|
||||
gboolean lcid_present;
|
||||
guint8 lcid; /* Part of LogicalChannelConfig - optional */
|
||||
gboolean rlcMode_present;
|
||||
guint8 rlcMode; /* Part of RLC config - optional */
|
||||
gboolean rlc_ul_ext_li_field; /* Part of RLC config - optional */
|
||||
gboolean rlc_dl_ext_li_field; /* Part of RLC config - optional */
|
||||
gboolean rlc_ul_ext_am_sn; /* Part of RLC config - optional */
|
||||
gboolean rlc_dl_ext_am_sn; /* Part of RLC config - optional */
|
||||
gboolean um_sn_length_present;
|
||||
guint8 um_sn_length; /* Part of RLC config - optional */
|
||||
gboolean ul_priority_present;
|
||||
guint8 ul_priority; /* Part of LogicalChannelConfig - optional */
|
||||
gboolean pdcp_sn_size_present;
|
||||
guint8 pdcp_sn_size; /* Part of pdcp-Config - optional */
|
||||
} drb_mapping_t;
|
||||
|
||||
|
||||
/* Set details of an LCID -> drb channel mapping. To be called from
|
||||
configuration protocol (e.g. RRC) */
|
||||
void set_mac_lte_channel_mapping(drb_mapping_t *drb_mapping);
|
||||
|
||||
|
||||
/* Dedicated DRX config. Used to verify that a sensible config is given.
|
||||
Also, beginning to configure MAC with this config and (optionally) show
|
||||
DRX config and state (cycles/timers) attached to each UL/DL PDU! */
|
||||
typedef struct drx_config_t {
|
||||
gboolean configured;
|
||||
guint32 frameNum;
|
||||
guint32 previousFrameNum;
|
||||
|
||||
guint32 onDurationTimer;
|
||||
guint32 inactivityTimer;
|
||||
guint32 retransmissionTimer;
|
||||
guint32 longCycle;
|
||||
guint32 cycleOffset;
|
||||
/* Optional Short cycle */
|
||||
gboolean shortCycleConfigured;
|
||||
guint32 shortCycle;
|
||||
guint32 shortCycleTimer;
|
||||
} drx_config_t;
|
||||
|
||||
/* Functions to set/release up dedicated DRX config */
|
||||
void set_mac_lte_drx_config(guint16 ueid, drx_config_t *drx_config, packet_info *pinfo);
|
||||
void set_mac_lte_drx_config_release(guint16 ueid, packet_info *pinfo);
|
||||
|
||||
/* RRC can tell this dissector which RAPIDs are Group A, Group A&B */
|
||||
void set_mac_lte_rapid_ranges(guint groupA, guint all_RA);
|
||||
|
||||
/* RRC can indicate whether extended BSR sizes are used */
|
||||
void set_mac_lte_extended_bsr_sizes(guint16 ueid, gboolean use_ext_bsr_sizes, packet_info *pinfo);
|
||||
|
||||
/* RRC can indicate whether simultaneous PUCCH/PUSCH is used */
|
||||
typedef enum {
|
||||
SIMULT_PUCCH_PUSCH_PCELL = 0,
|
||||
SIMULT_PUCCH_PUSCH_PSCELL
|
||||
} simult_pucch_pusch_cell_type;
|
||||
void set_mac_lte_simult_pucch_pusch(guint16 ueid, simult_pucch_pusch_cell_type cell_type, gboolean use_simult_pucch_pusch, packet_info *pinfo);
|
||||
|
||||
/* Functions to be called from outside this module (e.g. in a plugin, where mac_lte_info
|
||||
isn't available) to get/set per-packet data */
|
||||
WS_DLL_PUBLIC
|
||||
mac_lte_info *get_mac_lte_proto_data(packet_info *pinfo);
|
||||
WS_DLL_PUBLIC
|
||||
void set_mac_lte_proto_data(packet_info *pinfo, mac_lte_info *p_mac_lte_info);
|
||||
|
||||
/* Function to attempt to populate p_mac_lte_info using framing definition above */
|
||||
gboolean dissect_mac_lte_context_fields(struct mac_lte_info *p_mac_lte_info, tvbuff_t *tvb,
|
||||
gint *p_offset);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -123,14 +123,22 @@ int main(int n, char **v)
|
||||
if (signal(SIGINT, force_stop) == SIG_ERR) abort();
|
||||
if (signal(SIGTSTP, force_stop) == SIG_ERR) abort();
|
||||
|
||||
OBUF ebuf = { osize: 0, omaxsize: 0, obuf: NULL };
|
||||
|
||||
/* read messages */
|
||||
while (run) {
|
||||
int type;
|
||||
int32_t length;
|
||||
char v[T_BUFFER_MAX];
|
||||
char *v;
|
||||
int vpos = 0;
|
||||
|
||||
if (fullread(socket, &length, 4) == -1) goto read_error;
|
||||
if (ebuf.omaxsize < length) {
|
||||
ebuf.omaxsize = (length + 65535) & ~65535;
|
||||
ebuf.obuf = realloc(ebuf.obuf, ebuf.omaxsize);
|
||||
if (ebuf.obuf == NULL) { printf("out of memory\n"); exit(1); }
|
||||
}
|
||||
v = ebuf.obuf;
|
||||
memcpy(v+vpos, &length, 4);
|
||||
vpos += 4;
|
||||
#ifdef T_SEND_TIME
|
||||
|
||||
@@ -136,14 +136,22 @@ int main(int n, char **v)
|
||||
|
||||
new_thread(get_message_thread, &socket);
|
||||
|
||||
OBUF ebuf = { osize: 0, omaxsize: 0, obuf: NULL };
|
||||
|
||||
while (1) {
|
||||
int type;
|
||||
int32_t length;
|
||||
char v[T_BUFFER_MAX];
|
||||
char *v;
|
||||
int vpos = 0;
|
||||
|
||||
/* read event from file */
|
||||
if (fread(&length, 4, 1, in) != 1) break;
|
||||
if (ebuf.omaxsize < length) {
|
||||
ebuf.omaxsize = (length + 65535) & ~65535;
|
||||
ebuf.obuf = realloc(ebuf.obuf, ebuf.omaxsize);
|
||||
if (ebuf.obuf == NULL) { printf("out of memory\n"); exit(1); }
|
||||
}
|
||||
v = ebuf.obuf;
|
||||
memcpy(v+vpos, &length, 4);
|
||||
vpos += 4;
|
||||
#ifdef T_SEND_TIME
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
#include "view/view.h"
|
||||
#include "gui/gui.h"
|
||||
#include "utils.h"
|
||||
#include "../T_defs.h"
|
||||
#include "event_selector.h"
|
||||
#include "config.h"
|
||||
|
||||
@@ -182,11 +181,12 @@ int main(int n, char **v)
|
||||
/* send the first message - activate selected traces */
|
||||
is_on_changed(&textlog_data);
|
||||
|
||||
OBUF ebuf = { osize: 0, omaxsize: 0, obuf: NULL };
|
||||
|
||||
/* read messages */
|
||||
while (1) {
|
||||
char v[T_BUFFER_MAX];
|
||||
event e;
|
||||
e = get_event(textlog_data.socket, v, database);
|
||||
e = get_event(textlog_data.socket, &ebuf, database);
|
||||
if (e.type == -1) abort();
|
||||
handle_event(h, e);
|
||||
}
|
||||
|
||||
+101
-19
@@ -12,7 +12,14 @@
|
||||
#include "logger/logger.h"
|
||||
#include "view/view.h"
|
||||
|
||||
enum var_type {
|
||||
DEFAULT,
|
||||
VCD_FUNCTION,
|
||||
VCD_VARIABLE
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
enum var_type type;
|
||||
char *event;
|
||||
char *arg;
|
||||
char *vcd_name;
|
||||
@@ -44,16 +51,39 @@ void vcd_write_header(vcd_vars *v, int n)
|
||||
"$version\n"
|
||||
" to_vcd\n"
|
||||
"$end\n"
|
||||
"$timescale 1ns $end\n"
|
||||
"$timescale 1ns $end\n") <= 0) abort();
|
||||
|
||||
if (fprintf(out,
|
||||
"$scope module logic $end\n") <= 0) abort();
|
||||
for (i = 0; i < n; i++)
|
||||
if (v[i].type == DEFAULT)
|
||||
if (fprintf(out, "$var wire %d %s %s $end\n",
|
||||
v[i].boolean ? 1 : 64,
|
||||
v[i].vcd_name, v[i].vcd_name) <= 0) abort();
|
||||
if (fprintf(out,
|
||||
"$upscope $end\n") <= 0) abort();
|
||||
|
||||
if (fprintf(out,
|
||||
"$scope module functions $end\n") <= 0) abort();
|
||||
for (i = 0; i < n; i++)
|
||||
if (v[i].type == VCD_FUNCTION)
|
||||
if (fprintf(out, "$var wire %d %s %s $end\n",
|
||||
v[i].boolean ? 1 : 64,
|
||||
v[i].vcd_name, v[i].vcd_name) <= 0) abort();
|
||||
if (fprintf(out,
|
||||
"$upscope $end\n") <= 0) abort();
|
||||
|
||||
if (fprintf(out,
|
||||
"$scope module variables $end\n") <= 0) abort();
|
||||
for (i = 0; i < n; i++)
|
||||
if (fprintf(out, "$var wire %d %s %s $end\n",
|
||||
v[i].boolean ? 1 : 64,
|
||||
v[i].vcd_name, v[i].vcd_name) <= 0) abort();
|
||||
if (v[i].type == VCD_VARIABLE)
|
||||
if (fprintf(out, "$var wire %d %s %s $end\n",
|
||||
v[i].boolean ? 1 : 64,
|
||||
v[i].vcd_name, v[i].vcd_name) <= 0) abort();
|
||||
if (fprintf(out,
|
||||
"$upscope $end\n") <= 0) abort();
|
||||
|
||||
if (fprintf(out,
|
||||
"$upscope $end\n"
|
||||
"$enddefinitions $end\n"
|
||||
"$dumpvars\n") <= 0) abort();
|
||||
|
||||
@@ -174,7 +204,8 @@ void usage(void)
|
||||
" -ip <host> connect to given IP address (default %s)\n"
|
||||
" -p <port> connect to given port (default %d)\n"
|
||||
" -b <event> <arg> <vcd name> trace as binary (0 off, anything else on)\n"
|
||||
" -l <event> <arg> <vcd name> trace as uint64_t\n",
|
||||
" -l <event> <arg> <vcd name> trace as uint64_t\n"
|
||||
" -vcd trace all VCD variables and functions\n",
|
||||
DEFAULT_REMOTE_IP,
|
||||
DEFAULT_REMOTE_PORT
|
||||
);
|
||||
@@ -192,6 +223,21 @@ void force_stop(int x)
|
||||
run = 0;
|
||||
}
|
||||
|
||||
vcd_vars *add_var(vcd_vars *vars, int nvars,
|
||||
char *event, char *arg, char *vcd_name, int is_boolean, enum var_type t)
|
||||
{
|
||||
if (nvars % 64 == 0) {
|
||||
vars = realloc(vars, (nvars+64) * sizeof(vcd_vars));
|
||||
if (vars == NULL) abort();
|
||||
}
|
||||
vars[nvars].type = t;
|
||||
vars[nvars].event = event;
|
||||
vars[nvars].arg = arg;
|
||||
vars[nvars].vcd_name = vcd_name;
|
||||
vars[nvars].boolean = is_boolean;
|
||||
return vars;
|
||||
}
|
||||
|
||||
int main(int n, char **v)
|
||||
{
|
||||
char *output_filename = NULL;
|
||||
@@ -202,11 +248,12 @@ int main(int n, char **v)
|
||||
int *is_on;
|
||||
int number_of_events;
|
||||
int i;
|
||||
vcd_vars vars[n];
|
||||
vcd_vars *vars = NULL;
|
||||
int nvars = 0;
|
||||
view *vcd_view;
|
||||
event_handler *h;
|
||||
logger *textlog;
|
||||
int all_vcd = 0;
|
||||
|
||||
/* write on a socket fails if the other end is closed and we get SIGPIPE */
|
||||
if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) abort();
|
||||
@@ -221,19 +268,22 @@ int main(int n, char **v)
|
||||
if (!strcmp(v[i], "-p"))
|
||||
{ if (i > n-2) usage(); port = atoi(v[++i]); continue; }
|
||||
if (!strcmp(v[i], "-b")) { if(i>n-4)usage();
|
||||
vars[nvars].event = v[++i];
|
||||
vars[nvars].arg = v[++i];
|
||||
vars[nvars].vcd_name = v[++i];
|
||||
vars[nvars++].boolean = 1;
|
||||
char *event = v[++i];
|
||||
char *arg = v[++i];
|
||||
char *vcd_name = v[++i];
|
||||
vars = add_var(vars, nvars, event, arg, vcd_name, 1, DEFAULT);
|
||||
nvars++;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(v[i], "-l")) { if(i>n-4)usage();
|
||||
vars[nvars].event = v[++i];
|
||||
vars[nvars].arg = v[++i];
|
||||
vars[nvars].vcd_name = v[++i];
|
||||
vars[nvars++].boolean = 0;
|
||||
char *event = v[++i];
|
||||
char *arg = v[++i];
|
||||
char *vcd_name = v[++i];
|
||||
vars = add_var(vars, nvars, event, arg, vcd_name, 0, DEFAULT);
|
||||
nvars++;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(v[i], "-vcd")) { all_vcd = 1; continue; }
|
||||
usage();
|
||||
}
|
||||
|
||||
@@ -260,11 +310,42 @@ int main(int n, char **v)
|
||||
/* create the view */
|
||||
vcd_view = new_view_vcd();
|
||||
|
||||
if (all_vcd) {
|
||||
/* activate all VCD traces */
|
||||
for (i = 0; i < number_of_events; i++) {
|
||||
int is_boolean;
|
||||
enum var_type type;
|
||||
int prefix_length;
|
||||
char *name = event_name_from_id(database, i);
|
||||
char *vcd_name;
|
||||
char *var_prefix = "VCD_VARIABLE_";
|
||||
char *fun_prefix = "VCD_FUNCTION_";
|
||||
if (!strncmp(name, var_prefix, strlen(var_prefix))) {
|
||||
prefix_length = strlen(var_prefix);
|
||||
is_boolean = 0;
|
||||
type = VCD_VARIABLE;
|
||||
} else if (!strncmp(name, fun_prefix, strlen(fun_prefix))) {
|
||||
prefix_length = strlen(fun_prefix);
|
||||
is_boolean = 1;
|
||||
type = VCD_FUNCTION;
|
||||
} else
|
||||
continue;
|
||||
vcd_name = event_vcd_name_from_id(database, i);
|
||||
if (vcd_name == NULL) {
|
||||
vcd_name = name+prefix_length;
|
||||
printf("WARNING: ID %s does not define VCD_NAME in the file %s, using %s\n",
|
||||
name, database_filename, vcd_name);
|
||||
}
|
||||
vars = add_var(vars, nvars,
|
||||
name, "value", vcd_name, is_boolean, type);
|
||||
nvars++;
|
||||
}
|
||||
}
|
||||
|
||||
/* setup traces */
|
||||
for (i = 0; i < nvars; i++) {
|
||||
char format[256];
|
||||
if (strlen(vars[i].arg) > 256-3) abort();
|
||||
if (strlen(vars[i].vcd_name) > 256-1) abort();
|
||||
if (strlen(vars[i].arg) + strlen(vars[i].vcd_name) > 256-16) abort();
|
||||
sprintf(format, "%c [%s] %s",
|
||||
vars[i].boolean ? 'b' : 'l',
|
||||
vars[i].arg,
|
||||
@@ -287,11 +368,12 @@ int main(int n, char **v)
|
||||
if (signal(SIGINT, force_stop) == SIG_ERR) abort();
|
||||
if (signal(SIGTSTP, force_stop) == SIG_ERR) abort();
|
||||
|
||||
OBUF ebuf = { osize: 0, omaxsize: 0, obuf: NULL };
|
||||
|
||||
/* read messages */
|
||||
while (run) {
|
||||
char v[T_BUFFER_MAX];
|
||||
event e;
|
||||
e = get_event(socket, v, database);
|
||||
e = get_event(socket, &ebuf, database);
|
||||
if (e.type == -1) { printf("disconnected? let's quit gently\n"); break; }
|
||||
handle_event(h, e);
|
||||
}
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
#include "gui/gui.h"
|
||||
#include "filter/filter.h"
|
||||
#include "utils.h"
|
||||
#include "../T_defs.h"
|
||||
#include "event_selector.h"
|
||||
#include "openair_logo.h"
|
||||
#include "config.h"
|
||||
@@ -854,8 +853,11 @@ int main(int n, char **v)
|
||||
if (pthread_mutex_init(&ue_data.lock, NULL)) abort();
|
||||
setup_event_selector(g, database, is_on, is_on_changed, &ue_data);
|
||||
|
||||
OBUF ebuf = { osize: 0, omaxsize: 0, obuf: NULL };
|
||||
|
||||
restart:
|
||||
clear_remote_config();
|
||||
if (ue_data.socket != -1) close(ue_data.socket);
|
||||
ue_data.socket = connect_to(ip, port);
|
||||
|
||||
/* send the first message - activate selected traces */
|
||||
@@ -863,9 +865,8 @@ restart:
|
||||
|
||||
/* read messages */
|
||||
while (1) {
|
||||
char v[T_BUFFER_MAX];
|
||||
event e;
|
||||
e = get_event(ue_data.socket, v, database);
|
||||
e = get_event(ue_data.socket, &ebuf, database);
|
||||
if (e.type == -1) goto restart;
|
||||
if (pthread_mutex_lock(&ue_data.lock)) abort();
|
||||
handle_event(h, e);
|
||||
|
||||
@@ -79,6 +79,36 @@ list *list_append(list *l, void *data)
|
||||
/* socket */
|
||||
/****************************************************************************/
|
||||
|
||||
int create_listen_socket(char *addr, int port)
|
||||
{
|
||||
struct sockaddr_in a;
|
||||
int s;
|
||||
int v;
|
||||
|
||||
s = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (s == -1) { perror("socket"); exit(1); }
|
||||
v = 1;
|
||||
if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &v, sizeof(int)))
|
||||
{ perror("setsockopt"); exit(1); }
|
||||
|
||||
a.sin_family = AF_INET;
|
||||
a.sin_port = htons(port);
|
||||
a.sin_addr.s_addr = inet_addr(addr);
|
||||
|
||||
if (bind(s, (struct sockaddr *)&a, sizeof(a))) { perror("bind"); exit(1); }
|
||||
if (listen(s, 5)) { perror("listen"); exit(1); }
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
int socket_accept(int s)
|
||||
{
|
||||
struct sockaddr_in a;
|
||||
socklen_t alen;
|
||||
alen = sizeof(a);
|
||||
return accept(s, (struct sockaddr *)&a, &alen);
|
||||
}
|
||||
|
||||
int socket_send(int socket, void *buffer, int size)
|
||||
{
|
||||
char *x = buffer;
|
||||
@@ -94,26 +124,13 @@ int socket_send(int socket, void *buffer, int size)
|
||||
|
||||
int get_connection(char *addr, int port)
|
||||
{
|
||||
struct sockaddr_in a;
|
||||
socklen_t alen;
|
||||
int s, t;
|
||||
|
||||
printf("waiting for connection on %s:%d\n", addr, port);
|
||||
|
||||
s = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (s == -1) { perror("socket"); exit(1); }
|
||||
t = 1;
|
||||
if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &t, sizeof(int)))
|
||||
{ perror("setsockopt"); exit(1); }
|
||||
s = create_listen_socket(addr, port);
|
||||
|
||||
a.sin_family = AF_INET;
|
||||
a.sin_port = htons(port);
|
||||
a.sin_addr.s_addr = inet_addr(addr);
|
||||
|
||||
if (bind(s, (struct sockaddr *)&a, sizeof(a))) { perror("bind"); exit(1); }
|
||||
if (listen(s, 5)) { perror("bind"); exit(1); }
|
||||
alen = sizeof(a);
|
||||
t = accept(s, (struct sockaddr *)&a, &alen);
|
||||
t = socket_accept(s);
|
||||
if (t == -1) { perror("accept"); exit(1); }
|
||||
close(s);
|
||||
|
||||
@@ -137,14 +154,11 @@ int fullread(int fd, void *_buf, int count)
|
||||
return ret;
|
||||
}
|
||||
|
||||
int connect_to(char *addr, int port)
|
||||
int try_connect_to(char *addr, int port)
|
||||
{
|
||||
int s;
|
||||
struct sockaddr_in a;
|
||||
|
||||
printf("connecting to %s:%d\n", addr, port);
|
||||
|
||||
again:
|
||||
s = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (s == -1) { perror("socket"); exit(1); }
|
||||
|
||||
@@ -155,6 +169,21 @@ again:
|
||||
if (connect(s, (struct sockaddr *)&a, sizeof(a)) == -1) {
|
||||
perror("connect");
|
||||
close(s);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
int connect_to(char *addr, int port)
|
||||
{
|
||||
int s;
|
||||
|
||||
printf("connecting to %s:%d\n", addr, port);
|
||||
|
||||
again:
|
||||
s = try_connect_to(addr, port);
|
||||
if (s == -1) {
|
||||
printf("trying again in 1s\n");
|
||||
sleep(1);
|
||||
goto again;
|
||||
|
||||
@@ -24,11 +24,14 @@ list *list_append(list *l, void *data);
|
||||
#define DEFAULT_REMOTE_IP "127.0.0.1"
|
||||
#define DEFAULT_REMOTE_PORT 2021
|
||||
|
||||
int create_listen_socket(char *addr, int port);
|
||||
int socket_accept(int s);
|
||||
/* socket_send: return 0 if okay, -1 on error */
|
||||
int socket_send(int socket, void *buffer, int size);
|
||||
int get_connection(char *addr, int port);
|
||||
/* fullread: return length read if okay (that is: 'count'), -1 on error */
|
||||
int fullread(int fd, void *_buf, int count);
|
||||
int try_connect_to(char *addr, int port);
|
||||
int connect_to(char *addr, int port);
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
#include "view/view.h"
|
||||
#include "gui/gui.h"
|
||||
#include "utils.h"
|
||||
#include "../T_defs.h"
|
||||
#include "event_selector.h"
|
||||
#include "config.h"
|
||||
|
||||
@@ -188,11 +187,12 @@ int main(int n, char **v)
|
||||
/* send the first message - activate selected traces */
|
||||
is_on_changed(&vcd_data);
|
||||
|
||||
OBUF ebuf = { osize: 0, omaxsize: 0, obuf: NULL };
|
||||
|
||||
/* read messages */
|
||||
while (1) {
|
||||
char v[T_BUFFER_MAX];
|
||||
event e;
|
||||
e = get_event(vcd_data.socket, v, database);
|
||||
e = get_event(vcd_data.socket, &ebuf, database);
|
||||
if (e.type == -1) abort();
|
||||
handle_event(h, e);
|
||||
}
|
||||
|
||||
@@ -95,7 +95,7 @@ hash_table_t *hashtable_create(const hash_size_t sizeP, hash_size_t (*hashfuncP)
|
||||
* Cleanup
|
||||
* The hashtable_destroy() walks through the linked lists for each possible hash value, and releases the elements. It also releases the nodes array and the hash_table_t.
|
||||
*/
|
||||
hashtable_rc_t hashtable_destroy(hash_table_t * const hashtblP)
|
||||
hashtable_rc_t hashtable_destroy(hash_table_t * hashtblP)
|
||||
{
|
||||
hash_size_t n;
|
||||
hash_node_t *node, *oldnode;
|
||||
@@ -117,6 +117,7 @@ hashtable_rc_t hashtable_destroy(hash_table_t * const hashtblP)
|
||||
}
|
||||
free(hashtblP->nodes);
|
||||
free(hashtblP);
|
||||
hashtblP=NULL;
|
||||
return HASH_TABLE_OK;
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#ifndef ASSERTIONS_H_
|
||||
#define ASSERTIONS_H_
|
||||
|
||||
void output_log_mem(void);
|
||||
#define _Assert_Exit_ \
|
||||
{ \
|
||||
fprintf(stderr, "\nExiting execution\n"); \
|
||||
|
||||
@@ -39,7 +39,6 @@
|
||||
|
||||
#include "assertions.h"
|
||||
#include "intertask_interface.h"
|
||||
#include "intertask_interface_dump.h"
|
||||
|
||||
#if T_TRACER
|
||||
#include "T.h"
|
||||
@@ -328,22 +327,17 @@ int itti_send_msg_to_task(task_id_t destination_task_id, instance_t instance, Me
|
||||
/* Increment the global message number */
|
||||
message_number = itti_increment_message_number ();
|
||||
|
||||
#if 0
|
||||
/* itti dump is disabled */
|
||||
itti_dump_queue_message (origin_task_id, message_number, message, itti_desc.messages_info[message_id].name,
|
||||
sizeof(MessageHeader) + message->ittiMsgHeader.ittiMsgSize);
|
||||
#endif
|
||||
|
||||
if (destination_task_id != TASK_UNKNOWN) {
|
||||
|
||||
if (itti_desc.threads[destination_thread_id].task_state == TASK_STATE_ENDED) {
|
||||
ITTI_DEBUG(ITTI_DEBUG_ISSUES, " Message %s, number %lu with priority %d can not be sent from %s to queue (%u:%s), ended destination task!\n",
|
||||
itti_desc.messages_info[message_id].name,
|
||||
message_number,
|
||||
priority,
|
||||
itti_get_task_name(origin_task_id),
|
||||
destination_task_id,
|
||||
itti_get_task_name(destination_task_id));
|
||||
if (itti_desc.threads[destination_thread_id].task_state == TASK_STATE_ENDED ||
|
||||
itti_desc.threads[destination_thread_id].task_state == TASK_STATE_NOT_CONFIGURED) {
|
||||
ITTI_DEBUG(ITTI_DEBUG_ISSUES, " Message %s, number %lu with priority %d can not be sent from %s to queue (%u:%s), unconfigured or ended destination task!\n",
|
||||
itti_desc.messages_info[message_id].name,
|
||||
message_number,
|
||||
priority,
|
||||
itti_get_task_name(origin_task_id),
|
||||
destination_task_id,
|
||||
itti_get_task_name(destination_task_id));
|
||||
} else {
|
||||
if(!emulate_rf){
|
||||
/* We cannot send a message if the task is not running */
|
||||
@@ -429,22 +423,17 @@ int itti_try_send_msg_to_task(task_id_t destination_task_id, instance_t instance
|
||||
/* Increment the global message number */
|
||||
message_number = itti_increment_message_number ();
|
||||
|
||||
#if 0
|
||||
/* itti dump is disabled */
|
||||
itti_dump_queue_message (origin_task_id, message_number, message, itti_desc.messages_info[message_id].name,
|
||||
sizeof(MessageHeader) + message->ittiMsgHeader.ittiMsgSize);
|
||||
#endif
|
||||
|
||||
if (destination_task_id != TASK_UNKNOWN) {
|
||||
|
||||
if (itti_desc.threads[destination_thread_id].task_state == TASK_STATE_ENDED) {
|
||||
ITTI_DEBUG(ITTI_DEBUG_ISSUES, " Message %s, number %lu with priority %d can not be sent from %s to queue (%u:%s), ended destination task!\n",
|
||||
itti_desc.messages_info[message_id].name,
|
||||
message_number,
|
||||
priority,
|
||||
itti_get_task_name(origin_task_id),
|
||||
destination_task_id,
|
||||
itti_get_task_name(destination_task_id));
|
||||
if (itti_desc.threads[destination_thread_id].task_state == TASK_STATE_ENDED ||
|
||||
itti_desc.threads[destination_thread_id].task_state == TASK_STATE_NOT_CONFIGURED) {
|
||||
ITTI_DEBUG(ITTI_DEBUG_ISSUES, " Message %s, number %lu with priority %d can not be sent from %s to queue (%u:%s), unconfigured or ended destination task!\n",
|
||||
itti_desc.messages_info[message_id].name,
|
||||
message_number,
|
||||
priority,
|
||||
itti_get_task_name(origin_task_id),
|
||||
destination_task_id,
|
||||
itti_get_task_name(destination_task_id));
|
||||
} else {
|
||||
/* We cannot send a message if the task is not running */
|
||||
AssertFatal (itti_desc.threads[destination_thread_id].task_state == TASK_STATE_READY,
|
||||
@@ -727,15 +716,18 @@ void itti_mark_task_ready(task_id_t task_id)
|
||||
|
||||
AssertFatal (thread_id < itti_desc.thread_max, "Thread id (%d) is out of range (%d)!\n", thread_id, itti_desc.thread_max);
|
||||
|
||||
#if 0
|
||||
/* itti dump is disabled */
|
||||
/* Register the thread in itti dump */
|
||||
itti_dump_thread_use_ring_buffer();
|
||||
#endif
|
||||
|
||||
/* Mark the thread as using LFDS queue */
|
||||
lfds611_queue_use(itti_desc.tasks[task_id].message_queue);
|
||||
|
||||
#if defined(UE_EXPANSION) || defined(RTAI)
|
||||
/* Assign low priority to created threads */
|
||||
{
|
||||
struct sched_param sched_param;
|
||||
sched_param.sched_priority = sched_get_priority_min(SCHED_FIFO) + 1;
|
||||
sched_setscheduler(0, SCHED_FIFO, &sched_param);
|
||||
}
|
||||
#endif
|
||||
|
||||
itti_desc.threads[thread_id].task_state = TASK_STATE_READY;
|
||||
itti_desc.ready_tasks ++;
|
||||
|
||||
@@ -753,7 +745,7 @@ void itti_exit_task(void)
|
||||
|
||||
#if defined(OAI_EMU) || defined(RTAI)
|
||||
if (task_id > TASK_UNKNOWN) {
|
||||
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLE_ITTI_RECV_MSG,
|
||||
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_ITTI_RECV_MSG,
|
||||
__sync_and_and_fetch (&itti_desc.vcd_receive_msg, ~(1L << task_id)));
|
||||
}
|
||||
#endif
|
||||
@@ -777,7 +769,7 @@ void itti_terminate_tasks(task_id_t task_id)
|
||||
}
|
||||
|
||||
int itti_init(task_id_t task_max, thread_id_t thread_max, MessagesIds messages_id_max, const task_info_t *tasks_info,
|
||||
const message_info_t *messages_info, const char * const messages_definition_xml, const char * const dump_file_name)
|
||||
const message_info_t *messages_info)
|
||||
{
|
||||
task_id_t task_id;
|
||||
thread_id_t thread_id;
|
||||
@@ -862,11 +854,6 @@ int itti_init(task_id_t task_max, thread_id_t thread_max, MessagesIds messages_i
|
||||
itti_desc.wait_tasks = 0;
|
||||
itti_desc.created_tasks = 0;
|
||||
itti_desc.ready_tasks = 0;
|
||||
#if 0
|
||||
/* itti dump is disabled */
|
||||
itti_dump_init (messages_definition_xml, dump_file_name);
|
||||
#endif
|
||||
|
||||
CHECK_INIT_RETURN(timer_init ());
|
||||
|
||||
return 0;
|
||||
@@ -931,11 +918,6 @@ void itti_wait_tasks_end(void)
|
||||
ITTI_DEBUG(ITTI_DEBUG_ISSUES, " Some threads are still running, force exit\n");
|
||||
exit (0);
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* itti dump is disabled */
|
||||
itti_dump_exit();
|
||||
#endif
|
||||
}
|
||||
|
||||
void itti_send_terminate_message(task_id_t task_id)
|
||||
|
||||
@@ -1,790 +0,0 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
/** @brief Intertask Interface Signal Dumper
|
||||
* Allows users to connect their itti_analyzer to this process and dump
|
||||
* signals exchanged between tasks.
|
||||
* @author Sebastien Roux <sebastien.roux@eurecom.fr>
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE // required for pthread_setname_np()
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <error.h>
|
||||
#include <sched.h>
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/types.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <sys/eventfd.h>
|
||||
|
||||
#include "assertions.h"
|
||||
#include "liblfds611.h"
|
||||
|
||||
#include "itti_types.h"
|
||||
#include "intertask_interface.h"
|
||||
#include "intertask_interface_dump.h"
|
||||
|
||||
#if T_TRACER
|
||||
#include "T.h"
|
||||
#endif
|
||||
|
||||
static const int itti_dump_debug = 0; // 0x8 | 0x4 | 0x2;
|
||||
|
||||
# define ITTI_DUMP_DEBUG(m, x, args...) do { if ((m) & itti_dump_debug) fprintf(stdout, "[ITTI_DUMP][D]"x, ##args); } \
|
||||
while(0)
|
||||
#define ITTI_DUMP_ERROR(x, args...) do { fprintf(stdout, "[ITTI_DUMP][E]"x, ##args); } \
|
||||
while(0)
|
||||
|
||||
|
||||
typedef struct itti_dump_queue_item_s {
|
||||
MessageDef *data;
|
||||
uint32_t data_size;
|
||||
uint32_t message_number;
|
||||
uint32_t message_type;
|
||||
uint32_t message_size;
|
||||
} itti_dump_queue_item_t;
|
||||
|
||||
typedef struct {
|
||||
int sd;
|
||||
uint32_t last_message_number;
|
||||
} itti_client_desc_t;
|
||||
|
||||
typedef struct itti_desc_s {
|
||||
/* Asynchronous thread that write to file/accept new clients */
|
||||
pthread_t itti_acceptor_thread;
|
||||
pthread_attr_t attr;
|
||||
|
||||
/* List of messages to dump.
|
||||
* NOTE: we limit the size of this queue to retain only the last exchanged
|
||||
* messages. The size can be increased by setting up the ITTI_QUEUE_MAX_ELEMENTS
|
||||
* in mme_default_values.h or by putting a custom in the configuration file.
|
||||
*/
|
||||
struct lfds611_ringbuffer_state *itti_message_queue;
|
||||
|
||||
int nb_connected;
|
||||
|
||||
/* Event fd used to notify new messages (semaphore) */
|
||||
int event_fd;
|
||||
int itti_listen_socket;
|
||||
|
||||
itti_client_desc_t itti_clients[ITTI_DUMP_MAX_CON];
|
||||
} itti_desc_t;
|
||||
|
||||
typedef struct {
|
||||
itti_socket_header_t socket_header;
|
||||
|
||||
itti_signal_header_t signal_header;
|
||||
|
||||
/* Message payload is added here, this struct is used as an header */
|
||||
} itti_dump_message_t;
|
||||
|
||||
typedef struct {
|
||||
itti_socket_header_t socket_header;
|
||||
} itti_statistic_message_t;
|
||||
|
||||
static const itti_message_types_t itti_dump_xml_definition_end = ITTI_DUMP_XML_DEFINITION_END;
|
||||
static const itti_message_types_t itti_dump_message_type_end = ITTI_DUMP_MESSAGE_TYPE_END;
|
||||
|
||||
static itti_desc_t itti_dump_queue;
|
||||
static FILE *dump_file = NULL;
|
||||
static int itti_dump_running = 1;
|
||||
|
||||
static volatile uint32_t pending_messages = 0;
|
||||
|
||||
/*------------------------------------------------------------------------------*/
|
||||
static int itti_dump_send_message(int sd, itti_dump_queue_item_t *message)
|
||||
{
|
||||
itti_dump_message_t *new_message;
|
||||
ssize_t bytes_sent = 0, total_sent = 0;
|
||||
uint8_t *data_ptr;
|
||||
|
||||
/* Allocate memory for message header and payload */
|
||||
size_t size = sizeof(itti_dump_message_t) + message->data_size + sizeof(itti_message_types_t);
|
||||
|
||||
AssertFatal (sd > 0, "Socket descriptor (%d) is invalid!\n", sd);
|
||||
AssertFatal (message != NULL, "Message is NULL!\n");
|
||||
|
||||
new_message = malloc(size);
|
||||
AssertFatal (new_message != NULL, "New message allocation failed!\n");
|
||||
|
||||
/* Preparing the header */
|
||||
new_message->socket_header.message_size = size;
|
||||
new_message->socket_header.message_type = ITTI_DUMP_MESSAGE_TYPE;
|
||||
/* Adds message number in unsigned decimal ASCII format */
|
||||
snprintf(new_message->signal_header.message_number_char, sizeof(new_message->signal_header.message_number_char),
|
||||
MESSAGE_NUMBER_CHAR_FORMAT, message->message_number);
|
||||
new_message->signal_header.message_number_char[sizeof(new_message->signal_header.message_number_char) - 1] = '\n';
|
||||
/* Appends message payload */
|
||||
memcpy(&new_message[1], message->data, message->data_size);
|
||||
|
||||
memcpy(((void *) &new_message[1]) + message->data_size, &itti_dump_message_type_end, sizeof(itti_message_types_t));
|
||||
|
||||
data_ptr = (uint8_t *)&new_message[0];
|
||||
|
||||
do {
|
||||
bytes_sent = send(sd, &data_ptr[total_sent], size - total_sent, 0);
|
||||
|
||||
if (bytes_sent < 0) {
|
||||
ITTI_DUMP_ERROR("[%d] Failed to send %zu bytes to socket (%d:%s)\n",
|
||||
sd, size, errno, strerror(errno));
|
||||
free(new_message);
|
||||
return -1;
|
||||
}
|
||||
|
||||
total_sent += bytes_sent;
|
||||
} while (total_sent != size);
|
||||
|
||||
free(new_message);
|
||||
return total_sent;
|
||||
}
|
||||
|
||||
static int itti_dump_fwrite_message(itti_dump_queue_item_t *message)
|
||||
{
|
||||
itti_dump_message_t new_message_header;
|
||||
|
||||
if ((dump_file != NULL) && (message != NULL)) {
|
||||
|
||||
new_message_header.socket_header.message_size = message->message_size + sizeof(itti_dump_message_t) + sizeof(itti_message_types_t);
|
||||
new_message_header.socket_header.message_type = message->message_type;
|
||||
snprintf(new_message_header.signal_header.message_number_char, sizeof(new_message_header.signal_header.message_number_char),
|
||||
MESSAGE_NUMBER_CHAR_FORMAT, message->message_number);
|
||||
new_message_header.signal_header.message_number_char[sizeof(new_message_header.signal_header.message_number_char) - 1] = '\n';
|
||||
|
||||
fwrite (&new_message_header, sizeof(itti_dump_message_t), 1, dump_file);
|
||||
fwrite (message->data, message->data_size, 1, dump_file);
|
||||
fwrite (&itti_dump_message_type_end, sizeof(itti_message_types_t), 1, dump_file);
|
||||
fflush (dump_file);
|
||||
return (1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int itti_dump_send_xml_definition(const int sd, const char *message_definition_xml,
|
||||
const uint32_t message_definition_xml_length)
|
||||
{
|
||||
itti_socket_header_t *itti_dump_message;
|
||||
/* Allocate memory for message header and payload */
|
||||
size_t itti_dump_message_size;
|
||||
ssize_t bytes_sent = 0, total_sent = 0;
|
||||
uint8_t *data_ptr;
|
||||
|
||||
AssertFatal (sd > 0, "Socket descriptor (%d) is invalid!\n", sd);
|
||||
AssertFatal (message_definition_xml != NULL, "Message definition XML is NULL!\n");
|
||||
|
||||
itti_dump_message_size = sizeof(itti_socket_header_t) + message_definition_xml_length + sizeof(itti_message_types_t);
|
||||
|
||||
itti_dump_message = calloc(1, itti_dump_message_size);
|
||||
|
||||
ITTI_DUMP_DEBUG(0x2, "[%d] Sending XML definition message of size %zu to observer peer\n",
|
||||
sd, itti_dump_message_size);
|
||||
|
||||
itti_dump_message->message_size = itti_dump_message_size;
|
||||
itti_dump_message->message_type = ITTI_DUMP_XML_DEFINITION;
|
||||
|
||||
/* Copying message definition */
|
||||
memcpy (&itti_dump_message[1], message_definition_xml, message_definition_xml_length);
|
||||
memcpy (((void *) &itti_dump_message[1]) + message_definition_xml_length, &itti_dump_xml_definition_end, sizeof(itti_message_types_t));
|
||||
|
||||
data_ptr = (uint8_t *)&itti_dump_message[0];
|
||||
|
||||
do {
|
||||
bytes_sent = send(sd, &data_ptr[total_sent], itti_dump_message_size - total_sent, 0);
|
||||
|
||||
if (bytes_sent < 0) {
|
||||
ITTI_DUMP_ERROR("[%d] Failed to send %zu bytes to socket (%d:%s)\n",
|
||||
sd, itti_dump_message_size, errno, strerror(errno));
|
||||
free(itti_dump_message);
|
||||
return -1;
|
||||
}
|
||||
|
||||
total_sent += bytes_sent;
|
||||
} while (total_sent != itti_dump_message_size);
|
||||
|
||||
free(itti_dump_message);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void itti_dump_user_data_delete_function(void *user_data, void *user_state)
|
||||
{
|
||||
(void)user_state; // UNUSED
|
||||
|
||||
if (user_data != NULL) {
|
||||
itti_dump_queue_item_t *item;
|
||||
task_id_t task_id;
|
||||
int result;
|
||||
|
||||
item = (itti_dump_queue_item_t *)user_data;
|
||||
|
||||
if (item->data != NULL) {
|
||||
task_id = ITTI_MSG_ORIGIN_ID(item->data);
|
||||
result = itti_free(task_id, item->data);
|
||||
AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result);
|
||||
} else {
|
||||
task_id = TASK_UNKNOWN;
|
||||
}
|
||||
|
||||
result = itti_free(task_id, item);
|
||||
AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result);
|
||||
}
|
||||
}
|
||||
|
||||
static int itti_dump_enqueue_message(itti_dump_queue_item_t *new, uint32_t message_size,
|
||||
uint32_t message_type)
|
||||
{
|
||||
struct lfds611_freelist_element *new_queue_element = NULL;
|
||||
int overwrite_flag;
|
||||
AssertFatal (new != NULL, "Message to queue is NULL!\n");
|
||||
|
||||
new->message_type = message_type;
|
||||
new->message_size = message_size;
|
||||
|
||||
ITTI_DUMP_DEBUG (0x1, " itti_dump_enqueue_message: lfds611_ringbuffer_get_write_element\n");
|
||||
new_queue_element = lfds611_ringbuffer_get_write_element (itti_dump_queue.itti_message_queue, &new_queue_element, &overwrite_flag);
|
||||
|
||||
if (overwrite_flag != 0) {
|
||||
// no free element available: overwrite a non read one => data loss!
|
||||
void *old = NULL;
|
||||
|
||||
lfds611_freelist_get_user_data_from_element(new_queue_element, &old);
|
||||
ITTI_DUMP_DEBUG (0x4, " overwrite_flag set, freeing old data %p %p\n", new_queue_element, old);
|
||||
itti_dump_user_data_delete_function (old, NULL);
|
||||
}
|
||||
|
||||
lfds611_freelist_set_user_data_in_element(new_queue_element, new);
|
||||
lfds611_ringbuffer_put_write_element(itti_dump_queue.itti_message_queue, new_queue_element);
|
||||
|
||||
if (overwrite_flag == 0) {
|
||||
{
|
||||
ssize_t write_ret;
|
||||
eventfd_t sem_counter = 1;
|
||||
|
||||
/* Call to write for an event fd must be of 8 bytes */
|
||||
write_ret = write(itti_dump_queue.event_fd, &sem_counter, sizeof(sem_counter));
|
||||
AssertFatal (write_ret == sizeof(sem_counter), "Write to dump event failed (%d/%d)!\n", (int) write_ret, (int) sizeof(sem_counter));
|
||||
}
|
||||
// add one to pending_messages, atomically
|
||||
__sync_fetch_and_add (&pending_messages, 1);
|
||||
}
|
||||
|
||||
ITTI_DUMP_DEBUG (0x2, " Added element to queue %p %p, pending %u, type %u\n", new_queue_element, new, pending_messages, message_type);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void itti_dump_socket_exit(void)
|
||||
{
|
||||
close(itti_dump_queue.event_fd);
|
||||
close(itti_dump_queue.itti_listen_socket);
|
||||
|
||||
/* Leave the thread as we detected end signal */
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
static int itti_dump_flush_ring_buffer(int flush_all)
|
||||
{
|
||||
struct lfds611_freelist_element *element = NULL;
|
||||
void *user_data;
|
||||
int j;
|
||||
int consumer;
|
||||
|
||||
/* Check if there is a least one consumer */
|
||||
consumer = 0;
|
||||
|
||||
if (dump_file != NULL) {
|
||||
consumer = 1;
|
||||
} else {
|
||||
for (j = 0; j < ITTI_DUMP_MAX_CON; j++) {
|
||||
if (itti_dump_queue.itti_clients[j].sd > 0) {
|
||||
consumer = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (consumer > 0) {
|
||||
do {
|
||||
/* Acquire the ring element */
|
||||
lfds611_ringbuffer_get_read_element(itti_dump_queue.itti_message_queue, &element);
|
||||
|
||||
// subtract one from pending_messages, atomically
|
||||
__sync_fetch_and_sub (&pending_messages, 1);
|
||||
|
||||
if (element == NULL) {
|
||||
if (flush_all != 0) {
|
||||
flush_all = 0;
|
||||
} else {
|
||||
AssertFatal (0, "Dump event with no data!\n");
|
||||
}
|
||||
} else {
|
||||
/* Retrieve user part of the message */
|
||||
lfds611_freelist_get_user_data_from_element(element, &user_data);
|
||||
|
||||
ITTI_DUMP_DEBUG (0x2, " removed element from queue %p %p, pending %u\n", element, user_data, pending_messages);
|
||||
|
||||
if (((itti_dump_queue_item_t *)user_data)->message_type == ITTI_DUMP_EXIT_SIGNAL) {
|
||||
lfds611_ringbuffer_put_read_element(itti_dump_queue.itti_message_queue, element);
|
||||
itti_dump_socket_exit();
|
||||
}
|
||||
|
||||
/* Write message to file */
|
||||
itti_dump_fwrite_message((itti_dump_queue_item_t *)user_data);
|
||||
|
||||
/* Send message to remote analyzer */
|
||||
for (j = 0; j < ITTI_DUMP_MAX_CON; j++) {
|
||||
if (itti_dump_queue.itti_clients[j].sd > 0) {
|
||||
itti_dump_send_message(itti_dump_queue.itti_clients[j].sd,
|
||||
(itti_dump_queue_item_t *)user_data);
|
||||
}
|
||||
}
|
||||
|
||||
itti_dump_user_data_delete_function (user_data, NULL);
|
||||
lfds611_freelist_set_user_data_in_element(element, NULL);
|
||||
|
||||
/* We have finished with this element, reinsert it in the ring buffer */
|
||||
lfds611_ringbuffer_put_read_element(itti_dump_queue.itti_message_queue, element);
|
||||
}
|
||||
} while(flush_all
|
||||
);
|
||||
}
|
||||
|
||||
return (consumer);
|
||||
}
|
||||
|
||||
static int itti_dump_handle_new_connection(int sd, const char *xml_definition, uint32_t xml_definition_length)
|
||||
{
|
||||
if (itti_dump_queue.nb_connected < ITTI_DUMP_MAX_CON) {
|
||||
uint8_t i;
|
||||
|
||||
for (i = 0; i < ITTI_DUMP_MAX_CON; i++) {
|
||||
/* Let's find a place to store the new client */
|
||||
if (itti_dump_queue.itti_clients[i].sd == -1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ITTI_DUMP_DEBUG(0x2, " Found place to store new connection: %d\n", i);
|
||||
|
||||
AssertFatal (i < ITTI_DUMP_MAX_CON, "No more connection available (%d/%d) for socked %d!\n", i, ITTI_DUMP_MAX_CON, sd);
|
||||
|
||||
ITTI_DUMP_DEBUG(0x2, " Socket %d accepted\n", sd);
|
||||
|
||||
/* Send the XML message definition */
|
||||
if (itti_dump_send_xml_definition(sd, xml_definition, xml_definition_length) < 0) {
|
||||
AssertError (0, {}, "Failed to send XML definition!\n");
|
||||
close (sd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
itti_dump_queue.itti_clients[i].sd = sd;
|
||||
itti_dump_queue.nb_connected++;
|
||||
} else {
|
||||
ITTI_DUMP_DEBUG(0x2, " Socket %d rejected\n", sd);
|
||||
/* We have reached max number of users connected...
|
||||
* Reject the connection.
|
||||
*/
|
||||
close (sd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void *itti_dump_socket(void *arg_p)
|
||||
{
|
||||
uint32_t message_definition_xml_length;
|
||||
char *message_definition_xml;
|
||||
int rc;
|
||||
int itti_listen_socket, max_sd;
|
||||
int on = 1;
|
||||
fd_set read_set, working_set;
|
||||
struct sockaddr_in servaddr; /* socket address structure */
|
||||
|
||||
struct timeval *timeout_p = NULL;
|
||||
|
||||
ITTI_DUMP_DEBUG(0x2, " Creating TCP dump socket on port %u\n", ITTI_PORT);
|
||||
|
||||
message_definition_xml = (char *)arg_p;
|
||||
AssertFatal (message_definition_xml != NULL, "Message definition XML is NULL!\n");
|
||||
|
||||
message_definition_xml_length = strlen(message_definition_xml) + 1;
|
||||
|
||||
if ((itti_listen_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
|
||||
ITTI_DUMP_ERROR(" ocket creation failed (%d:%s)\n", errno, strerror(errno));
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
/* Allow socket reuse */
|
||||
rc = setsockopt(itti_listen_socket, SOL_SOCKET, SO_REUSEADDR,
|
||||
(char *)&on, sizeof(on));
|
||||
|
||||
if (rc < 0) {
|
||||
ITTI_DUMP_ERROR(" setsockopt SO_REUSEADDR failed (%d:%s)\n", errno, strerror(errno));
|
||||
close(itti_listen_socket);
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
/* Set socket to be non-blocking.
|
||||
* NOTE: sockets accepted will inherit this option.
|
||||
*/
|
||||
rc = ioctl(itti_listen_socket, FIONBIO, (char *)&on);
|
||||
|
||||
if (rc < 0) {
|
||||
ITTI_DUMP_ERROR(" ioctl FIONBIO (non-blocking) failed (%d:%s)\n", errno, strerror(errno));
|
||||
close(itti_listen_socket);
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
memset(&servaddr, 0, sizeof(servaddr));
|
||||
servaddr.sin_family = AF_INET;
|
||||
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
servaddr.sin_port = htons(ITTI_PORT);
|
||||
|
||||
if (bind(itti_listen_socket, (struct sockaddr *) &servaddr,
|
||||
sizeof(servaddr)) < 0) {
|
||||
ITTI_DUMP_ERROR(" Bind failed (%d:%s)\n", errno, strerror(errno));
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
if (listen(itti_listen_socket, 5) < 0) {
|
||||
ITTI_DUMP_ERROR(" Listen failed (%d:%s)\n", errno, strerror(errno));
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
FD_ZERO(&read_set);
|
||||
|
||||
/* Add the listener */
|
||||
FD_SET(itti_listen_socket, &read_set);
|
||||
|
||||
/* Add the event fd */
|
||||
FD_SET(itti_dump_queue.event_fd, &read_set);
|
||||
|
||||
/* Max of both sd */
|
||||
max_sd = itti_listen_socket > itti_dump_queue.event_fd ? itti_listen_socket : itti_dump_queue.event_fd;
|
||||
|
||||
itti_dump_queue.itti_listen_socket = itti_listen_socket;
|
||||
|
||||
/* Loop waiting for incoming connects or for incoming data
|
||||
* on any of the connected sockets.
|
||||
*/
|
||||
while (1) {
|
||||
int desc_ready;
|
||||
int client_socket = -1;
|
||||
int i;
|
||||
|
||||
memcpy(&working_set, &read_set, sizeof(read_set));
|
||||
timeout_p = NULL;
|
||||
|
||||
/* No timeout: select blocks till a new event has to be handled
|
||||
* on sd's.
|
||||
*/
|
||||
rc = select(max_sd + 1, &working_set, NULL, NULL, timeout_p);
|
||||
|
||||
if (rc < 0) {
|
||||
ITTI_DUMP_ERROR(" select failed (%d:%s)\n", errno, strerror(errno));
|
||||
pthread_exit(NULL);
|
||||
} else if (rc == 0) {
|
||||
/* Timeout */
|
||||
if (itti_dump_flush_ring_buffer(1) == 0) {
|
||||
if (itti_dump_running) {
|
||||
ITTI_DUMP_DEBUG (0x4, " No messages consumers, waiting ...\n");
|
||||
usleep(100 * 1000);
|
||||
} else {
|
||||
itti_dump_socket_exit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
desc_ready = rc;
|
||||
|
||||
for (i = 0; i <= max_sd && desc_ready > 0; i++) {
|
||||
if (FD_ISSET(i, &working_set)) {
|
||||
desc_ready -= 1;
|
||||
|
||||
if (i == itti_dump_queue.event_fd) {
|
||||
/* Notification of new element to dump from other tasks */
|
||||
eventfd_t sem_counter;
|
||||
ssize_t read_ret;
|
||||
|
||||
/* Read will always return 1 for kernel versions > 2.6.30 */
|
||||
read_ret = read (itti_dump_queue.event_fd, &sem_counter, sizeof(sem_counter));
|
||||
|
||||
if (read_ret < 0) {
|
||||
ITTI_DUMP_ERROR(" Failed read for semaphore: %s\n", strerror(errno));
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
AssertFatal (read_ret == sizeof(sem_counter), "Failed to read from dump event FD (%d/%d)!\n", (int) read_ret, (int) sizeof(sem_counter));
|
||||
|
||||
if (itti_dump_flush_ring_buffer(0) == 0) {
|
||||
if (itti_dump_running) {
|
||||
ITTI_DUMP_DEBUG (0x4, " No messages consumers, waiting ...\n");
|
||||
usleep(100 * 1000);
|
||||
{
|
||||
ssize_t write_ret;
|
||||
|
||||
sem_counter = 1;
|
||||
/* Call to write for an event fd must be of 8 bytes */
|
||||
write_ret = write(itti_dump_queue.event_fd, &sem_counter, sizeof(sem_counter));
|
||||
AssertFatal (write_ret == sizeof(sem_counter), "Failed to write to dump event FD (%d/%d)!\n", (int) write_ret, (int) sem_counter);
|
||||
}
|
||||
} else {
|
||||
itti_dump_socket_exit();
|
||||
}
|
||||
} else {
|
||||
ITTI_DUMP_DEBUG(0x1, " Write element to file\n");
|
||||
}
|
||||
} else
|
||||
if (i == itti_listen_socket) {
|
||||
do {
|
||||
client_socket = accept(itti_listen_socket, NULL, NULL);
|
||||
|
||||
if (client_socket < 0) {
|
||||
if (errno == EWOULDBLOCK || errno == EAGAIN) {
|
||||
/* No more new connection */
|
||||
ITTI_DUMP_DEBUG(0x2, " No more new connection\n");
|
||||
continue;
|
||||
} else {
|
||||
ITTI_DUMP_ERROR(" accept failed (%d:%s)\n", errno, strerror(errno));
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
if (itti_dump_handle_new_connection(client_socket, message_definition_xml,
|
||||
message_definition_xml_length) == 0) {
|
||||
/* The socket has been accepted.
|
||||
* We have to update the set to include this new sd.
|
||||
*/
|
||||
FD_SET(client_socket, &read_set);
|
||||
|
||||
if (client_socket > max_sd)
|
||||
max_sd = client_socket;
|
||||
}
|
||||
} while(client_socket != -1);
|
||||
} else {
|
||||
/* For now the MME itti dumper should not receive data
|
||||
* other than connection oriented (CLOSE).
|
||||
*/
|
||||
uint8_t j;
|
||||
|
||||
ITTI_DUMP_DEBUG(0x2, " Socket %d disconnected\n", i);
|
||||
|
||||
/* Close the socket and update info related to this connection */
|
||||
close(i);
|
||||
|
||||
for (j = 0; j < ITTI_DUMP_MAX_CON; j++) {
|
||||
if (itti_dump_queue.itti_clients[j].sd == i)
|
||||
break;
|
||||
}
|
||||
|
||||
/* In case we don't find the matching sd in list of known
|
||||
* connections -> assert.
|
||||
*/
|
||||
AssertFatal (j < ITTI_DUMP_MAX_CON, "Connection index not found (%d/%d) for socked %d!\n", j, ITTI_DUMP_MAX_CON, i);
|
||||
|
||||
/* Re-initialize the socket to -1 so we can accept new
|
||||
* incoming connections.
|
||||
*/
|
||||
itti_dump_queue.itti_clients[j].sd = -1;
|
||||
itti_dump_queue.itti_clients[j].last_message_number = 0;
|
||||
itti_dump_queue.nb_connected--;
|
||||
|
||||
/* Remove the socket from the FD set and update the max sd */
|
||||
FD_CLR(i, &read_set);
|
||||
|
||||
if (i == max_sd) {
|
||||
if (itti_dump_queue.nb_connected == 0) {
|
||||
/* No more new connection max_sd = itti_listen_socket */
|
||||
max_sd = itti_listen_socket;
|
||||
} else {
|
||||
while (FD_ISSET(max_sd, &read_set) == 0) {
|
||||
max_sd -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------------*/
|
||||
int itti_dump_queue_message(task_id_t sender_task,
|
||||
message_number_t message_number,
|
||||
MessageDef *message_p,
|
||||
const char *message_name,
|
||||
const uint32_t message_size)
|
||||
{
|
||||
if (itti_dump_running) {
|
||||
itti_dump_queue_item_t *new;
|
||||
|
||||
AssertFatal (message_name != NULL, "Message name is NULL!\n");
|
||||
AssertFatal (message_p != NULL, "Message is NULL!\n");
|
||||
|
||||
new = itti_malloc(sender_task, TASK_MAX, sizeof(itti_dump_queue_item_t));
|
||||
|
||||
new->data = itti_malloc(sender_task, TASK_MAX, message_size);
|
||||
|
||||
memcpy(new->data, message_p, message_size);
|
||||
new->data_size = message_size;
|
||||
new->message_number = message_number;
|
||||
|
||||
itti_dump_enqueue_message(new, message_size, ITTI_DUMP_MESSAGE_TYPE);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This function should be called by each thread that will use the ring buffer */
|
||||
void itti_dump_thread_use_ring_buffer(void)
|
||||
{
|
||||
lfds611_ringbuffer_use(itti_dump_queue.itti_message_queue);
|
||||
}
|
||||
|
||||
int itti_dump_init(const char * const messages_definition_xml, const char * const dump_file_name)
|
||||
{
|
||||
int i, ret;
|
||||
struct sched_param scheduler_param;
|
||||
|
||||
scheduler_param.sched_priority = sched_get_priority_min(SCHED_FIFO) + 1;
|
||||
|
||||
if (dump_file_name != NULL) {
|
||||
dump_file = fopen(dump_file_name, "wb");
|
||||
|
||||
if (dump_file == NULL) {
|
||||
ITTI_DUMP_ERROR(" can not open dump file \"%s\" (%d:%s)\n", dump_file_name, errno, strerror(errno));
|
||||
} else {
|
||||
/* Output the XML to file */
|
||||
uint32_t message_size = strlen(messages_definition_xml) + 1;
|
||||
itti_socket_header_t header;
|
||||
|
||||
header.message_size = sizeof(itti_socket_header_t) + message_size + sizeof(itti_message_types_t);
|
||||
header.message_type = ITTI_DUMP_XML_DEFINITION;
|
||||
|
||||
fwrite (&header, sizeof(itti_socket_header_t), 1, dump_file);
|
||||
fwrite (messages_definition_xml, message_size, 1, dump_file);
|
||||
fwrite (&itti_dump_xml_definition_end, sizeof(itti_message_types_t), 1, dump_file);
|
||||
fflush (dump_file);
|
||||
}
|
||||
}
|
||||
|
||||
memset(&itti_dump_queue, 0, sizeof(itti_desc_t));
|
||||
|
||||
ITTI_DUMP_DEBUG(0x2, " Creating new ring buffer for itti dump of %u elements\n",
|
||||
ITTI_QUEUE_MAX_ELEMENTS);
|
||||
|
||||
if (lfds611_ringbuffer_new(&itti_dump_queue.itti_message_queue,
|
||||
ITTI_QUEUE_MAX_ELEMENTS,
|
||||
NULL,
|
||||
NULL) != 1) {
|
||||
/* Always assert on this condition */
|
||||
AssertFatal (0, " Failed to create ring buffer!\n");
|
||||
}
|
||||
|
||||
itti_dump_queue.event_fd = eventfd(0, EFD_SEMAPHORE);
|
||||
|
||||
if (itti_dump_queue.event_fd == -1) {
|
||||
/* Always assert on this condition */
|
||||
AssertFatal (0, "eventfd failed: %s!\n", strerror(errno));
|
||||
}
|
||||
|
||||
itti_dump_queue.nb_connected = 0;
|
||||
|
||||
for(i = 0; i < ITTI_DUMP_MAX_CON; i++) {
|
||||
itti_dump_queue.itti_clients[i].sd = -1;
|
||||
itti_dump_queue.itti_clients[i].last_message_number = 0;
|
||||
}
|
||||
|
||||
/* initialized with default attributes */
|
||||
ret = pthread_attr_init(&itti_dump_queue.attr);
|
||||
|
||||
if (ret < 0) {
|
||||
AssertFatal (0, "pthread_attr_init failed (%d:%s)!\n", errno, strerror(errno));
|
||||
}
|
||||
|
||||
ret = pthread_attr_setschedpolicy(&itti_dump_queue.attr, SCHED_FIFO);
|
||||
|
||||
if (ret < 0) {
|
||||
AssertFatal (0, "pthread_attr_setschedpolicy (SCHED_IDLE) failed (%d:%s)!\n", errno, strerror(errno));
|
||||
}
|
||||
|
||||
ret = pthread_attr_setschedparam(&itti_dump_queue.attr, &scheduler_param);
|
||||
|
||||
if (ret < 0) {
|
||||
AssertFatal (0, "pthread_attr_setschedparam failed (%d:%s)!\n", errno, strerror(errno));
|
||||
}
|
||||
|
||||
ret = pthread_create(&itti_dump_queue.itti_acceptor_thread, &itti_dump_queue.attr,
|
||||
&itti_dump_socket, (void *)messages_definition_xml);
|
||||
|
||||
if (ret < 0) {
|
||||
AssertFatal (0, "pthread_create failed (%d:%s)!\n", errno, strerror(errno));
|
||||
}
|
||||
|
||||
pthread_setname_np( itti_dump_queue.itti_acceptor_thread, "ITTI acceptor" );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void itti_dump_exit(void)
|
||||
{
|
||||
void *arg;
|
||||
itti_dump_queue_item_t *new;
|
||||
|
||||
new = itti_malloc(TASK_UNKNOWN, TASK_UNKNOWN, sizeof(itti_dump_queue_item_t));
|
||||
memset(new, 0, sizeof(itti_dump_queue_item_t));
|
||||
|
||||
/* Set a flag to stop recording message */
|
||||
itti_dump_running = 0;
|
||||
|
||||
/* Send the exit signal to other thread */
|
||||
itti_dump_enqueue_message(new, 0, ITTI_DUMP_EXIT_SIGNAL);
|
||||
|
||||
ITTI_DUMP_DEBUG(0x2, " waiting for dumper thread to finish\n");
|
||||
|
||||
/* wait for the thread to terminate */
|
||||
pthread_join(itti_dump_queue.itti_acceptor_thread, &arg);
|
||||
|
||||
ITTI_DUMP_DEBUG(0x2, " dumper thread correctly exited\n");
|
||||
|
||||
if (dump_file != NULL) {
|
||||
/* Synchronise file and then close it */
|
||||
fclose(dump_file);
|
||||
dump_file = NULL;
|
||||
}
|
||||
|
||||
if (itti_dump_queue.itti_message_queue) {
|
||||
lfds611_ringbuffer_delete(itti_dump_queue.itti_message_queue,
|
||||
itti_dump_user_data_delete_function, NULL);
|
||||
}
|
||||
}
|
||||
@@ -41,10 +41,6 @@
|
||||
|
||||
#ifndef CHECK_PROTOTYPE_ONLY
|
||||
|
||||
const char * const messages_definition_xml = {
|
||||
#include "messages_xml.h"
|
||||
};
|
||||
|
||||
/* Map task id to printable name. */
|
||||
const task_info_t tasks_info[] = {
|
||||
{0, TASK_UNKNOWN, 0, 0, "TASK_UNKNOWN"},
|
||||
@@ -71,8 +67,7 @@ const message_info_t messages_info[] = {
|
||||
* \param messages_info Pointer on messages information as created by this include file
|
||||
**/
|
||||
int itti_init(task_id_t task_max, thread_id_t thread_max, MessagesIds messages_id_max, const task_info_t *tasks_info,
|
||||
const message_info_t *messages_info, const char * const messages_definition_xml,
|
||||
const char * const dump_file_name);
|
||||
const message_info_t *messages_info);
|
||||
|
||||
#endif /* INTERTASK_INTERFACE_INIT_H_ */
|
||||
/* @} */
|
||||
|
||||
@@ -42,8 +42,8 @@
|
||||
#include "log.h"
|
||||
|
||||
#if defined (LOG_D) && defined (LOG_E)
|
||||
# define SIG_DEBUG(x, args...) LOG_D(EMU, x, ##args)
|
||||
# define SIG_ERROR(x, args...) LOG_E(EMU, x, ##args)
|
||||
# define SIG_DEBUG(x, args...) LOG_D(RRC, x, ##args)
|
||||
# define SIG_ERROR(x, args...) LOG_E(RRC, x, ##args)
|
||||
#endif
|
||||
|
||||
#ifndef SIG_DEBUG
|
||||
|
||||
@@ -740,25 +740,6 @@ int xml_parse_buffer(char *xml_buffer, const int size) {
|
||||
return xml_parse_doc(doc);
|
||||
}
|
||||
|
||||
#if 0 /* Not used anymore */
|
||||
int xml_parse_file(const char *filename) {
|
||||
xmlDocPtr doc; /* the resulting document tree */
|
||||
|
||||
if (filename == NULL) {
|
||||
return RC_NULL_POINTER;
|
||||
}
|
||||
|
||||
doc = xmlReadFile (filename, NULL, 0);
|
||||
|
||||
if (doc == NULL) {
|
||||
ui_notification_dialog(GTK_MESSAGE_ERROR, FALSE, "parse messages format definition", "Failed to parse file \"%s\"", filename);
|
||||
return RC_FAIL;
|
||||
}
|
||||
|
||||
return xml_parse_doc(doc);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int update_filters() {
|
||||
types_t *types;
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
|
||||
#ifdef TELNETSRV_LOADER_MAIN
|
||||
|
||||
#include "UTIL/LOG/log.h"
|
||||
#include "common/utils/LOG/log.h"
|
||||
|
||||
|
||||
#include "common/utils/load_module_shlib.h"
|
||||
|
||||
@@ -32,10 +32,10 @@
|
||||
|
||||
#ifdef TELNETSRV_PHYCMD_MAIN
|
||||
|
||||
#include "UTIL/LOG/log.h"
|
||||
#include "common/utils/LOG/log.h"
|
||||
|
||||
|
||||
#include "openair1/PHY/extern.h"
|
||||
#include "openair1/PHY/phy_extern.h"
|
||||
|
||||
|
||||
#define TELNETVAR_PHYCC0 0
|
||||
|
||||
@@ -52,10 +52,9 @@
|
||||
#define TELNETSERVERCODE
|
||||
#include "telnetsrv.h"
|
||||
#define TELNETSRV_PROCCMD_MAIN
|
||||
#include "log.h"
|
||||
#include "log_extern.h"
|
||||
#include "common/utils/LOG/log.h"
|
||||
#include "common/config/config_userapi.h"
|
||||
#include "openair1/PHY/extern.h"
|
||||
#include "openair1/PHY/phy_extern.h"
|
||||
#include "telnetsrv_proccmd.h"
|
||||
|
||||
void decode_procstat(char *record, int debug, telnet_printfunc_t prnt)
|
||||
@@ -193,7 +192,6 @@ struct dirent *entry;
|
||||
|
||||
int proccmd_show(char *buf, int debug, telnet_printfunc_t prnt)
|
||||
{
|
||||
extern log_t *g_log;
|
||||
|
||||
if (debug > 0)
|
||||
prnt(" proccmd_show received %s\n",buf);
|
||||
@@ -201,12 +199,28 @@ extern log_t *g_log;
|
||||
print_threads(buf,debug,prnt);
|
||||
}
|
||||
if (strcasestr(buf,"loglvl") != NULL) {
|
||||
prnt("component verbosity level enabled\n");
|
||||
prnt(" component level enabled\n");
|
||||
for (int i=MIN_LOG_COMPONENTS; i < MAX_LOG_COMPONENTS; i++) {
|
||||
prnt("%02i %17.17s:%10.10s%10.10s %s\n",i ,g_log->log_component[i].name,
|
||||
map_int_to_str(log_verbosity_names,g_log->log_component[i].flag),
|
||||
map_int_to_str(log_level_names,g_log->log_component[i].level),
|
||||
((g_log->log_component[i].interval>0)?"Y":"N") );
|
||||
if (g_log->log_component[i].name != NULL) {
|
||||
prnt("%02i %17.17s:%10.10s %s\n",i ,g_log->log_component[i].name,
|
||||
map_int_to_str(log_level_names,g_log->log_component[i].level),
|
||||
((g_log->log_component[i].interval>0)?"Y":"N") );
|
||||
}
|
||||
}
|
||||
}
|
||||
if (strcasestr(buf,"logopt") != NULL) {
|
||||
prnt(" option enabled\n");
|
||||
for (int i=0; log_options[i].name != NULL; i++) {
|
||||
prnt("%02i %17.17s %10.10s \n",i ,log_options[i].name,
|
||||
((g_log->flag & log_options[i].value)?"Y":"N") );
|
||||
}
|
||||
}
|
||||
if (strcasestr(buf,"dbgopt") != NULL) {
|
||||
prnt(" option debug matlab\n");
|
||||
for (int i=0; log_maskmap[i].name != NULL ; i++) {
|
||||
prnt("%02i %17.17s %5.5s %5.5s\n",i ,log_maskmap[i].name,
|
||||
((g_log->debug_mask & log_maskmap[i].value)?"Y":"N"),
|
||||
((g_log->matlab_mask & log_maskmap[i].value)?"Y":"N") );
|
||||
}
|
||||
}
|
||||
if (strcasestr(buf,"config") != NULL) {
|
||||
@@ -323,24 +337,76 @@ int s = sscanf(buf,"%ms %i-%i\n",&logsubcmd, &idx1,&idx2);
|
||||
prnt("Available log levels: \n ");
|
||||
for (int i=0; log_level_names[i].name != NULL; i++)
|
||||
prnt("%s ",log_level_names[i].name);
|
||||
prnt("\nAvailable verbosity: \n ");
|
||||
for (int i=0; log_verbosity_names[i].name != NULL; i++)
|
||||
prnt("%s ",log_verbosity_names[i].name);
|
||||
prnt("\n");
|
||||
prnt("Available display options: \n ");
|
||||
for (int i=0; log_options[i].name != NULL; i++)
|
||||
prnt("%s ",log_options[i].name);
|
||||
prnt("\n");
|
||||
prnt("Available debug or matlab options: \n ");
|
||||
for (int i=0; log_maskmap[i].name != NULL; i++)
|
||||
prnt("%s ",log_maskmap[i].name);
|
||||
prnt("\n");
|
||||
proccmd_show("loglvl",debug,prnt);
|
||||
proccmd_show("logopt",debug,prnt);
|
||||
proccmd_show("dbgopt",debug,prnt);
|
||||
}
|
||||
else if (strcasestr(logsubcmd,"help") != NULL) {
|
||||
prnt(PROCCMD_LOG_HELP_STRING);
|
||||
} else {
|
||||
prnt("%s: wrong log command...\n",logsubcmd);
|
||||
}
|
||||
} else if ( s == 2 && logsubcmd != NULL) {
|
||||
char *opt=NULL;
|
||||
char *logparam=NULL;
|
||||
int l;
|
||||
int optbit;
|
||||
|
||||
l=sscanf(logsubcmd,"%m[^'_']_%ms",&logparam,&opt);
|
||||
if (l == 2 && strcmp(logparam,"print") == 0){
|
||||
optbit=map_str_to_int(log_options,opt);
|
||||
if (optbit < 0) {
|
||||
prnt("option %s unknown\n",opt);
|
||||
} else {
|
||||
if (idx1 > 0)
|
||||
SET_LOG_OPTION(optbit);
|
||||
else
|
||||
CLEAR_LOG_OPTION(optbit);
|
||||
proccmd_show("logopt",debug,prnt);
|
||||
}
|
||||
}
|
||||
else if (l == 2 && strcmp(logparam,"debug") == 0){
|
||||
optbit=map_str_to_int(log_maskmap,opt);
|
||||
if (optbit < 0) {
|
||||
prnt("debug flag %s unknown\n",opt);
|
||||
} else {
|
||||
if (idx1 > 0)
|
||||
SET_LOG_DEBUG(optbit);
|
||||
else
|
||||
CLEAR_LOG_DEBUG(optbit);
|
||||
proccmd_show("dbgopt",debug,prnt);
|
||||
}
|
||||
}
|
||||
else if (l == 2 && strcmp(logparam,"matlab") == 0){
|
||||
optbit=map_str_to_int(log_maskmap,opt);
|
||||
if (optbit < 0) {
|
||||
prnt("matlab flag %s unknown\n",opt);
|
||||
} else {
|
||||
if (idx1 > 0)
|
||||
SET_LOG_MATLAB(optbit);
|
||||
else
|
||||
CLEAR_LOG_MATLAB(optbit);
|
||||
proccmd_show("dbgopt",debug,prnt);
|
||||
}
|
||||
}
|
||||
if (logparam != NULL) free(logparam);
|
||||
if (opt != NULL) free(opt);
|
||||
} else if ( s == 3 && logsubcmd != NULL) {
|
||||
int level, verbosity, interval;
|
||||
int level, interval;
|
||||
char *tmpstr=NULL;
|
||||
char *logparam=NULL;
|
||||
int l;
|
||||
|
||||
level = verbosity = interval = -1;
|
||||
level = interval = -1;
|
||||
l=sscanf(logsubcmd,"%m[^'_']_%m[^'_']",&logparam,&tmpstr);
|
||||
if (debug > 0)
|
||||
prnt("l=%i, %s %s\n",l,((logparam==NULL)?"\"\"":logparam), ((tmpstr==NULL)?"\"\"":tmpstr));
|
||||
@@ -348,9 +414,6 @@ int s = sscanf(buf,"%ms %i-%i\n",&logsubcmd, &idx1,&idx2);
|
||||
if (strcmp(logparam,"level") == 0) {
|
||||
level=map_str_to_int(log_level_names,tmpstr);
|
||||
if (level < 0) prnt("level %s unknown\n",tmpstr);
|
||||
} else if (strcmp(logparam,"verbos") == 0) {
|
||||
verbosity=map_str_to_int(log_verbosity_names,tmpstr);
|
||||
if (verbosity < 0) prnt("verbosity %s unknown\n",tmpstr);
|
||||
} else {
|
||||
prnt("%s%s unknown log sub command \n",logparam, tmpstr);
|
||||
}
|
||||
@@ -368,11 +431,16 @@ int s = sscanf(buf,"%ms %i-%i\n",&logsubcmd, &idx1,&idx2);
|
||||
if (logparam != NULL) free(logparam);
|
||||
if (tmpstr != NULL) free(tmpstr);
|
||||
for (int i=idx1; i<=idx2 ; i++) {
|
||||
set_comp_log(i, level, verbosity, interval);
|
||||
prnt("log level/verbosity comp %i %s set to %s / %s (%s)\n",
|
||||
if (level < 0) {
|
||||
level=g_log->log_component[i].level;
|
||||
}
|
||||
if (interval < 0) {
|
||||
interval=g_log->log_component[i].interval;
|
||||
}
|
||||
set_log(i, level, interval);
|
||||
prnt("log level comp %i %s set to %s (%s)\n",
|
||||
i,((g_log->log_component[i].name==NULL)?"":g_log->log_component[i].name),
|
||||
map_int_to_str(log_level_names,g_log->log_component[i].level),
|
||||
map_int_to_str(log_verbosity_names,g_log->log_component[i].flag),
|
||||
((g_log->log_component[i].interval>0)?"enabled":"disabled"));
|
||||
|
||||
|
||||
|
||||
@@ -49,9 +49,12 @@ telnetshell_vardef_t proc_vardef[] = {
|
||||
online, noonline: enable or disable console logs \n\
|
||||
enable, disable id1-id2: enable or disable logs for components index id1 to id2 \n\
|
||||
level_<level> id1-id2: set log level to <level> for components index id1 to id2 \n\
|
||||
level_<verbosity> id1-id2: set log verbosity to <verbosity> for components index id1 to id2 \n\
|
||||
use the show command to get the values for <level>, <verbosity> and the list of component indexes \
|
||||
that can be used for id1 and id2 \n"
|
||||
use the show command to get the authorized values for <level> and the list of component \
|
||||
indexes that can be used for id1 and id2 \n\
|
||||
print_<opt> <0|1> disable or enable the \"opt\" log option, use the show command to get \
|
||||
the available options\n\
|
||||
matlab_<opt> debug_<func> disable or enable the debug code or matlab file generation \
|
||||
for \"func\" function. use the show command to get the available options\n"
|
||||
|
||||
#define PROCCMD_THREAD_HELP_STRING " thread sub commands: \n\
|
||||
<thread id> aff <core> : set affinity of thread <thread id> to core <core> \n\
|
||||
|
||||
Reference in New Issue
Block a user