Commit e329ba78 authored by frtabu's avatar frtabu

fix command line parsing for config_getlist, also improve help processing and...

fix command line parsing for config_getlist, also improve help processing and fix probe (opt) parameters processing
parent 8260607e
......@@ -37,7 +37,7 @@
#include <errno.h>
#include <platform_types.h>
#include "config_userapi.h"
#include "../utils/LOG/log.h"
int parse_stringlist(paramdef_t *cfgoptions, char *val) {
char *atoken;
......@@ -74,15 +74,15 @@ int processoption(paramdef_t *cfgoptions, char *value) {
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);
exit_fun("[CONFIG] command line parsing fatal error");
return 0;
CONFIG_PRINTF_ERROR("[CONFIG] command line, option %s requires an argument\n",cfgoptions->optname);
} else { /* boolean value option without argument, set value to true*/
tmpval = defbool;
}
}
switch(cfgoptions->type) {
char *charptr;
case TYPE_STRING:
if (cfgoptions->numelt == 0 ) {
config_check_valptr(cfgoptions, cfgoptions->strptr, strlen(tmpval)+1);
......@@ -106,14 +106,24 @@ int processoption(paramdef_t *cfgoptions, char *value) {
case TYPE_UINT8:
case TYPE_INT8:
config_check_valptr(cfgoptions, (char **)&(cfgoptions->iptr),sizeof(int32_t));
config_assign_int(cfgoptions,cfgoptions->optname,(int32_t)strtol(tmpval,NULL,0));
config_assign_int(cfgoptions,cfgoptions->optname,(int32_t)strtol(tmpval,&charptr,0));
if( *charptr != 0) {
CONFIG_PRINTF_ERROR("[CONFIG] command line, option %s requires an integer argument\n",cfgoptions->optname);
}
optisset=1;
break;
case TYPE_UINT64:
case TYPE_INT64:
config_check_valptr(cfgoptions, (char **)&(cfgoptions->i64ptr),sizeof(uint64_t));
*(cfgoptions->i64ptr)=strtoll(tmpval,NULL,0);
*(cfgoptions->i64ptr)=strtoll(tmpval,&charptr,0);
if( *charptr != 0) {
CONFIG_PRINTF_ERROR("[CONFIG] command line, option %s requires an integer argument\n",cfgoptions->optname);
}
printf_cmdl("[CONFIG] %s set to %lli from command line\n", cfgoptions->optname, (long long)*(cfgoptions->i64ptr));
optisset=1;
break;
......@@ -124,7 +134,12 @@ int processoption(paramdef_t *cfgoptions, char *value) {
case TYPE_DOUBLE:
config_check_valptr(cfgoptions, (char **)&(cfgoptions->dblptr),sizeof(double));
*(cfgoptions->dblptr) = strtof(tmpval,NULL);
*(cfgoptions->dblptr) = strtof(tmpval,&charptr);
if( *charptr != 0) {
CONFIG_PRINTF_ERROR("[CONFIG] command line, option %s requires a double argument\n",cfgoptions->optname);
}
printf_cmdl("[CONFIG] %s set to %lf from command line\n", cfgoptions->optname, *(cfgoptions->dblptr));
optisset=1;
break;
......@@ -133,7 +148,7 @@ int processoption(paramdef_t *cfgoptions, char *value) {
break;
default:
fprintf(stderr,"[CONFIG] command line, %s type %i not supported\n",cfgoptions->optname, cfgoptions->type);
CONFIG_PRINTF_ERROR("[CONFIG] command line, %s type %i not supported\n",cfgoptions->optname, cfgoptions->type);
break;
} /* switch on param type */
......@@ -176,8 +191,11 @@ int config_check_unknown_cmdlineopt(char *prefix) {
}
}
printf_cmdl("[CONFIG] %i unknown option(s) in command line starting with %s (section %s)\n",
if (unknowndetected > 0) {
CONFIG_PRINTF_ERROR("[CONFIG] %i unknown option(s) in command line starting with %s (section %s)\n",
unknowndetected,testprefix,((prefix==NULL)?"":prefix));
}
return unknowndetected;
} /* config_check_unknown_cmdlineopt */
......@@ -200,7 +218,7 @@ int config_process_cmdline(paramdef_t *cfgoptions,int numoptions, char *prefix)
if (pp == NULL || strcasecmp(pp,config_get_if()->argv[i] ) == 0 ) {
if( prefix == NULL) {
config_printhelp(cfgoptions,numoptions);
config_printhelp(cfgoptions,numoptions,"(root section)");
if ( ! ( CONFIG_ISFLAGSET(CONFIG_NOEXITONHELP)))
exit_fun("[CONFIG] Exiting after displaying help\n");
......@@ -209,8 +227,7 @@ int config_process_cmdline(paramdef_t *cfgoptions,int numoptions, char *prefix)
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);
config_printhelp(cfgoptions,numoptions,prefix);
if ( ! (CONFIG_ISFLAGSET(CONFIG_NOEXITONHELP))) {
fprintf(stderr,"[CONFIG] %s %i section %s:", __FILE__, __LINE__, prefix);
......@@ -273,16 +290,4 @@ int config_process_cmdline(paramdef_t *cfgoptions,int numoptions, char *prefix)
} /* fin du while */
printf_cmdl("[CONFIG] %s %i options set from command line\n",((prefix == NULL) ? "(root)":prefix),j);
if ( !(CONFIG_ISFLAGSET( CONFIG_NOCHECKUNKOPT )) ) {
i=config_check_unknown_cmdlineopt(prefix);
if (i > 0) {
fprintf(stderr,"[CONFIG] %i unknown options for section %s detected in command line\n",
i,((prefix==NULL)?"\"root section\"":prefix));
exit_fun(" Exiting after detecting errors in command line \n");
}
}
return j;
} /* parse_cmdline*/
......@@ -36,12 +36,15 @@
#include <unistd.h>
#include <errno.h>
#include <dlfcn.h>
#include <platform_types.h>
#define CONFIG_LOADCONFIG_MAIN
#include "config_load_configmodule.h"
#include "config_userapi.h"
#include "../utils/LOG/log.h"
#define CONFIG_SHAREDLIBFORMAT "libparams_%s.so"
int load_config_sharedlib(configmodule_interface_t *cfgptr) {
void *lib_handle;
char fname[128];
......@@ -198,7 +201,7 @@ configmodule_interface_t *load_configmodule(int argc, char **argv, uint32_t init
}
if ( strstr(argv[i], "help_config") != NULL ) {
config_printhelp(Config_Params,CONFIG_PARAMLENGTH(Config_Params));
config_printhelp(Config_Params,CONFIG_PARAMLENGTH(Config_Params),CONFIG_SECTIONNAME);
exit(0);
}
......@@ -304,7 +307,7 @@ configmodule_interface_t *load_configmodule(int argc, char **argv, uint32_t init
if (cfgmode != NULL) free(cfgmode);
if (CONFIG_ISFLAGSET(CONFIG_ABORT)) {
config_printhelp(Config_Params,CONFIG_PARAMLENGTH(Config_Params));
config_printhelp(Config_Params,CONFIG_PARAMLENGTH(Config_Params),CONFIG_SECTIONNAME );
// exit(-1);
}
......
......@@ -51,7 +51,6 @@
#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_NOCHECKUNKOPT (1<<3) // disable check unprocessed (so invalid) command line options
#define CONFIG_NOABORTONCHKF (1<<4) // 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
......@@ -109,5 +108,7 @@ extern configmodule_interface_t *cfgptr;
#define CONFIG_ENABLECMDLINEONLY (1<<1)
extern configmodule_interface_t *load_configmodule(int argc, char **argv, uint32_t initflags);
extern void end_configmodule(void);
#define CONFIG_PRINTF_ERROR(f, x... ) if (isLogInitDone ()) { LOG_E(ENB_APP,f,x);} else {printf(f,x);}; if ( !CONFIG_ISFLAGSET(CONFIG_NOABORTONCHKF) ) exit_fun("exit because configuration failed\n");
#endif /* INCLUDE_CONFIG_LOADCONFIGMODULE_H */
......@@ -39,15 +39,13 @@
#include <errno.h>
#include <dlfcn.h>
#include <arpa/inet.h>
#include <platform_types.h>
#include "config_userapi.h"
#include "../utils/LOG/log.h"
configmodule_interface_t *config_get_if(void) {
if (cfgptr == NULL) {
fprintf(stderr,"[CONFIG] %s %d config module not initialized\n",__FILE__, __LINE__);
exit(-1);
CONFIG_PRINTF_ERROR("[CONFIG] %s %d config module not initialized\n",__FILE__,__LINE__);
}
return cfgptr;
......@@ -66,9 +64,8 @@ char *config_check_valptr(paramdef_t *cfgoptions, char **ptr, int length) {
config_get_if()->numptrs++;
}
} else {
fprintf(stderr, "[CONFIG] %s %d option %s, cannot allocate pointer: %s \n",
CONFIG_PRINTF_ERROR("[CONFIG] %s %d option %s, cannot allocate pointer: %s \n",
__FILE__, __LINE__, cfgoptions->optname, strerror(errno));
exit(-1);
}
}
......@@ -78,9 +75,8 @@ char *config_check_valptr(paramdef_t *cfgoptions, char **ptr, int length) {
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",
CONFIG_PRINTF_ERROR("[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);
}
}
......@@ -95,8 +91,7 @@ char *config_check_valptr(paramdef_t *cfgoptions, char **ptr, int length) {
config_get_if()->numptrs++;
}
} else {
fprintf (stderr,"[CONFIG] %s %d malloc error\n",__FILE__, __LINE__);
exit(-1);
CONFIG_PRINTF_ERROR("[CONFIG] %s %d malloc error\n",__FILE__, __LINE__);
}
}
......@@ -157,8 +152,7 @@ void config_assign_processedint(paramdef_t *cfgoption, int val) {
if ( cfgoption->processedvalue != NULL) {
*(cfgoption->processedvalue) = val;
} else {
fprintf (stderr,"[CONFIG] %s %d malloc error\n",__FILE__, __LINE__);
exit(-1);
CONFIG_PRINTF_ERROR("[CONFIG] %s %d malloc error\n",__FILE__, __LINE__);
}
}
......@@ -177,15 +171,17 @@ int config_get_processedint(paramdef_t *cfgoption) {
return ret;
}
void config_printhelp(paramdef_t *params,int numparams) {
void config_printhelp(paramdef_t *params,int numparams, char *prefix) {
printf("\n-----Help for section %-26s: %03i entries------\n",(prefix==NULL)?"(root section)":prefix ,numparams);
for (int i=0 ; i<numparams ; i++) {
if ( params[i].helpstr != NULL) {
printf("%s%s: %s",
printf(" %s%s: %s",
(strlen(params[i].optname) <= 1) ? "-" : "--",
params[i].optname,
params[i].helpstr);
}
}
(params[i].helpstr != NULL)?params[i].helpstr:"Help string not specified");
} /* for on params entries */
printf("--------------------------------------------------------------------\n\n");
}
int config_execcheck(paramdef_t *params,int numparams, char *prefix) {
......@@ -202,11 +198,7 @@ int config_execcheck(paramdef_t *params,int numparams, char *prefix) {
}
if (st != 0) {
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");
}
CONFIG_PRINTF_ERROR("[CONFIG] config_execcheck: section %s %i parameters with wrong value\n", prefix, -st);
}
return st;
......@@ -263,6 +255,7 @@ int config_getlist(paramlist_def_t *ParamList, paramdef_t *params, int numparams
for (int i = 0; i < ParamList->numelt; ++i) {
// TODO config_process_cmdline?
sprintf(cfgpath, "%s.[%i]", newprefix, i);
config_process_cmdline(ParamList->paramarray[i],numparams,cfgpath);
config_execcheck(ParamList->paramarray[i], numparams, cfgpath);
}
......
......@@ -49,7 +49,7 @@ extern "C"
/* utility functions, to be used by configuration module and/or configuration libraries */
extern configmodule_interface_t *config_get_if(void);
extern char *config_check_valptr(paramdef_t *cfgoptions, char **ptr, int length) ;
extern void config_printhelp(paramdef_t *,int numparams);
extern void config_printhelp(paramdef_t *,int numparams, char *prefix);
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);
......
......@@ -219,7 +219,6 @@ void log_getconfig(log_t *g_log) {
paramdef_t logparams_logfile[MAX_LOG_PREDEF_COMPONENTS];
paramdef_t logparams_debug[sizeof(log_maskmap)/sizeof(mapping)];
paramdef_t logparams_dump[sizeof(log_maskmap)/sizeof(mapping)];
CONFIG_SETRTFLAG(CONFIG_NOCHECKUNKOPT);
int ret = config_get( logparams_defaults,sizeof(logparams_defaults)/sizeof(paramdef_t),CONFIG_STRING_LOG_PREFIX);
if (ret <0) {
......@@ -305,8 +304,8 @@ void log_getconfig(log_t *g_log) {
}
config_get( logparams_debug,(sizeof(log_maskmap)/sizeof(mapping)) - 1 ,CONFIG_STRING_LOG_PREFIX);
CONFIG_CLEARRTFLAG(CONFIG_NOCHECKUNKOPT);
config_get( logparams_dump,(sizeof(log_maskmap)/sizeof(mapping)) - 1 ,CONFIG_STRING_LOG_PREFIX);
config_check_unknown_cmdlineopt(CONFIG_STRING_LOG_PREFIX);
/* set the debug mask according to the debug parameters values */
for (int i=0; log_maskmap[i].name != NULL ; i++) {
......
......@@ -345,6 +345,8 @@ int32_t write_file_matlab(const char *fname, const char *vname, void *data, int
}
#define LOG_OPTIONS_IDX 2
/*----------------------------------------------------------------------------------*/
/** @defgroup _debugging debugging macros
* @ingroup _macro
......
......@@ -14,13 +14,15 @@
#define QUIT(x) do { \
printf("T tracer: QUIT: %s\n", x); \
exit(1); \
} while (0)
} while (0)
/* array used to activate/disactivate a log */
static int T_IDs[T_NUMBER_OF_IDS];
int *T_active = T_IDs;
int T_stdout = 1;
static int T_socket;
/* T_cache
......@@ -32,67 +34,90 @@ 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;
/* 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)
{
static void get_message(int s) {
char t;
int l;
int id;
int is_on;
if (read(s, &t, 1) != 1) QUIT("get_message fails");
printf("T tracer: got mess %d\n", t);
printf("T tracer: got mess %d\n", t);
switch (t) {
case 0:
/* toggle all those IDs */
/* optimze? (too much syscalls) */
if (read(s, &l, sizeof(int)) != sizeof(int)) QUIT("get_message fails");
while (l) {
if (read(s, &id, sizeof(int)) != sizeof(int)) QUIT("get_message fails");
T_IDs[id] = 1 - T_IDs[id];
l--;
}
break;
case 1:
/* set IDs as given */
/* optimize? */
if (read(s, &l, sizeof(int)) != sizeof(int)) QUIT("get_message fails");
id = 0;
while (l) {
if (read(s, &is_on, sizeof(int)) != sizeof(int))
QUIT("get_message fails");
T_IDs[id] = is_on;
id++;
l--;
}
break;
case 2: break; /* do nothing, this message is to wait for local tracer */
case 2:
break; /* do nothing, this message is to wait for local tracer */
}
}
static void *T_receive_thread(void *_)
{
static void *T_receive_thread(void *_) {
while (1) get_message(T_socket);
return NULL;
}
static void new_thread(void *(*f)(void *), void *data)
{
static void new_thread(void *(*f)(void *), void *data) {
pthread_t t;
pthread_attr_t att;
if (pthread_attr_init(&att))
{ fprintf(stderr, "pthread_attr_init err\n"); exit(1); }
if (pthread_attr_setdetachstate(&att, PTHREAD_CREATE_DETACHED))
{ fprintf(stderr, "pthread_attr_setdetachstate err\n"); exit(1); }
if (pthread_create(&t, &att, f, data))
{ fprintf(stderr, "pthread_create err\n"); exit(1); }
if (pthread_attr_destroy(&att))
{ fprintf(stderr, "pthread_attr_destroy err\n"); exit(1); }
if (pthread_attr_init(&att)) {
fprintf(stderr, "pthread_attr_init err\n");
exit(1);
}
if (pthread_attr_setdetachstate(&att, PTHREAD_CREATE_DETACHED)) {
fprintf(stderr, "pthread_attr_setdetachstate err\n");
exit(1);
}
if (pthread_create(&t, &att, f, data)) {
fprintf(stderr, "pthread_create err\n");
exit(1);
}
if (pthread_attr_destroy(&att)) {
fprintf(stderr, "pthread_attr_destroy err\n");
exit(1);
}
}
/* defined in local_tracer.c */
......@@ -104,53 +129,64 @@ void T_local_tracer_main(int remote_port, int wait_for_tracer,
*/
#include <sys/types.h>
#include <sys/wait.h>
static void monitor_and_kill(int child1, int child2)
{
static void monitor_and_kill(int child1, int child2) {
int child;
int status;
child = wait(&status);
if (child == -1) perror("wait");
kill(child1, SIGKILL);
kill(child2, SIGKILL);
exit(0);
}
void T_init(int remote_port, int wait_for_tracer, int dont_fork)
{
void T_init(int remote_port, int wait_for_tracer, int dont_fork) {
int socket_pair[2];
int s;
int child1, child2;
int i;
if (socketpair(AF_UNIX, SOCK_STREAM, 0, socket_pair))
{ perror("socketpair"); abort(); }
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(); }
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();
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_cache);
exit(0);
}
close(socket_pair[0]);
if (dont_fork == 0) {
child2 = fork(); if (child2 == -1) abort();
child2 = fork();
if (child2 == -1) abort();
if (child2 != 0) {
close(socket_pair[1]);
munmap(T_cache, T_CACHE_SIZE * sizeof(T_cache_t));
......@@ -161,27 +197,21 @@ void T_init(int remote_port, int wait_for_tracer, int dont_fork)
s = socket_pair[1];
/* wait for first message - initial list of active T events */
get_message(s);
T_socket = s;
new_thread(T_receive_thread, NULL);
}
void T_Config_Init(void)
{
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),
......
......@@ -33,26 +33,23 @@ This header file must be included */
#define OPT_H_
#ifndef sys_include
#define sys_include
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <time.h>
#define sys_include
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <time.h>
#endif
#ifndef project_include
#define project_include
#include "common/utils/LOG/log_if.h"
// #include "UTIL/LOG/log_extern.h"
//#include "PHY/defs.h"
//#include "PHY/extern.h"
#include "PHY/impl_defs_lte.h"
#define project_include
#include "common/utils/LOG/log_if.h"
#include "PHY/impl_defs_lte.h"
#endif
#define PACKET_MAC_LTE_DEFAULT_UDP_PORT (9999)
......@@ -65,6 +62,32 @@ typedef guint8 gboolean;
#include "packet-mac-lte.h"
#include "mac_pcap.h"
/* OPT parameters definitions */
#define OPT_CONFIGPREFIX "opt"
#define CONFIG_HLP_TYPEMON "Type of L2 monitoring messages: none,pcap,wireshark \n"
#define CONFIG_HLP_L2MONIP "ip address for wireshark messages \n"
#define CONFIG_HLP_L2MONPATH "file path for pcap messages on localhost \n"
/*-----------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
/* command line parameters for LOG utility */
/* optname helpstr paramflags XXXptr defXXXval type numelt */
/*-----------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
#define OPT_PARAMS_DESC { \
{"type" , CONFIG_HLP_TYPEMON, 0, strptr:&in_type, defstrval:"none", TYPE_STRING, 0}, \
{"ip" , CONFIG_HLP_L2MONIP, 0, strptr:&in_ip, defstrval:"127.0.0.1", TYPE_STRING, 0}, \
{"path" , CONFIG_HLP_L2MONPATH, 0, strptr:&in_path, defstrval:"/tmp/oai_opt.pcap", TYPE_STRING, 0}, \
}
#define OPTTYPE_IDX 0
/* check function for opt parameters */
#define OPTTYPE_OKSTRINGS {"none","pcap","wireshark"}
#define OPTTYPE_VALUES {OPT_NONE,OPT_PCAP,OPT_WIRESHARK}
#define OPTPARAMS_CHECK_DESC { \
{ .s3a= { config_checkstr_assign_integer, OPTTYPE_OKSTRINGS,OPTTYPE_VALUES ,3}} ,\
{ .s5= {NULL }} , \
{ .s5= {NULL }} , \
}
#ifdef OCP_FRAMEWORK
#include <enums.h>
#else
......@@ -82,9 +105,7 @@ typedef enum radio_type_e {
RADIO_TYPE_MAX
} radio_type_t;
extern trace_mode_t opt_type;
extern char in_ip[40];
extern char in_path[FILENAME_MAX];
/**
* function def
......@@ -94,7 +115,7 @@ void trace_pdu(int direction, uint8_t *pdu_buffer, unsigned int pdu_buffer_size,
int ueid, int rntiType, int rnti, uint16_t sysFrame, uint8_t subframe,
int oob_event, int oob_event_value);
int init_opt(char *path, char *ip);
int init_opt(void);
void terminate_opt(void);
......
......@@ -90,7 +90,7 @@ what about the implementation
#include <pthread.h>
#include <stdint.h>
#include "common/config/config_userapi.h"
#include "opt.h"
int opt_enabled=0;
......@@ -98,8 +98,8 @@ int opt_enabled=0;
//static unsigned char g_PDUBuffer[1600];
//static unsigned int g_PDUOffset;
char in_ip[40];
char in_path[FILENAME_MAX];
static char *in_ip;
static char *in_path;
FILE *file_fd = NULL;
pcap_hdr_t file_header = {
0xa1b2c3d4, /* magic number */
......@@ -133,17 +133,15 @@ static void SendFrame(guint8 radioType, guint8 direction, guint8 rntiType,
static int MAC_LTE_PCAP_WritePDU(MAC_Context_Info_t *context,
const unsigned char *PDU, unsigned int length);
static void *opt_listener_thread(void *arg)
{
static void *opt_listener_thread(void *arg) {
ssize_t ret;
struct sockaddr_in from_address;
socklen_t socklen = sizeof(from_address);
memset(&from_address, 0, sizeof(from_address));
while(1) {
/* Simply drop packets */
ret = recvfrom(opt_listener.sd, NULL, 0, 0, (struct sockaddr*)&from_address,
ret = recvfrom(opt_listener.sd, NULL, 0, 0, (struct sockaddr *)&from_address,
&socklen);
if (ret == 0) {
......@@ -165,17 +163,13 @@ static void *opt_listener_thread(void *arg)
}
static
int opt_create_listener_socket(char *ip_address, uint16_t port)
{
int opt_create_listener_socket(char *ip_address, uint16_t port) {
/* Create an UDP socket and listen on it.
* Silently discard PDU received.
*/
int sd = -1;
int ret = -1;
memset(&opt_listener, 0, sizeof(opt_listener_t));
sd = socket(AF_INET, SOCK_DGRAM, 0);
if (sd < 0) {
......@@ -190,8 +184,7 @@ int opt_create_listener_socket(char *ip_address, uint16_t port)
/* Listening only on provided IP address */
opt_listener.address.sin_addr.s_addr = inet_addr(ip_address);
opt_listener.address.sin_port = htons(port);
ret = bind(opt_listener.sd, (struct sockaddr*) &opt_listener.address, sizeof(opt_listener.address));
ret = bind(opt_listener.sd, (struct sockaddr *) &opt_listener.address, sizeof(opt_listener.address));
if (ret != 0) {
LOG_E(OPT, "Failed to bind socket to (%s:%u): %s\n",
......@@ -231,49 +224,39 @@ static void SendFrame(guint8 radioType, guint8 direction, guint8 rntiType,
guint16 rnti, guint16 ueid, guint16 sfnSf,
guint8 isPredefinedData, guint8 retx, guint8 crcStatus,
guint8 oob_event, guint8 oob_event_value,
uint8_t *pdu_buffer, unsigned int pdu_buffer_size)
{
uint8_t *pdu_buffer, unsigned int pdu_buffer_size) {
unsigned char frameBuffer[9000];
unsigned int frameOffset;
ssize_t bytesSent;
frameOffset = 0;
uint16_t tmp16;
memcpy(frameBuffer+frameOffset, MAC_LTE_START_STRING,
strlen(MAC_LTE_START_STRING));
frameOffset += strlen(MAC_LTE_START_STRING);
/******************************************************************************/
/* Now write out fixed fields (the mandatory elements of struct mac_lte_info) */
frameBuffer[frameOffset++] = radioType;
frameBuffer[frameOffset++] = direction;
frameBuffer[frameOffset++] = rntiType;
/*************************************/
/* Now optional fields */
/* RNTI */
frameBuffer[frameOffset++] = MAC_LTE_RNTI_TAG;
tmp16 = htons(rnti);
memcpy(frameBuffer+frameOffset, &tmp16, 2);
frameOffset += 2;
/* UEId */
frameBuffer[frameOffset++] = MAC_LTE_UEID_TAG;
tmp16 = htons(ueid);
memcpy(frameBuffer+frameOffset, &tmp16, 2);
frameOffset += 2;
/* Subframe number */
frameBuffer[frameOffset++] = MAC_LTE_FRAME_SUBFRAME_TAG;
tmp16 = htons(sfnSf); // frame counter : this will give an expert info as wireshark expects SF and not F
memcpy(frameBuffer+frameOffset, &tmp16, 2);
frameOffset += 2;
frameBuffer[frameOffset++] = MAC_LTE_CRC_STATUS_TAG;
frameBuffer[frameOffset++] = crcStatus;
#ifdef WIRESHARK_DEV
frameOffset += 2;
tmp16 = htons(sfnSf); // subframe
......@@ -293,7 +276,7 @@ static void SendFrame(guint8 radioType, guint8 direction, guint8 rntiType,
frameBuffer[frameOffset++] = retx;
}
//#ifdef WIRESHARK_DEV
//#ifdef WIRESHARK_DEV
/* Relating to out-of-band events */
/* N.B. dissector will only look to these fields if length is 0... */
......@@ -332,7 +315,7 @@ static void SendFrame(guint8 radioType, guint8 direction, guint8 rntiType,
}
}
//#endif
//#endif
/***************************************/
/* Now write the MAC PDU */
frameBuffer[frameOffset++] = MAC_LTE_PAYLOAD_TAG;
......@@ -341,7 +324,7 @@ static void SendFrame(guint8 radioType, guint8 direction, guint8 rntiType,
//memcpy(frameBuffer+frameOffset, g_PDUBuffer, g_PDUOffset);
//frameOffset += g_PDUOffset;
if (pdu_buffer != NULL) {
memcpy(frameBuffer+frameOffset, (void*)pdu_buffer, pdu_buffer_size);
memcpy(frameBuffer+frameOffset, (void *)pdu_buffer, pdu_buffer_size);
frameOffset += pdu_buffer_size;
}
......@@ -358,44 +341,36 @@ static void SendFrame(guint8 radioType, guint8 direction, guint8 rntiType,
/* Write an individual PDU (PCAP packet header + mac-context + mac-pdu) */
static int MAC_LTE_PCAP_WritePDU(MAC_Context_Info_t *context,
const uint8_t *PDU, unsigned int length)
{
const uint8_t *PDU, unsigned int length) {
pcaprec_hdr_t packet_header;
uint8_t context_header[256];
int offset = 0;
unsigned short tmp16;
/*****************************************************************/
/* Context information (same as written by UDP heuristic clients */
context_header[offset++] = context->radioType;
context_header[offset++] = context->direction;
context_header[offset++] = context->rntiType;
/* RNTI */
context_header[offset++] = MAC_LTE_RNTI_TAG;
tmp16 = htons(context->rnti);
memcpy(context_header+offset, &tmp16, 2);
offset += 2;
/* UEId */
context_header[offset++] = MAC_LTE_UEID_TAG;
tmp16 = htons(context->ueid);
memcpy(context_header+offset, &tmp16, 2);
offset += 2;
/* Subframe number */
context_header[offset++] = MAC_LTE_FRAME_SUBFRAME_TAG;
tmp16 = htons(context->subFrameNumber);
memcpy(context_header+offset, &tmp16, 2);
offset += 2;
/* CRC Status */
context_header[offset++] = MAC_LTE_CRC_STATUS_TAG;
context_header[offset++] = context->crcStatusOK;
/* Data tag immediately preceding PDU */
context_header[offset++] = MAC_LTE_PAYLOAD_TAG;
/****************************************************************/
/* PCAP Header */
/* TODO: Timestamp might want to be relative to a more sensible
......@@ -404,13 +379,11 @@ static int MAC_LTE_PCAP_WritePDU(MAC_Context_Info_t *context,
packet_header.ts_usec = (context->subframesSinceCaptureStart % 1000) * 1000;
packet_header.incl_len = offset + length;
packet_header.orig_len = offset + length;
/***************************************************************/
/* Now write everything to the file */
fwrite(&packet_header, sizeof(pcaprec_hdr_t), 1, file_fd);
fwrite(context_header, 1, offset, file_fd);
fwrite(PDU, 1, length, file_fd);
return 1;
}
#include <common/ran_context.h>
......@@ -419,14 +392,16 @@ extern RAN_CONTEXT_t RC;
/* Remote serveraddress (where Wireshark is running) */
void trace_pdu(int direction, uint8_t *pdu_buffer, unsigned int pdu_buffer_size,
int ueid, int rntiType, int rnti, uint16_t sysFrameNumber, uint8_t subFrameNumber, int oob_event,
int oob_event_value)
{
int oob_event_value) {
MAC_Context_Info_t pdu_context;
int radioType=FDD_RADIO;
if (RC.eNB[0][0]!=NULL)
radioType=RC.eNB[0][0]->frame_parms.frame_type== FDD ? FDD_RADIO:TDD_RADIO;
if (PHY_vars_UE_g[0][0] != NULL)
radioType=PHY_vars_UE_g[0][0]->frame_parms.frame_type== FDD ? FDD_RADIO:TDD_RADIO;
switch (opt_type) {
case OPT_WIRESHARK :
if (g_socksd == -1) {
......@@ -466,23 +441,32 @@ void trace_pdu(int direction, uint8_t *pdu_buffer, unsigned int pdu_buffer_size,
}
}
/*---------------------------------------------------*/
int init_opt(char *path, char *ip)
{
int init_opt(void) {
char *in_type=NULL;
paramdef_t opt_params[] = OPT_PARAMS_DESC ;
checkedparam_t opt_checkParams[] = OPTPARAMS_CHECK_DESC;
uint16_t in_port;
config_set_checkfunctions(opt_params, opt_checkParams,
sizeof(opt_params)/sizeof(paramdef_t));
config_get( opt_params,sizeof(opt_params)/sizeof(paramdef_t),OPT_CONFIGPREFIX);
subframesSinceCaptureStart = 0;
int tmptype = config_get_processedint( &(opt_params[OPTTYPE_IDX]));
if (path != NULL) {
strncpy( in_path, path, sizeof(in_path) );
in_path[sizeof(in_path) - 1] = 0; // terminate string
} else {
strcpy( in_path, "/tmp/opt.pcap" );
}
if (ip != NULL) {
strncpy( in_ip, ip, sizeof(in_ip) );
in_ip[sizeof(in_ip) - 1] = 0; // terminate string
if (tmptype == OPT_NONE) {
opt_enabled=0;
LOG_I(OPT,"OPT disabled\n");
return 0;
} else if (tmptype == OPT_PCAP && strlen(in_path) > 0) {
opt_type = OPT_PCAP;
opt_enabled=1;
LOG_I(OPT,"Enabling OPT for PCAP with the following file %s \n",in_path);
} else if (tmptype == OPT_WIRESHARK && strlen(in_ip) > 0) {
opt_enabled=1;
opt_type = OPT_WIRESHARK;
LOG_I(OPT,"Enabling OPT for wireshark for local interface %s\n",in_ip);
} else {
strcpy( in_ip, "127.0.0.1" );
LOG_E(OPT,"Invalid OPT configuration\n");
config_printhelp(opt_params,sizeof(opt_params)/sizeof(paramdef_t),OPT_CONFIGPREFIX);
}
in_port = PACKET_MAC_LTE_DEFAULT_UDP_PORT;
......@@ -517,6 +501,7 @@ int init_opt(char *path, char *ip)
LOG_D(OPT, "Failed to open file \"%s\" for writing\n", in_path);
return (-1);
}
/* Write the file header */
fwrite(&file_header, sizeof(pcap_hdr_t), 1, file_fd);
break;
......@@ -543,8 +528,7 @@ int init_opt(char *path, char *ip)
// memset(mac_info, 0, sizeof(mac_lte_info)+pdu_buffer_size + 8);
return (1);
}
void terminate_opt(void)
{
void terminate_opt(void) {
/* Close local socket */
// free(mac_info);
if (opt_type != OPT_NONE) {
......
......@@ -47,46 +47,33 @@ uint64_t set_softmodem_optmask(uint64_t bitmask) {
return softmodem_params.optmask;
}
softmodem_params_t* get_softmodem_params(void) {
softmodem_params_t *get_softmodem_params(void) {
return &softmodem_params;
}
void get_common_options(void)
{
uint32_t online_log_messages;
uint32_t glog_level ;
uint32_t start_telnetsrv;
uint32_t noS1;
uint32_t nokrnmod;
uint32_t nonbiot;
paramdef_t cmdline_params[] =CMDLINE_PARAMS_DESC ;
paramdef_t cmdline_logparams[] =CMDLINE_LOGPARAMS_DESC ;
config_process_cmdline( cmdline_params,sizeof(cmdline_params)/sizeof(paramdef_t),NULL);
if (strlen(in_path) > 0) {
opt_type = OPT_PCAP;
opt_enabled=1;
printf("Enabling OPT for PCAP with the following file %s \n",in_path);
}
if (strlen(in_ip) > 0) {
opt_enabled=1;
opt_type = OPT_WIRESHARK;
printf("Enabling OPT for wireshark for local interface");
}
config_process_cmdline( cmdline_logparams,sizeof(cmdline_logparams)/sizeof(paramdef_t),NULL);
void get_common_options(void) {
uint32_t online_log_messages;
uint32_t glog_level ;
uint32_t start_telnetsrv;
uint32_t noS1;
uint32_t nokrnmod;
uint32_t nonbiot;
paramdef_t cmdline_params[] =CMDLINE_PARAMS_DESC ;
paramdef_t cmdline_logparams[] =CMDLINE_LOGPARAMS_DESC ;
checkedparam_t cmdline_log_CheckParams[] = CMDLINE_LOGPARAMS_CHECK_DESC;
config_get( cmdline_params,sizeof(cmdline_params)/sizeof(paramdef_t),NULL);
config_set_checkfunctions(cmdline_logparams, cmdline_log_CheckParams,
sizeof(cmdline_logparams)/sizeof(paramdef_t));
config_get( cmdline_logparams,sizeof(cmdline_logparams)/sizeof(paramdef_t),NULL);
if(config_isparamset(cmdline_logparams,CMDLINE_ONLINELOG_IDX)) {
set_glog_onlinelog(online_log_messages);
}
if(config_isparamset(cmdline_logparams,CMDLINE_GLOGLEVEL_IDX)) {
set_glog(glog_level);
}
if (start_telnetsrv) {
load_module_shlib("telnetsrv",NULL,0,NULL);
}
......@@ -94,12 +81,16 @@ paramdef_t cmdline_logparams[] =CMDLINE_LOGPARAMS_DESC ;
if (noS1) {
set_softmodem_optmask(SOFTMODEM_NOS1_BIT);
}
if (nokrnmod) {
set_softmodem_optmask(SOFTMODEM_NOKRNMOD_BIT);
}
if (nonbiot) {
set_softmodem_optmask(SOFTMODEM_NONBIOT_BIT);
}
if(parallel_config != NULL) set_parallel_conf(parallel_config);
if(worker_config != NULL) set_worker_conf(worker_config);
}
......@@ -305,9 +305,6 @@ void exit_function(const char *file, const char *function, const int line, const
}
sleep(1); //allow lte-softmodem threads to exit first
#if defined(ENABLE_ITTI)
itti_terminate_tasks (TASK_UNKNOWN);
#endif
exit(1);
}
......@@ -449,7 +446,7 @@ static void get_options(void) {
NB_eNB_INST = RC.nb_inst;
printf("Configuration: nb_rrc_inst %d, nb_L1_inst %d, nb_ru %d\n",NB_eNB_INST,RC.nb_L1_inst,RC.nb_RU);
if (!SOFTMODEM_NONBIOT) {
if (!IS_SOFTMODEM_NONBIOT) {
load_NB_IoT();
printf(" nb_nbiot_rrc_inst %d, nb_nbiot_L1_inst %d, nb_nbiot_macrlc_inst %d\n",
RC.nb_nb_iot_rrc_inst, RC.nb_nb_iot_L1_inst, RC.nb_nb_iot_macrlc_inst);
......@@ -505,7 +502,8 @@ void set_default_frame_parms(LTE_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs]) {
}
void wait_RUs(void) {
LOG_I(PHY,"Waiting for RUs to be configured ... RC.ru_mask:%02lx\n", RC.ru_mask);
/* do not modify the following LOG_UI message, which is used by CI */
LOG_UI(ENB_APP,"Waiting for RUs to be configured ... RC.ru_mask:%02lx\n", RC.ru_mask);
// wait for all RUs to be configured over fronthaul
pthread_mutex_lock(&RC.ru_mutex);
......@@ -678,7 +676,6 @@ int main( int argc, char **argv ) {
set_latency_target();
logInit();
printf("Reading in command-line options\n");
CONFIG_SETRTFLAG(CONFIG_NOCHECKUNKOPT);
get_options ();
if (CONFIG_ISFLAGSET(CONFIG_ABORT) ) {
......@@ -689,14 +686,6 @@ int main( int argc, char **argv ) {
#if T_TRACER
T_Config_Init();
#endif
ret=config_check_unknown_cmdlineopt(NULL);
if (ret != 0) {
LOG_E(ENB_APP, "%i unknown options in command line\n",ret);
exit_fun("");
}
CONFIG_CLEARRTFLAG(CONFIG_NOCHECKUNKOPT);
//randominit (0);
set_taus_seed (0);
printf("configuring for RAU/RRU\n");
......@@ -717,12 +706,7 @@ int main( int argc, char **argv ) {
MSC_INIT(MSC_E_UTRAN, THREAD_MAX+TASK_MAX);
#endif
if (opt_type != OPT_NONE) {
if (init_opt(in_path, in_ip) == -1)
LOG_E(OPT,"failed to run OPT \n");
}
init_opt();
#ifdef PDCP_USE_NETLINK
printf("PDCP netlink\n");
netlink_init();
......@@ -947,13 +931,7 @@ if (nfapi_mode==2) {// VNF
sync_var=0;
pthread_cond_broadcast(&sync_cond);
pthread_mutex_unlock(&sync_mutex);
ret=config_check_unknown_cmdlineopt(CONFIG_CHECKALLSECTIONS);
if (ret != 0) {
LOG_E(ENB_APP, "%i unknown options in command line (invalid section name)\n",ret);
exit_fun("");
}
config_check_unknown_cmdlineopt(CONFIG_CHECKALLSECTIONS);
// wait for end of program
printf("TYPE <CTRL-C> TO TERMINATE\n");
//getchar();
......@@ -1008,9 +986,7 @@ if (nfapi_mode==2) {// VNF
}
free_lte_top();
printf("About to call end_configmodule() from %s() %s:%d\n", __FUNCTION__, __FILE__, __LINE__);
end_configmodule();
printf("Called end_configmodule() from %s() %s:%d\n", __FUNCTION__, __FILE__, __LINE__);
pthread_cond_destroy(&sync_cond);
pthread_mutex_destroy(&sync_mutex);
pthread_cond_destroy(&nfapi_sync_cond);
......@@ -1029,9 +1005,7 @@ if (nfapi_mode==2) {// VNF
}
}
if (opt_enabled == 1)
terminate_opt();
logClean();
printf("Bye.\n");
return 0;
......
......@@ -35,12 +35,12 @@
#include "flexran_agent.h"
#if defined(ENABLE_ITTI)
#if defined(ENABLE_USE_MME)
#include "s1ap_eNB.h"
#ifdef PDCP_USE_NETLINK
#include "SIMULATION/ETH_TRANSPORT/proto.h"
#endif
#endif
#if defined(ENABLE_USE_MME)
#include "s1ap_eNB.h"
#ifdef PDCP_USE_NETLINK
#include "SIMULATION/ETH_TRANSPORT/proto.h"
#endif
#endif
#endif
/* help strings definition for command line options, used in CMDLINE_XXX_DESC macros and printed when -h option is used */
......@@ -84,8 +84,6 @@
#define CONFIG_HLP_TDD "Set hardware to TDD mode (default: FDD). Used only with -U (otherwise set in config file).\n"
#define CONFIG_HLP_SNR "Set average SNR in dB (for --siml1 option)\n"
#define CONFIG_HLP_UE "Set the lte softmodem as a UE\n"
#define CONFIG_HLP_L2MONW "Enable L2 wireshark messages on localhost \n"
#define CONFIG_HLP_L2MONP "Enable L2 pcap messages on localhost \n"
#define CONFIG_HLP_TQFS "Apply three-quarter of sampling frequency, 23.04 Msps to reduce the data rate on USB/PCIe transfers (only valid for 20 MHz)\n"
#define CONFIG_HLP_TPORT "tracer port\n"
#define CONFIG_HLP_NOTWAIT "don't wait for tracer, start immediately\n"
......@@ -112,15 +110,15 @@
/* optname helpstr paramflags XXXptr defXXXval type numelt */
/*------------------------------------------------------------------------------------------------------------------------------------------*/
#define CMDLINE_UEMODEPARAMS_DESC { \
{"calib-ue-rx", CONFIG_HLP_CALUER, 0, iptr:&rx_input_level_dBm, defintval:0, TYPE_INT, 0}, \
{"calib-ue-rx-med", CONFIG_HLP_CALUERM, 0, iptr:&rx_input_level_dBm, defintval:0, TYPE_INT, 0}, \
{"calib-ue-rx-byp", CONFIG_HLP_CALUERB, 0, iptr:&rx_input_level_dBm, defintval:0, TYPE_INT, 0}, \
{"debug-ue-prach", CONFIG_HLP_DBGUEPR, PARAMFLAG_BOOL, uptr:NULL, defuintval:1, TYPE_INT, 0}, \
{"no-L2-connect", CONFIG_HLP_NOL2CN, PARAMFLAG_BOOL, uptr:NULL, defuintval:1, TYPE_INT, 0}, \
{"calib-prach-tx", CONFIG_HLP_CALPRACH, PARAMFLAG_BOOL, uptr:NULL, defuintval:1, TYPE_INT, 0}, \
{"loop-memory", CONFIG_HLP_UELOOP, 0, strptr:&loopfile, defstrval:"iqs.in", TYPE_STRING,0}, \
{"ue-dump-frame", CONFIG_HLP_DUMPFRAME, PARAMFLAG_BOOL, iptr:&dumpframe, defintval:0, TYPE_INT, 0}, \
}
{"calib-ue-rx", CONFIG_HLP_CALUER, 0, iptr:&rx_input_level_dBm, defintval:0, TYPE_INT, 0}, \
{"calib-ue-rx-med", CONFIG_HLP_CALUERM, 0, iptr:&rx_input_level_dBm, defintval:0, TYPE_INT, 0}, \
{"calib-ue-rx-byp", CONFIG_HLP_CALUERB, 0, iptr:&rx_input_level_dBm, defintval:0, TYPE_INT, 0}, \
{"debug-ue-prach", CONFIG_HLP_DBGUEPR, PARAMFLAG_BOOL, uptr:NULL, defuintval:1, TYPE_INT, 0}, \
{"no-L2-connect", CONFIG_HLP_NOL2CN, PARAMFLAG_BOOL, uptr:NULL, defuintval:1, TYPE_INT, 0}, \
{"calib-prach-tx", CONFIG_HLP_CALPRACH, PARAMFLAG_BOOL, uptr:NULL, defuintval:1, TYPE_INT, 0}, \
{"loop-memory", CONFIG_HLP_UELOOP, 0, strptr:&loopfile, defstrval:"iqs.in", TYPE_STRING,0}, \
{"ue-dump-frame", CONFIG_HLP_DUMPFRAME, PARAMFLAG_BOOL, iptr:&dumpframe, defintval:0, TYPE_INT, 0}, \
}
#define CMDLINE_CALIBUERX_IDX 0
#define CMDLINE_CALIBUERXMED_IDX 1
#define CMDLINE_CALIBUERXBYP_IDX 2
......@@ -138,42 +136,42 @@
/*-------------------------------------------------------------------------------------------------------------------------------------------------------*/
#define CMDLINE_UEPARAMS_DESC { \
{"siml1", CONFIG_HLP_SIML1, PARAMFLAG_BOOL, iptr:&simL1flag, defintval:0, TYPE_INT, 0}, \
{"U", CONFIG_HLP_NUMUE, 0, u8ptr:&NB_UE_INST, defuintval:1, TYPE_UINT, 0}, \
{"ue-rxgain", CONFIG_HLP_UERXG, 0, dblptr:&(rx_gain[0][0]), defdblval:130, TYPE_DOUBLE, 0}, \
{"ue-rxgain-off", CONFIG_HLP_UERXGOFF, 0, dblptr:&rx_gain_off, defdblval:0, TYPE_DOUBLE, 0}, \
{"ue-txgain", CONFIG_HLP_UETXG, 0, dblptr:&(tx_gain[0][0]), defdblval:0, TYPE_DOUBLE, 0}, \
{"ue-nb-ant-rx", CONFIG_HLP_UENANTR, 0, u8ptr:&nb_antenna_rx, defuintval:1, TYPE_UINT8, 0}, \
{"ue-nb-ant-tx", CONFIG_HLP_UENANTT, 0, u8ptr:&nb_antenna_tx, defuintval:1, TYPE_UINT8, 0}, \
{"ue-scan-carrier", CONFIG_HLP_UESCAN, PARAMFLAG_BOOL, iptr:&UE_scan_carrier, defintval:0, TYPE_INT, 0}, \
{"ue-max-power", NULL, 0, iptr:&(tx_max_power[0]), defintval:23, TYPE_INT, 0}, \
{"emul-iface", CONFIG_HLP_EMULIFACE, 0, strptr:&emul_iface, defstrval:"lo", TYPE_STRING, 100}, \
{"L2-emul", NULL, 0, u8ptr:&nfapi_mode, defuintval:3, TYPE_UINT8, 0}, \
{"num-ues", NULL, 0, u8ptr:&(NB_UE_INST), defuintval:1, TYPE_UINT8, 0}, \
{"nums_ue_thread", NULL, 0, u16ptr:&(NB_THREAD_INST), defuintval:1, TYPE_UINT16, 0}, \
{"r" , CONFIG_HLP_PRB, 0, u8ptr:&(frame_parms[0]->N_RB_DL), defintval:25, TYPE_UINT8, 0}, \
{"dlsch-demod-shift", CONFIG_HLP_DLSHIFT, 0, iptr:(int32_t *)&dlsch_demod_shift, defintval:0, TYPE_INT, 0}, \
{"usrp-args", CONFIG_HLP_USRP_ARGS, 0, strptr:(char **)&usrp_args, defstrval:"type=b200",TYPE_STRING, 0}, \
{"usrp-clksrc", CONFIG_HLP_USRP_CLK_SRC,0, strptr:(char **)&usrp_clksrc, defstrval:"internal", TYPE_STRING, 0}, \
{"mmapped-dma", CONFIG_HLP_DMAMAP, PARAMFLAG_BOOL, uptr:&mmapped_dma, defintval:0, TYPE_INT, 0}, \
{"clock", CONFIG_HLP_CLK, 0, uptr:&clock_source, defintval:0, TYPE_UINT, 0}, \
{"s" , CONFIG_HLP_SNR, 0, iptr:&snr_dB, defintval:25, TYPE_INT, 0}, \
{"T" , CONFIG_HLP_TDD, PARAMFLAG_BOOL, iptr:&tddflag, defintval:0, TYPE_INT, 0}, \
{"A", CONFIG_HLP_TADV, 0, iptr:&(timingadv), defintval:0, TYPE_INT, 0} \
}
{"siml1", CONFIG_HLP_SIML1, PARAMFLAG_BOOL, iptr:&simL1flag, defintval:0, TYPE_INT, 0}, \
{"U", CONFIG_HLP_NUMUE, 0, u8ptr:&NB_UE_INST, defuintval:1, TYPE_UINT, 0}, \
{"ue-rxgain", CONFIG_HLP_UERXG, 0, dblptr:&(rx_gain[0][0]), defdblval:130, TYPE_DOUBLE, 0}, \
{"ue-rxgain-off", CONFIG_HLP_UERXGOFF, 0, dblptr:&rx_gain_off, defdblval:0, TYPE_DOUBLE, 0}, \
{"ue-txgain", CONFIG_HLP_UETXG, 0, dblptr:&(tx_gain[0][0]), defdblval:0, TYPE_DOUBLE, 0}, \
{"ue-nb-ant-rx", CONFIG_HLP_UENANTR, 0, u8ptr:&nb_antenna_rx, defuintval:1, TYPE_UINT8, 0}, \
{"ue-nb-ant-tx", CONFIG_HLP_UENANTT, 0, u8ptr:&nb_antenna_tx, defuintval:1, TYPE_UINT8, 0}, \
{"ue-scan-carrier", CONFIG_HLP_UESCAN, PARAMFLAG_BOOL, iptr:&UE_scan_carrier, defintval:0, TYPE_INT, 0}, \
{"ue-max-power", NULL, 0, iptr:&(tx_max_power[0]), defintval:23, TYPE_INT, 0}, \
{"emul-iface", CONFIG_HLP_EMULIFACE, 0, strptr:&emul_iface, defstrval:"lo", TYPE_STRING, 100}, \
{"L2-emul", NULL, 0, u8ptr:&nfapi_mode, defuintval:3, TYPE_UINT8, 0}, \
{"num-ues", NULL, 0, u8ptr:&(NB_UE_INST), defuintval:1, TYPE_UINT8, 0}, \
{"nums_ue_thread", NULL, 0, u16ptr:&(NB_THREAD_INST), defuintval:1, TYPE_UINT16, 0}, \
{"r" , CONFIG_HLP_PRB, 0, u8ptr:&(frame_parms[0]->N_RB_DL), defintval:25, TYPE_UINT8, 0}, \
{"dlsch-demod-shift", CONFIG_HLP_DLSHIFT, 0, iptr:(int32_t *)&dlsch_demod_shift, defintval:0, TYPE_INT, 0}, \
{"usrp-args", CONFIG_HLP_USRP_ARGS, 0, strptr:(char **)&usrp_args, defstrval:"type=b200",TYPE_STRING, 0}, \
{"usrp-clksrc", CONFIG_HLP_USRP_CLK_SRC,0, strptr:(char **)&usrp_clksrc, defstrval:"internal", TYPE_STRING, 0}, \
{"mmapped-dma", CONFIG_HLP_DMAMAP, PARAMFLAG_BOOL, uptr:&mmapped_dma, defintval:0, TYPE_INT, 0}, \
{"clock", CONFIG_HLP_CLK, 0, uptr:&clock_source, defintval:0, TYPE_UINT, 0}, \
{"s" , CONFIG_HLP_SNR, 0, iptr:&snr_dB, defintval:25, TYPE_INT, 0}, \
{"T" , CONFIG_HLP_TDD, PARAMFLAG_BOOL, iptr:&tddflag, defintval:0, TYPE_INT, 0}, \
{"A", CONFIG_HLP_TADV, 0, iptr:&(timingadv), defintval:0, TYPE_INT, 0} \
}
/*-------------------------------------------------------------------------------------------------------------------------------------------------------*/
/* command line parameters specific to UE threads */
/* optname helpstr paramflags XXXptr defXXXval type numelt */
/*-------------------------------------------------------------------------------------------------------------------------------------------------------*/
#define CMDLINE_UETHREADSPARAMS_DESC { \
{"threadIQ", NULL, 0, iptr:&(threads.iq), defintval:1, TYPE_INT, 0}, \
{"threadOneSubframe", NULL, 0, iptr:&(threads.one), defintval:1, TYPE_INT, 0}, \
{"threadTwoSubframe", NULL, 0, iptr:&(threads.two), defintval:1, TYPE_INT, 0}, \
{"threadThreeSubframe", NULL, 0, iptr:&(threads.three), defintval:1, TYPE_INT, 0}, \
{"threadSlot1ProcOne", NULL, 0, iptr:&(threads.slot1_proc_one), defintval:1, TYPE_INT, 0}, \
{"threadSlot1ProcTwo", NULL, 0, iptr:&(threads.slot1_proc_two), defintval:1, TYPE_INT, 0}, \
}
{"threadIQ", NULL, 0, iptr:&(threads.iq), defintval:1, TYPE_INT, 0}, \
{"threadOneSubframe", NULL, 0, iptr:&(threads.one), defintval:1, TYPE_INT, 0}, \
{"threadTwoSubframe", NULL, 0, iptr:&(threads.two), defintval:1, TYPE_INT, 0}, \
{"threadThreeSubframe", NULL, 0, iptr:&(threads.three), defintval:1, TYPE_INT, 0}, \
{"threadSlot1ProcOne", NULL, 0, iptr:&(threads.slot1_proc_one), defintval:1, TYPE_INT, 0}, \
{"threadSlot1ProcTwo", NULL, 0, iptr:&(threads.slot1_proc_two), defintval:1, TYPE_INT, 0}, \
}
#define DEFAULT_DLF 2680000000
......@@ -192,28 +190,28 @@
#define CLOCK_SOURCE softmodem_params.clock_source
#define USIM_TEST softmodem_params.usim_test
#define CMDLINE_PARAMS_DESC { \
{"rf-config-file", CONFIG_HLP_RFCFGF, 0, strptr:(char **)&RF_CONFIG_FILE, defstrval:NULL, TYPE_STRING, sizeof(RF_CONFIG_FILE)}, \
{"ulsch-max-errors", CONFIG_HLP_ULMAXE, 0, uptr:&ULSCH_max_consecutive_errors, defuintval:0, TYPE_UINT, 0}, \
{"phy-test", CONFIG_HLP_PHYTST, PARAMFLAG_BOOL, iptr:&PHY_TEST, defintval:0, TYPE_INT, 0}, \
{"usim-test", CONFIG_HLP_USIM, PARAMFLAG_BOOL, u8ptr:&USIM_TEST, defintval:0, TYPE_UINT8, 0}, \
{"emulate-rf" , CONFIG_HLP_EMULATE_RF, PARAMFLAG_BOOL, iptr:&EMULATE_RF, defintval:0, TYPE_INT, 0}, \
{"clock", CONFIG_HLP_CLK, 0, uptr:&CLOCK_SOURCE, defintval:0, TYPE_UINT, 0}, \
{"wait-for-sync", NULL, PARAMFLAG_BOOL, iptr:&WAIT_FOR_SYNC, defintval:0, TYPE_INT, 0}, \
{"single-thread-enable", CONFIG_HLP_NOSNGLT, PARAMFLAG_BOOL, iptr:&SINGLE_THREAD_FLAG, defintval:0, TYPE_INT, 0}, \
{"C" , CONFIG_HLP_DLF, 0, uptr:&(downlink_frequency[0][0]), defuintval:2680000000, TYPE_UINT, 0}, \
{"a" , CONFIG_HLP_CHOFF, 0, iptr:&CHAIN_OFFSET, defintval:0, TYPE_INT, 0}, \
{"d" , CONFIG_HLP_SOFTS, PARAMFLAG_BOOL, uptr:(uint32_t *)&DO_FORMS, defintval:0, TYPE_INT8, 0}, \
{"W" , CONFIG_HLP_L2MONW, 0, strptr:(char **)&in_ip, defstrval:"127.0.0.1", TYPE_STRING, sizeof(in_ip)}, \
{"P" , CONFIG_HLP_L2MONP, 0, strptr:(char **)&in_path, defstrval:"/tmp/oai_opt.pcap", TYPE_STRING, sizeof(in_path)}, \
{"q" , CONFIG_HLP_STMON, PARAMFLAG_BOOL, iptr:&opp_enabled, defintval:0, TYPE_INT, 0}, \
{"S" , CONFIG_HLP_MSLOTS, PARAMFLAG_BOOL, u8ptr:&exit_missed_slots, defintval:1, TYPE_UINT8, 0}, \
{"numerology" , CONFIG_HLP_NUMEROLOGY, PARAMFLAG_BOOL, iptr:&NUMEROLOGY, defintval:0, TYPE_INT, 0}, \
{"parallel-config", CONFIG_HLP_PARALLEL_CMD,0, strptr:(char **)&parallel_config, defstrval:NULL, TYPE_STRING, 0}, \
{"worker-config", CONFIG_HLP_WORKER_CMD, 0, strptr:(char **)&worker_config, defstrval:NULL, TYPE_STRING, 0}, \
{"noS1", CONFIG_HLP_NOS1, PARAMFLAG_BOOL, uptr:&noS1, defintval:0, TYPE_INT, 0}, \
{"nokrnmod", CONFIG_HLP_NOKRNMOD, PARAMFLAG_BOOL, uptr:&nokrnmod, defintval:0, TYPE_INT, 0}, \
{"nbiot-disable", CONFIG_HLP_DISABLNBIOT, PARAMFLAG_BOOL, uptr:&nonbiot, defuintval:0, TYPE_INT, 0}, \
}
{"rf-config-file", CONFIG_HLP_RFCFGF, 0, strptr:(char **)&RF_CONFIG_FILE, defstrval:NULL, TYPE_STRING, sizeof(RF_CONFIG_FILE)}, \
{"ulsch-max-errors", CONFIG_HLP_ULMAXE, 0, uptr:&ULSCH_max_consecutive_errors, defuintval:0, TYPE_UINT, 0}, \
{"phy-test", CONFIG_HLP_PHYTST, PARAMFLAG_BOOL, iptr:&PHY_TEST, defintval:0, TYPE_INT, 0}, \
{"usim-test", CONFIG_HLP_USIM, PARAMFLAG_BOOL, u8ptr:&USIM_TEST, defintval:0, TYPE_UINT8, 0}, \
{"emulate-rf" , CONFIG_HLP_EMULATE_RF, PARAMFLAG_BOOL, iptr:&EMULATE_RF, defintval:0, TYPE_INT, 0}, \
{"clock", CONFIG_HLP_CLK, 0, uptr:&CLOCK_SOURCE, defintval:0, TYPE_UINT, 0}, \
{"wait-for-sync", NULL, PARAMFLAG_BOOL, iptr:&WAIT_FOR_SYNC, defintval:0, TYPE_INT, 0}, \
{"single-thread-enable", CONFIG_HLP_NOSNGLT, PARAMFLAG_BOOL, iptr:&SINGLE_THREAD_FLAG, defintval:0, TYPE_INT, 0}, \
{"C" , CONFIG_HLP_DLF, 0, uptr:&(downlink_frequency[0][0]), defuintval:2680000000, TYPE_UINT, 0}, \
{"a" , CONFIG_HLP_CHOFF, 0, iptr:&CHAIN_OFFSET, defintval:0, TYPE_INT, 0}, \
{"d" , CONFIG_HLP_SOFTS, PARAMFLAG_BOOL, uptr:(uint32_t *)&DO_FORMS, defintval:0, TYPE_INT8, 0}, \
{"W" , CONFIG_HLP_L2MONW, 0, strptr:(char **)&in_ip, defstrval:"127.0.0.1", TYPE_STRING, sizeof(in_ip)}, \
{"P" , CONFIG_HLP_L2MONP, 0, strptr:(char **)&in_path, defstrval:"/tmp/oai_opt.pcap", TYPE_STRING, sizeof(in_path)}, \
{"q" , CONFIG_HLP_STMON, PARAMFLAG_BOOL, iptr:&opp_enabled, defintval:0, TYPE_INT, 0}, \
{"S" , CONFIG_HLP_MSLOTS, PARAMFLAG_BOOL, u8ptr:&exit_missed_slots, defintval:1, TYPE_UINT8, 0}, \
{"numerology" , CONFIG_HLP_NUMEROLOGY, PARAMFLAG_BOOL, iptr:&NUMEROLOGY, defintval:0, TYPE_INT, 0}, \
{"parallel-config", CONFIG_HLP_PARALLEL_CMD,0, strptr:(char **)&parallel_config, defstrval:NULL, TYPE_STRING, 0}, \
{"worker-config", CONFIG_HLP_WORKER_CMD, 0, strptr:(char **)&worker_config, defstrval:NULL, TYPE_STRING, 0}, \
{"noS1", CONFIG_HLP_NOS1, PARAMFLAG_BOOL, uptr:&noS1, defintval:0, TYPE_INT, 0}, \
{"nokrnmod", CONFIG_HLP_NOKRNMOD, PARAMFLAG_BOOL, uptr:&nokrnmod, defintval:0, TYPE_INT, 0}, \
{"nbiot-disable", CONFIG_HLP_DISABLNBIOT, PARAMFLAG_BOOL, uptr:&nonbiot, defuintval:0, TYPE_INT, 0}, \
}
#define CONFIG_HLP_FLOG "Enable online log \n"
#define CONFIG_HLP_LOGL "Set the global log level, valide options: (4:trace, 3:debug, 2:info, 1:warn, (0:error))\n"
......@@ -225,16 +223,22 @@
/*---------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
#define START_MSC softmodem_params.start_msc
#define CMDLINE_LOGPARAMS_DESC { \
{"R" , CONFIG_HLP_FLOG, 0, uptr:&online_log_messages, defintval:1, TYPE_INT, 0}, \
{"g" , CONFIG_HLP_LOGL, 0, uptr:&glog_level, defintval:0, TYPE_UINT, 0}, \
{"telnetsrv", CONFIG_HLP_TELN, PARAMFLAG_BOOL, uptr:&start_telnetsrv, defintval:0, TYPE_UINT, 0}, \
{"msc", CONFIG_HLP_MSC, PARAMFLAG_BOOL, uptr:&START_MSC, defintval:0, TYPE_UINT, 0}, \
}
{"R" , CONFIG_HLP_FLOG, 0, uptr:&online_log_messages, defintval:1, TYPE_INT, 0}, \
{"g" , CONFIG_HLP_LOGL, 0, uptr:&glog_level, defintval:0, TYPE_UINT, 0}, \
{"telnetsrv", CONFIG_HLP_TELN, PARAMFLAG_BOOL, uptr:&start_telnetsrv, defintval:0, TYPE_UINT, 0}, \
{"msc", CONFIG_HLP_MSC, PARAMFLAG_BOOL, uptr:&START_MSC, defintval:0, TYPE_UINT, 0}, \
}
#define CMDLINE_ONLINELOG_IDX 0
#define CMDLINE_GLOGLEVEL_IDX 1
#define CMDLINE_STARTTELN_IDX 2
/* check function for global log level */
#define CMDLINE_LOGPARAMS_CHECK_DESC { \
{ .s5= {NULL }} , \
{ .s2= { config_check_intrange, {0,4}}}, \
{ .s5= {NULL }} , \
{ .s5= {NULL }} , \
}
/***************************************************************************************************************************************/
/* */
#include "threads_t.h"
......@@ -255,18 +259,17 @@ typedef struct {
uint32_t do_forms;
int numerology;
unsigned int start_msc;
int nonbiotflag;
uint32_t clock_source;
int hw_timing_advance;
} softmodem_params_t;
#define SOFTMODEM_NOS1 ( get_softmodem_optmask() & SOFTMODEM_NOS1_BIT)
#define SOFTMODEM_NOKRNMOD ( get_softmodem_optmask() & SOFTMODEM_NOKRNMOD_BIT)
#define SOFTMODEM_NONBIOT ( get_softmodem_optmask() & SOFTMODEM_NONBIOT_BIT)
#define IS_SOFTMODEM_NOS1 ( get_softmodem_optmask() & SOFTMODEM_NOS1_BIT)
#define IS_SOFTMODEM_NOKRNMOD ( get_softmodem_optmask() & SOFTMODEM_NOKRNMOD_BIT)
#define IS_SOFTMODEM_NONBIOT ( get_softmodem_optmask() & SOFTMODEM_NONBIOT_BIT)
extern uint64_t get_softmodem_optmask(void);
extern uint64_t set_softmodem_optmask(uint64_t bitmask);
extern void get_common_options(void);
extern softmodem_params_t* get_softmodem_params(void);
extern softmodem_params_t *get_softmodem_params(void);
uint64_t get_pdcp_optmask(void);
extern pthread_cond_t sync_cond;
......@@ -292,8 +295,8 @@ extern int transmission_mode;
extern double cpuf;
#if defined(ENABLE_ITTI)
extern volatile int start_eNB;
extern volatile int start_UE;
extern volatile int start_eNB;
extern volatile int start_UE;
#endif
......@@ -305,7 +308,7 @@ extern void stop_eNB(int);
extern void kill_eNB_proc(int inst);
// In lte-ru.c
extern void init_RU(char*);
extern void init_RU(char *);
extern void stop_ru(RU_t *ru);
extern void init_ru_vnf(void);
extern void init_RU_proc(RU_t *ru);
......@@ -317,8 +320,9 @@ extern void set_function_spec_param(RU_t *ru);
extern int setup_ue_buffers(PHY_VARS_UE **phy_vars_ue, openair0_config_t *openair0_cfg);
extern void fill_ue_band_info(void);
extern void init_UE(int nb_inst,int eMBMS_active, int uecap_xer_in, int timing_correction, int phy_test, int UE_scan, int UE_scan_carrier, runmode_t mode,int rxgain,int txpowermax, LTE_DL_FRAME_PARMS *fp);
extern void init_thread(int sched_runtime, int sched_deadline, int sched_fifo, cpu_set_t *cpuset, char * name);
extern void init_UE(int nb_inst,int eMBMS_active, int uecap_xer_in, int timing_correction, int phy_test, int UE_scan, int UE_scan_carrier, runmode_t mode,int rxgain,int txpowermax,
LTE_DL_FRAME_PARMS *fp);
extern void init_thread(int sched_runtime, int sched_deadline, int sched_fifo, cpu_set_t *cpuset, char *name);
extern void reset_opp_meas(void);
extern void print_opp_meas(void);
......@@ -333,7 +337,7 @@ extern void RCConfig_sim(void);
extern void init_ocm(double,double);
extern void init_ue_devices(PHY_VARS_UE *);
PHY_VARS_UE* init_ue_vars(LTE_DL_FRAME_PARMS *frame_parms,
PHY_VARS_UE *init_ue_vars(LTE_DL_FRAME_PARMS *frame_parms,
uint8_t UE_id,
uint8_t abstraction_flag);
void init_eNB_afterRU(void);
......@@ -348,7 +352,7 @@ extern int restart_L1L2(module_id_t enb_id);
extern void init_UE_stub_single_thread(int nb_inst,int eMBMS_active, int uecap_xer_in, char *emul_iface);
extern PHY_VARS_UE* init_ue_vars(LTE_DL_FRAME_PARMS *frame_parms,
extern PHY_VARS_UE *init_ue_vars(LTE_DL_FRAME_PARMS *frame_parms,
uint8_t UE_id,
uint8_t abstraction_flag);
......
......@@ -456,7 +456,6 @@ static void get_options(void) {
CONFIG_SETRTFLAG(CONFIG_NOEXITONHELP);
/* unknown parameters on command line will be checked in main
after all init have been performed */
CONFIG_SETRTFLAG(CONFIG_NOCHECKUNKOPT);
get_common_options();
get_uethreads_params();
paramdef_t cmdline_uemodeparams[] =CMDLINE_UEMODEPARAMS_DESC;
......@@ -754,7 +753,6 @@ int main( int argc, char **argv ) {
for (int i=0; i<MAX_NUM_CCs; i++) tx_max_power[i]=23;
CONFIG_SETRTFLAG(CONFIG_NOCHECKUNKOPT);
get_options ();
printf("Running with %d UE instances\n",NB_UE_INST);
......@@ -791,7 +789,6 @@ int main( int argc, char **argv ) {
#if T_TRACER
T_Config_Init();
#endif
CONFIG_CLEARRTFLAG(CONFIG_NOCHECKUNKOPT);
//randominit (0);
set_taus_seed (0);
cpuf=get_cpu_freq_GHz();
......@@ -808,12 +805,7 @@ int main( int argc, char **argv ) {
MSC_INIT(MSC_E_UTRAN, THREAD_MAX+TASK_MAX);
#endif
if (opt_type != OPT_NONE) {
if (init_opt(in_path, in_ip) == -1)
LOG_E(OPT,"failed to run OPT \n");
}
init_opt();
#ifdef PDCP_USE_NETLINK
printf("PDCP netlink\n");
netlink_init();
......@@ -1077,13 +1069,7 @@ int main( int argc, char **argv ) {
}
#endif
ret=config_check_unknown_cmdlineopt(CONFIG_CHECKALLSECTIONS);
if (ret != 0) {
LOG_E(ENB_APP, "%i unknown options in command line (invalid section name)\n",ret);
exit_fun("");
}
config_check_unknown_cmdlineopt(CONFIG_CHECKALLSECTIONS);
printf("Sending sync to all threads (%p,%p,%p)\n",&sync_var,&sync_cond,&sync_mutex);
pthread_mutex_lock(&sync_mutex);
sync_var=0;
......@@ -1134,9 +1120,7 @@ int main( int argc, char **argv ) {
if (PHY_vars_UE_g[0][0]->rfdevice.trx_end_func)
PHY_vars_UE_g[0][0]->rfdevice.trx_end_func(&PHY_vars_UE_g[0][0]->rfdevice);
if (opt_enabled == 1)
terminate_opt();
logClean();
printf("Bye.\n");
return 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment