Merge remote-tracking branch 'origin/develop' into enhancement-ltem
Conflicts: openair1/PHY/INIT/lte_init.c openair1/PHY/LTE_ESTIMATION/lte_ul_channel_estimation.c openair1/PHY/LTE_TRANSPORT/dci.c openair1/PHY/LTE_TRANSPORT/dci_tools.c openair1/PHY/LTE_TRANSPORT/dlsch_coding.c openair1/PHY/LTE_TRANSPORT/edci.c openair1/PHY/LTE_TRANSPORT/if4_tools.c openair1/PHY/LTE_TRANSPORT/prach.c openair1/PHY/LTE_TRANSPORT/print_stats.c openair1/PHY/LTE_TRANSPORT/pucch.c openair1/PHY/LTE_TRANSPORT/transport_eNB.h openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c openair1/PHY/LTE_UE_TRANSPORT/transport_proto_ue.h openair1/PHY/impl_defs_lte.h openair1/SCHED/fapi_l1.c openair1/SCHED/phy_procedures_lte_eNb.c openair2/COMMON/rrc_messages_types.h openair2/ENB_APP/enb_config.c openair2/ENB_APP/enb_paramdef.h openair2/LAYER2/MAC/config.c openair2/LAYER2/MAC/defs.h openair2/LAYER2/MAC/eNB_scheduler.c openair2/LAYER2/MAC/eNB_scheduler_RA.c openair2/LAYER2/MAC/eNB_scheduler_bch.c openair2/LAYER2/MAC/eNB_scheduler_dlsch.c openair2/LAYER2/MAC/eNB_scheduler_primitives.c openair2/LAYER2/MAC/eNB_scheduler_ulsch.c openair2/LAYER2/MAC/pre_processor.c openair2/LAYER2/MAC/rar_tools.c openair2/LAYER2/MAC/ue_procedures.c openair2/PHY_INTERFACE/IF_Module.c openair2/RRC/LITE/rrc_common.c openair2/RRC/LTE/L2_interface_ue.c openair2/RRC/LTE/MESSAGES/asn1_msg.c openair2/RRC/LTE/rrc_eNB.c targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp targets/RT/USER/lte-enb.c targets/RT/USER/lte-ru.c
This commit is contained in:
@@ -10,4 +10,10 @@ tracer/replay
|
||||
tracer/textlog
|
||||
tracer/vcd
|
||||
tracer/macpdu2wireshark
|
||||
tracer/ue
|
||||
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 172
|
||||
#define VCD_NUM_FUNCTIONS 190
|
||||
|
||||
/* number of VCD variables (to be kept up to date! see in T_messages.txt) */
|
||||
#define VCD_NUM_VARIABLES 118
|
||||
#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)
|
||||
|
||||
+500
-44
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) {
|
||||
|
||||
@@ -3,10 +3,11 @@ CFLAGS=-Wall -g -pthread -DT_TRACER -I.
|
||||
|
||||
#CFLAGS += -O3 -ffast-math -fomit-frame-pointer
|
||||
|
||||
LIBS=-lX11 -lm -lpng -lXft
|
||||
LIBS=-lm
|
||||
XLIBS=-lX11 -lpng -lXft
|
||||
|
||||
all: record replay extract_config textlog enb ue vcd macpdu2wireshark \
|
||||
extract_input_subframe
|
||||
extract_input_subframe extract_output_subframe to_vcd extract multi
|
||||
|
||||
record: utils.o record.o database.o config.o
|
||||
$(CC) $(CFLAGS) -o record $^ $(LIBS)
|
||||
@@ -21,43 +22,57 @@ extract_input_subframe: extract_input_subframe.o database.o event.o utils.o \
|
||||
config.o
|
||||
$(CC) $(CFLAGS) -o $@ $^ $(LIBS)
|
||||
|
||||
extract_output_subframe: extract_output_subframe.o database.o event.o utils.o \
|
||||
config.o
|
||||
$(CC) $(CFLAGS) -o $@ $^ $(LIBS)
|
||||
|
||||
extract: extract.o database.o event.o utils.o config.o
|
||||
$(CC) $(CFLAGS) -o $@ $^ $(LIBS)
|
||||
|
||||
textlog: utils.o textlog.o database.o event.o handler.o config.o \
|
||||
event_selector.o view/view.a gui/gui.a logger/logger.a \
|
||||
filter/filter.a
|
||||
$(CC) $(CFLAGS) -o textlog $^ $(LIBS)
|
||||
$(CC) $(CFLAGS) -o textlog $^ $(LIBS) $(XLIBS)
|
||||
|
||||
enb: utils.o enb.o database.o event.o handler.o config.o \
|
||||
event_selector.o view/view.a gui/gui.a logger/logger.a \
|
||||
filter/filter.a
|
||||
$(CC) $(CFLAGS) -o enb $^ $(LIBS)
|
||||
$(CC) $(CFLAGS) -o enb $^ $(LIBS) $(XLIBS)
|
||||
|
||||
ue: utils.o ue.o database.o event.o handler.o config.o \
|
||||
event_selector.o view/view.a gui/gui.a logger/logger.a \
|
||||
filter/filter.a
|
||||
$(CC) $(CFLAGS) -o ue $^ $(LIBS)
|
||||
$(CC) $(CFLAGS) -o ue $^ $(LIBS) $(XLIBS)
|
||||
|
||||
vcd: utils.o vcd.o database.o event.o handler.o config.o \
|
||||
event_selector.o view/view.a gui/gui.a logger/logger.a \
|
||||
filter/filter.a
|
||||
$(CC) $(CFLAGS) -o vcd $^ $(LIBS)
|
||||
$(CC) $(CFLAGS) -o vcd $^ $(LIBS) $(XLIBS)
|
||||
|
||||
to_vcd: to_vcd.o database.o event.o handler.o utils.o config.o \
|
||||
logger/logger.a filter/filter.a
|
||||
$(CC) $(CFLAGS) -o to_vcd $^ $(LIBS)
|
||||
|
||||
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 $@ $<
|
||||
@@ -65,8 +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
|
||||
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,
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include "database.h"
|
||||
#include "event.h"
|
||||
#include "config.h"
|
||||
|
||||
void usage(void)
|
||||
{
|
||||
printf(
|
||||
"usage: [options] <file> <event> <buffer name>\n"
|
||||
"options:\n"
|
||||
" -d <database file> this option is mandatory\n"
|
||||
" -o <output file> this option is mandatory\n"
|
||||
" -f <name> <value> field 'name' of 'event' has to match 'value'\n"
|
||||
" type of 'name' must be int\n"
|
||||
" (you can use several -f options)\n"
|
||||
);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int get_filter_arg(database_event_format *f, char *field, char *type)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < f->count; i++)
|
||||
if (!strcmp(f->name[i], field)) {
|
||||
if (strcmp(f->type[i], type)) break;
|
||||
return i;
|
||||
}
|
||||
printf("bad field %s, check that it exists and has type '%s'\n",field,type);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main(int n, char **v)
|
||||
{
|
||||
char *database_filename = NULL;
|
||||
void *database;
|
||||
int i;
|
||||
int input_event_id;
|
||||
database_event_format f;
|
||||
char *file = NULL;
|
||||
char *output_file = NULL;
|
||||
FILE *out;
|
||||
int fd;
|
||||
char *event_name = NULL;
|
||||
char *buffer_name = NULL;
|
||||
char *filter[n];
|
||||
int filter_arg[n];
|
||||
int filter_value[n];
|
||||
int filter_count = 0;
|
||||
int buffer_arg;
|
||||
int found;
|
||||
|
||||
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], "-o"))
|
||||
{ if (i > n-2) usage(); output_file = v[++i]; continue; }
|
||||
if (!strcmp(v[i], "-f")) { if (i>n-3) usage();
|
||||
filter[filter_count] = v[++i];
|
||||
filter_value[filter_count++] = atoi(v[++i]);
|
||||
continue;
|
||||
}
|
||||
if (file == NULL) { file = v[i]; continue; }
|
||||
if (event_name == NULL) { event_name = v[i]; continue; }
|
||||
if (buffer_name == NULL) { buffer_name = v[i]; continue; }
|
||||
usage();
|
||||
}
|
||||
if (file == NULL || event_name == NULL || buffer_name == NULL) usage();
|
||||
|
||||
if (database_filename == NULL) {
|
||||
printf("ERROR: provide a database file (-d)\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (output_file == NULL) {
|
||||
printf("gimme -o <output file>, thanks\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
out = fopen(output_file, "w"); if(out==NULL){perror(output_file);exit(1);}
|
||||
|
||||
database = parse_database(database_filename);
|
||||
|
||||
load_config_file(database_filename);
|
||||
|
||||
input_event_id = event_id_from_name(database, event_name);
|
||||
f = get_format(database, input_event_id);
|
||||
|
||||
buffer_arg = get_filter_arg(&f, buffer_name, "buffer");
|
||||
|
||||
for (i = 0; i < filter_count; i++)
|
||||
filter_arg[i] = get_filter_arg(&f, filter[i], "int");
|
||||
|
||||
fd = open(file, O_RDONLY);
|
||||
if (fd == -1) { perror(file); exit(1); }
|
||||
|
||||
found = 0;
|
||||
|
||||
OBUF ebuf = { osize: 0, omaxsize: 0, obuf: NULL };
|
||||
|
||||
while (1) {
|
||||
event e;
|
||||
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++)
|
||||
if (filter_value[i] != e.e[filter_arg[i]].i)
|
||||
break;
|
||||
if (i != filter_count)
|
||||
continue;
|
||||
if (fwrite(e.e[buffer_arg].b, e.e[buffer_arg].bsize, 1, out) != 1)
|
||||
{ perror(output_file); exit(1); }
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (found == 0) printf("ERROR: event not found\n");
|
||||
|
||||
fclose(out);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -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++;
|
||||
|
||||
@@ -0,0 +1,154 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include "database.h"
|
||||
#include "event.h"
|
||||
#include "config.h"
|
||||
|
||||
void usage(void)
|
||||
{
|
||||
printf(
|
||||
"usage: [options] <file> <frame> <subframe> <number of subframes>\n"
|
||||
" the program dumps 'number of subframes' subframes starting\n"
|
||||
" at 'frame:suubframe'\n"
|
||||
"options:\n"
|
||||
" -d <database file> this option is mandatory\n"
|
||||
" -o <output file> output to file (default: stdout)\n"
|
||||
" -v verbose\n"
|
||||
);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main(int n, char **v)
|
||||
{
|
||||
char *database_filename = NULL;
|
||||
void *database;
|
||||
int i;
|
||||
int output_event_id;
|
||||
database_event_format f;
|
||||
char *file = NULL;
|
||||
int fd;
|
||||
int frame = -1, subframe = -1;
|
||||
int number_of_subframes = -1;
|
||||
int frame_arg, subframe_arg, buffer_arg;
|
||||
int verbose = 0;
|
||||
char *out_filename = NULL;
|
||||
FILE *out;
|
||||
|
||||
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], "-o"))
|
||||
{ if (i > n-2) usage(); out_filename = v[++i]; continue; }
|
||||
if (!strcmp(v[i], "-v")) { verbose = 1; continue; }
|
||||
if (file == NULL) { file = v[i]; continue; }
|
||||
if (frame == -1) { frame = atoi(v[i]); continue; }
|
||||
if (subframe == -1) { subframe = atoi(v[i]); continue; }
|
||||
if (number_of_subframes == -1) {number_of_subframes=atoi(v[i]);continue;}
|
||||
usage();
|
||||
}
|
||||
if (file == NULL || frame == -1 || subframe == -1 ||
|
||||
number_of_subframes == -1) usage();
|
||||
|
||||
if (database_filename == NULL) {
|
||||
printf("ERROR: provide a database file (-d)\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (out_filename == NULL) out = stdout;
|
||||
else {
|
||||
out = fopen(out_filename, "w");
|
||||
if (out == NULL) { perror(out_filename); exit(1); }
|
||||
}
|
||||
|
||||
database = parse_database(database_filename);
|
||||
|
||||
load_config_file(database_filename);
|
||||
|
||||
output_event_id = event_id_from_name(database, "ENB_PHY_OUTPUT_SIGNAL");
|
||||
f = get_format(database, output_event_id);
|
||||
|
||||
frame_arg = subframe_arg = buffer_arg = -1;
|
||||
for (i = 0; i < f.count; i++) {
|
||||
if (!strcmp(f.name[i], "frame")) {
|
||||
if (frame_arg != -1) goto err;
|
||||
if (strcmp(f.type[i], "int")) goto err;
|
||||
frame_arg = i;
|
||||
}
|
||||
if (!strcmp(f.name[i], "subframe")) {
|
||||
if (subframe_arg != -1) goto err;
|
||||
if (strcmp(f.type[i], "int")) goto err;
|
||||
subframe_arg = i;
|
||||
}
|
||||
if (!strcmp(f.name[i], "txdata")) {
|
||||
if (buffer_arg != -1) goto err;
|
||||
if (strcmp(f.type[i], "buffer")) goto err;
|
||||
buffer_arg = i;
|
||||
}
|
||||
continue;
|
||||
err:
|
||||
printf("cannot deal with ENB_PHY_OUTPUT_SIGNAL from database file\n");
|
||||
exit(1);
|
||||
}
|
||||
if (frame_arg == -1 || subframe_arg == -1 || buffer_arg == -1) goto err;
|
||||
|
||||
fd = open(file, O_RDONLY);
|
||||
if (fd == -1) { perror(file); exit(1); }
|
||||
|
||||
int last_frame = -1;
|
||||
int last_subframe = -1;
|
||||
int subframe_written = 0;
|
||||
|
||||
OBUF ebuf = { osize: 0, omaxsize: 0, obuf: NULL };
|
||||
|
||||
while (1) {
|
||||
event e;
|
||||
e = get_event(fd, &ebuf, database);
|
||||
if (e.type == -1) break;
|
||||
if (e.type != output_event_id) continue;
|
||||
if (verbose)
|
||||
printf("found output frame %d subframe %d size %d\n",
|
||||
e.e[frame_arg].i, e.e[subframe_arg].i, e.e[buffer_arg].bsize);
|
||||
if (!(last_frame != -1 ||
|
||||
(frame == e.e[frame_arg].i && subframe == e.e[subframe_arg].i)))
|
||||
continue;
|
||||
frame = e.e[frame_arg].i;
|
||||
subframe = e.e[subframe_arg].i;
|
||||
if (last_frame != -1) {
|
||||
if (frame*10+subframe != (last_frame*10+last_subframe + 1) % 10240) {
|
||||
printf("error: discontinuity, not what you want...\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
last_frame = frame;
|
||||
last_subframe = subframe;
|
||||
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);
|
||||
if (fwrite(e.e[buffer_arg].b, e.e[buffer_arg].bsize, 1, out) != 1) {
|
||||
perror(out_filename);
|
||||
exit(1);
|
||||
}
|
||||
subframe_written++;
|
||||
if (subframe_written != number_of_subframes)
|
||||
continue;
|
||||
|
||||
/* done */
|
||||
fflush(out);
|
||||
if (out_filename != NULL) {
|
||||
if (fclose(out)) perror(out_filename);
|
||||
}
|
||||
if (verbose)
|
||||
printf("%d subframes written\n", subframe_written);
|
||||
return 0;
|
||||
}
|
||||
|
||||
printf("error with input file, %d subframe written\n", subframe_written);
|
||||
fflush(out);
|
||||
if (out_filename != NULL) {
|
||||
if (fclose(out)) perror(out_filename);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -164,7 +150,17 @@ x_image *x_create_image(x_connection *_x, unsigned char *data,
|
||||
vs = XGetVisualInfo(x->d, VisualDepthMask | VisualClassMask |
|
||||
VisualRedMaskMask | VisualGreenMaskMask | VisualBlueMaskMask |
|
||||
VisualBitsPerRGBMask, &template, &nvs);
|
||||
if (vs == NULL || nvs == 0) ERR("no good visual found\n");
|
||||
|
||||
if (vs == NULL) {
|
||||
/* try again with 32 bpp */
|
||||
template.depth = 32;
|
||||
vs = XGetVisualInfo(x->d, VisualDepthMask | VisualClassMask |
|
||||
VisualRedMaskMask | VisualGreenMaskMask | VisualBlueMaskMask |
|
||||
VisualBitsPerRGBMask, &template, &nvs);
|
||||
}
|
||||
|
||||
if (vs == NULL) ERR("no good visual found\n");
|
||||
|
||||
v = vs[0].visual;
|
||||
XFree(vs);
|
||||
|
||||
@@ -265,14 +261,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);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,384 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <inttypes.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include "database.h"
|
||||
#include "utils.h"
|
||||
#include "handler.h"
|
||||
#include "config.h"
|
||||
#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;
|
||||
int boolean;
|
||||
} vcd_vars;
|
||||
|
||||
/****************************************************************************/
|
||||
/* VCD file handling begin */
|
||||
/****************************************************************************/
|
||||
|
||||
FILE *out;
|
||||
|
||||
uint64_t start_time;
|
||||
int start_time_inited;
|
||||
|
||||
void vcd_init(char *file)
|
||||
{
|
||||
out = fopen(file, "w"); if (out == NULL) { perror(file); exit(1); }
|
||||
}
|
||||
|
||||
void vcd_write_header(vcd_vars *v, int n)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (fprintf(out,
|
||||
"$date\n"
|
||||
" January, 1, 1970.\n"
|
||||
"$end\n"
|
||||
"$version\n"
|
||||
" to_vcd\n"
|
||||
"$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 (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,
|
||||
"$enddefinitions $end\n"
|
||||
"$dumpvars\n") <= 0) abort();
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
if (v[i].boolean) {
|
||||
if (fprintf(out, "0%s\n", v[i].vcd_name) <= 0) abort();
|
||||
} else {
|
||||
if (fprintf(out, "b0 %s\n", v[i].vcd_name) <= 0) abort();
|
||||
}
|
||||
|
||||
if (fprintf(out,
|
||||
"$end\n") <= 0) abort();
|
||||
|
||||
}
|
||||
|
||||
void vcd_end(void)
|
||||
{
|
||||
if (fclose(out)) { perror("error closing VCD file"); exit(1); }
|
||||
}
|
||||
|
||||
char *b64(uint64_t val)
|
||||
{
|
||||
static char v[65];
|
||||
char *s = &v[64];
|
||||
*s = 0;
|
||||
if (val == 0) { s--; *s = '0'; return s; }
|
||||
while (val) {
|
||||
s--;
|
||||
*s = val&1 ? '1' : '0';
|
||||
val >>= 1;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
void vcd_dump(char *v)
|
||||
{
|
||||
uint64_t h, m, s, ns;
|
||||
char t;
|
||||
uint64_t val;
|
||||
uint64_t time;
|
||||
char var[256];
|
||||
if (sscanf(v, "%"SCNu64":%"SCNu64":%"SCNu64".%"SCNu64": %c %"SCNu64" %s",
|
||||
&h, &m, &s, &ns, &t, &val, var) != 7)
|
||||
goto err;
|
||||
time = h*60*60*1000000000 +
|
||||
m*60*1000000000 +
|
||||
s*1000000000 +
|
||||
ns;
|
||||
if (!start_time_inited) {
|
||||
start_time = time;
|
||||
start_time_inited = 1;
|
||||
}
|
||||
if (fprintf(out, "#%"PRIu64"\n", time - start_time) <= 0) abort();
|
||||
switch (t) {
|
||||
case 'b': if (fprintf(out, "%d%s\n", val!=0, var) <= 0) abort(); break;
|
||||
case 'l': if (fprintf(out, "b%s %s\n", b64(val), var) <= 0) abort(); break;
|
||||
default: goto err;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
err:
|
||||
printf("bad vcd_dump line '%s'\n", v);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
/* VCD file handling end */
|
||||
/****************************************************************************/
|
||||
|
||||
|
||||
/****************************************************************************/
|
||||
/* vcd view start */
|
||||
/****************************************************************************/
|
||||
|
||||
struct vcd_view {
|
||||
view common;
|
||||
};
|
||||
|
||||
static void vcd_view_clear(view *this)
|
||||
{
|
||||
/* nothing */
|
||||
}
|
||||
|
||||
static void vcd_view_append(view *_this, char *s)
|
||||
{
|
||||
vcd_dump(s);
|
||||
}
|
||||
|
||||
static view *new_view_vcd(void)
|
||||
{
|
||||
struct vcd_view *ret = calloc(1, sizeof(struct vcd_view));
|
||||
if (ret == NULL) abort();
|
||||
ret->common.clear = vcd_view_clear;
|
||||
ret->common.append = (void (*)(view *, ...))vcd_view_append;
|
||||
return (view *)ret;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
/* vcd view end */
|
||||
/****************************************************************************/
|
||||
|
||||
void activate_traces(int socket, int number_of_events, int *is_on)
|
||||
{
|
||||
char t = 1;
|
||||
if (socket_send(socket, &t, 1) == -1 ||
|
||||
socket_send(socket, &number_of_events, sizeof(int)) == -1 ||
|
||||
socket_send(socket, is_on, number_of_events * sizeof(int)) == -1)
|
||||
abort();
|
||||
}
|
||||
|
||||
void usage(void)
|
||||
{
|
||||
printf(
|
||||
"options:\n"
|
||||
" -d <database file> this option is mandatory\n"
|
||||
" -o <output 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"
|
||||
" -b <event> <arg> <vcd name> trace as binary (0 off, anything else on)\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
|
||||
);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int run = 1;
|
||||
static int socket = -1;
|
||||
|
||||
void force_stop(int x)
|
||||
{
|
||||
printf("\ngently quit...\n");
|
||||
close(socket);
|
||||
socket = -1;
|
||||
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;
|
||||
char *database_filename = NULL;
|
||||
void *database;
|
||||
char *ip = DEFAULT_REMOTE_IP;
|
||||
int port = DEFAULT_REMOTE_PORT;
|
||||
int *is_on;
|
||||
int number_of_events;
|
||||
int i;
|
||||
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();
|
||||
|
||||
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], "-o"))
|
||||
{ if (i > n-2) usage(); output_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], "-b")) { if(i>n-4)usage();
|
||||
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();
|
||||
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();
|
||||
}
|
||||
|
||||
if (output_filename == NULL) {
|
||||
printf("ERROR; provide an output file (-o)\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (database_filename == NULL) {
|
||||
printf("ERROR: provide a database file (-d)\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
database = parse_database(database_filename);
|
||||
|
||||
load_config_file(database_filename);
|
||||
|
||||
number_of_events = number_of_ids(database);
|
||||
is_on = calloc(number_of_events, sizeof(int));
|
||||
if (is_on == NULL) abort();
|
||||
|
||||
h = new_handler(database);
|
||||
|
||||
/* 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) + strlen(vars[i].vcd_name) > 256-16) abort();
|
||||
sprintf(format, "%c [%s] %s",
|
||||
vars[i].boolean ? 'b' : 'l',
|
||||
vars[i].arg,
|
||||
vars[i].vcd_name);
|
||||
textlog = new_textlog(h, database, vars[i].event, format);
|
||||
logger_add_view(textlog, vcd_view);
|
||||
on_off(database, vars[i].event, is_on, 1);
|
||||
}
|
||||
|
||||
socket = connect_to(ip, port);
|
||||
|
||||
/* activate selected traces */
|
||||
activate_traces(socket, number_of_events, is_on);
|
||||
|
||||
vcd_init(output_filename);
|
||||
vcd_write_header(vars, nvars);
|
||||
|
||||
/* exit on ctrl+c and ctrl+z */
|
||||
if (signal(SIGQUIT, force_stop) == SIG_ERR) abort();
|
||||
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) {
|
||||
event e;
|
||||
e = get_event(socket, &ebuf, database);
|
||||
if (e.type == -1) { printf("disconnected? let's quit gently\n"); break; }
|
||||
handle_event(h, e);
|
||||
}
|
||||
|
||||
vcd_end();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user