From 1e20abdd9e025312024b3d1d6987f923ce23b0a9 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Mon, 14 Mar 2016 18:02:12 +0100 Subject: [PATCH 01/28] Initial commit of the T! --- Makefile | 33 ++++ T.c | 140 ++++++++++++++ T.h | 506 ++++++++++++++++++++++++++++++++++++++++++++++++ T_defs.h | 18 ++ T_messages.txt | 140 ++++++++++++++ generate_Txx.c | 25 +++ genids.c | 150 ++++++++++++++ main.c | 19 ++ tracer/Makefile | 20 ++ tracer/main.c | 254 ++++++++++++++++++++++++ 10 files changed, 1305 insertions(+) create mode 100644 Makefile create mode 100644 T.c create mode 100644 T.h create mode 100644 T_defs.h create mode 100644 T_messages.txt create mode 100644 generate_Txx.c create mode 100644 genids.c create mode 100644 main.c create mode 100644 tracer/Makefile create mode 100644 tracer/main.c diff --git a/Makefile b/Makefile new file mode 100644 index 0000000000..06315e4585 --- /dev/null +++ b/Makefile @@ -0,0 +1,33 @@ +CC=gcc +CFLAGS=-Wall -g -pthread + +#comment those two lines to NOT use shared memory +CFLAGS += -DT_USE_SHARED_MEMORY +LIBS += -lrt + +PROG=t +OBJS=main.o T.o + +GENIDS=genids +GENIDS_OBJS=genids.o + +ALL=$(PROG) $(GENIDS) + +all : $(ALL) + +$(GENIDS): $(GENIDS_OBJS) + $(CC) $(CFLAGS) -o $(GENIDS) $(GENIDS_OBJS) + +$(PROG): $(OBJS) + $(CC) $(CFLAGS) -o $(PROG) $(OBJS) $(LIBS) + +%.o: %.c + $(CC) $(CFLAGS) -c -o $@ $< + +T_IDs.h: $(GENIDS) T_messages.txt + ./$(GENIDS) T_messages.txt T_IDs.h + +main.o: T.h T_IDs.h + +clean: + rm -f *.o $(PROG) $(GENIDS) core T_IDs.h diff --git a/T.c b/T.c new file mode 100644 index 0000000000..a33d1e90b6 --- /dev/null +++ b/T.c @@ -0,0 +1,140 @@ +#include "T.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* array used to activate/disactivate a log */ +static int T_IDs[T_NUMBER_OF_IDS]; +int *T_active = T_IDs; + +static int T_socket; + +/* T_cache + * - the T macro picks up the head of freelist and marks it busy + * - the T sender thread periodically wakes up and sends what's to be sent + */ +volatile int _T_freelist_head; +volatile int *T_freelist_head = &_T_freelist_head; +int T_busylist_head; +T_cache_t _T_cache[T_CACHE_SIZE]; +T_cache_t *T_cache = _T_cache; + +static void get_message(int s) +{ + char t; + int l; + int id; + + if (read(s, &t, 1) != 1) abort(); +printf("got mess %d\n", t); + switch (t) { + case 0: + /* toggle all those IDs */ + /* optimze? (too much syscalls) */ + if (read(s, &l, sizeof(int)) != sizeof(int)) abort(); + while (l) { + if (read(s, &id, sizeof(int)) != sizeof(int)) abort(); + T_IDs[id] = 1 - T_IDs[id]; + l--; + } + break; + } +} + +#ifndef T_USE_SHARED_MEMORY + +static void *T_send_thread(void *_) +{ + while (1) { + usleep(5000); + while (T_cache[T_busylist_head].busy) { + char *b = T_cache[T_busylist_head].buffer; + int l = T_cache[T_busylist_head].length; + while (l) { + int done = write(T_socket, b, l); + if (done <= 0) { + printf("%s:%d:%s: error sending to socket\n", + __FILE__, __LINE__, __FUNCTION__); + abort(); + } + b += done; + l -= done; + } + T_cache[T_busylist_head].busy = 0; + T_busylist_head++; + T_busylist_head &= T_CACHE_SIZE - 1; + } + } + return NULL; +} + +#endif /* T_USE_SHARED_MEMORY */ + +static void *T_receive_thread(void *_) +{ + while (1) get_message(T_socket); + return NULL; +} + +static void new_thread(void *(*f)(void *), void *data) +{ + pthread_t t; + pthread_attr_t att; + + if (pthread_attr_init(&att)) + { fprintf(stderr, "pthread_attr_init err\n"); exit(1); } + if (pthread_attr_setdetachstate(&att, PTHREAD_CREATE_DETACHED)) + { fprintf(stderr, "pthread_attr_setdetachstate err\n"); exit(1); } + if (pthread_create(&t, &att, f, data)) + { fprintf(stderr, "pthread_create err\n"); exit(1); } + if (pthread_attr_destroy(&att)) + { fprintf(stderr, "pthread_attr_destroy err\n"); exit(1); } +} + +void T_connect_to_tracer(char *addr, int port) +{ + struct sockaddr_in a; + int s; +#ifdef T_USE_SHARED_MEMORY + int T_shm_fd; +#endif + + s = socket(AF_INET, SOCK_STREAM, 0); + if (s == -1) { perror("socket"); exit(1); } + + a.sin_family = AF_INET; + a.sin_port = htons(port); + a.sin_addr.s_addr = inet_addr(addr); + + if (connect(s, (struct sockaddr *)&a, sizeof(a)) == -1) + { perror("connect"); exit(1); } + + /* wait for first message - initial list of active T events */ + get_message(s); + + T_socket = s; + +#ifdef T_USE_SHARED_MEMORY + /* setup shared memory */ + T_shm_fd = shm_open(T_SHM_FILENAME, O_RDWR, 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); +#endif + +#ifndef T_USE_SHARED_MEMORY + new_thread(T_send_thread, NULL); +#endif + new_thread(T_receive_thread, NULL); +} diff --git a/T.h b/T.h new file mode 100644 index 0000000000..884a9b6f89 --- /dev/null +++ b/T.h @@ -0,0 +1,506 @@ +#ifndef _T_T_T_ +#define _T_T_T_ + +#include + +#include "T_defs.h" + +/* T message IDs */ +#include "T_IDs.h" + +/* known type - this is where you add new types */ + +#define T_INT(x) int, (x) +#define T_FLOAT(x) float, (x) +#define T_BUFFER(x, len) buffer, ((T_buffer){addr:(x), length:(len)}) +#define T_STRING(x) string, (x) +#define T_PRINTF(...) printf, (__VA_ARGS__) + +/* for each known type a T_PUT_XX macro is defined */ + +#define T_PUT_int(argnum, val) \ + do { \ + int T_PUT_var = (val); \ + T_CHECK_SIZE(sizeof(int), argnum); \ + memcpy(T_LOCAL_buf + T_LOCAL_size, &T_PUT_var, sizeof(int)); \ + T_LOCAL_size += sizeof(int); \ + } while (0) + +#define T_PUT_float(argnum, val) \ + do { \ + float T_PUT_var = (val); \ + T_CHECK_SIZE(sizeof(float), argnum); \ + memcpy(T_LOCAL_buf + T_LOCAL_size, &T_PUT_var, sizeof(float)); \ + T_LOCAL_size += sizeof(float); \ + } while (0) + +#define T_PUT_buffer(argnum, val) \ + do { \ + T_buffer T_PUT_var = (val); \ + T_CHECK_SIZE(T_PUT_var.length, argnum); \ + memcpy(T_LOCAL_buf + T_LOCAL_size, T_PUT_var.addr, T_PUT_var.length); \ + T_LOCAL_size += T_PUT_var.length; \ + } while (0) + +#define T_PUT_string(argnum, val) \ + do { \ + char *T_PUT_var = (val); \ + int T_PUT_len = strlen(T_PUT_var) + 1; \ + T_CHECK_SIZE(T_PUT_len, argnum); \ + memcpy(T_LOCAL_buf + T_LOCAL_size, T_PUT_var, T_PUT_len); \ + T_LOCAL_size += T_PUT_len; \ + } while (0) + +#define T_PUT_printf_deref(...) __VA_ARGS__ + +#define T_PUT_printf(argnum, x) \ + do { \ + int T_PUT_len = snprintf(T_LOCAL_buf + T_LOCAL_size, \ + T_BUFFER_MAX - T_LOCAL_size, T_PUT_printf_deref x); \ + if (T_PUT_len < 0) { \ + printf("%s:%d:%s: you can't read this, or can you?", \ + __FILE__, __LINE__, __FUNCTION__); \ + abort(); \ + } \ + if (T_PUT_len >= T_BUFFER_MAX - T_LOCAL_size) { \ + 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(); \ + } \ + T_LOCAL_size += T_PUT_len + 1; \ + } while (0) + +/* structure type to detect that you pass a known type as first arg of T */ +struct T_header; + +/* to define message ID */ +#define T_ID(x) ((struct T_header *)(uintptr_t)(x)) + +/* T macro tricks */ + +#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__) + +/* type used to send arbitrary buffer data */ +typedef struct { + void *addr; + int length; +} T_buffer; + +extern volatile int *T_freelist_head; +extern T_cache_t *T_cache; + +/* used at header of Tn, allocates buffer */ +#define T_LOCAL_DATA \ + char *T_LOCAL_buf; \ + int T_LOCAL_size = 0; \ + int T_LOCAL_slot; \ + 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) { \ + printf("%s:%d:%s: T cache is full - consider increasing its size\n", \ + __FILE__, __LINE__, __FUNCTION__); \ + abort(); \ + } \ + T_LOCAL_buf = T_cache[T_LOCAL_slot].buffer; + +#define T_ACTIVE(x) T_active[(intptr_t)x] + +#define T_SEND() \ + T_cache[T_LOCAL_slot].busy = 1; \ + T_cache[T_LOCAL_slot].length = T_LOCAL_size; \ + T_send(T_LOCAL_buf, T_LOCAL_size) + +#define T_CHECK_SIZE(len, argnum) \ + if (T_LOCAL_size + len > 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(); \ + } + +#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 + +#define T_HEADER(x) \ + do { \ + if (!__builtin_types_compatible_p(typeof(x), struct T_header *)) { \ + printf("%s:%d:%s: " \ + "bad use of T, pass a message ID as first parameter\n", \ + __FILE__, __LINE__, __FUNCTION__); \ + abort(); \ + } \ + T_PUT_int(1, (int)(uintptr_t)(x)); \ + } while (0) + +#define T1(t) \ + do { \ + if (T_ACTIVE(t)) { \ + T_LOCAL_DATA \ + T_HEADER(t); \ + T_SEND(); \ + } \ + } while (0) + +#define T3(t,t0,x0) \ + do { \ + if (T_ACTIVE(t)) { \ + T_LOCAL_DATA \ + T_HEADER(t); \ + T_PUT_##t0(2, x0); \ + T_SEND(); \ + } \ + } while (0) + +#define T5(t,t0,x0,t1,x1) \ + do { \ + if (T_ACTIVE(t)) { \ + T_LOCAL_DATA \ + T_HEADER(t); \ + T_PUT_##t0(2, x0); \ + T_PUT_##t1(3, x1); \ + T_SEND(); \ + } \ + } while (0) + +#define T7(t,t0,x0,t1,x1,t2,x2) \ + do { \ + if (T_ACTIVE(t)) { \ + T_LOCAL_DATA \ + T_HEADER(t); \ + T_PUT_##t0(2, x0); \ + T_PUT_##t1(3, x1); \ + T_PUT_##t2(4, x2); \ + T_SEND(); \ + } \ + } while (0) + +#define T9(t,t0,x0,t1,x1,t2,x2,t3,x3) \ + do { \ + if (T_ACTIVE(t)) { \ + T_LOCAL_DATA \ + T_HEADER(t); \ + T_PUT_##t0(2, x0); \ + T_PUT_##t1(3, x1); \ + T_PUT_##t2(4, x2); \ + T_PUT_##t3(5, x3); \ + T_SEND(); \ + } \ + } while (0) + +#define T11(t,t0,x0,t1,x1,t2,x2,t3,x3) \ + do { \ + if (T_ACTIVE(t)) { \ + T_LOCAL_DATA \ + T_HEADER(t); \ + T_PUT_##t0(2, x0); \ + T_PUT_##t1(3, x1); \ + T_PUT_##t2(4, x2); \ + T_PUT_##t3(5, x3); \ + T_SEND(); \ + } \ + } while (0) + +#define T13(t,t0,x0,t1,x1,t2,x2,t3,x3,t4,x4) \ + do { \ + if (T_ACTIVE(t)) { \ + T_LOCAL_DATA \ + T_HEADER(t); \ + T_PUT_##t0(2, x0); \ + T_PUT_##t1(3, x1); \ + T_PUT_##t2(4, x2); \ + T_PUT_##t3(5, x3); \ + T_PUT_##t4(6, x4); \ + T_SEND(); \ + } \ + } while (0) + +#define T15(t,t0,x0,t1,x1,t2,x2,t3,x3,t4,x4,t5,x5) \ + do { \ + if (T_ACTIVE(t)) { \ + T_LOCAL_DATA \ + T_HEADER(t); \ + T_PUT_##t0(2, x0); \ + T_PUT_##t1(3, x1); \ + T_PUT_##t2(4, x2); \ + T_PUT_##t3(5, x3); \ + T_PUT_##t4(6, x4); \ + T_PUT_##t5(7, x5); \ + T_SEND(); \ + } \ + } while (0) + +#define T17(t,t0,x0,t1,x1,t2,x2,t3,x3,t4,x4,t5,x5,t6,x6) \ + do { \ + if (T_ACTIVE(t)) { \ + T_LOCAL_DATA \ + T_HEADER(t); \ + T_PUT_##t0(2, x0); \ + T_PUT_##t1(3, x1); \ + T_PUT_##t2(4, x2); \ + T_PUT_##t3(5, x3); \ + T_PUT_##t4(6, x4); \ + T_PUT_##t5(7, x5); \ + T_PUT_##t6(8, x6); \ + T_SEND(); \ + } \ + } while (0) + +#define T19(t,t0,x0,t1,x1,t2,x2,t3,x3,t4,x4,t5,x5,t6,x6,t7,x7) \ + do { \ + if (T_ACTIVE(t)) { \ + T_LOCAL_DATA \ + T_HEADER(t); \ + T_PUT_##t0(2, x0); \ + T_PUT_##t1(3, x1); \ + T_PUT_##t2(4, x2); \ + T_PUT_##t3(5, x3); \ + T_PUT_##t4(6, x4); \ + T_PUT_##t5(7, x5); \ + T_PUT_##t6(8, x6); \ + T_PUT_##t7(9, x7); \ + T_SEND(); \ + } \ + } while (0) + +#define T21(t,t0,x0,t1,x1,t2,x2,t3,x3,t4,x4,t5,x5,t6,x6,t7,x7,t8,x8) \ + do { \ + if (T_ACTIVE(t)) { \ + T_LOCAL_DATA \ + T_HEADER(t); \ + T_PUT_##t0(2, x0); \ + T_PUT_##t1(3, x1); \ + T_PUT_##t2(4, x2); \ + T_PUT_##t3(5, x3); \ + T_PUT_##t4(6, x4); \ + T_PUT_##t5(7, x5); \ + T_PUT_##t6(8, x6); \ + T_PUT_##t7(9, x7); \ + T_PUT_##t8(10, x8); \ + T_SEND(); \ + } \ + } while (0) + +#define T23(t,t0,x0,t1,x1,t2,x2,t3,x3,t4,x4,t5,x5,t6,x6,t7,x7,t8,x8,t9,x9) \ + do { \ + if (T_ACTIVE(t)) { \ + T_LOCAL_DATA \ + T_HEADER(t); \ + T_PUT_##t0(2, x0); \ + T_PUT_##t1(3, x1); \ + T_PUT_##t2(4, x2); \ + T_PUT_##t3(5, x3); \ + T_PUT_##t4(6, x4); \ + T_PUT_##t5(7, x5); \ + T_PUT_##t6(8, x6); \ + T_PUT_##t7(9, x7); \ + T_PUT_##t8(10, x8); \ + T_PUT_##t9(11, x9); \ + T_SEND(); \ + } \ + } while (0) + +#define T25(t,t0,x0,t1,x1,t2,x2,t3,x3,t4,x4,t5,x5,t6,x6,t7,x7,t8,x8,t9,x9,t10,x10) \ + do { \ + if (T_ACTIVE(t)) { \ + T_LOCAL_DATA \ + T_HEADER(t); \ + T_PUT_##t0(2, x0); \ + T_PUT_##t1(3, x1); \ + T_PUT_##t2(4, x2); \ + T_PUT_##t3(5, x3); \ + T_PUT_##t4(6, x4); \ + T_PUT_##t5(7, x5); \ + T_PUT_##t6(8, x6); \ + T_PUT_##t7(9, x7); \ + T_PUT_##t8(10, x8); \ + T_PUT_##t9(11, x9); \ + T_PUT_##t10(12, x10); \ + T_SEND(); \ + } \ + } while (0) + +#define T27(t,t0,x0,t1,x1,t2,x2,t3,x3,t4,x4,t5,x5,t6,x6,t7,x7,t8,x8,t9,x9,t10,x10,t11,x11) \ + do { \ + if (T_ACTIVE(t)) { \ + T_LOCAL_DATA \ + T_HEADER(t); \ + T_PUT_##t0(2, x0); \ + T_PUT_##t1(3, x1); \ + T_PUT_##t2(4, x2); \ + T_PUT_##t3(5, x3); \ + T_PUT_##t4(6, x4); \ + T_PUT_##t5(7, x5); \ + T_PUT_##t6(8, x6); \ + T_PUT_##t7(9, x7); \ + T_PUT_##t8(10, x8); \ + T_PUT_##t9(11, x9); \ + T_PUT_##t10(12, x10); \ + T_PUT_##t11(13, x11); \ + T_SEND(); \ + } \ + } while (0) + +#define T29(t,t0,x0,t1,x1,t2,x2,t3,x3,t4,x4,t5,x5,t6,x6,t7,x7,t8,x8,t9,x9,t10,x10,t11,x11,t12,x12) \ + do { \ + if (T_ACTIVE(t)) { \ + T_LOCAL_DATA \ + T_HEADER(t); \ + T_PUT_##t0(2, x0); \ + T_PUT_##t1(3, x1); \ + T_PUT_##t2(4, x2); \ + T_PUT_##t3(5, x3); \ + T_PUT_##t4(6, x4); \ + T_PUT_##t5(7, x5); \ + T_PUT_##t6(8, x6); \ + T_PUT_##t7(9, x7); \ + T_PUT_##t8(10, x8); \ + T_PUT_##t9(11, x9); \ + T_PUT_##t10(12, x10); \ + T_PUT_##t11(13, x11); \ + T_PUT_##t12(14, x12); \ + T_SEND(); \ + } \ + } while (0) + +#define T31(t,t0,x0,t1,x1,t2,x2,t3,x3,t4,x4,t5,x5,t6,x6,t7,x7,t8,x8,t9,x9,t10,x10,t11,x11,t12,x12,t13,x13) \ + do { \ + if (T_ACTIVE(t)) { \ + T_LOCAL_DATA \ + T_HEADER(t); \ + T_PUT_##t0(2, x0); \ + T_PUT_##t1(3, x1); \ + T_PUT_##t2(4, x2); \ + T_PUT_##t3(5, x3); \ + T_PUT_##t4(6, x4); \ + T_PUT_##t5(7, x5); \ + T_PUT_##t6(8, x6); \ + T_PUT_##t7(9, x7); \ + T_PUT_##t8(10, x8); \ + T_PUT_##t9(11, x9); \ + T_PUT_##t10(12, x10); \ + T_PUT_##t11(13, x11); \ + T_PUT_##t12(14, x12); \ + T_PUT_##t13(15, x13); \ + T_SEND(); \ + } \ + } while (0) + +#define T33(t,t0,x0,t1,x1,t2,x2,t3,x3,t4,x4,t5,x5,t6,x6,t7,x7,t8,x8,t9,x9,t10,x10,t11,x11,t12,x12,t13,x13,t14,x14) \ + do { \ + if (T_ACTIVE(t)) { \ + T_LOCAL_DATA \ + T_HEADER(t); \ + T_PUT_##t0(2, x0); \ + T_PUT_##t1(3, x1); \ + T_PUT_##t2(4, x2); \ + T_PUT_##t3(5, x3); \ + T_PUT_##t4(6, x4); \ + T_PUT_##t5(7, x5); \ + T_PUT_##t6(8, x6); \ + T_PUT_##t7(9, x7); \ + T_PUT_##t8(10, x8); \ + T_PUT_##t9(11, x9); \ + T_PUT_##t10(12, x10); \ + T_PUT_##t11(13, x11); \ + T_PUT_##t12(14, x12); \ + T_PUT_##t13(15, x13); \ + T_PUT_##t14(16, x14); \ + T_SEND(); \ + } \ + } while (0) + +#define T_CALL_ERROR \ + do { \ + printf("%s:%d:%s: error calling T, you have to use T_INT() or T_XX()\n", \ + __FILE__, __LINE__, __FUNCTION__); \ + } while (0) + +#define T2(...) T_CALL_ERROR +#define T4(...) T_CALL_ERROR +#define T6(...) T_CALL_ERROR +#define T8(...) T_CALL_ERROR +#define T10(...) T_CALL_ERROR +#define T12(...) T_CALL_ERROR +#define T14(...) T_CALL_ERROR +#define T16(...) T_CALL_ERROR +#define T18(...) T_CALL_ERROR +#define T20(...) T_CALL_ERROR +#define T22(...) T_CALL_ERROR +#define T24(...) T_CALL_ERROR +#define T26(...) T_CALL_ERROR +#define T28(...) T_CALL_ERROR +#define T30(...) T_CALL_ERROR +#define T32(...) T_CALL_ERROR + +#ifndef T_USE_SHARED_MEMORY + +#include + +static inline void T_send(char *buf, int size) +{ + int i; +return; + printf("sending %d bytes", size); + for (i = 0; i < size; i++) + printf("%s%2.2x", i?" ":"\n", (unsigned char)buf[i]); + printf("\n"); +} + +#else /* T_USE_SHARED_MEMORY */ + +#define T_send(...) /**/ + +#endif /* T_USE_SHARED_MEMORY */ + +extern int *T_active; + +void T_connect_to_tracer(char *addr, int port); + +#endif /* _T_T_T_ */ diff --git a/T_defs.h b/T_defs.h new file mode 100644 index 0000000000..1d01ea7415 --- /dev/null +++ b/T_defs.h @@ -0,0 +1,18 @@ +#ifndef _T_defs_H_ +#define _T_defs_H_ + +/* maximum size of a message - increase if needed */ +#define T_BUFFER_MAX 1024 + +/* size of the local cache for messages (must be pow(2,something)) */ +#define T_CACHE_SIZE (65536 * 2) + +typedef struct { + volatile int busy; + char buffer[T_BUFFER_MAX]; + int length; +} T_cache_t; + +#define T_SHM_FILENAME "/T_shm_segment" + +#endif /* _T_defs_H_ */ diff --git a/T_messages.txt b/T_messages.txt new file mode 100644 index 0000000000..b0e6cb00ed --- /dev/null +++ b/T_messages.txt @@ -0,0 +1,140 @@ +#legacy logs +ID = LEGACY_MAC_INFO + DESC = MAC legacy logs + GROUP = MAC:INFO:LEGACY +ID = LEGACY_MAC_ERROR +ID = LEGACY_MAC_WARNING +ID = LEGACY_MAC_DEBUG +ID = LEGACY_MAC_TRACE + +ID = LEGACY_PHY_INFO +ID = LEGACY_PHY_ERROR +ID = LEGACY_PHY_WARNING +ID = LEGACY_PHY_DEBUG +ID = LEGACY_PHY_TRACE + +ID = LEGACY_S1AP_INFO +ID = LEGACY_S1AP_ERROR +ID = LEGACY_S1AP_WARNING +ID = LEGACY_S1AP_DEBUG +ID = LEGACY_S1AP_TRACE + +ID = LEGACY_RRC_INFO +ID = LEGACY_RRC_ERROR +ID = LEGACY_RRC_WARNING +ID = LEGACY_RRC_DEBUG +ID = LEGACY_RRC_TRACE + +ID = LEGACY_RLC_INFO +ID = LEGACY_RLC_ERROR +ID = LEGACY_RLC_WARNING +ID = LEGACY_RLC_DEBUG +ID = LEGACY_RLC_TRACE + +ID = LEGACY_PDCP_INFO +ID = LEGACY_PDCP_ERROR +ID = LEGACY_PDCP_WARNING +ID = LEGACY_PDCP_DEBUG +ID = LEGACY_PDCP_TRACE + +ID = LEGACY_ENB_APP_INFO +ID = LEGACY_ENB_APP_ERROR +ID = LEGACY_ENB_APP_WARNING +ID = LEGACY_ENB_APP_DEBUG +ID = LEGACY_ENB_APP_TRACE + +ID = LEGACY_SCTP_INFO +ID = LEGACY_SCTP_ERROR +ID = LEGACY_SCTP_WARNING +ID = LEGACY_SCTP_DEBUG +ID = LEGACY_SCTP_TRACE + +ID = LEGACY_UDP__INFO +ID = LEGACY_UDP__ERROR +ID = LEGACY_UDP__WARNING +ID = LEGACY_UDP__DEBUG +ID = LEGACY_UDP__TRACE + +ID = LEGACY_NAS_INFO +ID = LEGACY_NAS_ERROR +ID = LEGACY_NAS_WARNING +ID = LEGACY_NAS_DEBUG +ID = LEGACY_NAS_TRACE + +ID = LEGACY_HW_INFO +ID = LEGACY_HW_ERROR +ID = LEGACY_HW_WARNING +ID = LEGACY_HW_DEBUG +ID = LEGACY_HW_TRACE + +ID = LEGACY_EMU_INFO +ID = LEGACY_EMU_ERROR +ID = LEGACY_EMU_WARNING +ID = LEGACY_EMU_DEBUG +ID = LEGACY_EMU_TRACE + +ID = LEGACY_OTG_INFO +ID = LEGACY_OTG_ERROR +ID = LEGACY_OTG_WARNING +ID = LEGACY_OTG_DEBUG +ID = LEGACY_OTG_TRACE + +ID = LEGACY_OCG_INFO +ID = LEGACY_OCG_ERROR +ID = LEGACY_OCG_WARNING +ID = LEGACY_OCG_DEBUG +ID = LEGACY_OCG_TRACE + +ID = LEGACY_OMG_INFO +ID = LEGACY_OMG_ERROR +ID = LEGACY_OMG_WARNING +ID = LEGACY_OMG_DEBUG +ID = LEGACY_OMG_TRACE + +ID = LEGACY_OPT_INFO +ID = LEGACY_OPT_ERROR +ID = LEGACY_OPT_WARNING +ID = LEGACY_OPT_DEBUG +ID = LEGACY_OPT_TRACE + +ID = LEGACY_GTPU_INFO +ID = LEGACY_GTPU_ERROR +ID = LEGACY_GTPU_WARNING +ID = LEGACY_GTPU_DEBUG +ID = LEGACY_GTPU_TRACE + +ID = LEGACY_TMR_INFO +ID = LEGACY_TMR_ERROR +ID = LEGACY_TMR_WARNING +ID = LEGACY_TMR_DEBUG +ID = LEGACY_TMR_TRACE + +ID = LEGACY_OSA_INFO +ID = LEGACY_OSA_ERROR +ID = LEGACY_OSA_WARNING +ID = LEGACY_OSA_DEBUG +ID = LEGACY_OSA_TRACE + +# this is a bad hack but I won't fix (function util_print_hex_octets +# in openairinterface5g/openair2/LAYER2/PDCP_v10.1.0/pdcp_util.c +# does funky things with the LOG_x macros but we work on the C pre-processor +# level and this funkyness is not easily dealable with, so be it...) +ID = LEGACY_component_INFO +ID = LEGACY_component_ERROR +ID = LEGACY_component_WARNING +ID = LEGACY_component_DEBUG +ID = LEGACY_component_TRACE +ID = LEGACY_componentP_INFO +ID = LEGACY_componentP_ERROR +ID = LEGACY_componentP_WARNING +ID = LEGACY_componentP_DEBUG +ID = LEGACY_componentP_TRACE + +#needed? +ID = LEGACY_CLI_INFO +ID = LEGACY_CLI_ERROR +ID = LEGACY_CLI_WARNING +ID = LEGACY_CLI_DEBUG +ID = LEGACY_CLI_TRACE + +ID = first diff --git a/generate_Txx.c b/generate_Txx.c new file mode 100644 index 0000000000..6e803aac50 --- /dev/null +++ b/generate_Txx.c @@ -0,0 +1,25 @@ +#include + +void print(int n) +{ + int i; + printf("#define T%d(t", n); + for(i=0; i<(n-3)/2; i++) printf(",t%d,x%d", i, i); + printf(") \\\n"); + printf(" do { \\\n"); + printf(" if (T_ACTIVE(t)) { \\\n"); + printf(" T_LOCAL_DATA \\\n"); + printf(" T_HEADER(t); \\\n"); + for(i=0; i<(n-3)/2; i++) printf(" T_PUT_##t%d(%d, x%d); \\\n", i, i+2, i); + printf(" T_SEND(); \\\n"); + printf(" } \\\n"); + printf(" } while (0)\n"); + printf("\n"); +} + +int main(void) +{ + int i; + for (i = 11; i <= 33; i+=2) print(i); + return 0; +} diff --git a/genids.c b/genids.c new file mode 100644 index 0000000000..47383eccf3 --- /dev/null +++ b/genids.c @@ -0,0 +1,150 @@ +#include +#include +#include +#include +#include + +char **unique_ids; +int unique_ids_size; +int unique_ids_maxsize; + +int cmp(const void *p1, const void *p2) +{ + return strcmp(*(char * const *)p1, *(char * const *)p2); +} + +/* return 1 if s was not already known, 0 if it was */ +int new_unique_id(char *s) +{ + 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); + 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(); } + } + unique_ids[unique_ids_size] = strdup(s); + if (unique_ids[unique_ids_size] == NULL) + { printf("out of memory\n"); abort(); } + unique_ids_size++; + qsort(unique_ids, unique_ids_size, sizeof(char *), cmp); + return 1; +} + +char *bufname; +int bufname_size; +int bufname_maxsize; + +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); } + } + bufname[bufname_size] = c; + bufname_size++; +} + +char *bufvalue; +int bufvalue_size; +int bufvalue_maxsize; + +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); } + } + bufvalue[bufvalue_size] = c; + bufvalue_size++; +} + +void smash_spaces(FILE *f) +{ + int c; + while (1) { + c = fgetc(f); + if (isspace(c)) continue; + if (c == ' ') continue; + if (c == '\t') continue; + if (c == '\n') continue; + if (c == 10 || c == 13) continue; + if (c == '#') { + while (1) { + c = fgetc(f); + if (c == '\n' || c == EOF) break; + } + continue; + } + break; + } + if (c != EOF) ungetc(c, f); +} + +void get_line(FILE *f, char **name, char **value) +{ + int c; + bufname_size = 0; + bufvalue_size = 0; + *name = NULL; + *value = NULL; + smash_spaces(f); + c = fgetc(f); + while (!(c == '=' || isspace(c) || c == EOF)) { putname(c); c = fgetc(f); } + if (c == EOF) return; + putname(0); + while (!(c == EOF || c == '=')) c = fgetc(f); + if (c == EOF) return; + smash_spaces(f); + c = fgetc(f); + while (!(c == 10 || c == 13 || c == EOF)) { putvalue(c); c = fgetc(f); } + putvalue(0); + if (bufname_size <= 1) return; + if (bufvalue_size <= 1) return; + *name = bufname; + *value = bufvalue; +} + +int main(int n, char **v) +{ + FILE *in; + FILE *out; + char *name; + char *value; + char *in_name; + char *out_name; + + if (n != 3) { printf("gimme \n"); exit(1); } + + n = 0; + + in_name = v[1]; + out_name = v[2]; + + in = fopen(in_name, "r"); if (in == NULL) { perror(in_name); exit(1); } + out = fopen(out_name, "w"); if (out == NULL) { perror(out_name); exit(1); } + + fprintf(out, "/* generated file, do not edit by hand */\n\n"); + + while (1) { + get_line(in, &name, &value); + if (name == NULL) break; + printf("name '%s' value '%s'\n", name, value); + if (!strcmp(name, "ID")) { + if (!new_unique_id(value)) { unlink(out_name); exit(1); } + fprintf(out, "#define T_%s T_ID(%d)\n", value, n); + n++; + } + } + fprintf(out, "#define T_NUMBER_OF_IDS %d\n", n); + + fclose(in); + fclose(out); + + return 0; +} diff --git a/main.c b/main.c new file mode 100644 index 0000000000..50b1d9339c --- /dev/null +++ b/main.c @@ -0,0 +1,19 @@ +#include "T.h" +#include +#include +#include +#include +#include + +int main(void) +{ + T_connect_to_tracer("127.0.0.1", 2020); + printf("after connect\n"); + while (1) { + T(T_first, T_PRINTF("hello world %s!\n", "yo")); + //usleep(1); + } + while (1) pause(); + + return 0; +} diff --git a/tracer/Makefile b/tracer/Makefile new file mode 100644 index 0000000000..156700812e --- /dev/null +++ b/tracer/Makefile @@ -0,0 +1,20 @@ +CC=gcc +CFLAGS=-Wall -g -O3 + +#comment those two lines to NOT use shared memory +CFLAGS += -DT_USE_SHARED_MEMORY +LIBS += -lrt + +PROG=tracer +OBJS=main.o + +$(PROG): $(OBJS) + $(CC) $(CFLAGS) -o $(PROG) $(OBJS) $(LIBS) + +%.o: %.c + $(CC) $(CFLAGS) -c -o $@ $< + +main.o: ../T_IDs.h ../T_defs.h + +clean: + rm -f *.o $(PROG) core diff --git a/tracer/main.c b/tracer/main.c new file mode 100644 index 0000000000..fa19a6237b --- /dev/null +++ b/tracer/main.c @@ -0,0 +1,254 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define T_ID(x) x +#include "../T_IDs.h" +#include "../T_defs.h" + +#ifdef T_USE_SHARED_MEMORY + +T_cache_t *T_cache; +int T_busylist_head; +int T_pos; + +static inline int GET(int s, void *out, int count) +{ + if (count == 1) { + *(char *)out = T_cache[T_busylist_head].buffer[T_pos]; + T_pos++; + return 1; + } + memcpy(out, T_cache[T_busylist_head].buffer + T_pos, count); + T_pos += count; + return count; +} + +#else /* T_USE_SHARED_MEMORY */ + +#define GET read + +#endif /* T_USE_SHARED_MEMORY */ + +int get_connection(char *addr, int port) +{ + struct sockaddr_in a; + socklen_t alen; + int s, t; + + 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); } + + 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); + if (t == -1) { perror("accept"); exit(1); } + close(s); + return t; +} + +void get_string(int s, char *out) +{ + while (1) { + if (GET(s, out, 1) != 1) abort(); + if (*out == 0) break; + out++; + } +} + +void get_message(int s) +{ +#define S(x, y) do { \ + char str[1024]; \ + get_string(s, str); \ + printf("["x"]["y"] %s", str); \ + } while (0) + + int m; +#ifdef T_USE_SHARED_MEMORY + T_pos = 0; +#endif + if (GET(s, &m, sizeof(int)) != sizeof(int)) abort(); + switch (m) { + case T_first: { + char str[1024]; + get_string(s, str); + printf("%s", str); + break; + } + case T_LEGACY_MAC_INFO: S("MAC", "INFO"); break; + case T_LEGACY_MAC_ERROR: S("MAC", "ERROR"); break; + case T_LEGACY_MAC_WARNING: S("MAC", "WARNING"); break; + case T_LEGACY_MAC_DEBUG: S("MAC", "DEBUG"); break; + case T_LEGACY_MAC_TRACE: S("MAC", "TRACE"); break; + case T_LEGACY_PHY_INFO: S("PHY", "INFO"); break; + case T_LEGACY_PHY_ERROR: S("PHY", "ERROR"); break; + case T_LEGACY_PHY_WARNING: S("PHY", "WARNING"); break; + case T_LEGACY_PHY_DEBUG: S("PHY", "DEBUG"); break; + case T_LEGACY_PHY_TRACE: S("PHY", "TRACE"); break; + case T_LEGACY_S1AP_INFO: S("S1AP", "INFO"); break; + case T_LEGACY_S1AP_ERROR: S("S1AP", "ERROR"); break; + case T_LEGACY_S1AP_WARNING: S("S1AP", "WARNING"); break; + case T_LEGACY_S1AP_DEBUG: S("S1AP", "DEBUG"); break; + case T_LEGACY_S1AP_TRACE: S("S1AP", "TRACE"); break; + case T_LEGACY_RRC_INFO: S("RRC", "INFO"); break; + case T_LEGACY_RRC_ERROR: S("RRC", "ERROR"); break; + case T_LEGACY_RRC_WARNING: S("RRC", "WARNING"); break; + case T_LEGACY_RRC_DEBUG: S("RRC", "DEBUG"); break; + case T_LEGACY_RRC_TRACE: S("RRC", "TRACE"); break; + case T_LEGACY_RLC_INFO: S("RLC", "INFO"); break; + case T_LEGACY_RLC_ERROR: S("RLC", "ERROR"); break; + case T_LEGACY_RLC_WARNING: S("RLC", "WARNING"); break; + case T_LEGACY_RLC_DEBUG: S("RLC", "DEBUG"); break; + case T_LEGACY_RLC_TRACE: S("RLC", "TRACE"); break; + case T_LEGACY_PDCP_INFO: S("PDCP", "INFO"); break; + case T_LEGACY_PDCP_ERROR: S("PDCP", "ERROR"); break; + case T_LEGACY_PDCP_WARNING: S("PDCP", "WARNING"); break; + case T_LEGACY_PDCP_DEBUG: S("PDCP", "DEBUG"); break; + case T_LEGACY_PDCP_TRACE: S("PDCP", "TRACE"); break; + case T_LEGACY_ENB_APP_INFO: S("ENB_APP", "INFO"); break; + case T_LEGACY_ENB_APP_ERROR: S("ENB_APP", "ERROR"); break; + case T_LEGACY_ENB_APP_WARNING: S("ENB_APP", "WARNING"); break; + case T_LEGACY_ENB_APP_DEBUG: S("ENB_APP", "DEBUG"); break; + case T_LEGACY_ENB_APP_TRACE: S("ENB_APP", "TRACE"); break; + case T_LEGACY_SCTP_INFO: S("SCTP", "INFO"); break; + case T_LEGACY_SCTP_ERROR: S("SCTP", "ERROR"); break; + case T_LEGACY_SCTP_WARNING: S("SCTP", "WARNING"); break; + case T_LEGACY_SCTP_DEBUG: S("SCTP", "DEBUG"); break; + case T_LEGACY_SCTP_TRACE: S("SCTP", "TRACE"); break; + case T_LEGACY_UDP__INFO: S("UDP", "INFO"); break; + case T_LEGACY_UDP__ERROR: S("UDP", "ERROR"); break; + case T_LEGACY_UDP__WARNING: S("UDP", "WARNING"); break; + case T_LEGACY_UDP__DEBUG: S("UDP", "DEBUG"); break; + case T_LEGACY_UDP__TRACE: S("UDP", "TRACE"); break; + case T_LEGACY_NAS_INFO: S("NAS", "INFO"); break; + case T_LEGACY_NAS_ERROR: S("NAS", "ERROR"); break; + case T_LEGACY_NAS_WARNING: S("NAS", "WARNING"); break; + case T_LEGACY_NAS_DEBUG: S("NAS", "DEBUG"); break; + case T_LEGACY_NAS_TRACE: S("NAS", "TRACE"); break; + case T_LEGACY_HW_INFO: S("HW", "INFO"); break; + case T_LEGACY_HW_ERROR: S("HW", "ERROR"); break; + case T_LEGACY_HW_WARNING: S("HW", "WARNING"); break; + case T_LEGACY_HW_DEBUG: S("HW", "DEBUG"); break; + case T_LEGACY_HW_TRACE: S("HW", "TRACE"); break; + case T_LEGACY_EMU_INFO: S("EMU", "INFO"); break; + case T_LEGACY_EMU_ERROR: S("EMU", "ERROR"); break; + case T_LEGACY_EMU_WARNING: S("EMU", "WARNING"); break; + case T_LEGACY_EMU_DEBUG: S("EMU", "DEBUG"); break; + case T_LEGACY_EMU_TRACE: S("EMU", "TRACE"); break; + case T_LEGACY_OTG_INFO: S("OTG", "INFO"); break; + case T_LEGACY_OTG_ERROR: S("OTG", "ERROR"); break; + case T_LEGACY_OTG_WARNING: S("OTG", "WARNING"); break; + case T_LEGACY_OTG_DEBUG: S("OTG", "DEBUG"); break; + case T_LEGACY_OTG_TRACE: S("OTG", "TRACE"); break; + case T_LEGACY_OCG_INFO: S("OCG", "INFO"); break; + case T_LEGACY_OCG_ERROR: S("OCG", "ERROR"); break; + case T_LEGACY_OCG_WARNING: S("OCG", "WARNING"); break; + case T_LEGACY_OCG_DEBUG: S("OCG", "DEBUG"); break; + case T_LEGACY_OCG_TRACE: S("OCG", "TRACE"); break; + case T_LEGACY_OMG_INFO: S("OMG", "INFO"); break; + case T_LEGACY_OMG_ERROR: S("OMG", "ERROR"); break; + case T_LEGACY_OMG_WARNING: S("OMG", "WARNING"); break; + case T_LEGACY_OMG_DEBUG: S("OMG", "DEBUG"); break; + case T_LEGACY_OMG_TRACE: S("OMG", "TRACE"); break; + case T_LEGACY_GTPU_INFO: S("GTPU", "INFO"); break; + case T_LEGACY_GTPU_ERROR: S("GTPU", "ERROR"); break; + case T_LEGACY_GTPU_WARNING: S("GTPU", "WARNING"); break; + case T_LEGACY_GTPU_DEBUG: S("GTPU", "DEBUG"); break; + case T_LEGACY_GTPU_TRACE: S("GTPU", "TRACE"); break; + case T_LEGACY_TMR_INFO: S("TMR", "INFO"); break; + case T_LEGACY_TMR_ERROR: S("TMR", "ERROR"); break; + case T_LEGACY_TMR_WARNING: S("TMR", "WARNING"); break; + case T_LEGACY_TMR_DEBUG: S("TMR", "DEBUG"); break; + case T_LEGACY_TMR_TRACE: S("TMR", "TRACE"); break; + case T_LEGACY_OSA_INFO: S("OSA", "INFO"); break; + case T_LEGACY_OSA_ERROR: S("OSA", "ERROR"); break; + case T_LEGACY_OSA_WARNING: S("OSA", "WARNING"); break; + case T_LEGACY_OSA_DEBUG: S("OSA", "DEBUG"); break; + case T_LEGACY_OSA_TRACE: S("OSA", "TRACE"); break; + case T_LEGACY_component_INFO: S("XXX", "INFO"); break; + case T_LEGACY_component_ERROR: S("XXX", "ERROR"); break; + case T_LEGACY_component_WARNING: S("XXX", "WARNING"); break; + case T_LEGACY_component_DEBUG: S("XXX", "DEBUG"); break; + case T_LEGACY_component_TRACE: S("XXX", "TRACE"); break; + case T_LEGACY_componentP_INFO: S("XXX", "INFO"); break; + case T_LEGACY_componentP_ERROR: S("XXX", "ERROR"); break; + case T_LEGACY_componentP_WARNING: S("XXX", "WARNING"); break; + case T_LEGACY_componentP_DEBUG: S("XXX", "DEBUG"); break; + case T_LEGACY_componentP_TRACE: S("XXX", "TRACE"); break; + case T_LEGACY_CLI_INFO: S("CLI", "INFO"); break; + case T_LEGACY_CLI_ERROR: S("CLI", "ERROR"); break; + case T_LEGACY_CLI_WARNING: S("CLI", "WARNING"); break; + case T_LEGACY_CLI_DEBUG: S("CLI", "DEBUG"); break; + case T_LEGACY_CLI_TRACE: S("CLI", "TRACE"); break; + default: printf("unkown message type %d\n", m); abort(); + } + +#ifdef T_USE_SHARED_MEMORY + T_cache[T_busylist_head].busy = 0; + T_busylist_head++; + T_busylist_head &= T_CACHE_SIZE - 1; +#endif +} + +#ifdef T_USE_SHARED_MEMORY + +void wait_message(void) +{ + while (T_cache[T_busylist_head].busy == 0) usleep(1000); +} + +void init_shm(void) +{ + int s = shm_open(T_SHM_FILENAME, O_RDWR | O_CREAT, 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_cache = mmap(NULL, T_CACHE_SIZE * sizeof(T_cache_t), + PROT_READ | PROT_WRITE, MAP_SHARED, s, 0); + if (T_cache == NULL) + { perror(T_SHM_FILENAME); abort(); } + close(s); +} + +#endif /* T_USE_SHARED_MEMORY */ + +int main(void) +{ + int s; + int l; + char t; +#ifdef T_USE_SHARED_MEMORY + init_shm(); +#endif + s = get_connection("127.0.0.1", 2020); + /* send the first message - activate all traces */ + t = 0; + if (write(s, &t, 1) != 1) abort(); + l = T_NUMBER_OF_IDS; + if (write(s, &l, sizeof(int)) != sizeof(int)) abort(); + for (l = 0; l < T_NUMBER_OF_IDS; l++) + if (write(s, &l, sizeof(int)) != sizeof(int)) abort(); + /* read messages */ + while (1) { +#ifdef T_USE_SHARED_MEMORY + wait_message(); +#endif + get_message(s); + } + return 0; +} From 4b68033b2dc24df6800097f5f16b0352d4f4b9e3 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Tue, 15 Mar 2016 10:43:10 +0100 Subject: [PATCH 02/28] some work for buffer handling --- T.h | 12 +++++++----- T_messages.txt | 1 + main.c | 6 ++++-- tracer/main.c | 13 +++++++++++-- 4 files changed, 23 insertions(+), 9 deletions(-) diff --git a/T.h b/T.h index 884a9b6f89..ec7b1d2a0c 100644 --- a/T.h +++ b/T.h @@ -36,10 +36,12 @@ #define T_PUT_buffer(argnum, val) \ do { \ - T_buffer T_PUT_var = (val); \ - T_CHECK_SIZE(T_PUT_var.length, argnum); \ - memcpy(T_LOCAL_buf + T_LOCAL_size, T_PUT_var.addr, T_PUT_var.length); \ - T_LOCAL_size += T_PUT_var.length; \ + T_buffer T_PUT_buffer_var = (val); \ + T_PUT_int(argnum, T_PUT_buffer_var.length); \ + T_CHECK_SIZE(T_PUT_buffer_var.length, argnum); \ + memcpy(T_LOCAL_buf + T_LOCAL_size, T_PUT_buffer_var.addr, \ + T_PUT_buffer_var.length); \ + T_LOCAL_size += T_PUT_buffer_var.length; \ } while (0) #define T_PUT_string(argnum, val) \ @@ -117,7 +119,7 @@ extern T_cache_t *T_cache; T_send(T_LOCAL_buf, T_LOCAL_size) #define T_CHECK_SIZE(len, argnum) \ - if (T_LOCAL_size + len > T_BUFFER_MAX) { \ + if (T_LOCAL_size + (len) > 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); \ diff --git a/T_messages.txt b/T_messages.txt index b0e6cb00ed..8cca071ae8 100644 --- a/T_messages.txt +++ b/T_messages.txt @@ -138,3 +138,4 @@ ID = LEGACY_CLI_DEBUG ID = LEGACY_CLI_TRACE ID = first +ID = buf_test diff --git a/main.c b/main.c index 50b1d9339c..3552f19df5 100644 --- a/main.c +++ b/main.c @@ -10,8 +10,10 @@ int main(void) T_connect_to_tracer("127.0.0.1", 2020); printf("after connect\n"); while (1) { - T(T_first, T_PRINTF("hello world %s!\n", "yo")); - //usleep(1); + char *buf = "hello world %s!\n"; + //T(T_first, T_PRINTF("hello world %s!\n", "yo")); + T(T_buf_test, T_BUFFER("hello world %s!\n", strlen(buf)+1)); + usleep(1); } while (1) pause(); diff --git a/tracer/main.c b/tracer/main.c index fa19a6237b..f9da2085bf 100644 --- a/tracer/main.c +++ b/tracer/main.c @@ -73,7 +73,7 @@ void get_string(int s, char *out) void get_message(int s) { #define S(x, y) do { \ - char str[1024]; \ + char str[T_BUFFER_MAX]; \ get_string(s, str); \ printf("["x"]["y"] %s", str); \ } while (0) @@ -85,7 +85,7 @@ void get_message(int s) if (GET(s, &m, sizeof(int)) != sizeof(int)) abort(); switch (m) { case T_first: { - char str[1024]; + char str[T_BUFFER_MAX]; get_string(s, str); printf("%s", str); break; @@ -195,6 +195,15 @@ void get_message(int s) case T_LEGACY_CLI_WARNING: S("CLI", "WARNING"); break; case T_LEGACY_CLI_DEBUG: S("CLI", "DEBUG"); break; case T_LEGACY_CLI_TRACE: S("CLI", "TRACE"); break; + case T_buf_test: { + unsigned char buf[T_BUFFER_MAX]; + int size; + GET(s, &size, sizeof(int)); + GET(s, buf, size); + printf("got buffer size %d %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x\n", + size, buf[0],buf[1],buf[2],buf[3],buf[4],buf[5],buf[6],buf[7],buf[8],buf[9],buf[10],buf[11],buf[12],buf[13],buf[14],buf[15]); + break; + } default: printf("unkown message type %d\n", m); abort(); } From 6fa2737027914bce7b409460b973bd7636ab094d Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Tue, 15 Mar 2016 17:01:05 +0100 Subject: [PATCH 03/28] add a plotter for raw IQ samples from eNB uplink received data only works for 5MHz (7680 samples per TTI), one transport block (basic FDD thing) --- Makefile | 2 +- T.h | 60 +++++++++++++---------- T_defs.h | 4 +- T_messages.txt | 27 ++++++++++- generate_Txx.c | 4 +- tracer/Makefile | 6 ++- tracer/defs.h | 8 ++++ tracer/main.c | 24 ++++++++++ tracer/plot.c | 123 ++++++++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 226 insertions(+), 32 deletions(-) create mode 100644 tracer/defs.h create mode 100644 tracer/plot.c diff --git a/Makefile b/Makefile index 06315e4585..c65ed27b8e 100644 --- a/Makefile +++ b/Makefile @@ -27,7 +27,7 @@ $(PROG): $(OBJS) T_IDs.h: $(GENIDS) T_messages.txt ./$(GENIDS) T_messages.txt T_IDs.h -main.o: T.h T_IDs.h +main.o: T.h T_IDs.h T_defs.h clean: rm -f *.o $(PROG) $(GENIDS) core T_IDs.h diff --git a/T.h b/T.h index ec7b1d2a0c..46c5bdc180 100644 --- a/T.h +++ b/T.h @@ -236,20 +236,7 @@ extern T_cache_t *T_cache; } \ } while (0) -#define T11(t,t0,x0,t1,x1,t2,x2,t3,x3) \ - do { \ - if (T_ACTIVE(t)) { \ - T_LOCAL_DATA \ - T_HEADER(t); \ - T_PUT_##t0(2, x0); \ - T_PUT_##t1(3, x1); \ - T_PUT_##t2(4, x2); \ - T_PUT_##t3(5, x3); \ - T_SEND(); \ - } \ - } while (0) - -#define T13(t,t0,x0,t1,x1,t2,x2,t3,x3,t4,x4) \ +#define T11(t,t0,x0,t1,x1,t2,x2,t3,x3,t4,x4) \ do { \ if (T_ACTIVE(t)) { \ T_LOCAL_DATA \ @@ -263,7 +250,7 @@ extern T_cache_t *T_cache; } \ } while (0) -#define T15(t,t0,x0,t1,x1,t2,x2,t3,x3,t4,x4,t5,x5) \ +#define T13(t,t0,x0,t1,x1,t2,x2,t3,x3,t4,x4,t5,x5) \ do { \ if (T_ACTIVE(t)) { \ T_LOCAL_DATA \ @@ -278,7 +265,7 @@ extern T_cache_t *T_cache; } \ } while (0) -#define T17(t,t0,x0,t1,x1,t2,x2,t3,x3,t4,x4,t5,x5,t6,x6) \ +#define T15(t,t0,x0,t1,x1,t2,x2,t3,x3,t4,x4,t5,x5,t6,x6) \ do { \ if (T_ACTIVE(t)) { \ T_LOCAL_DATA \ @@ -294,7 +281,7 @@ extern T_cache_t *T_cache; } \ } while (0) -#define T19(t,t0,x0,t1,x1,t2,x2,t3,x3,t4,x4,t5,x5,t6,x6,t7,x7) \ +#define T17(t,t0,x0,t1,x1,t2,x2,t3,x3,t4,x4,t5,x5,t6,x6,t7,x7) \ do { \ if (T_ACTIVE(t)) { \ T_LOCAL_DATA \ @@ -311,7 +298,7 @@ extern T_cache_t *T_cache; } \ } while (0) -#define T21(t,t0,x0,t1,x1,t2,x2,t3,x3,t4,x4,t5,x5,t6,x6,t7,x7,t8,x8) \ +#define T19(t,t0,x0,t1,x1,t2,x2,t3,x3,t4,x4,t5,x5,t6,x6,t7,x7,t8,x8) \ do { \ if (T_ACTIVE(t)) { \ T_LOCAL_DATA \ @@ -329,7 +316,7 @@ extern T_cache_t *T_cache; } \ } while (0) -#define T23(t,t0,x0,t1,x1,t2,x2,t3,x3,t4,x4,t5,x5,t6,x6,t7,x7,t8,x8,t9,x9) \ +#define T21(t,t0,x0,t1,x1,t2,x2,t3,x3,t4,x4,t5,x5,t6,x6,t7,x7,t8,x8,t9,x9) \ do { \ if (T_ACTIVE(t)) { \ T_LOCAL_DATA \ @@ -348,7 +335,7 @@ extern T_cache_t *T_cache; } \ } while (0) -#define T25(t,t0,x0,t1,x1,t2,x2,t3,x3,t4,x4,t5,x5,t6,x6,t7,x7,t8,x8,t9,x9,t10,x10) \ +#define T23(t,t0,x0,t1,x1,t2,x2,t3,x3,t4,x4,t5,x5,t6,x6,t7,x7,t8,x8,t9,x9,t10,x10) \ do { \ if (T_ACTIVE(t)) { \ T_LOCAL_DATA \ @@ -368,7 +355,7 @@ extern T_cache_t *T_cache; } \ } while (0) -#define T27(t,t0,x0,t1,x1,t2,x2,t3,x3,t4,x4,t5,x5,t6,x6,t7,x7,t8,x8,t9,x9,t10,x10,t11,x11) \ +#define T25(t,t0,x0,t1,x1,t2,x2,t3,x3,t4,x4,t5,x5,t6,x6,t7,x7,t8,x8,t9,x9,t10,x10,t11,x11) \ do { \ if (T_ACTIVE(t)) { \ T_LOCAL_DATA \ @@ -389,7 +376,7 @@ extern T_cache_t *T_cache; } \ } while (0) -#define T29(t,t0,x0,t1,x1,t2,x2,t3,x3,t4,x4,t5,x5,t6,x6,t7,x7,t8,x8,t9,x9,t10,x10,t11,x11,t12,x12) \ +#define T27(t,t0,x0,t1,x1,t2,x2,t3,x3,t4,x4,t5,x5,t6,x6,t7,x7,t8,x8,t9,x9,t10,x10,t11,x11,t12,x12) \ do { \ if (T_ACTIVE(t)) { \ T_LOCAL_DATA \ @@ -411,7 +398,7 @@ extern T_cache_t *T_cache; } \ } while (0) -#define T31(t,t0,x0,t1,x1,t2,x2,t3,x3,t4,x4,t5,x5,t6,x6,t7,x7,t8,x8,t9,x9,t10,x10,t11,x11,t12,x12,t13,x13) \ +#define T29(t,t0,x0,t1,x1,t2,x2,t3,x3,t4,x4,t5,x5,t6,x6,t7,x7,t8,x8,t9,x9,t10,x10,t11,x11,t12,x12,t13,x13) \ do { \ if (T_ACTIVE(t)) { \ T_LOCAL_DATA \ @@ -434,7 +421,7 @@ extern T_cache_t *T_cache; } \ } while (0) -#define T33(t,t0,x0,t1,x1,t2,x2,t3,x3,t4,x4,t5,x5,t6,x6,t7,x7,t8,x8,t9,x9,t10,x10,t11,x11,t12,x12,t13,x13,t14,x14) \ +#define T31(t,t0,x0,t1,x1,t2,x2,t3,x3,t4,x4,t5,x5,t6,x6,t7,x7,t8,x8,t9,x9,t10,x10,t11,x11,t12,x12,t13,x13,t14,x14) \ do { \ if (T_ACTIVE(t)) { \ T_LOCAL_DATA \ @@ -458,6 +445,31 @@ extern T_cache_t *T_cache; } \ } while (0) +#define T33(t,t0,x0,t1,x1,t2,x2,t3,x3,t4,x4,t5,x5,t6,x6,t7,x7,t8,x8,t9,x9,t10,x10,t11,x11,t12,x12,t13,x13,t14,x14,t15,x15) \ + do { \ + if (T_ACTIVE(t)) { \ + T_LOCAL_DATA \ + T_HEADER(t); \ + T_PUT_##t0(2, x0); \ + T_PUT_##t1(3, x1); \ + T_PUT_##t2(4, x2); \ + T_PUT_##t3(5, x3); \ + T_PUT_##t4(6, x4); \ + T_PUT_##t5(7, x5); \ + T_PUT_##t6(8, x6); \ + T_PUT_##t7(9, x7); \ + T_PUT_##t8(10, x8); \ + T_PUT_##t9(11, x9); \ + T_PUT_##t10(12, x10); \ + T_PUT_##t11(13, x11); \ + T_PUT_##t12(14, x12); \ + T_PUT_##t13(15, x13); \ + T_PUT_##t14(16, x14); \ + T_PUT_##t15(17, x15); \ + T_SEND(); \ + } \ + } while (0) + #define T_CALL_ERROR \ do { \ printf("%s:%d:%s: error calling T, you have to use T_INT() or T_XX()\n", \ diff --git a/T_defs.h b/T_defs.h index 1d01ea7415..5aca54e8d6 100644 --- a/T_defs.h +++ b/T_defs.h @@ -2,10 +2,10 @@ #define _T_defs_H_ /* maximum size of a message - increase if needed */ -#define T_BUFFER_MAX 1024 +#define T_BUFFER_MAX (1024*64) /* size of the local cache for messages (must be pow(2,something)) */ -#define T_CACHE_SIZE (65536 * 2) +#define T_CACHE_SIZE (8192 * 2) typedef struct { volatile int busy; diff --git a/T_messages.txt b/T_messages.txt index 8cca071ae8..e5f0c916a3 100644 --- a/T_messages.txt +++ b/T_messages.txt @@ -1,17 +1,41 @@ +#PHY logs +ID = ENB_INPUT_SIGNAL + DESC = eNodeB received signal in the time domain for a duration of 1ms + GROUP = PHY:GRAPHIC:HEAVY + FORMAT = int,eNB_ID : int,frame : int,subframe : int,antenna : buffer,rxdata + #legacy logs ID = LEGACY_MAC_INFO - DESC = MAC legacy logs + DESC = MAC legacy logs - info level GROUP = MAC:INFO:LEGACY ID = LEGACY_MAC_ERROR + DESC = MAC legacy logs - error level + GROUP = MAC:ERROR:LEGACY ID = LEGACY_MAC_WARNING + DESC = MAC legacy logs - warning level + GROUP = MAC:WARNING:LEGACY ID = LEGACY_MAC_DEBUG + DESC = MAC legacy logs - debug level + GROUP = MAC:DEBUG:LEGACY ID = LEGACY_MAC_TRACE + DESC = MAC legacy logs - trace level + GROUP = MAC:TRACE:LEGACY ID = LEGACY_PHY_INFO + DESC = PHY legacy logs - info level + GROUP = PHY:INFO:LEGACY ID = LEGACY_PHY_ERROR + DESC = PHY legacy logs - error level + GROUP = PHY:ERROR:LEGACY ID = LEGACY_PHY_WARNING + DESC = PHY legacy logs - warning level + GROUP = PHY:WARNING:LEGACY ID = LEGACY_PHY_DEBUG + DESC = PHY legacy logs - debug level + GROUP = PHY:DEBUG:LEGACY ID = LEGACY_PHY_TRACE + DESC = PHY legacy logs - trace level + GROUP = PHY:TRACE:LEGACY ID = LEGACY_S1AP_INFO ID = LEGACY_S1AP_ERROR @@ -137,5 +161,6 @@ ID = LEGACY_CLI_WARNING ID = LEGACY_CLI_DEBUG ID = LEGACY_CLI_TRACE +#for debug/test - not used ID = first ID = buf_test diff --git a/generate_Txx.c b/generate_Txx.c index 6e803aac50..da6282adc1 100644 --- a/generate_Txx.c +++ b/generate_Txx.c @@ -4,13 +4,13 @@ void print(int n) { int i; printf("#define T%d(t", n); - for(i=0; i<(n-3)/2; i++) printf(",t%d,x%d", i, i); + for(i=0; i<(n-1)/2; i++) printf(",t%d,x%d", i, i); printf(") \\\n"); printf(" do { \\\n"); printf(" if (T_ACTIVE(t)) { \\\n"); printf(" T_LOCAL_DATA \\\n"); printf(" T_HEADER(t); \\\n"); - for(i=0; i<(n-3)/2; i++) printf(" T_PUT_##t%d(%d, x%d); \\\n", i, i+2, i); + for(i=0; i<(n-1)/2; i++) printf(" T_PUT_##t%d(%d, x%d); \\\n", i, i+2, i); printf(" T_SEND(); \\\n"); printf(" } \\\n"); printf(" } while (0)\n"); diff --git a/tracer/Makefile b/tracer/Makefile index 156700812e..047e1a5c38 100644 --- a/tracer/Makefile +++ b/tracer/Makefile @@ -1,12 +1,14 @@ CC=gcc -CFLAGS=-Wall -g -O3 +CFLAGS=-Wall -g -pthread + +LIBS=-lX11 -lm #comment those two lines to NOT use shared memory CFLAGS += -DT_USE_SHARED_MEMORY LIBS += -lrt PROG=tracer -OBJS=main.o +OBJS=main.o plot.o $(PROG): $(OBJS) $(CC) $(CFLAGS) -o $(PROG) $(OBJS) $(LIBS) diff --git a/tracer/defs.h b/tracer/defs.h new file mode 100644 index 0000000000..73e11a0c7d --- /dev/null +++ b/tracer/defs.h @@ -0,0 +1,8 @@ +#ifndef _TRACER_DEFS_H_ +#define _TRACER_DEFS_H_ + +void *make_plot(int width, int height, int bufsize); +void plot_set(void *plot, float *data, int len, int pos); +void iq_plot_set(void *plot, short *data, int len, int pos); + +#endif /* _TRACER_DEFS_H_ */ diff --git a/tracer/main.c b/tracer/main.c index f9da2085bf..e80c5691a1 100644 --- a/tracer/main.c +++ b/tracer/main.c @@ -8,10 +8,14 @@ #include #include +#include "defs.h" + #define T_ID(x) x #include "../T_IDs.h" #include "../T_defs.h" +void *ul_plot; + #ifdef T_USE_SHARED_MEMORY T_cache_t *T_cache; @@ -195,6 +199,23 @@ void get_message(int s) case T_LEGACY_CLI_WARNING: S("CLI", "WARNING"); break; case T_LEGACY_CLI_DEBUG: S("CLI", "DEBUG"); break; case T_LEGACY_CLI_TRACE: S("CLI", "TRACE"); break; + case T_ENB_INPUT_SIGNAL: { + unsigned char buf[T_BUFFER_MAX]; + int size; + int eNB, frame, subframe, antenna; + GET(s, &eNB, sizeof(int)); + GET(s, &frame, sizeof(int)); + GET(s, &subframe, sizeof(int)); + GET(s, &antenna, sizeof(int)); + GET(s, &size, sizeof(int)); + GET(s, buf, size); + printf("got T_ENB_INPUT_SIGNAL eNB %d frame %d subframe %d antenna %d size %d %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x\n", + eNB, frame, subframe, antenna, size, buf[0],buf[1],buf[2],buf[3],buf[4],buf[5],buf[6],buf[7],buf[8],buf[9],buf[10],buf[11],buf[12],buf[13],buf[14],buf[15]); + if (size != 4 * 7680) + {printf("bad T_ENB_INPUT_SIGNAL, only 7680 samples allowed\n");abort();} + iq_plot_set(ul_plot, (short*)buf, 7680, subframe*7680); + break; + } case T_buf_test: { unsigned char buf[T_BUFFER_MAX]; int size; @@ -252,6 +273,9 @@ int main(void) if (write(s, &l, sizeof(int)) != sizeof(int)) abort(); for (l = 0; l < T_NUMBER_OF_IDS; l++) if (write(s, &l, sizeof(int)) != sizeof(int)) abort(); + + ul_plot = make_plot(512, 100, 7680*2*10); + /* read messages */ while (1) { #ifdef T_USE_SHARED_MEMORY diff --git a/tracer/plot.c b/tracer/plot.c new file mode 100644 index 0000000000..ba203b0886 --- /dev/null +++ b/tracer/plot.c @@ -0,0 +1,123 @@ +#include "defs.h" +#include +#include +#include +#include +#include +#include +#include + +typedef struct { + Display *d; + Window w; + Pixmap p; + int width; + int height; + float *buf; + short *iqbuf; + int bufsize; +} plot; + +static void *plot_thread(void *_p) +{ + float v; + float *s; + int i, j; + plot *p = _p; + while (1) { + while (XPending(p->d)) { + XEvent e; + XNextEvent(p->d, &e); + } + + { + /* TODO: get white & black GCs at startup */ + GC gc; + XGCValues v; + gc = DefaultGC(p->d, DefaultScreen(p->d)); + v.foreground = WhitePixel(p->d, DefaultScreen(p->d)); + XChangeGC(p->d, gc, GCForeground, &v); + XFillRectangle(p->d, p->p, gc, 0, 0, p->width, p->height); + v.foreground = BlackPixel(p->d, DefaultScreen(p->d)); + XChangeGC(p->d, gc, GCForeground, &v); + } + + { + int i; + for (i = 0; i < 512*150; i++) + p->buf[i] = 10*log10(1.0+(float)(p->iqbuf[2*i]*p->iqbuf[2*i]+ + p->iqbuf[2*i+1]*p->iqbuf[2*i+1])); + } + s = p->buf; + for (i = 0; i < 512; i++) { + v = 0; + for (j = 0; j < 150; j++, s++) v += *s; + v /= 150; + XDrawLine(p->d, p->p, DefaultGC(p->d, DefaultScreen(p->d)), i, 100, i, 100-v); + } + + XCopyArea(p->d, p->p, p->w, DefaultGC(p->d, DefaultScreen(p->d)), + 0, 0, p->width, p->height, 0, 0); + usleep(100*1000); + } + + return NULL; +} + +static void new_thread(void *(*f)(void *), void *data) +{ + pthread_t t; + pthread_attr_t att; + + if (pthread_attr_init(&att)) + { fprintf(stderr, "pthread_attr_init err\n"); exit(1); } + if (pthread_attr_setdetachstate(&att, PTHREAD_CREATE_DETACHED)) + { fprintf(stderr, "pthread_attr_setdetachstate err\n"); exit(1); } + if (pthread_create(&t, &att, f, data)) + { fprintf(stderr, "pthread_create err\n"); exit(1); } + if (pthread_attr_destroy(&att)) + { fprintf(stderr, "pthread_attr_destroy err\n"); exit(1); } +} + +void *make_plot(int width, int height, int bufsize) +{ + plot *p; + Display *d; + Window w; + Pixmap pm; + + d = XOpenDisplay(0); if (d == NULL) abort(); + w = XCreateSimpleWindow(d, DefaultRootWindow(d), 0, 0, width, height, + 0, WhitePixel(d, DefaultScreen(d)), WhitePixel(d, DefaultScreen(d))); + XSelectInput(d, w, ExposureMask); + XMapWindow(d, w); + + pm = XCreatePixmap(d, w, width, height, DefaultDepth(d, DefaultScreen(d))); + + p = malloc(sizeof(*p)); if (p == NULL) abort(); + p->width = width; + p->height = height; + p->buf = malloc(sizeof(float) * bufsize); if (p->buf == NULL) abort(); + p->iqbuf = malloc(sizeof(short) * 2 * bufsize); if (p->buf == NULL) abort(); + p->bufsize = bufsize; + + p->d = d; + p->w = w; + p->p = pm; + + new_thread(plot_thread, p); + + return p; +} + +void plot_set(void *_plot, float *data, int len, int pos) +{ + plot *p = _plot; + memcpy(p->buf + pos, data, len * sizeof(float)); +} + +void iq_plot_set(void *_plot, short *data, int len, int pos) +{ + plot *p = _plot; + memcpy(p->iqbuf + pos * 2, data, len * 2 * sizeof(short)); +} From 75b827f84689ff9cb2edef0d90dc06a0af4bac47 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Tue, 15 Mar 2016 18:44:00 +0100 Subject: [PATCH 04/28] don't accept spaces at end of lines in the messages' file --- genids.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/genids.c b/genids.c index 47383eccf3..734c506368 100644 --- a/genids.c +++ b/genids.c @@ -135,6 +135,11 @@ int main(int n, char **v) 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); + unlink(out_name); + exit(1); + } if (!strcmp(name, "ID")) { if (!new_unique_id(value)) { unlink(out_name); exit(1); } fprintf(out, "#define T_%s T_ID(%d)\n", value, n); From fe808cc3b411b19de8e49d8410185f9920f2cc72 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Tue, 15 Mar 2016 18:45:51 +0100 Subject: [PATCH 05/28] add a database of groups to, well, group IDs --- tracer/Makefile | 2 +- tracer/defs.h | 4 + tracer/main.c | 7 +- tracer/t_data.c | 213 ++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 224 insertions(+), 2 deletions(-) create mode 100644 tracer/t_data.c diff --git a/tracer/Makefile b/tracer/Makefile index 047e1a5c38..99385f4593 100644 --- a/tracer/Makefile +++ b/tracer/Makefile @@ -8,7 +8,7 @@ CFLAGS += -DT_USE_SHARED_MEMORY LIBS += -lrt PROG=tracer -OBJS=main.o plot.o +OBJS=main.o plot.o t_data.o $(PROG): $(OBJS) $(CC) $(CFLAGS) -o $(PROG) $(OBJS) $(LIBS) diff --git a/tracer/defs.h b/tracer/defs.h index 73e11a0c7d..5ba87131de 100644 --- a/tracer/defs.h +++ b/tracer/defs.h @@ -5,4 +5,8 @@ void *make_plot(int width, int height, int bufsize); void plot_set(void *plot, float *data, int len, int pos); void iq_plot_set(void *plot, short *data, int len, int pos); +/* returns an opaque pointer - truly a 'database *', see t_data.c */ +void *parse_database(char *filename); +void dump_database(void *database); + #endif /* _TRACER_DEFS_H_ */ diff --git a/tracer/main.c b/tracer/main.c index e80c5691a1..b045c58652 100644 --- a/tracer/main.c +++ b/tracer/main.c @@ -257,11 +257,16 @@ void init_shm(void) #endif /* T_USE_SHARED_MEMORY */ -int main(void) +int main(int n, char **v) { + void *database; int s; int l; char t; + + database = parse_database("../T_messages.txt"); + dump_database(database); + #ifdef T_USE_SHARED_MEMORY init_shm(); #endif diff --git a/tracer/t_data.c b/tracer/t_data.c new file mode 100644 index 0000000000..dc006e5830 --- /dev/null +++ b/tracer/t_data.c @@ -0,0 +1,213 @@ +#include "defs.h" +#include +#include +#include +#include + +typedef struct { + char *name; + char *desc; +} id; + +typedef struct { + char *name; + char **ids; + int size; +} group; + +typedef struct { + id *i; + int isize; + group *g; + int gsize; +} database; + +typedef struct { + char *data; + int size; + int maxsize; +} buffer; + +typedef struct { + buffer name; + buffer value; +} parser; + +void put(buffer *b, int c) +{ + if (b->size == b->maxsize) { + b->maxsize += 256; + b->data = realloc(b->data, b->maxsize); + if (b->data == NULL) { printf("memory allocation error\n"); exit(1); } + } + b->data[b->size] = c; + b->size++; +} + +void smash_spaces(FILE *f) +{ + int c; + while (1) { + c = fgetc(f); + if (isspace(c)) continue; + if (c == ' ') continue; + if (c == '\t') continue; + if (c == '\n') continue; + if (c == 10 || c == 13) continue; + if (c == '#') { + while (1) { + c = fgetc(f); + if (c == '\n' || c == EOF) break; + } + continue; + } + break; + } + if (c != EOF) ungetc(c, f); +} + +void get_line(parser *p, FILE *f, char **name, char **value) +{ + int c; + p->name.size = 0; + p->value.size = 0; + *name = NULL; + *value = NULL; + smash_spaces(f); + c = fgetc(f); + while (!(c == '=' || isspace(c) || c == EOF)) + { put(&p->name, c); c = fgetc(f); } + if (c == EOF) return; + put(&p->name, 0); + while (!(c == EOF || c == '=')) c = fgetc(f); + if (c == EOF) return; + smash_spaces(f); + c = fgetc(f); + while (!(c == 10 || c == 13 || c == EOF)) + { put(&p->value, c); c = fgetc(f); } + put(&p->value, 0); + if (p->name.size <= 1) return; + if (p->value.size <= 1) return; + *name = p->name.data; + *value = p->value.data; +} + +void add_id(database *r, char *id) +{ + if ((r->isize & 1023) == 0) { + r->i = realloc(r->i, (r->isize + 1024) * sizeof(id)); + if (r->i == NULL) { printf("out of memory\n"); exit(1); } + } + r->i[r->isize].name = strdup(id); + if (r->i[r->isize].name == NULL) { printf("out of memory\n"); exit(1); } + r->isize++; +} + +int group_cmp(const void *_p1, const void *_p2) +{ + const group *p1 = _p1; + const group *p2 = _p2; + return strcmp(p1->name, p2->name); +} + +group *get_group(database *r, char *group_name) +{ + group gsearch; + group *ret; + + gsearch.name = group_name; + ret = bsearch(&gsearch, r->g, r->gsize, sizeof(group), group_cmp); + if (ret != NULL) return ret; + + if ((r->gsize & 1023) == 0) { + r->g = realloc(r->g, (r->gsize + 1024) * sizeof(group)); + if (r->g == NULL) abort(); + } + r->g[r->gsize].name = strdup(group_name); + if (r->g[r->gsize].name == NULL) abort(); + r->g[r->gsize].ids = NULL; + r->g[r->gsize].size = 0; + r->gsize++; + + qsort(r->g, r->gsize, sizeof(group), group_cmp); + + return bsearch(&gsearch, r->g, r->gsize, sizeof(group), group_cmp); +} + +void group_add_id(group *g, char *id) +{ + if ((g->size & 1023) == 0) { + g->ids = realloc(g->ids, (g->size + 1024) * sizeof(char *)); + if (g->ids == NULL) abort(); + } + g->ids[g->size] = id; + g->size++; +} + +void add_groups(database *r, char *groups) +{ + group *g; + + while (1) { + char *start = groups; + char *end = start; + while (!isspace(*end) && *end != ':' && *end != 0) end++; + if (end == start) { + printf("bad group line: groups are seperated by ':'\n"); + abort(); + } + if (*end == 0) end = NULL; else *end = 0; + + g = get_group(r, start); + group_add_id(g, r->i[r->isize-1].name); + + if (end == NULL) break; + end++; + while ((isspace(*end) || *end == ':') && *end != 0) end++; + if (*end == 0) break; + groups = end; + } +} + +void *parse_database(char *filename) +{ + FILE *in; + parser p; + database *r; + char *name, *value; + + r = calloc(1, sizeof(*r)); if (r == NULL) abort(); + memset(&p, 0, sizeof(p)); + + in = fopen(filename, "r"); if (in == NULL) { perror(filename); abort(); } + + while (1) { + get_line(&p, in, &name, &value); + if (name == NULL) break; + printf("%s %s\n", name, value); + if (!strcmp(name, "ID")) add_id(r, value); + if (!strcmp(name, "GROUP")) add_groups(r, value); + } + + fclose(in); + free(p.name.data); + free(p.value.data); + + return r; +} + +void dump_database(void *_d) +{ + database *d = _d; + int i; + + printf("database: %d IDs, %d GROUPs\n", d->isize, d->gsize); + for (i = 0; i < d->isize; i++) + printf("ID %s [%s]\n", d->i[i].name, d->i[i].desc); + for (i = 0; i < d->gsize; i++) { + int j; + printf("GROUP %s [size %d]\n", d->g[i].name, d->g[i].size); + for (j = 0; j < d->g[i].size; j++) + printf(" ID %s\n", d->g[i].ids[j]); + } +} From 1f4f0305810bfecfe39ae33e31f5027932918e6d Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Wed, 16 Mar 2016 11:00:39 +0100 Subject: [PATCH 06/28] more work on database --- tracer/Makefile | 2 +- tracer/{t_data.c => database.c} | 119 +++++++++++++++++++++++++------- tracer/defs.h | 2 + tracer/main.c | 44 ++++++++++-- 4 files changed, 137 insertions(+), 30 deletions(-) rename tracer/{t_data.c => database.c} (59%) diff --git a/tracer/Makefile b/tracer/Makefile index 99385f4593..8388ec91e2 100644 --- a/tracer/Makefile +++ b/tracer/Makefile @@ -8,7 +8,7 @@ CFLAGS += -DT_USE_SHARED_MEMORY LIBS += -lrt PROG=tracer -OBJS=main.o plot.o t_data.o +OBJS=main.o plot.o database.o $(PROG): $(OBJS) $(CC) $(CFLAGS) -o $(PROG) $(OBJS) $(LIBS) diff --git a/tracer/t_data.c b/tracer/database.c similarity index 59% rename from tracer/t_data.c rename to tracer/database.c index dc006e5830..87e793b8c3 100644 --- a/tracer/t_data.c +++ b/tracer/database.c @@ -7,6 +7,8 @@ typedef struct { char *name; char *desc; + char **groups; + int size; } id; typedef struct { @@ -16,6 +18,7 @@ typedef struct { } group; typedef struct { + char *name; id *i; int isize; group *g; @@ -92,17 +95,6 @@ void get_line(parser *p, FILE *f, char **name, char **value) *value = p->value.data; } -void add_id(database *r, char *id) -{ - if ((r->isize & 1023) == 0) { - r->i = realloc(r->i, (r->isize + 1024) * sizeof(id)); - if (r->i == NULL) { printf("out of memory\n"); exit(1); } - } - r->i[r->isize].name = strdup(id); - if (r->i[r->isize].name == NULL) { printf("out of memory\n"); exit(1); } - r->isize++; -} - int group_cmp(const void *_p1, const void *_p2) { const group *p1 = _p1; @@ -110,13 +102,44 @@ int group_cmp(const void *_p1, const void *_p2) return strcmp(p1->name, p2->name); } +int id_cmp(const void *_p1, const void *_p2) +{ + const id *p1 = _p1; + const id *p2 = _p2; + return strcmp(p1->name, p2->name); +} + +int string_cmp(const void *_p1, const void *_p2) +{ + char * const *p1 = _p1; + char * const *p2 = _p2; + return strcmp(*p1, *p2); +} + +id *add_id(database *r, char *idname) +{ + if (bsearch(&(id){name:idname}, r->i, r->isize, sizeof(id), id_cmp) != NULL) + { printf("ERROR: ID '%s' declared more than once\n", idname); exit(1); } + if ((r->isize & 1023) == 0) { + r->i = realloc(r->i, (r->isize + 1024) * sizeof(id)); + if (r->i == NULL) { printf("out of memory\n"); exit(1); } + } + r->i[r->isize].name = strdup(idname); + if (r->i[r->isize].name == NULL) { printf("out of memory\n"); exit(1); } + r->i[r->isize].desc = NULL; + r->i[r->isize].groups = NULL; + r->i[r->isize].size = 0; + r->isize++; + qsort(r->i, r->isize, sizeof(id), id_cmp); + return (id*)bsearch(&(id){name:idname}, r->i, r->isize, sizeof(id), id_cmp); +} + group *get_group(database *r, char *group_name) { - group gsearch; group *ret; - gsearch.name = group_name; - ret = bsearch(&gsearch, r->g, r->gsize, sizeof(group), group_cmp); + ret = bsearch(&(group){name:group_name}, + r->g, r->gsize, sizeof(group), group_cmp); if (ret != NULL) return ret; if ((r->gsize & 1023) == 0) { @@ -131,7 +154,8 @@ group *get_group(database *r, char *group_name) qsort(r->g, r->gsize, sizeof(group), group_cmp); - return bsearch(&gsearch, r->g, r->gsize, sizeof(group), group_cmp); + return bsearch(&(group){name:group_name}, + r->g, r->gsize, sizeof(group), group_cmp); } void group_add_id(group *g, char *id) @@ -144,10 +168,24 @@ void group_add_id(group *g, char *id) g->size++; } -void add_groups(database *r, char *groups) +void id_add_group(id *i, char *group) +{ + char *g = bsearch(&group, i->groups, i->size, sizeof(char *), string_cmp); + if (g != NULL) return; + + if ((i->size & 1023) == 0) { + i->groups = realloc(i->groups, (i->size+1024) * sizeof(char *)); + if (i->groups == NULL) abort(); + } + i->groups[i->size] = group; + i->size++; + qsort(i->groups, i->size, sizeof(char *), string_cmp); +} + +void add_groups(database *r, id *i, char *groups) { group *g; - + if (i == NULL) {printf("ERROR: GROUP line before ID line\n");exit(1);} while (1) { char *start = groups; char *end = start; @@ -159,7 +197,8 @@ void add_groups(database *r, char *groups) if (*end == 0) end = NULL; else *end = 0; g = get_group(r, start); - group_add_id(g, r->i[r->isize-1].name); + group_add_id(g, i->name); + id_add_group(i, g->name); if (end == NULL) break; end++; @@ -169,24 +208,34 @@ void add_groups(database *r, char *groups) } } +void add_desc(id *i, char *desc) +{ + if (i == NULL) {printf("ERROR: DESC line before ID line\n");exit(1);} + i->desc = strdup(desc); if (i->desc == NULL) abort(); +} + void *parse_database(char *filename) { FILE *in; parser p; database *r; char *name, *value; + id *last_id = NULL; r = calloc(1, sizeof(*r)); if (r == NULL) abort(); memset(&p, 0, sizeof(p)); + r->name = strdup(filename); if (r->name == NULL) abort(); + in = fopen(filename, "r"); if (in == NULL) { perror(filename); abort(); } while (1) { get_line(&p, in, &name, &value); if (name == NULL) break; - printf("%s %s\n", name, value); - if (!strcmp(name, "ID")) add_id(r, value); - if (!strcmp(name, "GROUP")) add_groups(r, value); +//printf("%s %s\n", name, value); + if (!strcmp(name, "ID")) last_id = add_id(r, value); + if (!strcmp(name, "GROUP")) add_groups(r, last_id, value); + if (!strcmp(name, "DESC")) add_desc(last_id, value); } fclose(in); @@ -201,13 +250,33 @@ void dump_database(void *_d) database *d = _d; int i; - printf("database: %d IDs, %d GROUPs\n", d->isize, d->gsize); - for (i = 0; i < d->isize; i++) - printf("ID %s [%s]\n", d->i[i].name, d->i[i].desc); + printf("database %s: %d IDs, %d GROUPs\n", d->name, d->isize, d->gsize); + for (i = 0; i < d->isize; i++) { + int j; + printf("ID %s [%s] [in %d group%s]\n", + d->i[i].name, d->i[i].desc ? d->i[i].desc : "", + d->i[i].size, d->i[i].size > 1 ? "s" : ""); + for (j = 0; j < d->i[i].size; j++) + printf(" in GROUP: %s\n", d->i[i].groups[j]); + } for (i = 0; i < d->gsize; i++) { int j; printf("GROUP %s [size %d]\n", d->g[i].name, d->g[i].size); for (j = 0; j < d->g[i].size; j++) - printf(" ID %s\n", d->g[i].ids[j]); + printf(" contains ID: %s\n", d->g[i].ids[j]); } } + +void list_ids(void *_d) +{ + database *d = _d; + int i; + for (i = 0; i < d->isize; i++) printf("%s\n", d->i[i].name); +} + +void list_groups(void *_d) +{ + database *d = _d; + int i; + for (i = 0; i < d->gsize; i++) printf("%s\n", d->g[i].name); +} diff --git a/tracer/defs.h b/tracer/defs.h index 5ba87131de..6c2a026600 100644 --- a/tracer/defs.h +++ b/tracer/defs.h @@ -8,5 +8,7 @@ void iq_plot_set(void *plot, short *data, int len, int pos); /* returns an opaque pointer - truly a 'database *', see t_data.c */ void *parse_database(char *filename); void dump_database(void *database); +void list_ids(void *database); +void list_groups(void *database); #endif /* _TRACER_DEFS_H_ */ diff --git a/tracer/main.c b/tracer/main.c index b045c58652..fb5fcc99d9 100644 --- a/tracer/main.c +++ b/tracer/main.c @@ -257,15 +257,53 @@ void init_shm(void) #endif /* T_USE_SHARED_MEMORY */ +void usage(void) +{ + printf( +"options:\n" +" -d this option is mandatory\n" +" -li print IDs in the database\n" +" -lg print GROUPs in the database\n" +" -dump dump the database\n" + ); + exit(1); +} + int main(int n, char **v) { + char *database_filename = NULL; void *database; int s; int l; char t; + int i; + int do_list_ids = 0; + int do_list_groups = 0; + int do_dump_database = 0; - database = parse_database("../T_messages.txt"); - dump_database(database); + 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], "-li")) { do_list_ids = 1; continue; } + if (!strcmp(v[i], "-lg")) { do_list_groups = 1; continue; } + if (!strcmp(v[i], "-dump")) { do_dump_database = 1; continue; } + usage(); + } + + if (database_filename == NULL) { + printf("ERROR: provide a database file (-d)\n"); + exit(1); + } + + database = parse_database(database_filename); + + if (do_list_ids + do_list_groups + do_dump_database > 1) usage(); + if (do_list_ids) { list_ids(database); return 0; } + if (do_list_groups) { list_groups(database); return 0; } + if (do_dump_database) { dump_database(database); return 0; } + + ul_plot = make_plot(512, 100, 7680*2*10); #ifdef T_USE_SHARED_MEMORY init_shm(); @@ -279,8 +317,6 @@ int main(int n, char **v) for (l = 0; l < T_NUMBER_OF_IDS; l++) if (write(s, &l, sizeof(int)) != sizeof(int)) abort(); - ul_plot = make_plot(512, 100, 7680*2*10); - /* read messages */ while (1) { #ifdef T_USE_SHARED_MEMORY From f18d59c95a6ff6de8072df823492892fde22f54f Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Wed, 16 Mar 2016 16:26:53 +0100 Subject: [PATCH 07/28] - add channel estimation plot - add on/off command line options --- T_messages.txt | 4 ++++ tracer/Makefile | 2 ++ tracer/database.c | 33 +++++++++++++++++++++++++-- tracer/defs.h | 3 ++- tracer/main.c | 57 +++++++++++++++++++++++++++++++++++++++++++---- tracer/plot.c | 10 +++++---- 6 files changed, 98 insertions(+), 11 deletions(-) diff --git a/T_messages.txt b/T_messages.txt index e5f0c916a3..043062c598 100644 --- a/T_messages.txt +++ b/T_messages.txt @@ -3,6 +3,10 @@ ID = ENB_INPUT_SIGNAL DESC = eNodeB received signal in the time domain for a duration of 1ms GROUP = PHY:GRAPHIC:HEAVY FORMAT = int,eNB_ID : int,frame : int,subframe : int,antenna : buffer,rxdata +ID = ENB_UL_CHANNEL_ESTIMATE + DESC = eNodeB channel estimation in the time domain + GROUP = PHY:GRAPHIC:HEAVY + FORMAT = int,eNB_ID : int,UE_ID : int,frame : int,subframe : int,antenna : buffer,chest_t #legacy logs ID = LEGACY_MAC_INFO diff --git a/tracer/Makefile b/tracer/Makefile index 8388ec91e2..23309eb85e 100644 --- a/tracer/Makefile +++ b/tracer/Makefile @@ -1,6 +1,8 @@ CC=gcc CFLAGS=-Wall -g -pthread +CFLAGS += -O3 -ffast-math -fomit-frame-pointer + LIBS=-lX11 -lm #comment those two lines to NOT use shared memory diff --git a/tracer/database.c b/tracer/database.c index 87e793b8c3..3172105250 100644 --- a/tracer/database.c +++ b/tracer/database.c @@ -9,6 +9,7 @@ typedef struct { char *desc; char **groups; int size; + int id; } id; typedef struct { @@ -116,7 +117,7 @@ int string_cmp(const void *_p1, const void *_p2) return strcmp(*p1, *p2); } -id *add_id(database *r, char *idname) +id *add_id(database *r, char *idname, int i) { if (bsearch(&(id){name:idname}, r->i, r->isize, sizeof(id), id_cmp) != NULL) { printf("ERROR: ID '%s' declared more than once\n", idname); exit(1); } @@ -129,6 +130,7 @@ id *add_id(database *r, char *idname) r->i[r->isize].desc = NULL; r->i[r->isize].groups = NULL; r->i[r->isize].size = 0; + r->i[r->isize].id = i; r->isize++; qsort(r->i, r->isize, sizeof(id), id_cmp); return (id*)bsearch(&(id){name:idname}, r->i, r->isize, sizeof(id), id_cmp); @@ -221,6 +223,7 @@ void *parse_database(char *filename) database *r; char *name, *value; id *last_id = NULL; + int i; r = calloc(1, sizeof(*r)); if (r == NULL) abort(); memset(&p, 0, sizeof(p)); @@ -229,11 +232,13 @@ void *parse_database(char *filename) in = fopen(filename, "r"); if (in == NULL) { perror(filename); abort(); } + i = 0; + while (1) { get_line(&p, in, &name, &value); if (name == NULL) break; //printf("%s %s\n", name, value); - if (!strcmp(name, "ID")) last_id = add_id(r, value); + if (!strcmp(name, "ID")) { last_id = add_id(r, value, i); i++; } if (!strcmp(name, "GROUP")) add_groups(r, last_id, value); if (!strcmp(name, "DESC")) add_desc(last_id, value); } @@ -280,3 +285,27 @@ void list_groups(void *_d) int i; for (i = 0; i < d->gsize; i++) printf("%s\n", d->g[i].name); } + +static void onoff_id(database *d, char *name, int *a, int onoff) +{ + id *i; + i = bsearch(&(id){name:name}, d->i, d->isize, sizeof(id), id_cmp); + if (i == NULL) return; + a[i->id] = onoff; + printf("turning %s %s\n", name, onoff ? "ON" : "OFF"); +} + +static void onoff_group(database *d, char *name, int *a, int onoff) +{ + group *g; + int i; + g = bsearch(&(group){name:name}, d->g, d->gsize, sizeof(group), group_cmp); + if (g == NULL) return; + for (i = 0; i < g->size; i++) onoff_id(d, g->ids[i], a, onoff); +} + +void on_off(void *d, char *item, int *a, int onoff) +{ + onoff_group(d, item, a, onoff); + onoff_id(d, item, a, onoff); +} diff --git a/tracer/defs.h b/tracer/defs.h index 6c2a026600..71b9dd0cfb 100644 --- a/tracer/defs.h +++ b/tracer/defs.h @@ -1,7 +1,7 @@ #ifndef _TRACER_DEFS_H_ #define _TRACER_DEFS_H_ -void *make_plot(int width, int height, int bufsize); +void *make_plot(int width, int height, int bufsize, char *title); void plot_set(void *plot, float *data, int len, int pos); void iq_plot_set(void *plot, short *data, int len, int pos); @@ -10,5 +10,6 @@ void *parse_database(char *filename); void dump_database(void *database); void list_ids(void *database); void list_groups(void *database); +void on_off(void *d, char *item, int *a, int onoff); #endif /* _TRACER_DEFS_H_ */ diff --git a/tracer/main.c b/tracer/main.c index fb5fcc99d9..37774be4e5 100644 --- a/tracer/main.c +++ b/tracer/main.c @@ -15,6 +15,7 @@ #include "../T_defs.h" void *ul_plot; +void *chest_plot; #ifdef T_USE_SHARED_MEMORY @@ -209,11 +210,30 @@ void get_message(int s) GET(s, &antenna, sizeof(int)); GET(s, &size, sizeof(int)); GET(s, buf, size); +#if 0 printf("got T_ENB_INPUT_SIGNAL eNB %d frame %d subframe %d antenna %d size %d %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x\n", eNB, frame, subframe, antenna, size, buf[0],buf[1],buf[2],buf[3],buf[4],buf[5],buf[6],buf[7],buf[8],buf[9],buf[10],buf[11],buf[12],buf[13],buf[14],buf[15]); +#endif if (size != 4 * 7680) {printf("bad T_ENB_INPUT_SIGNAL, only 7680 samples allowed\n");abort();} - iq_plot_set(ul_plot, (short*)buf, 7680, subframe*7680); + if (ul_plot) iq_plot_set(ul_plot, (short*)buf, 7680, subframe*7680); + break; + } + case T_ENB_UL_CHANNEL_ESTIMATE: { + unsigned char buf[T_BUFFER_MAX]; + int size; + int eNB, UE, frame, subframe, antenna; + GET(s, &eNB, sizeof(int)); + GET(s, &UE, sizeof(int)); + GET(s, &frame, sizeof(int)); + GET(s, &subframe, sizeof(int)); + GET(s, &antenna, sizeof(int)); + GET(s, &size, sizeof(int)); + GET(s, buf, size); + if (size != 512*4) + {printf("bad T_ENB_UL_CHANNEL_ESTIMATE, only 512 samples allowed\n"); + abort();} + if (chest_plot) iq_plot_set(chest_plot, (short*)buf, 512, 0); break; } case T_buf_test: { @@ -265,6 +285,11 @@ void usage(void) " -li print IDs in the database\n" " -lg print GROUPs in the database\n" " -dump dump the database\n" +" -x run with XFORMS (revisited)\n" +" -on turn log ON for given GROUP or ID\n" +" -off turn log OFF for given GROUP or ID\n" +"note: you may pass several -on and -off, they will be processed in order\n" +" by default, all is off\n" ); exit(1); } @@ -280,6 +305,16 @@ int main(int n, char **v) int do_list_ids = 0; int do_list_groups = 0; int do_dump_database = 0; + int do_xforms = 0; + char **on_off_name; + int *on_off_action; + int on_off_n = 0; + int is_on[T_NUMBER_OF_IDS]; + + memset(is_on, 0, sizeof(is_on)); + + on_off_name = malloc(n * sizeof(char *)); if (on_off_name == NULL) abort(); + on_off_action = malloc(n * sizeof(int)); if (on_off_action == NULL) abort(); for (i = 1; i < n; i++) { if (!strcmp(v[i], "-h") || !strcmp(v[i], "--help")) usage(); @@ -288,6 +323,12 @@ int main(int n, char **v) if (!strcmp(v[i], "-li")) { do_list_ids = 1; continue; } if (!strcmp(v[i], "-lg")) { do_list_groups = 1; continue; } if (!strcmp(v[i], "-dump")) { do_dump_database = 1; continue; } + if (!strcmp(v[i], "-x")) { do_xforms = 1; continue; } + if (!strcmp(v[i], "-on")) { if (i > n-2) usage(); + on_off_name[on_off_n]=v[++i]; on_off_action[on_off_n++]=1; continue; } + if (!strcmp(v[i], "-off")) { if (i > n-2) usage(); + on_off_name[on_off_n]=v[++i]; on_off_action[on_off_n++]=0; continue; } + printf("ERROR: unknown option %s\n", v[i]); usage(); } @@ -303,7 +344,13 @@ int main(int n, char **v) if (do_list_groups) { list_groups(database); return 0; } if (do_dump_database) { dump_database(database); return 0; } - ul_plot = make_plot(512, 100, 7680*2*10); + if (do_xforms) { + ul_plot = make_plot(512, 100, 7680*2*10, "UL Input Signal"); + chest_plot = make_plot(512, 100, 512*2, "UL Channel Estimate UE 0"); + } + + for (i = 0; i < on_off_n; i++) + on_off(database, on_off_name[i], is_on, on_off_action[i]); #ifdef T_USE_SHARED_MEMORY init_shm(); @@ -312,10 +359,12 @@ int main(int n, char **v) /* send the first message - activate all traces */ t = 0; if (write(s, &t, 1) != 1) abort(); - l = T_NUMBER_OF_IDS; + l = 0; + for (i = 0; i < T_NUMBER_OF_IDS; i++) if (is_on[i]) l++; if (write(s, &l, sizeof(int)) != sizeof(int)) abort(); for (l = 0; l < T_NUMBER_OF_IDS; l++) - if (write(s, &l, sizeof(int)) != sizeof(int)) abort(); + if (is_on[l]) + if (write(s, &l, sizeof(int)) != sizeof(int)) abort(); /* read messages */ while (1) { diff --git a/tracer/plot.c b/tracer/plot.c index ba203b0886..3cc0ad069f 100644 --- a/tracer/plot.c +++ b/tracer/plot.c @@ -44,15 +44,15 @@ static void *plot_thread(void *_p) { int i; - for (i = 0; i < 512*150; i++) + for (i = 0; i < p->bufsize/2; i++) p->buf[i] = 10*log10(1.0+(float)(p->iqbuf[2*i]*p->iqbuf[2*i]+ p->iqbuf[2*i+1]*p->iqbuf[2*i+1])); } s = p->buf; for (i = 0; i < 512; i++) { v = 0; - for (j = 0; j < 150; j++, s++) v += *s; - v /= 150; + for (j = 0; j < p->bufsize/2/512; j++, s++) v += *s; + v /= p->bufsize/2/512; XDrawLine(p->d, p->p, DefaultGC(p->d, DefaultScreen(p->d)), i, 100, i, 100-v); } @@ -79,7 +79,7 @@ static void new_thread(void *(*f)(void *), void *data) { fprintf(stderr, "pthread_attr_destroy err\n"); exit(1); } } -void *make_plot(int width, int height, int bufsize) +void *make_plot(int width, int height, int bufsize, char *title) { plot *p; Display *d; @@ -92,6 +92,8 @@ void *make_plot(int width, int height, int bufsize) XSelectInput(d, w, ExposureMask); XMapWindow(d, w); + XStoreName(d, w, title); + pm = XCreatePixmap(d, w, width, height, DefaultDepth(d, DefaultScreen(d))); p = malloc(sizeof(*p)); if (p == NULL) abort(); From 9f0789e0d02193be156e79312f0423f88abb0a75 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Wed, 16 Mar 2016 17:41:16 +0100 Subject: [PATCH 08/28] - add groups in T_messages.txt - minor fix --- T_messages.txt | 200 ++++++++++++++++++++++++++++++++++++++++++++++ tracer/database.c | 2 +- 2 files changed, 201 insertions(+), 1 deletion(-) diff --git a/T_messages.txt b/T_messages.txt index 043062c598..ba6197b569 100644 --- a/T_messages.txt +++ b/T_messages.txt @@ -42,128 +42,328 @@ ID = LEGACY_PHY_TRACE GROUP = PHY:TRACE:LEGACY ID = LEGACY_S1AP_INFO + DESC = S1AP legacy logs - info level + GROUP = S1AP:INFO:LEGACY ID = LEGACY_S1AP_ERROR + DESC = S1AP legacy logs - error level + GROUP = S1AP:ERROR:LEGACY ID = LEGACY_S1AP_WARNING + DESC = S1AP legacy logs - warning level + GROUP = S1AP:WARNING:LEGACY ID = LEGACY_S1AP_DEBUG + DESC = S1AP legacy logs - debug level + GROUP = S1AP:DEBUG:LEGACY ID = LEGACY_S1AP_TRACE + DESC = S1AP legacy logs - trace level + GROUP = S1AP:TRACE:LEGACY ID = LEGACY_RRC_INFO + DESC = RRC legacy logs - info level + GROUP = RRC:INFO:LEGACY ID = LEGACY_RRC_ERROR + DESC = RRC legacy logs - error level + GROUP = RRC:ERROR:LEGACY ID = LEGACY_RRC_WARNING + DESC = RRC legacy logs - warning level + GROUP = RRC:WARNING:LEGACY ID = LEGACY_RRC_DEBUG + DESC = RRC legacy logs - debug level + GROUP = RRC:DEBUG:LEGACY ID = LEGACY_RRC_TRACE + DESC = RRC legacy logs - trace level + GROUP = RRC:TRACE:LEGACY ID = LEGACY_RLC_INFO + DESC = RLC legacy logs - info level + GROUP = RLC:INFO:LEGACY ID = LEGACY_RLC_ERROR + DESC = RLC legacy logs - error level + GROUP = RLC:ERROR:LEGACY ID = LEGACY_RLC_WARNING + DESC = RLC legacy logs - warning level + GROUP = RLC:WARNING:LEGACY ID = LEGACY_RLC_DEBUG + DESC = RLC legacy logs - debug level + GROUP = RLC:DEBUG:LEGACY ID = LEGACY_RLC_TRACE + DESC = RLC legacy logs - trace level + GROUP = RLC:TRACE:LEGACY ID = LEGACY_PDCP_INFO + DESC = PDCP legacy logs - info level + GROUP = PDCP:INFO:LEGACY ID = LEGACY_PDCP_ERROR + DESC = PDCP legacy logs - error level + GROUP = PDCP:ERROR:LEGACY ID = LEGACY_PDCP_WARNING + DESC = PDCP legacy logs - warning level + GROUP = PDCP:WARNING:LEGACY ID = LEGACY_PDCP_DEBUG + DESC = PDCP legacy logs - debug level + GROUP = PDCP:DEBUG:LEGACY ID = LEGACY_PDCP_TRACE + DESC = PDCP legacy logs - trace level + GROUP = PDCP:TRACE:LEGACY ID = LEGACY_ENB_APP_INFO + DESC = ENB_APP legacy logs - info level + GROUP = ENB_APP:INFO:LEGACY ID = LEGACY_ENB_APP_ERROR + DESC = ENB_APP legacy logs - error level + GROUP = ENB_APP:ERROR:LEGACY ID = LEGACY_ENB_APP_WARNING + DESC = ENB_APP legacy logs - warning level + GROUP = ENB_APP:WARNING:LEGACY ID = LEGACY_ENB_APP_DEBUG + DESC = ENB_APP legacy logs - debug level + GROUP = ENB_APP:DEBUG:LEGACY ID = LEGACY_ENB_APP_TRACE + DESC = ENB_APP legacy logs - trace level + GROUP = ENB_APP:TRACE:LEGACY ID = LEGACY_SCTP_INFO + DESC = SCTP legacy logs - info level + GROUP = SCTP:INFO:LEGACY ID = LEGACY_SCTP_ERROR + DESC = SCTP legacy logs - error level + GROUP = SCTP:ERROR:LEGACY ID = LEGACY_SCTP_WARNING + DESC = SCTP legacy logs - warning level + GROUP = SCTP:WARNING:LEGACY ID = LEGACY_SCTP_DEBUG + DESC = SCTP legacy logs - debug level + GROUP = SCTP:DEBUG:LEGACY ID = LEGACY_SCTP_TRACE + DESC = SCTP legacy logs - trace level + GROUP = SCTP:TRACE:LEGACY ID = LEGACY_UDP__INFO + DESC = UDP_ legacy logs - info level + GROUP = UDP_:INFO:LEGACY ID = LEGACY_UDP__ERROR + DESC = UDP_ legacy logs - error level + GROUP = UDP_:ERROR:LEGACY ID = LEGACY_UDP__WARNING + DESC = UDP_ legacy logs - warning level + GROUP = UDP_:WARNING:LEGACY ID = LEGACY_UDP__DEBUG + DESC = UDP_ legacy logs - debug level + GROUP = UDP_:DEBUG:LEGACY ID = LEGACY_UDP__TRACE + DESC = UDP_ legacy logs - trace level + GROUP = UDP_:TRACE:LEGACY ID = LEGACY_NAS_INFO + DESC = NAS legacy logs - info level + GROUP = NAS:INFO:LEGACY ID = LEGACY_NAS_ERROR + DESC = NAS legacy logs - error level + GROUP = NAS:ERROR:LEGACY ID = LEGACY_NAS_WARNING + DESC = NAS legacy logs - warning level + GROUP = NAS:WARNING:LEGACY ID = LEGACY_NAS_DEBUG + DESC = NAS legacy logs - debug level + GROUP = NAS:DEBUG:LEGACY ID = LEGACY_NAS_TRACE + DESC = NAS legacy logs - trace level + GROUP = NAS:TRACE:LEGACY ID = LEGACY_HW_INFO + DESC = HW legacy logs - info level + GROUP = HW:INFO:LEGACY ID = LEGACY_HW_ERROR + DESC = HW legacy logs - error level + GROUP = HW:ERROR:LEGACY ID = LEGACY_HW_WARNING + DESC = HW legacy logs - warning level + GROUP = HW:WARNING:LEGACY ID = LEGACY_HW_DEBUG + DESC = HW legacy logs - debug level + GROUP = HW:DEBUG:LEGACY ID = LEGACY_HW_TRACE + DESC = HW legacy logs - trace level + GROUP = HW:TRACE:LEGACY ID = LEGACY_EMU_INFO + DESC = EMU legacy logs - info level + GROUP = EMU:INFO:LEGACY ID = LEGACY_EMU_ERROR + DESC = EMU legacy logs - error level + GROUP = EMU:ERROR:LEGACY ID = LEGACY_EMU_WARNING + DESC = EMU legacy logs - warning level + GROUP = EMU:WARNING:LEGACY ID = LEGACY_EMU_DEBUG + DESC = EMU legacy logs - debug level + GROUP = EMU:DEBUG:LEGACY ID = LEGACY_EMU_TRACE + DESC = EMU legacy logs - trace level + GROUP = EMU:TRACE:LEGACY ID = LEGACY_OTG_INFO + DESC = OTG legacy logs - info level + GROUP = OTG:INFO:LEGACY ID = LEGACY_OTG_ERROR + DESC = OTG legacy logs - error level + GROUP = OTG:ERROR:LEGACY ID = LEGACY_OTG_WARNING + DESC = OTG legacy logs - warning level + GROUP = OTG:WARNING:LEGACY ID = LEGACY_OTG_DEBUG + DESC = OTG legacy logs - debug level + GROUP = OTG:DEBUG:LEGACY ID = LEGACY_OTG_TRACE + DESC = OTG legacy logs - trace level + GROUP = OTG:TRACE:LEGACY ID = LEGACY_OCG_INFO + DESC = OCG legacy logs - info level + GROUP = OCG:INFO:LEGACY ID = LEGACY_OCG_ERROR + DESC = OCG legacy logs - error level + GROUP = OCG:ERROR:LEGACY ID = LEGACY_OCG_WARNING + DESC = OCG legacy logs - warning level + GROUP = OCG:WARNING:LEGACY ID = LEGACY_OCG_DEBUG + DESC = OCG legacy logs - debug level + GROUP = OCG:DEBUG:LEGACY ID = LEGACY_OCG_TRACE + DESC = OCG legacy logs - trace level + GROUP = OCG:TRACE:LEGACY ID = LEGACY_OMG_INFO + DESC = OMG legacy logs - info level + GROUP = OMG:INFO:LEGACY ID = LEGACY_OMG_ERROR + DESC = OMG legacy logs - error level + GROUP = OMG:ERROR:LEGACY ID = LEGACY_OMG_WARNING + DESC = OMG legacy logs - warning level + GROUP = OMG:WARNING:LEGACY ID = LEGACY_OMG_DEBUG + DESC = OMG legacy logs - debug level + GROUP = OMG:DEBUG:LEGACY ID = LEGACY_OMG_TRACE + DESC = OMG legacy logs - trace level + GROUP = OMG:TRACE:LEGACY ID = LEGACY_OPT_INFO + DESC = OPT legacy logs - info level + GROUP = OPT:INFO:LEGACY ID = LEGACY_OPT_ERROR + DESC = OPT legacy logs - error level + GROUP = OPT:ERROR:LEGACY ID = LEGACY_OPT_WARNING + DESC = OPT legacy logs - warning level + GROUP = OPT:WARNING:LEGACY ID = LEGACY_OPT_DEBUG + DESC = OPT legacy logs - debug level + GROUP = OPT:DEBUG:LEGACY ID = LEGACY_OPT_TRACE + DESC = OPT legacy logs - trace level + GROUP = OPT:TRACE:LEGACY ID = LEGACY_GTPU_INFO + DESC = GTPU legacy logs - info level + GROUP = GTPU:INFO:LEGACY ID = LEGACY_GTPU_ERROR + DESC = GTPU legacy logs - error level + GROUP = GTPU:ERROR:LEGACY ID = LEGACY_GTPU_WARNING + DESC = GTPU legacy logs - warning level + GROUP = GTPU:WARNING:LEGACY ID = LEGACY_GTPU_DEBUG + DESC = GTPU legacy logs - debug level + GROUP = GTPU:DEBUG:LEGACY ID = LEGACY_GTPU_TRACE + DESC = GTPU legacy logs - trace level + GROUP = GTPU:TRACE:LEGACY ID = LEGACY_TMR_INFO + DESC = TMR legacy logs - info level + GROUP = TMR:INFO:LEGACY ID = LEGACY_TMR_ERROR + DESC = TMR legacy logs - error level + GROUP = TMR:ERROR:LEGACY ID = LEGACY_TMR_WARNING + DESC = TMR legacy logs - warning level + GROUP = TMR:WARNING:LEGACY ID = LEGACY_TMR_DEBUG + DESC = TMR legacy logs - debug level + GROUP = TMR:DEBUG:LEGACY ID = LEGACY_TMR_TRACE + DESC = TMR legacy logs - trace level + GROUP = TMR:TRACE:LEGACY ID = LEGACY_OSA_INFO + DESC = OSA legacy logs - info level + GROUP = OSA:INFO:LEGACY ID = LEGACY_OSA_ERROR + DESC = OSA legacy logs - error level + GROUP = OSA:ERROR:LEGACY ID = LEGACY_OSA_WARNING + DESC = OSA legacy logs - warning level + GROUP = OSA:WARNING:LEGACY ID = LEGACY_OSA_DEBUG + DESC = OSA legacy logs - debug level + GROUP = OSA:DEBUG:LEGACY ID = LEGACY_OSA_TRACE + DESC = OSA legacy logs - trace level + GROUP = OSA:TRACE:LEGACY # this is a bad hack but I won't fix (function util_print_hex_octets # in openairinterface5g/openair2/LAYER2/PDCP_v10.1.0/pdcp_util.c # does funky things with the LOG_x macros but we work on the C pre-processor # level and this funkyness is not easily dealable with, so be it...) ID = LEGACY_component_INFO + DESC = component legacy logs - info level + GROUP = component:INFO:LEGACY ID = LEGACY_component_ERROR + DESC = component legacy logs - error level + GROUP = component:ERROR:LEGACY ID = LEGACY_component_WARNING + DESC = component legacy logs - warning level + GROUP = component:WARNING:LEGACY ID = LEGACY_component_DEBUG + DESC = component legacy logs - debug level + GROUP = component:DEBUG:LEGACY ID = LEGACY_component_TRACE + DESC = component legacy logs - trace level + GROUP = component:TRACE:LEGACY ID = LEGACY_componentP_INFO + DESC = componentP legacy logs - info level + GROUP = componentP:INFO:LEGACY ID = LEGACY_componentP_ERROR + DESC = componentP legacy logs - error level + GROUP = componentP:ERROR:LEGACY ID = LEGACY_componentP_WARNING + DESC = componentP legacy logs - warning level + GROUP = componentP:WARNING:LEGACY ID = LEGACY_componentP_DEBUG + DESC = componentP legacy logs - debug level + GROUP = componentP:DEBUG:LEGACY ID = LEGACY_componentP_TRACE + DESC = componentP legacy logs - trace level + GROUP = componentP:TRACE:LEGACY #needed? ID = LEGACY_CLI_INFO + DESC = CLI legacy logs - info level + GROUP = CLI:INFO:LEGACY ID = LEGACY_CLI_ERROR + DESC = CLI legacy logs - error level + GROUP = CLI:ERROR:LEGACY ID = LEGACY_CLI_WARNING + DESC = CLI legacy logs - warning level + GROUP = CLI:WARNING:LEGACY ID = LEGACY_CLI_DEBUG + DESC = CLI legacy logs - debug level + GROUP = CLI:DEBUG:LEGACY ID = LEGACY_CLI_TRACE + DESC = CLI legacy logs - trace level + GROUP = CLI:TRACE:LEGACY #for debug/test - not used ID = first diff --git a/tracer/database.c b/tracer/database.c index 3172105250..a430d1a696 100644 --- a/tracer/database.c +++ b/tracer/database.c @@ -292,7 +292,7 @@ static void onoff_id(database *d, char *name, int *a, int onoff) i = bsearch(&(id){name:name}, d->i, d->isize, sizeof(id), id_cmp); if (i == NULL) return; a[i->id] = onoff; - printf("turning %s %s\n", name, onoff ? "ON" : "OFF"); + printf("turning %s %s\n", onoff ? "ON" : "OFF", name); } static void onoff_group(database *d, char *name, int *a, int onoff) From 2d10951a2ed9d9c6dc312097aca5d4ae9a30f331 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Fri, 18 Mar 2016 12:10:49 +0100 Subject: [PATCH 09/28] introduce T_TRACER to globally enable/disable the T --- Makefile | 2 +- T.h | 9 +++++++++ tracer/Makefile | 4 ++-- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index c65ed27b8e..27e1c8a5c0 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ CC=gcc -CFLAGS=-Wall -g -pthread +CFLAGS=-Wall -g -pthread -DT_TRACER #comment those two lines to NOT use shared memory CFLAGS += -DT_USE_SHARED_MEMORY diff --git a/T.h b/T.h index 46c5bdc180..d88f33a81c 100644 --- a/T.h +++ b/T.h @@ -1,6 +1,8 @@ #ifndef _T_T_T_ #define _T_T_T_ +#if T_TRACER + #include #include "T_defs.h" @@ -517,4 +519,11 @@ extern int *T_active; void T_connect_to_tracer(char *addr, int port); +#else /* T_TRACER */ + +/* if T_TRACER is not defined or is 0, the T is deactivated */ +#define T(...) /**/ + +#endif /* T_TRACER */ + #endif /* _T_T_T_ */ diff --git a/tracer/Makefile b/tracer/Makefile index 23309eb85e..a38ba5c2c6 100644 --- a/tracer/Makefile +++ b/tracer/Makefile @@ -1,7 +1,7 @@ CC=gcc -CFLAGS=-Wall -g -pthread +CFLAGS=-Wall -g -pthread -DT_TRACER -CFLAGS += -O3 -ffast-math -fomit-frame-pointer +#CFLAGS += -O3 -ffast-math -fomit-frame-pointer LIBS=-lX11 -lm From fa49fe6780b575345eeb5487fe60e39a26c74340 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Fri, 18 Mar 2016 12:11:42 +0100 Subject: [PATCH 10/28] - add PUSCH/PUCCH plots - update X events management - lock to protect data while plotting (may become a problem in the future) - better naming of dimensions this commit should be cut in small pieces bah --- T_messages.txt | 8 +++ tracer/defs.h | 8 ++- tracer/main.c | 47 ++++++++++++- tracer/plot.c | 176 ++++++++++++++++++++++++++++++++++++++++--------- 4 files changed, 204 insertions(+), 35 deletions(-) diff --git a/T_messages.txt b/T_messages.txt index ba6197b569..f954dd46ec 100644 --- a/T_messages.txt +++ b/T_messages.txt @@ -7,6 +7,14 @@ ID = ENB_UL_CHANNEL_ESTIMATE DESC = eNodeB channel estimation in the time domain GROUP = PHY:GRAPHIC:HEAVY FORMAT = int,eNB_ID : int,UE_ID : int,frame : int,subframe : int,antenna : buffer,chest_t +ID = PUSCH_IQ + DESC = eNodeB PUSCH received IQ data + GROUP = PHY:GRAPHIC:HEAVY + FORMAT = int,eNB_ID : int,UE_ID : int,frame : int,subframe : int,nb_rb : buffer,pusch_comp +ID = PUCCH_1AB_IQ + DESC = eNodeB PUCCH received IQ data + GROUP = PHY:GRAPHIC:HEAVY + FORMAT = int,eNB_ID : int,UE_ID : int,frame : int,subframe : int,I : int,Q #legacy logs ID = LEGACY_MAC_INFO diff --git a/tracer/defs.h b/tracer/defs.h index 71b9dd0cfb..873292a70c 100644 --- a/tracer/defs.h +++ b/tracer/defs.h @@ -1,9 +1,15 @@ #ifndef _TRACER_DEFS_H_ #define _TRACER_DEFS_H_ -void *make_plot(int width, int height, int bufsize, char *title); +/* types of plots */ +#define PLOT_VS_TIME 0 +#define PLOT_IQ_POINTS 1 + +void *make_plot(int width, int height, int bufsize, char *title, int type); void plot_set(void *plot, float *data, int len, int pos); void iq_plot_set(void *plot, short *data, int len, int pos); +void iq_plot_set_sized(void *_plot, short *data, int len); +void iq_plot_add_point_loop(void *_plot, short i, short q); /* returns an opaque pointer - truly a 'database *', see t_data.c */ void *parse_database(char *filename); diff --git a/tracer/main.c b/tracer/main.c index 37774be4e5..853ed46fed 100644 --- a/tracer/main.c +++ b/tracer/main.c @@ -16,6 +16,8 @@ void *ul_plot; void *chest_plot; +void *pusch_iq_plot; +void *pucch_iq_plot; #ifdef T_USE_SHARED_MEMORY @@ -236,6 +238,44 @@ void get_message(int s) if (chest_plot) iq_plot_set(chest_plot, (short*)buf, 512, 0); break; } + case T_PUSCH_IQ: { + unsigned char buf[T_BUFFER_MAX]; + int size; + int eNB, UE, frame, subframe, nb_rb; + GET(s, &eNB, sizeof(int)); + GET(s, &UE, sizeof(int)); + GET(s, &frame, sizeof(int)); + GET(s, &subframe, sizeof(int)); + GET(s, &nb_rb, sizeof(int)); + GET(s, &size, sizeof(int)); + GET(s, buf, size); + if (size != 12*25*14*4) + {printf("bad T_PUSCH_IQ, we want 25 RBs and 14 symbols/TTI\n"); + abort();} + if (pusch_iq_plot) { + uint32_t *src, *dst; + int i, l; + dst = (uint32_t*)buf; + for (l = 0; l < 14; l++) { + src = (uint32_t*)buf + l * 12 * 25; + for (i = 0; i < nb_rb*12; i++) *dst++ = *src++; + } + iq_plot_set_sized(pusch_iq_plot, (short*)buf, nb_rb*12*14); + } + break; + } + case T_PUCCH_1AB_IQ: { + int eNB, UE, frame, subframe, I, Q; + GET(s, &eNB, sizeof(int)); + GET(s, &UE, sizeof(int)); + GET(s, &frame, sizeof(int)); + GET(s, &subframe, sizeof(int)); + GET(s, &I, sizeof(int)); + GET(s, &Q, sizeof(int)); +printf("receiving %d %d\n", I, Q); + if (pucch_iq_plot) iq_plot_add_point_loop(pucch_iq_plot, I*10, Q*10); + break; + } case T_buf_test: { unsigned char buf[T_BUFFER_MAX]; int size; @@ -345,8 +385,11 @@ int main(int n, char **v) if (do_dump_database) { dump_database(database); return 0; } if (do_xforms) { - ul_plot = make_plot(512, 100, 7680*2*10, "UL Input Signal"); - chest_plot = make_plot(512, 100, 512*2, "UL Channel Estimate UE 0"); + ul_plot = make_plot(512, 100, 7680*10, "UL Input Signal", PLOT_VS_TIME); + chest_plot = make_plot(512, 100, 512, "UL Channel Estimate UE 0", + PLOT_VS_TIME); + pusch_iq_plot = make_plot(100, 100, 12*25*14, "PUSCH IQ",PLOT_IQ_POINTS); + pucch_iq_plot = make_plot(100, 100, 1000, "PUCCH IQ", PLOT_IQ_POINTS); } for (i = 0; i < on_off_n; i++) diff --git a/tracer/plot.c b/tracer/plot.c index 3cc0ad069f..e13398ab5e 100644 --- a/tracer/plot.c +++ b/tracer/plot.c @@ -6,6 +6,8 @@ #include #include #include +#include +#include typedef struct { Display *d; @@ -15,50 +17,117 @@ typedef struct { int height; float *buf; short *iqbuf; - int bufsize; + int count; + int type; + volatile int iq_count; /* for ULSCH IQ data */ + int iq_insert_pos; + pthread_mutex_t lock; + float zoom; + int timer_pipe[2]; } plot; +static void *timer_thread(void *_p) +{ + plot *p = _p; + char c; + + while (1) { + /* more or less 10Hz */ + usleep(100*1000); + c = 1; + if (write(p->timer_pipe[1], &c, 1) != 1) abort(); + } + + return NULL; +} + static void *plot_thread(void *_p) { float v; float *s; int i, j; plot *p = _p; + int redraw = 0; + int replot = 0; + fd_set rset; + int xfd = ConnectionNumber(p->d); + int maxfd = xfd > p->timer_pipe[0] ? xfd : p->timer_pipe[0]; + while (1) { while (XPending(p->d)) { XEvent e; XNextEvent(p->d, &e); + switch (e.type) { + case ButtonPress: + /* button 4: zoom out */ + if (e.xbutton.button == 4) { p->zoom = p->zoom * 1.25; replot = 1; } + /* button 5: zoom in */ + if (e.xbutton.button == 5) { p->zoom = p->zoom * 0.8; replot = 1; } + printf("zoom: %f\n", p->zoom); + break; + case Expose: redraw = 1; break; + } } - { + if (replot == 1) { + replot = 0; + redraw = 1; + /* TODO: get white & black GCs at startup */ - GC gc; - XGCValues v; - gc = DefaultGC(p->d, DefaultScreen(p->d)); - v.foreground = WhitePixel(p->d, DefaultScreen(p->d)); - XChangeGC(p->d, gc, GCForeground, &v); - XFillRectangle(p->d, p->p, gc, 0, 0, p->width, p->height); - v.foreground = BlackPixel(p->d, DefaultScreen(p->d)); - XChangeGC(p->d, gc, GCForeground, &v); + { + GC gc; + XGCValues v; + gc = DefaultGC(p->d, DefaultScreen(p->d)); + v.foreground = WhitePixel(p->d, DefaultScreen(p->d)); + XChangeGC(p->d, gc, GCForeground, &v); + XFillRectangle(p->d, p->p, gc, 0, 0, p->width, p->height); + v.foreground = BlackPixel(p->d, DefaultScreen(p->d)); + XChangeGC(p->d, gc, GCForeground, &v); + } + + if (pthread_mutex_lock(&p->lock)) abort(); + + if (p->type == PLOT_VS_TIME) { + for (i = 0; i < p->count; i++) + p->buf[i] = 10*log10(1.0+(float)(p->iqbuf[2*i]*p->iqbuf[2*i]+ + p->iqbuf[2*i+1]*p->iqbuf[2*i+1])); + s = p->buf; + for (i = 0; i < 512; i++) { + v = 0; + for (j = 0; j < p->count/512; j++, s++) v += *s; + v /= p->count/512; + XDrawLine(p->d, p->p, DefaultGC(p->d, DefaultScreen(p->d)), + i, 100, i, 100-v); + } + } else if (p->type == PLOT_IQ_POINTS) { + XPoint pts[p->iq_count]; + int count = p->iq_count; + for (i = 0; i < count; i++) { + pts[i].x = p->iqbuf[2*i]*p->zoom/20+50; + pts[i].y = -p->iqbuf[2*i+1]*p->zoom/20+50; + } + XDrawPoints(p->d, p->p, DefaultGC(p->d, DefaultScreen(p->d)), + pts, count, CoordModeOrigin); + } + + if (pthread_mutex_unlock(&p->lock)) abort(); } - { - int i; - for (i = 0; i < p->bufsize/2; i++) - p->buf[i] = 10*log10(1.0+(float)(p->iqbuf[2*i]*p->iqbuf[2*i]+ - p->iqbuf[2*i+1]*p->iqbuf[2*i+1])); - } - s = p->buf; - for (i = 0; i < 512; i++) { - v = 0; - for (j = 0; j < p->bufsize/2/512; j++, s++) v += *s; - v /= p->bufsize/2/512; - XDrawLine(p->d, p->p, DefaultGC(p->d, DefaultScreen(p->d)), i, 100, i, 100-v); + if (redraw) { + redraw = 0; + XCopyArea(p->d, p->p, p->w, DefaultGC(p->d, DefaultScreen(p->d)), + 0, 0, p->width, p->height, 0, 0); } - XCopyArea(p->d, p->p, p->w, DefaultGC(p->d, DefaultScreen(p->d)), - 0, 0, p->width, p->height, 0, 0); - usleep(100*1000); + FD_ZERO(&rset); + FD_SET(p->timer_pipe[0], &rset); + FD_SET(xfd, &rset); + if (select(maxfd+1, &rset, NULL, NULL, NULL) == -1) abort(); + if (FD_ISSET(p->timer_pipe[0], &rset)) { + char b[512]; + read(p->timer_pipe[0], b, 512); + replot = 1; + } } return NULL; @@ -73,13 +142,15 @@ static void new_thread(void *(*f)(void *), void *data) { fprintf(stderr, "pthread_attr_init err\n"); exit(1); } if (pthread_attr_setdetachstate(&att, PTHREAD_CREATE_DETACHED)) { fprintf(stderr, "pthread_attr_setdetachstate err\n"); exit(1); } + if (pthread_attr_setstacksize(&att, 10000000)) + { fprintf(stderr, "pthread_attr_setstacksize err\n"); exit(1); } if (pthread_create(&t, &att, f, data)) { fprintf(stderr, "pthread_create err\n"); exit(1); } if (pthread_attr_destroy(&att)) { fprintf(stderr, "pthread_attr_destroy err\n"); exit(1); } } -void *make_plot(int width, int height, int bufsize, char *title) +void *make_plot(int width, int height, int count, char *title, int type) { plot *p; Display *d; @@ -89,7 +160,7 @@ void *make_plot(int width, int height, int bufsize, char *title) d = XOpenDisplay(0); if (d == NULL) abort(); w = XCreateSimpleWindow(d, DefaultRootWindow(d), 0, 0, width, height, 0, WhitePixel(d, DefaultScreen(d)), WhitePixel(d, DefaultScreen(d))); - XSelectInput(d, w, ExposureMask); + XSelectInput(d, w, ExposureMask | ButtonPressMask); XMapWindow(d, w); XStoreName(d, w, title); @@ -99,15 +170,31 @@ void *make_plot(int width, int height, int bufsize, char *title) p = malloc(sizeof(*p)); if (p == NULL) abort(); p->width = width; p->height = height; - p->buf = malloc(sizeof(float) * bufsize); if (p->buf == NULL) abort(); - p->iqbuf = malloc(sizeof(short) * 2 * bufsize); if (p->buf == NULL) abort(); - p->bufsize = bufsize; + if (type == PLOT_VS_TIME) { + p->buf = malloc(sizeof(float) * count); if (p->buf == NULL) abort(); + p->iqbuf = malloc(sizeof(short) * count * 2); if(p->iqbuf==NULL)abort(); + } else { + p->buf = NULL; + p->iqbuf = malloc(sizeof(short) * count * 2); if(p->iqbuf==NULL)abort(); + } + p->count = count; p->d = d; p->w = w; p->p = pm; + p->type = type; + + p->iq_count = 0; + p->iq_insert_pos = 0; + + p->zoom = 1; + + pthread_mutex_init(&p->lock, NULL); + + if (pipe(p->timer_pipe)) abort(); new_thread(plot_thread, p); + new_thread(timer_thread, p); return p; } @@ -115,11 +202,36 @@ void *make_plot(int width, int height, int bufsize, char *title) void plot_set(void *_plot, float *data, int len, int pos) { plot *p = _plot; + if (pthread_mutex_lock(&p->lock)) abort(); memcpy(p->buf + pos, data, len * sizeof(float)); + if (pthread_mutex_unlock(&p->lock)) abort(); } -void iq_plot_set(void *_plot, short *data, int len, int pos) +void iq_plot_set(void *_plot, short *data, int count, int pos) { plot *p = _plot; - memcpy(p->iqbuf + pos * 2, data, len * 2 * sizeof(short)); + if (pthread_mutex_lock(&p->lock)) abort(); + memcpy(p->iqbuf + pos * 2, data, count * 2 * sizeof(short)); + if (pthread_mutex_unlock(&p->lock)) abort(); +} + +void iq_plot_set_sized(void *_plot, short *data, int count) +{ + plot *p = _plot; + if (pthread_mutex_lock(&p->lock)) abort(); + memcpy(p->iqbuf, data, count * 2 * sizeof(short)); + p->iq_count = count; + if (pthread_mutex_unlock(&p->lock)) abort(); +} + +void iq_plot_add_point_loop(void *_plot, short i, short q) +{ + plot *p = _plot; + if (pthread_mutex_lock(&p->lock)) abort(); + p->iqbuf[p->iq_insert_pos*2] = i; + p->iqbuf[p->iq_insert_pos*2+1] = q; + if (p->iq_count != p->count) p->iq_count++; + p->iq_insert_pos++; + if (p->iq_insert_pos == p->count) p->iq_insert_pos = 0; + if (pthread_mutex_unlock(&p->lock)) abort(); } From b168a283a6f363d2c3061779625bb981f00a2635 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Fri, 18 Mar 2016 15:12:11 +0100 Subject: [PATCH 11/28] prepare code to handle more than one plot per plot - array of plots - deal with colors --- tracer/defs.h | 11 ++-- tracer/main.c | 21 +++--- tracer/plot.c | 175 +++++++++++++++++++++++++++++++------------------- 3 files changed, 127 insertions(+), 80 deletions(-) diff --git a/tracer/defs.h b/tracer/defs.h index 873292a70c..483e42ae90 100644 --- a/tracer/defs.h +++ b/tracer/defs.h @@ -5,11 +5,12 @@ #define PLOT_VS_TIME 0 #define PLOT_IQ_POINTS 1 -void *make_plot(int width, int height, int bufsize, char *title, int type); -void plot_set(void *plot, float *data, int len, int pos); -void iq_plot_set(void *plot, short *data, int len, int pos); -void iq_plot_set_sized(void *_plot, short *data, int len); -void iq_plot_add_point_loop(void *_plot, short i, short q); +/* ... is { int count; int type; char *color; } for 'nplots' plots */ +void *make_plot(int width, int height, char *title, int nplots, ...); +void plot_set(void *plot, float *data, int len, int pos, int pp); +void iq_plot_set(void *plot, short *data, int len, int pos, int pp); +void iq_plot_set_sized(void *_plot, short *data, int len, int pp); +void iq_plot_add_point_loop(void *_plot, short i, short q, int pp); /* returns an opaque pointer - truly a 'database *', see t_data.c */ void *parse_database(char *filename); diff --git a/tracer/main.c b/tracer/main.c index 853ed46fed..0b529b132b 100644 --- a/tracer/main.c +++ b/tracer/main.c @@ -218,7 +218,7 @@ void get_message(int s) #endif if (size != 4 * 7680) {printf("bad T_ENB_INPUT_SIGNAL, only 7680 samples allowed\n");abort();} - if (ul_plot) iq_plot_set(ul_plot, (short*)buf, 7680, subframe*7680); + if (ul_plot) iq_plot_set(ul_plot, (short*)buf, 7680, subframe*7680, 0); break; } case T_ENB_UL_CHANNEL_ESTIMATE: { @@ -235,7 +235,7 @@ void get_message(int s) if (size != 512*4) {printf("bad T_ENB_UL_CHANNEL_ESTIMATE, only 512 samples allowed\n"); abort();} - if (chest_plot) iq_plot_set(chest_plot, (short*)buf, 512, 0); + if (chest_plot) iq_plot_set(chest_plot, (short*)buf, 512, 0, 0); break; } case T_PUSCH_IQ: { @@ -260,7 +260,7 @@ void get_message(int s) src = (uint32_t*)buf + l * 12 * 25; for (i = 0; i < nb_rb*12; i++) *dst++ = *src++; } - iq_plot_set_sized(pusch_iq_plot, (short*)buf, nb_rb*12*14); + iq_plot_set_sized(pusch_iq_plot, (short*)buf, nb_rb*12*14, 0); } break; } @@ -273,7 +273,7 @@ void get_message(int s) GET(s, &I, sizeof(int)); GET(s, &Q, sizeof(int)); printf("receiving %d %d\n", I, Q); - if (pucch_iq_plot) iq_plot_add_point_loop(pucch_iq_plot, I*10, Q*10); + if (pucch_iq_plot) iq_plot_add_point_loop(pucch_iq_plot, I*10, Q*10, 0); break; } case T_buf_test: { @@ -385,11 +385,14 @@ int main(int n, char **v) if (do_dump_database) { dump_database(database); return 0; } if (do_xforms) { - ul_plot = make_plot(512, 100, 7680*10, "UL Input Signal", PLOT_VS_TIME); - chest_plot = make_plot(512, 100, 512, "UL Channel Estimate UE 0", - PLOT_VS_TIME); - pusch_iq_plot = make_plot(100, 100, 12*25*14, "PUSCH IQ",PLOT_IQ_POINTS); - pucch_iq_plot = make_plot(100, 100, 1000, "PUCCH IQ", PLOT_IQ_POINTS); + ul_plot = make_plot(512, 100, "UL Input Signal", 1, + 7680*10, PLOT_VS_TIME, "blue"); + chest_plot = make_plot(512, 100, "UL Channel Estimate UE 0", 1, + 512, PLOT_VS_TIME, "blue"); + pusch_iq_plot = make_plot(100, 100, "PUSCH IQ", 1, + 12*25*14, PLOT_IQ_POINTS, "blue"); + pucch_iq_plot = make_plot(100, 100, "PUCCH IQ", 1, + 1000, PLOT_IQ_POINTS, "blue"); } for (i = 0; i < on_off_n; i++) diff --git a/tracer/plot.c b/tracer/plot.c index e13398ab5e..bdb864f295 100644 --- a/tracer/plot.c +++ b/tracer/plot.c @@ -8,22 +8,30 @@ #include #include #include +#include typedef struct { - Display *d; - Window w; - Pixmap p; - int width; - int height; float *buf; short *iqbuf; int count; int type; volatile int iq_count; /* for ULSCH IQ data */ int iq_insert_pos; + GC g; +} data; + +typedef struct { + Display *d; + Window w; + Pixmap px; + GC bg; + int width; + int height; pthread_mutex_t lock; float zoom; int timer_pipe[2]; + data *p; /* list of plots */ + int nplots; } plot; static void *timer_thread(void *_p) @@ -52,6 +60,7 @@ static void *plot_thread(void *_p) fd_set rset; int xfd = ConnectionNumber(p->d); int maxfd = xfd > p->timer_pipe[0] ? xfd : p->timer_pipe[0]; + int pp; while (1) { while (XPending(p->d)) { @@ -73,41 +82,31 @@ static void *plot_thread(void *_p) replot = 0; redraw = 1; - /* TODO: get white & black GCs at startup */ - { - GC gc; - XGCValues v; - gc = DefaultGC(p->d, DefaultScreen(p->d)); - v.foreground = WhitePixel(p->d, DefaultScreen(p->d)); - XChangeGC(p->d, gc, GCForeground, &v); - XFillRectangle(p->d, p->p, gc, 0, 0, p->width, p->height); - v.foreground = BlackPixel(p->d, DefaultScreen(p->d)); - XChangeGC(p->d, gc, GCForeground, &v); - } - if (pthread_mutex_lock(&p->lock)) abort(); - if (p->type == PLOT_VS_TIME) { - for (i = 0; i < p->count; i++) - p->buf[i] = 10*log10(1.0+(float)(p->iqbuf[2*i]*p->iqbuf[2*i]+ - p->iqbuf[2*i+1]*p->iqbuf[2*i+1])); - s = p->buf; - for (i = 0; i < 512; i++) { - v = 0; - for (j = 0; j < p->count/512; j++, s++) v += *s; - v /= p->count/512; - XDrawLine(p->d, p->p, DefaultGC(p->d, DefaultScreen(p->d)), - i, 100, i, 100-v); + for (pp = 0; pp < p->nplots; pp++) { + XFillRectangle(p->d, p->px, p->bg, 0, 0, p->width, p->height); + if (p->p[pp].type == PLOT_VS_TIME) { + for (i = 0; i < p->p[pp].count; i++) + p->p[pp].buf[i] = + 10*log10(1.0+(float)(p->p[pp].iqbuf[2*i]*p->p[pp].iqbuf[2*i]+ + p->p[pp].iqbuf[2*i+1]*p->p[pp].iqbuf[2*i+1])); + s = p->p[pp].buf; + for (i = 0; i < 512; i++) { + v = 0; + for (j = 0; j < p->p[pp].count/512; j++, s++) v += *s; + v /= p->p[pp].count/512; + XDrawLine(p->d, p->px, p->p[pp].g, i, 100, i, 100-v); + } + } else if (p->p[pp].type == PLOT_IQ_POINTS) { + XPoint pts[p->p[pp].iq_count]; + int count = p->p[pp].iq_count; + for (i = 0; i < count; i++) { + pts[i].x = p->p[pp].iqbuf[2*i]*p->zoom/20+50; + pts[i].y = -p->p[pp].iqbuf[2*i+1]*p->zoom/20+50; + } + XDrawPoints(p->d, p->px, p->p[pp].g, pts, count, CoordModeOrigin); } - } else if (p->type == PLOT_IQ_POINTS) { - XPoint pts[p->iq_count]; - int count = p->iq_count; - for (i = 0; i < count; i++) { - pts[i].x = p->iqbuf[2*i]*p->zoom/20+50; - pts[i].y = -p->iqbuf[2*i+1]*p->zoom/20+50; - } - XDrawPoints(p->d, p->p, DefaultGC(p->d, DefaultScreen(p->d)), - pts, count, CoordModeOrigin); } if (pthread_mutex_unlock(&p->lock)) abort(); @@ -115,7 +114,7 @@ static void *plot_thread(void *_p) if (redraw) { redraw = 0; - XCopyArea(p->d, p->p, p->w, DefaultGC(p->d, DefaultScreen(p->d)), + XCopyArea(p->d, p->px, p->w, DefaultGC(p->d, DefaultScreen(p->d)), 0, 0, p->width, p->height, 0, 0); } @@ -125,7 +124,7 @@ static void *plot_thread(void *_p) if (select(maxfd+1, &rset, NULL, NULL, NULL) == -1) abort(); if (FD_ISSET(p->timer_pipe[0], &rset)) { char b[512]; - read(p->timer_pipe[0], b, 512); + if (read(p->timer_pipe[0], b, 512) <= 0) abort(); replot = 1; } } @@ -150,12 +149,17 @@ static void new_thread(void *(*f)(void *), void *data) { fprintf(stderr, "pthread_attr_destroy err\n"); exit(1); } } -void *make_plot(int width, int height, int count, char *title, int type) +void *make_plot(int width, int height, char *title, int nplots, ...) { plot *p; Display *d; Window w; Pixmap pm; + int i; + va_list ap; + XGCValues gcv; + + p = malloc(sizeof(*p)); if (p == NULL) abort(); d = XOpenDisplay(0); if (d == NULL) abort(); w = XCreateSimpleWindow(d, DefaultRootWindow(d), 0, 0, width, height, @@ -163,31 +167,70 @@ void *make_plot(int width, int height, int count, char *title, int type) XSelectInput(d, w, ExposureMask | ButtonPressMask); XMapWindow(d, w); + { + XSetWindowAttributes att; + att.backing_store = Always; + XChangeWindowAttributes(d, w, CWBackingStore, &att); + } + XStoreName(d, w, title); + p->bg = XCreateGC(d, w, 0, NULL); + XCopyGC(d, DefaultGC(d, DefaultScreen(d)), -1L, p->bg); + gcv.foreground = WhitePixel(d, DefaultScreen(d)); + XChangeGC(d, p->bg, GCForeground, &gcv); + pm = XCreatePixmap(d, w, width, height, DefaultDepth(d, DefaultScreen(d))); - p = malloc(sizeof(*p)); if (p == NULL) abort(); p->width = width; p->height = height; - if (type == PLOT_VS_TIME) { - p->buf = malloc(sizeof(float) * count); if (p->buf == NULL) abort(); - p->iqbuf = malloc(sizeof(short) * count * 2); if(p->iqbuf==NULL)abort(); - } else { - p->buf = NULL; - p->iqbuf = malloc(sizeof(short) * count * 2); if(p->iqbuf==NULL)abort(); + p->p = malloc(nplots * sizeof(data)); if (p->p == NULL) abort(); + + va_start(ap, nplots); + for (i = 0; i < nplots; i++) { + int count; + int type; + char *color; + XColor rcol, scol; + + count = va_arg(ap, int); + type = va_arg(ap, int); + color = va_arg(ap, char *); + + p->p[i].g = XCreateGC(d, w, 0, NULL); + XCopyGC(d, DefaultGC(d, DefaultScreen(d)), -1L, p->p[i].g); + if (XAllocNamedColor(d, DefaultColormap(d, DefaultScreen(d)), + color, &scol, &rcol)) { + gcv.foreground = scol.pixel; + XChangeGC(d, p->p[i].g, GCForeground, &gcv); + } else { + printf("could not allocate color '%s'\n", color); + abort(); + } + + if (type == PLOT_VS_TIME) { + p->p[i].buf = malloc(sizeof(float) * count); + if (p->p[i].buf == NULL) abort(); + p->p[i].iqbuf = malloc(sizeof(short) * count * 2); + if(p->p[i].iqbuf==NULL)abort(); + } else { + p->p[i].buf = NULL; + p->p[i].iqbuf = malloc(sizeof(short) * count * 2); + if(p->p[i].iqbuf==NULL)abort(); + } + p->p[i].count = count; + p->p[i].type = type; + p->p[i].iq_count = 0; + p->p[i].iq_insert_pos = 0; } - p->count = count; + va_end(ap); p->d = d; p->w = w; - p->p = pm; - p->type = type; - - p->iq_count = 0; - p->iq_insert_pos = 0; + p->px = pm; p->zoom = 1; + p->nplots = nplots; pthread_mutex_init(&p->lock, NULL); @@ -199,39 +242,39 @@ void *make_plot(int width, int height, int count, char *title, int type) return p; } -void plot_set(void *_plot, float *data, int len, int pos) +void plot_set(void *_plot, float *data, int len, int pos, int pp) { plot *p = _plot; if (pthread_mutex_lock(&p->lock)) abort(); - memcpy(p->buf + pos, data, len * sizeof(float)); + memcpy(p->p[pp].buf + pos, data, len * sizeof(float)); if (pthread_mutex_unlock(&p->lock)) abort(); } -void iq_plot_set(void *_plot, short *data, int count, int pos) +void iq_plot_set(void *_plot, short *data, int count, int pos, int pp) { plot *p = _plot; if (pthread_mutex_lock(&p->lock)) abort(); - memcpy(p->iqbuf + pos * 2, data, count * 2 * sizeof(short)); + memcpy(p->p[pp].iqbuf + pos * 2, data, count * 2 * sizeof(short)); if (pthread_mutex_unlock(&p->lock)) abort(); } -void iq_plot_set_sized(void *_plot, short *data, int count) +void iq_plot_set_sized(void *_plot, short *data, int count, int pp) { plot *p = _plot; if (pthread_mutex_lock(&p->lock)) abort(); - memcpy(p->iqbuf, data, count * 2 * sizeof(short)); - p->iq_count = count; + memcpy(p->p[pp].iqbuf, data, count * 2 * sizeof(short)); + p->p[pp].iq_count = count; if (pthread_mutex_unlock(&p->lock)) abort(); } -void iq_plot_add_point_loop(void *_plot, short i, short q) +void iq_plot_add_point_loop(void *_plot, short i, short q, int pp) { plot *p = _plot; if (pthread_mutex_lock(&p->lock)) abort(); - p->iqbuf[p->iq_insert_pos*2] = i; - p->iqbuf[p->iq_insert_pos*2+1] = q; - if (p->iq_count != p->count) p->iq_count++; - p->iq_insert_pos++; - if (p->iq_insert_pos == p->count) p->iq_insert_pos = 0; + p->p[pp].iqbuf[p->p[pp].iq_insert_pos*2] = i; + p->p[pp].iqbuf[p->p[pp].iq_insert_pos*2+1] = q; + if (p->p[pp].iq_count != p->p[pp].count) p->p[pp].iq_count++; + p->p[pp].iq_insert_pos++; + if (p->p[pp].iq_insert_pos == p->p[pp].count) p->p[pp].iq_insert_pos = 0; if (pthread_mutex_unlock(&p->lock)) abort(); } From 26a5da6cef019ee2b346f94568d057e7c3920113 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Fri, 18 Mar 2016 15:13:21 +0100 Subject: [PATCH 12/28] bugfix yes you need this xflush before sleeping into select... --- tracer/plot.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tracer/plot.c b/tracer/plot.c index bdb864f295..e9aa57a5d2 100644 --- a/tracer/plot.c +++ b/tracer/plot.c @@ -118,6 +118,8 @@ static void *plot_thread(void *_p) 0, 0, p->width, p->height, 0, 0); } + XFlush(p->d); + FD_ZERO(&rset); FD_SET(p->timer_pipe[0], &rset); FD_SET(xfd, &rset); From 9e083707624636bf3f5e58c6a5baf74d5655dedb Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Fri, 18 Mar 2016 19:05:16 +0100 Subject: [PATCH 13/28] add pucch energy plot --- T_messages.txt | 4 ++++ tracer/defs.h | 4 +++- tracer/main.c | 50 ++++++++++++++++++++++++++++++++++++++++---------- tracer/plot.c | 33 ++++++++++++++++++++++++++++++--- 4 files changed, 77 insertions(+), 14 deletions(-) diff --git a/T_messages.txt b/T_messages.txt index f954dd46ec..dd5dd8eec1 100644 --- a/T_messages.txt +++ b/T_messages.txt @@ -15,6 +15,10 @@ ID = PUCCH_1AB_IQ DESC = eNodeB PUCCH received IQ data GROUP = PHY:GRAPHIC:HEAVY FORMAT = int,eNB_ID : int,UE_ID : int,frame : int,subframe : int,I : int,Q +ID = PUCCH_1_ENERGY + DESC = eNodeB PUCCH 1 energy and threshold + GROUP = PHY:GRAPHIC:HEAVY + FORMAT = int,eNB_ID : int,UE_ID : int,frame : int,subframe : int,energy : int,threshold #legacy logs ID = LEGACY_MAC_INFO diff --git a/tracer/defs.h b/tracer/defs.h index 483e42ae90..231255b46d 100644 --- a/tracer/defs.h +++ b/tracer/defs.h @@ -4,13 +4,15 @@ /* types of plots */ #define PLOT_VS_TIME 0 #define PLOT_IQ_POINTS 1 +#define PLOT_MINMAX 2 /* ... is { int count; int type; char *color; } for 'nplots' plots */ void *make_plot(int width, int height, char *title, int nplots, ...); void plot_set(void *plot, float *data, int len, int pos, int pp); void iq_plot_set(void *plot, short *data, int len, int pos, int pp); void iq_plot_set_sized(void *_plot, short *data, int len, int pp); -void iq_plot_add_point_loop(void *_plot, short i, short q, int pp); +void iq_plot_add_iq_point_loop(void *_plot, short i, short q, int pp); +void iq_plot_add_energy_point_loop(void *_plot, int e, int pp); /* returns an opaque pointer - truly a 'database *', see t_data.c */ void *parse_database(char *filename); diff --git a/tracer/main.c b/tracer/main.c index 0b529b132b..cedad0079d 100644 --- a/tracer/main.c +++ b/tracer/main.c @@ -7,6 +7,7 @@ #include #include #include +#include #include "defs.h" @@ -14,10 +15,14 @@ #include "../T_IDs.h" #include "../T_defs.h" +#define BLUE "#0c0c72" +#define RED "#d72828" + void *ul_plot; void *chest_plot; void *pusch_iq_plot; void *pucch_iq_plot; +void *pucch_plot; #ifdef T_USE_SHARED_MEMORY @@ -213,8 +218,12 @@ void get_message(int s) GET(s, &size, sizeof(int)); GET(s, buf, size); #if 0 - printf("got T_ENB_INPUT_SIGNAL eNB %d frame %d subframe %d antenna %d size %d %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x\n", - eNB, frame, subframe, antenna, size, buf[0],buf[1],buf[2],buf[3],buf[4],buf[5],buf[6],buf[7],buf[8],buf[9],buf[10],buf[11],buf[12],buf[13],buf[14],buf[15]); + printf("got T_ENB_INPUT_SIGNAL eNB %d frame %d subframe %d antenna " + "%d size %d %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x " + "%2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x\n", + eNB, frame, subframe, antenna, size, buf[0],buf[1],buf[2], + buf[3],buf[4],buf[5],buf[6],buf[7],buf[8],buf[9],buf[10], + buf[11],buf[12],buf[13],buf[14],buf[15]); #endif if (size != 4 * 7680) {printf("bad T_ENB_INPUT_SIGNAL, only 7680 samples allowed\n");abort();} @@ -272,8 +281,22 @@ void get_message(int s) GET(s, &subframe, sizeof(int)); GET(s, &I, sizeof(int)); GET(s, &Q, sizeof(int)); -printf("receiving %d %d\n", I, Q); - if (pucch_iq_plot) iq_plot_add_point_loop(pucch_iq_plot, I*10, Q*10, 0); + if (pucch_iq_plot) iq_plot_add_iq_point_loop(pucch_iq_plot,I*10,Q*10, 0); + break; + } + case T_PUCCH_1_ENERGY: { + int eNB, UE, frame, subframe, e, t; + GET(s, &eNB, sizeof(int)); + GET(s, &UE, sizeof(int)); + GET(s, &frame, sizeof(int)); + GET(s, &subframe, sizeof(int)); + GET(s, &e, sizeof(int)); + GET(s, &t, sizeof(int)); +//printf("t %d e %d\n", t, (int)(10*log10(e))); + if (pucch_plot) { + iq_plot_add_energy_point_loop(pucch_plot, t, 0); + iq_plot_add_energy_point_loop(pucch_plot, 10*log10(e), 1); + } break; } case T_buf_test: { @@ -281,8 +304,10 @@ printf("receiving %d %d\n", I, Q); int size; GET(s, &size, sizeof(int)); GET(s, buf, size); - printf("got buffer size %d %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x\n", - size, buf[0],buf[1],buf[2],buf[3],buf[4],buf[5],buf[6],buf[7],buf[8],buf[9],buf[10],buf[11],buf[12],buf[13],buf[14],buf[15]); + printf("got buffer size %d %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x" + " %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x\n", + size, buf[0],buf[1],buf[2],buf[3],buf[4],buf[5],buf[6],buf[7], + buf[8],buf[9],buf[10],buf[11],buf[12],buf[13],buf[14],buf[15]); break; } default: printf("unkown message type %d\n", m); abort(); @@ -386,13 +411,18 @@ int main(int n, char **v) if (do_xforms) { ul_plot = make_plot(512, 100, "UL Input Signal", 1, - 7680*10, PLOT_VS_TIME, "blue"); + 7680*10, PLOT_VS_TIME, BLUE); chest_plot = make_plot(512, 100, "UL Channel Estimate UE 0", 1, - 512, PLOT_VS_TIME, "blue"); + 512, PLOT_VS_TIME, BLUE); pusch_iq_plot = make_plot(100, 100, "PUSCH IQ", 1, - 12*25*14, PLOT_IQ_POINTS, "blue"); + 12*25*14, PLOT_IQ_POINTS, BLUE); pucch_iq_plot = make_plot(100, 100, "PUCCH IQ", 1, - 1000, PLOT_IQ_POINTS, "blue"); + 1000, PLOT_IQ_POINTS, BLUE); + pucch_plot = make_plot(512, 100, "PUCCH 1 energy (SR)", 2, + /* threshold */ + 10240, PLOT_MINMAX, RED, + /* pucch 1 */ + 10240, PLOT_MINMAX, BLUE); } for (i = 0; i < on_off_n; i++) diff --git a/tracer/plot.c b/tracer/plot.c index e9aa57a5d2..58f25fd41c 100644 --- a/tracer/plot.c +++ b/tracer/plot.c @@ -84,9 +84,21 @@ static void *plot_thread(void *_p) if (pthread_mutex_lock(&p->lock)) abort(); + XFillRectangle(p->d, p->px, p->bg, 0, 0, p->width, p->height); + for (pp = 0; pp < p->nplots; pp++) { - XFillRectangle(p->d, p->px, p->bg, 0, 0, p->width, p->height); - if (p->p[pp].type == PLOT_VS_TIME) { + if (p->p[pp].type == PLOT_MINMAX) { + s = p->p[pp].buf; + for (i = 0; i < 512; i++) { + int min = *s; + int max = *s; + for (j = 0; j < p->p[pp].count/512; j++, s++) { + if (*s < min) min = *s; + if (*s > max) max = *s; + } + XDrawLine(p->d, p->px, p->p[pp].g, i, 100-min, i, 100-max); + } + } else if (p->p[pp].type == PLOT_VS_TIME) { for (i = 0; i < p->p[pp].count; i++) p->p[pp].buf[i] = 10*log10(1.0+(float)(p->p[pp].iqbuf[2*i]*p->p[pp].iqbuf[2*i]+ @@ -215,6 +227,10 @@ void *make_plot(int width, int height, char *title, int nplots, ...) if (p->p[i].buf == NULL) abort(); p->p[i].iqbuf = malloc(sizeof(short) * count * 2); if(p->p[i].iqbuf==NULL)abort(); + } else if (type == PLOT_MINMAX) { + p->p[i].buf = malloc(sizeof(float) * count); + if (p->p[i].buf == NULL) abort(); + p->p[i].iqbuf = NULL; } else { p->p[i].buf = NULL; p->p[i].iqbuf = malloc(sizeof(short) * count * 2); @@ -269,7 +285,7 @@ void iq_plot_set_sized(void *_plot, short *data, int count, int pp) if (pthread_mutex_unlock(&p->lock)) abort(); } -void iq_plot_add_point_loop(void *_plot, short i, short q, int pp) +void iq_plot_add_iq_point_loop(void *_plot, short i, short q, int pp) { plot *p = _plot; if (pthread_mutex_lock(&p->lock)) abort(); @@ -280,3 +296,14 @@ void iq_plot_add_point_loop(void *_plot, short i, short q, int pp) if (p->p[pp].iq_insert_pos == p->p[pp].count) p->p[pp].iq_insert_pos = 0; if (pthread_mutex_unlock(&p->lock)) abort(); } + +void iq_plot_add_energy_point_loop(void *_plot, int e, int pp) +{ + plot *p = _plot; + if (pthread_mutex_lock(&p->lock)) abort(); + p->p[pp].buf[p->p[pp].iq_insert_pos] = e; + if (p->p[pp].iq_count != p->p[pp].count) p->p[pp].iq_count++; + p->p[pp].iq_insert_pos++; + if (p->p[pp].iq_insert_pos == p->p[pp].count) p->p[pp].iq_insert_pos = 0; + if (pthread_mutex_unlock(&p->lock)) abort(); +} From e11728a83bf16e002aad0b9c8077395fbcd1cdfb Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Sat, 19 Mar 2016 19:06:01 +0100 Subject: [PATCH 14/28] - make it work with oaisim - add global ON/OFF command line options (OFF is useless but just for completeness) --- T_messages.txt | 48 +++++++++++++++++++++++++++++++++++++++++++++++ tracer/database.c | 9 ++++++++- tracer/main.c | 13 ++++++++++++- 3 files changed, 68 insertions(+), 2 deletions(-) diff --git a/T_messages.txt b/T_messages.txt index dd5dd8eec1..4c6f6e7aca 100644 --- a/T_messages.txt +++ b/T_messages.txt @@ -69,6 +69,22 @@ ID = LEGACY_S1AP_TRACE DESC = S1AP legacy logs - trace level GROUP = S1AP:TRACE:LEGACY +ID = LEGACY_X2AP_INFO + DESC = X2AP legacy logs - info level + GROUP = X2AP:INFO:LEGACY +ID = LEGACY_X2AP_ERROR + DESC = X2AP legacy logs - error level + GROUP = X2AP:ERROR:LEGACY +ID = LEGACY_X2AP_WARNING + DESC = X2AP legacy logs - warning level + GROUP = X2AP:WARNING:LEGACY +ID = LEGACY_X2AP_DEBUG + DESC = X2AP legacy logs - debug level + GROUP = X2AP:DEBUG:LEGACY +ID = LEGACY_X2AP_TRACE + DESC = X2AP legacy logs - trace level + GROUP = X2AP:TRACE:LEGACY + ID = LEGACY_RRC_INFO DESC = RRC legacy logs - info level GROUP = RRC:INFO:LEGACY @@ -245,6 +261,38 @@ ID = LEGACY_OCG_TRACE DESC = OCG legacy logs - trace level GROUP = OCG:TRACE:LEGACY +ID = LEGACY_OCM_INFO + DESC = OCM legacy logs - info level + GROUP = OCM:INFO:LEGACY +ID = LEGACY_OCM_ERROR + DESC = OCM legacy logs - error level + GROUP = OCM:ERROR:LEGACY +ID = LEGACY_OCM_WARNING + DESC = OCM legacy logs - warning level + GROUP = OCM:WARNING:LEGACY +ID = LEGACY_OCM_DEBUG + DESC = OCM legacy logs - debug level + GROUP = OCM:DEBUG:LEGACY +ID = LEGACY_OCM_TRACE + DESC = OCM legacy logs - trace level + GROUP = OCM:TRACE:LEGACY + +ID = LEGACY_OIP_INFO + DESC = OIP legacy logs - info level + GROUP = OIP:INFO:LEGACY +ID = LEGACY_OIP_ERROR + DESC = OIP legacy logs - error level + GROUP = OIP:ERROR:LEGACY +ID = LEGACY_OIP_WARNING + DESC = OIP legacy logs - warning level + GROUP = OIP:WARNING:LEGACY +ID = LEGACY_OIP_DEBUG + DESC = OIP legacy logs - debug level + GROUP = OIP:DEBUG:LEGACY +ID = LEGACY_OIP_TRACE + DESC = OIP legacy logs - trace level + GROUP = OIP:TRACE:LEGACY + ID = LEGACY_OMG_INFO DESC = OMG legacy logs - info level GROUP = OMG:INFO:LEGACY diff --git a/tracer/database.c b/tracer/database.c index a430d1a696..5039deff5a 100644 --- a/tracer/database.c +++ b/tracer/database.c @@ -304,8 +304,15 @@ static void onoff_group(database *d, char *name, int *a, int onoff) for (i = 0; i < g->size; i++) onoff_id(d, g->ids[i], a, onoff); } -void on_off(void *d, char *item, int *a, int onoff) +void on_off(void *_d, char *item, int *a, int onoff) { + database *d = _d; + int i; + if (item == NULL) { + for (i = 0; i < d->isize; i++) a[i] = onoff; + printf("turning %s all traces\n", onoff ? "ON" : "OFF"); + return; + } onoff_group(d, item, a, onoff); onoff_id(d, item, a, onoff); } diff --git a/tracer/main.c b/tracer/main.c index cedad0079d..de0523673b 100644 --- a/tracer/main.c +++ b/tracer/main.c @@ -172,6 +172,11 @@ void get_message(int s) case T_LEGACY_OCG_WARNING: S("OCG", "WARNING"); break; case T_LEGACY_OCG_DEBUG: S("OCG", "DEBUG"); break; case T_LEGACY_OCG_TRACE: S("OCG", "TRACE"); break; + case T_LEGACY_OCM_INFO: S("OCM", "INFO"); break; + case T_LEGACY_OCM_ERROR: S("OCM", "ERROR"); break; + case T_LEGACY_OCM_WARNING: S("OCM", "WARNING"); break; + case T_LEGACY_OCM_DEBUG: S("OCM", "DEBUG"); break; + case T_LEGACY_OCM_TRACE: S("OCM", "TRACE"); break; case T_LEGACY_OMG_INFO: S("OMG", "INFO"); break; case T_LEGACY_OMG_ERROR: S("OMG", "ERROR"); break; case T_LEGACY_OMG_WARNING: S("OMG", "WARNING"); break; @@ -353,7 +358,9 @@ void usage(void) " -x run with XFORMS (revisited)\n" " -on turn log ON for given GROUP or ID\n" " -off turn log OFF for given GROUP or ID\n" -"note: you may pass several -on and -off, they will be processed in order\n" +" -ON turn all logs ON\n" +" -OFF turn all logs OFF\n" +"note: you may pass several -on/-off/-ON/-OFF, they will be processed in order\n" " by default, all is off\n" ); exit(1); @@ -393,6 +400,10 @@ int main(int n, char **v) on_off_name[on_off_n]=v[++i]; on_off_action[on_off_n++]=1; continue; } if (!strcmp(v[i], "-off")) { if (i > n-2) usage(); on_off_name[on_off_n]=v[++i]; on_off_action[on_off_n++]=0; continue; } + if (!strcmp(v[i], "-ON")) + { on_off_name[on_off_n]=NULL; on_off_action[on_off_n++]=1; continue; } + if (!strcmp(v[i], "-OFF")) + { on_off_name[on_off_n]=NULL; on_off_action[on_off_n++]=0; continue; } printf("ERROR: unknown option %s\n", v[i]); usage(); } From ef289848abc7cf81dc2a3419aa0180b3b07010b5 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Sat, 19 Mar 2016 19:09:12 +0100 Subject: [PATCH 15/28] - add OIP traces - oaisim generates one of it at the end --- tracer/main.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tracer/main.c b/tracer/main.c index de0523673b..31f5d54171 100644 --- a/tracer/main.c +++ b/tracer/main.c @@ -182,6 +182,11 @@ void get_message(int s) case T_LEGACY_OMG_WARNING: S("OMG", "WARNING"); break; case T_LEGACY_OMG_DEBUG: S("OMG", "DEBUG"); break; case T_LEGACY_OMG_TRACE: S("OMG", "TRACE"); break; + case T_LEGACY_OIP_INFO: S("OIP", "INFO"); break; + case T_LEGACY_OIP_ERROR: S("OIP", "ERROR"); break; + case T_LEGACY_OIP_WARNING: S("OIP", "WARNING"); break; + case T_LEGACY_OIP_DEBUG: S("OIP", "DEBUG"); break; + case T_LEGACY_OIP_TRACE: S("OIP", "TRACE"); break; case T_LEGACY_GTPU_INFO: S("GTPU", "INFO"); break; case T_LEGACY_GTPU_ERROR: S("GTPU", "ERROR"); break; case T_LEGACY_GTPU_WARNING: S("GTPU", "WARNING"); break; From 2bd870afdcfc8872e1a116af6fa7315dbe0c74e6 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Sat, 19 Mar 2016 22:40:20 +0100 Subject: [PATCH 16/28] - read may return partial content from a socket, deal with that --- tracer/main.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/tracer/main.c b/tracer/main.c index 31f5d54171..1a30bbef95 100644 --- a/tracer/main.c +++ b/tracer/main.c @@ -44,7 +44,22 @@ static inline int GET(int s, void *out, int count) #else /* T_USE_SHARED_MEMORY */ -#define GET read +#define GET fullread + +int fullread(int fd, void *_buf, int count) +{ + char *buf = _buf; + int ret = 0; + int l; + while (count) { + l = read(fd, buf, count); + if (l <= 0) { printf("read socket problem\n"); abort(); } + count -= l; + buf += l; + ret += l; + } + return ret; +} #endif /* T_USE_SHARED_MEMORY */ @@ -236,7 +251,8 @@ void get_message(int s) buf[11],buf[12],buf[13],buf[14],buf[15]); #endif if (size != 4 * 7680) - {printf("bad T_ENB_INPUT_SIGNAL, only 7680 samples allowed\n");abort();} + {printf("bad T_ENB_INPUT_SIGNAL, only 7680 samples allowed " + "(received %d bytes = %d samples)\n", size, size/4);abort();} if (ul_plot) iq_plot_set(ul_plot, (short*)buf, 7680, subframe*7680, 0); break; } From ee5d8c60fb8e614d85c28d7e1cf5cba4e42345d7 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Sat, 19 Mar 2016 23:52:09 +0100 Subject: [PATCH 17/28] prepare forwarder --- T.h | 13 +++++++++++ tracer/Makefile | 2 +- tracer/defs.h | 3 +++ tracer/forward.c | 10 +++++++++ tracer/main.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 84 insertions(+), 2 deletions(-) create mode 100644 tracer/forward.c diff --git a/T.h b/T.h index d88f33a81c..405594f2d4 100644 --- a/T.h +++ b/T.h @@ -115,11 +115,24 @@ extern T_cache_t *T_cache; #define T_ACTIVE(x) T_active[(intptr_t)x] +#ifdef T_USE_SHARED_MEMORY + #define T_SEND() \ T_cache[T_LOCAL_slot].busy = 1; \ T_cache[T_LOCAL_slot].length = T_LOCAL_size; \ T_send(T_LOCAL_buf, T_LOCAL_size) +#else /* T_USE_SHARED_MEMORY */ + +/* when not using shared memory, wait for send to finish */ +#define T_SEND() \ + T_cache[T_LOCAL_slot].busy = 1; \ + T_cache[T_LOCAL_slot].length = T_LOCAL_size; \ + T_send(T_LOCAL_buf, T_LOCAL_size); \ + while (T_cache[T_LOCAL_slot].busy) usleep(1*1000) + +#endif /* T_USE_SHARED_MEMORY */ + #define T_CHECK_SIZE(len, argnum) \ if (T_LOCAL_size + (len) > T_BUFFER_MAX) { \ printf("%s:%d:%s: cannot put argument %d in T macro, not enough space" \ diff --git a/tracer/Makefile b/tracer/Makefile index a38ba5c2c6..093acfbe3c 100644 --- a/tracer/Makefile +++ b/tracer/Makefile @@ -10,7 +10,7 @@ CFLAGS += -DT_USE_SHARED_MEMORY LIBS += -lrt PROG=tracer -OBJS=main.o plot.o database.o +OBJS=main.o plot.o database.o forward.o $(PROG): $(OBJS) $(CC) $(CFLAGS) -o $(PROG) $(OBJS) $(LIBS) diff --git a/tracer/defs.h b/tracer/defs.h index 231255b46d..d9074d35d7 100644 --- a/tracer/defs.h +++ b/tracer/defs.h @@ -21,4 +21,7 @@ void list_ids(void *database); void list_groups(void *database); void on_off(void *d, char *item, int *a, int onoff); +void *forwarder(char *ip, int port); +void forward(void *forwarder, char *buf, int size); + #endif /* _TRACER_DEFS_H_ */ diff --git a/tracer/forward.c b/tracer/forward.c new file mode 100644 index 0000000000..77ee156751 --- /dev/null +++ b/tracer/forward.c @@ -0,0 +1,10 @@ +#include "defs.h" + +void *forwarder(char *ip, int port) +{ + return 0; +} + +void forward(void *_fowarder, char *buf, int size) +{ +} diff --git a/tracer/main.c b/tracer/main.c index 1a30bbef95..ba6dc043c3 100644 --- a/tracer/main.c +++ b/tracer/main.c @@ -371,7 +371,7 @@ void init_shm(void) void usage(void) { printf( -"options:\n" +"common options:\n" " -d this option is mandatory\n" " -li print IDs in the database\n" " -lg print GROUPs in the database\n" @@ -383,6 +383,10 @@ void usage(void) " -OFF turn all logs OFF\n" "note: you may pass several -on/-off/-ON/-OFF, they will be processed in order\n" " by default, all is off\n" +"\n" +"remote mode options: in this mode you run a local tracer and a remote one\n" +" -r remote side\n" +" -l local side (forwards packets to remote IP:port)\n" ); exit(1); } @@ -403,6 +407,13 @@ int main(int n, char **v) int *on_off_action; int on_off_n = 0; int is_on[T_NUMBER_OF_IDS]; + int remote_local = 0; + int remote_remote = 0; + char *remote_ip = NULL; + int remote_port = -1; +#ifdef T_USE_SHARED_MEMORY + void *f; +#endif memset(is_on, 0, sizeof(is_on)); @@ -425,10 +436,43 @@ int main(int n, char **v) { on_off_name[on_off_n]=NULL; on_off_action[on_off_n++]=1; continue; } if (!strcmp(v[i], "-OFF")) { on_off_name[on_off_n]=NULL; on_off_action[on_off_n++]=0; continue; } + if (!strcmp(v[i], "-r")) { remote_remote = 1; continue; } + if (!strcmp(v[i], "-l")) { if (i > n-3) usage(); remote_local = 1; + remote_ip = v[++i]; remote_port = atoi(v[++i]); continue; } printf("ERROR: unknown option %s\n", v[i]); usage(); } +#ifndef T_USE_SHARED_MEMORY + /* gcc shut up */ + (void)remote_port; + (void)remote_ip; +#endif + +#ifdef T_USE_SHARED_MEMORY + if (remote_remote) { + printf("ERROR: remote 'remote side' does not run with shared memory\n"); + printf("recompile without T_USE_SHARED_MEMORY (edit Makefile)\n"); + exit(1); + } +#endif + + if (remote_remote) { + /* TODO: setup 'secure' connection with remote part */ + } + +#ifndef T_USE_SHARED_MEMORY + if (remote_local) { + printf("ERROR: remote 'local side' does not run without shared memory\n"); + printf("recompile with T_USE_SHARED_MEMORY (edit Makefile)\n"); + exit(1); + } +#endif + +#ifdef T_USE_SHARED_MEMORY + if (remote_local) f = forwarder(remote_ip, remote_port); +#endif + if (database_filename == NULL) { printf("ERROR: provide a database file (-d)\n"); exit(1); @@ -479,6 +523,18 @@ int main(int n, char **v) #ifdef T_USE_SHARED_MEMORY wait_message(); #endif + +#ifdef T_USE_SHARED_MEMORY + if (remote_local) { + forward(f, T_cache[T_busylist_head].buffer, + T_cache[T_busylist_head].length); + T_cache[T_busylist_head].busy = 0; + T_busylist_head++; + T_busylist_head &= T_CACHE_SIZE - 1; + continue; + } +#endif + get_message(s); } return 0; From cb2454cca3bbe3aaacafdf2ee02a068611885fd2 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Sun, 20 Mar 2016 00:23:15 +0100 Subject: [PATCH 18/28] first version of forwarder to be redone (the local tracer shall not configure the tracee by itself but only forward what the remote tracer sends) --- tracer/forward.c | 36 ++++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/tracer/forward.c b/tracer/forward.c index 77ee156751..9e0df61fbf 100644 --- a/tracer/forward.c +++ b/tracer/forward.c @@ -1,10 +1,42 @@ #include "defs.h" +#include +#include +#include +#include +#include + +typedef struct { + int s; +} forward_data; void *forwarder(char *ip, int port) { - return 0; + forward_data *f; + struct sockaddr_in a; + + f = malloc(sizeof(*f)); if (f == NULL) abort(); + + f->s = socket(AF_INET, SOCK_STREAM, 0); + if (f->s == -1) { perror("socket"); exit(1); } + + a.sin_family = AF_INET; + a.sin_port = htons(port); + a.sin_addr.s_addr = inet_addr(ip); + + if (connect(f->s, (struct sockaddr *)&a, sizeof(a)) == -1) + { perror("connect"); exit(1); } + + return f; } -void forward(void *_fowarder, char *buf, int size) +void forward(void *_forwarder, char *buf, int size) { + forward_data *f = _forwarder; + + while (size) { + int l = write(f->s, buf, size); + if (l <= 0) { printf("forward error\n"); exit(1); } + size -= l; + buf += l; + } } From 8ca955f371f0f82d4425bc63e25ae286b403c040 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Sun, 20 Mar 2016 19:44:57 +0100 Subject: [PATCH 19/28] better forwarder --- tracer/defs.h | 3 +++ tracer/forward.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++++ tracer/main.c | 37 +++++++++++++++++++++++++++++--- tracer/plot.c | 18 ---------------- 4 files changed, 92 insertions(+), 21 deletions(-) diff --git a/tracer/defs.h b/tracer/defs.h index d9074d35d7..69b379ce0b 100644 --- a/tracer/defs.h +++ b/tracer/defs.h @@ -6,6 +6,8 @@ #define PLOT_IQ_POINTS 1 #define PLOT_MINMAX 2 +void new_thread(void *(*f)(void *), void *data); + /* ... is { int count; int type; char *color; } for 'nplots' plots */ void *make_plot(int width, int height, char *title, int nplots, ...); void plot_set(void *plot, float *data, int len, int pos, int pp); @@ -23,5 +25,6 @@ void on_off(void *d, char *item, int *a, int onoff); void *forwarder(char *ip, int port); void forward(void *forwarder, char *buf, int size); +void forward_start_client(void *forwarder, int socket); #endif /* _TRACER_DEFS_H_ */ diff --git a/tracer/forward.c b/tracer/forward.c index 9e0df61fbf..cfb837f9e5 100644 --- a/tracer/forward.c +++ b/tracer/forward.c @@ -4,11 +4,60 @@ #include #include #include +#include typedef struct { int s; + int sc; + pthread_mutex_t lock; } forward_data; +static void do_forward(forward_data *f, int from, int to, int lock) +{ + int l, len; + char *b; + char buf[1024]; + while (1) { + len = read(from, buf, 1024); + if (len <= 0) break; + b = buf; + + if (lock) if (pthread_mutex_lock(&f->lock)) abort(); + + while (len) { + l = write(to, b, len); + if (l <= 0) break; + len -= l; + b += l; + } + + if (lock) if (pthread_mutex_unlock(&f->lock)) abort(); + } +} + +static void *forward_s_to_sc(void *_f) +{ + forward_data *f = _f; + do_forward(f, f->s, f->sc, 0); + return NULL; +} + +static void *forward_sc_to_s(void *_f) +{ + forward_data *f = _f; + do_forward(f, f->sc, f->s, 1); + printf("INFO: forwarder exits\n"); + return NULL; +} + +void forward_start_client(void *_f, int s) +{ + forward_data *f = _f; + f->sc = s; + new_thread(forward_s_to_sc, f); + new_thread(forward_sc_to_s, f); +} + void *forwarder(char *ip, int port) { forward_data *f; @@ -16,6 +65,8 @@ void *forwarder(char *ip, int port) f = malloc(sizeof(*f)); if (f == NULL) abort(); + pthread_mutex_init(&f->lock, NULL); + f->s = socket(AF_INET, SOCK_STREAM, 0); if (f->s == -1) { perror("socket"); exit(1); } @@ -33,10 +84,14 @@ void forward(void *_forwarder, char *buf, int size) { forward_data *f = _forwarder; + if (pthread_mutex_lock(&f->lock)) abort(); + while (size) { int l = write(f->s, buf, size); if (l <= 0) { printf("forward error\n"); exit(1); } size -= l; buf += l; } + + if (pthread_mutex_unlock(&f->lock)) abort(); } diff --git a/tracer/main.c b/tracer/main.c index ba6dc043c3..317644f5a5 100644 --- a/tracer/main.c +++ b/tracer/main.c @@ -8,6 +8,7 @@ #include #include #include +#include #include "defs.h" @@ -368,6 +369,23 @@ void init_shm(void) #endif /* T_USE_SHARED_MEMORY */ +void new_thread(void *(*f)(void *), void *data) +{ + pthread_t t; + pthread_attr_t att; + + if (pthread_attr_init(&att)) + { fprintf(stderr, "pthread_attr_init err\n"); exit(1); } + if (pthread_attr_setdetachstate(&att, PTHREAD_CREATE_DETACHED)) + { fprintf(stderr, "pthread_attr_setdetachstate err\n"); exit(1); } + if (pthread_attr_setstacksize(&att, 10000000)) + { fprintf(stderr, "pthread_attr_setstacksize err\n"); exit(1); } + if (pthread_create(&t, &att, f, data)) + { fprintf(stderr, "pthread_create err\n"); exit(1); } + if (pthread_attr_destroy(&att)) + { fprintf(stderr, "pthread_attr_destroy err\n"); exit(1); } +} + void usage(void) { printf( @@ -473,6 +491,8 @@ int main(int n, char **v) if (remote_local) f = forwarder(remote_ip, remote_port); #endif + if (remote_local) goto no_database; + if (database_filename == NULL) { printf("ERROR: provide a database file (-d)\n"); exit(1); @@ -485,6 +505,10 @@ int main(int n, char **v) if (do_list_groups) { list_groups(database); return 0; } if (do_dump_database) { dump_database(database); return 0; } + for (i = 0; i < on_off_n; i++) + on_off(database, on_off_name[i], is_on, on_off_action[i]); + +no_database: if (do_xforms) { ul_plot = make_plot(512, 100, "UL Input Signal", 1, 7680*10, PLOT_VS_TIME, BLUE); @@ -501,13 +525,18 @@ int main(int n, char **v) 10240, PLOT_MINMAX, BLUE); } - for (i = 0; i < on_off_n; i++) - on_off(database, on_off_name[i], is_on, on_off_action[i]); - #ifdef T_USE_SHARED_MEMORY init_shm(); #endif s = get_connection("127.0.0.1", 2020); + + if (remote_local) { +#ifdef T_USE_SHARED_MEMORY + forward_start_client(f, s); +#endif + goto no_init_message; + } + /* send the first message - activate all traces */ t = 0; if (write(s, &t, 1) != 1) abort(); @@ -518,6 +547,8 @@ int main(int n, char **v) if (is_on[l]) if (write(s, &l, sizeof(int)) != sizeof(int)) abort(); +no_init_message: + /* read messages */ while (1) { #ifdef T_USE_SHARED_MEMORY diff --git a/tracer/plot.c b/tracer/plot.c index 58f25fd41c..7447384288 100644 --- a/tracer/plot.c +++ b/tracer/plot.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #include @@ -146,23 +145,6 @@ static void *plot_thread(void *_p) return NULL; } -static void new_thread(void *(*f)(void *), void *data) -{ - pthread_t t; - pthread_attr_t att; - - if (pthread_attr_init(&att)) - { fprintf(stderr, "pthread_attr_init err\n"); exit(1); } - if (pthread_attr_setdetachstate(&att, PTHREAD_CREATE_DETACHED)) - { fprintf(stderr, "pthread_attr_setdetachstate err\n"); exit(1); } - if (pthread_attr_setstacksize(&att, 10000000)) - { fprintf(stderr, "pthread_attr_setstacksize err\n"); exit(1); } - if (pthread_create(&t, &att, f, data)) - { fprintf(stderr, "pthread_create err\n"); exit(1); } - if (pthread_attr_destroy(&att)) - { fprintf(stderr, "pthread_attr_destroy err\n"); exit(1); } -} - void *make_plot(int width, int height, char *title, int nplots, ...) { plot *p; From f846a9e564a15997d67bae02fa7fd196fed26f40 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Sun, 20 Mar 2016 21:22:56 +0100 Subject: [PATCH 20/28] forwarder uses a list to store messages better in case of slow link between local and remote tracers may smoke lots of memory though --- tracer/forward.c | 75 ++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 67 insertions(+), 8 deletions(-) diff --git a/tracer/forward.c b/tracer/forward.c index cfb837f9e5..b982a89027 100644 --- a/tracer/forward.c +++ b/tracer/forward.c @@ -5,13 +5,61 @@ #include #include #include +#include + +typedef struct databuf { + char *d; + int l; + struct databuf *next; +} databuf; typedef struct { int s; int sc; pthread_mutex_t lock; + pthread_mutex_t datalock; + pthread_cond_t datacond; + databuf * volatile head, *tail; } forward_data; +static void *data_sender(void *_f) +{ + forward_data *f = _f; + databuf *cur; + char *buf, *b; + int size; + +wait: + if (pthread_mutex_lock(&f->datalock)) abort(); + while (f->head == NULL) + if (pthread_cond_wait(&f->datacond, &f->datalock)) abort(); + cur = f->head; + buf = cur->d; + size = cur->l; + f->head = cur->next; + if (f->head == NULL) f->tail = NULL; + if (pthread_mutex_unlock(&f->datalock)) abort(); + free(cur); + goto process; + +process: + if (pthread_mutex_lock(&f->lock)) abort(); + + b = buf; + while (size) { + int l = write(f->s, b, size); + if (l <= 0) { printf("forward error\n"); exit(1); } + size -= l; + b += l; + } + + if (pthread_mutex_unlock(&f->lock)) abort(); + + free(buf); + + goto wait; +} + static void do_forward(forward_data *f, int from, int to, int lock) { int l, len; @@ -66,6 +114,11 @@ void *forwarder(char *ip, int port) f = malloc(sizeof(*f)); if (f == NULL) abort(); pthread_mutex_init(&f->lock, NULL); + pthread_mutex_init(&f->datalock, NULL); + pthread_cond_init(&f->datacond, NULL); + + f->sc = -1; + f->head = f->tail = NULL; f->s = socket(AF_INET, SOCK_STREAM, 0); if (f->s == -1) { perror("socket"); exit(1); } @@ -77,21 +130,27 @@ void *forwarder(char *ip, int port) if (connect(f->s, (struct sockaddr *)&a, sizeof(a)) == -1) { perror("connect"); exit(1); } + new_thread(data_sender, f); + return f; } void forward(void *_forwarder, char *buf, int size) { forward_data *f = _forwarder; + databuf *new; - if (pthread_mutex_lock(&f->lock)) abort(); + new = malloc(sizeof(*new)); if (new == NULL) abort(); - while (size) { - int l = write(f->s, buf, size); - if (l <= 0) { printf("forward error\n"); exit(1); } - size -= l; - buf += l; - } + if (pthread_mutex_lock(&f->datalock)) abort(); - if (pthread_mutex_unlock(&f->lock)) abort(); + new->d = malloc(size); if (new->d == NULL) abort(); + memcpy(new->d, buf, size); + new->l = size; + new->next = NULL; + if (f->head == NULL) f->head = new; + f->tail = new; + + if (pthread_cond_signal(&f->datacond)) abort(); + if (pthread_mutex_unlock(&f->datalock)) abort(); } From d4d361ed2f3ff99d56d069bb0aefe5cb48845327 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Sun, 20 Mar 2016 21:30:07 +0100 Subject: [PATCH 21/28] error if -on/-off id/group is not found --- tracer/database.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/tracer/database.c b/tracer/database.c index 5039deff5a..59d8cbdc85 100644 --- a/tracer/database.c +++ b/tracer/database.c @@ -286,26 +286,29 @@ void list_groups(void *_d) for (i = 0; i < d->gsize; i++) printf("%s\n", d->g[i].name); } -static void onoff_id(database *d, char *name, int *a, int onoff) +static int onoff_id(database *d, char *name, int *a, int onoff) { id *i; i = bsearch(&(id){name:name}, d->i, d->isize, sizeof(id), id_cmp); - if (i == NULL) return; + if (i == NULL) return 0; a[i->id] = onoff; printf("turning %s %s\n", onoff ? "ON" : "OFF", name); + return 1; } -static void onoff_group(database *d, char *name, int *a, int onoff) +static int onoff_group(database *d, char *name, int *a, int onoff) { group *g; int i; g = bsearch(&(group){name:name}, d->g, d->gsize, sizeof(group), group_cmp); - if (g == NULL) return; + if (g == NULL) return 0; for (i = 0; i < g->size; i++) onoff_id(d, g->ids[i], a, onoff); + return 1; } void on_off(void *_d, char *item, int *a, int onoff) { + int done; database *d = _d; int i; if (item == NULL) { @@ -313,6 +316,10 @@ void on_off(void *_d, char *item, int *a, int onoff) printf("turning %s all traces\n", onoff ? "ON" : "OFF"); return; } - onoff_group(d, item, a, onoff); - onoff_id(d, item, a, onoff); + done = onoff_group(d, item, a, onoff); + done += onoff_id(d, item, a, onoff); + if (done == 0) { + printf("ERROR: ID/group '%s' not found in database\n", item); + exit(1); + } } From fe057b1bc4013ecadb6304061ea18ffec6638da0 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Mon, 21 Mar 2016 09:54:23 +0100 Subject: [PATCH 22/28] add port to -r option --- tracer/main.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tracer/main.c b/tracer/main.c index 317644f5a5..18ed8087cc 100644 --- a/tracer/main.c +++ b/tracer/main.c @@ -403,7 +403,7 @@ void usage(void) " by default, all is off\n" "\n" "remote mode options: in this mode you run a local tracer and a remote one\n" -" -r remote side\n" +" -r remote side (use given port)\n" " -l local side (forwards packets to remote IP:port)\n" ); exit(1); @@ -429,6 +429,7 @@ int main(int n, char **v) int remote_remote = 0; char *remote_ip = NULL; int remote_port = -1; + int port = 2020; #ifdef T_USE_SHARED_MEMORY void *f; #endif @@ -454,7 +455,8 @@ int main(int n, char **v) { on_off_name[on_off_n]=NULL; on_off_action[on_off_n++]=1; continue; } if (!strcmp(v[i], "-OFF")) { on_off_name[on_off_n]=NULL; on_off_action[on_off_n++]=0; continue; } - if (!strcmp(v[i], "-r")) { remote_remote = 1; continue; } + if (!strcmp(v[i], "-r")) { if (i > n-2) usage(); remote_remote = 1; + port = atoi(v[++i]); continue; } if (!strcmp(v[i], "-l")) { if (i > n-3) usage(); remote_local = 1; remote_ip = v[++i]; remote_port = atoi(v[++i]); continue; } printf("ERROR: unknown option %s\n", v[i]); @@ -528,7 +530,7 @@ no_database: #ifdef T_USE_SHARED_MEMORY init_shm(); #endif - s = get_connection("127.0.0.1", 2020); + s = get_connection("127.0.0.1", port); if (remote_local) { #ifdef T_USE_SHARED_MEMORY From 7c7d5caed23d35656aebdbf864cd44b67f58d589 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Mon, 21 Mar 2016 16:42:24 +0100 Subject: [PATCH 23/28] do not forward data from tracee to remote tracer - no data is sent and it won't work anyway, it will mess up with the T --- tracer/forward.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tracer/forward.c b/tracer/forward.c index b982a89027..6082d5e7e3 100644 --- a/tracer/forward.c +++ b/tracer/forward.c @@ -92,9 +92,11 @@ static void *forward_s_to_sc(void *_f) static void *forward_sc_to_s(void *_f) { +#if 0 forward_data *f = _f; do_forward(f, f->sc, f->s, 1); printf("INFO: forwarder exits\n"); +#endif return NULL; } From 0fe08538e9b54abc95ccad708890523b2e284340 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Mon, 21 Mar 2016 16:44:12 +0100 Subject: [PATCH 24/28] add __synch_synchronize for the T_cache it probably makes things zillion times slower but it seems to be necessary --- T.c | 13 ++++++++++--- T.h | 6 ++++-- tracer/main.c | 10 +++++++++- 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/T.c b/T.c index a33d1e90b6..13bf25b324 100644 --- a/T.c +++ b/T.c @@ -54,9 +54,16 @@ static void *T_send_thread(void *_) { while (1) { usleep(5000); + __sync_synchronize(); while (T_cache[T_busylist_head].busy) { - char *b = T_cache[T_busylist_head].buffer; - int l = T_cache[T_busylist_head].length; + char *b; + int l; + /* TODO: be sure about those memory barriers - in doubt one is + * put here too + */ + __sync_synchronize(); + b = T_cache[T_busylist_head].buffer; + l = T_cache[T_busylist_head].length; while (l) { int done = write(T_socket, b, l); if (done <= 0) { @@ -123,7 +130,7 @@ void T_connect_to_tracer(char *addr, int port) #ifdef T_USE_SHARED_MEMORY /* setup shared memory */ - T_shm_fd = shm_open(T_SHM_FILENAME, O_RDWR, 0666); + 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), diff --git a/T.h b/T.h index 405594f2d4..6797213d31 100644 --- a/T.h +++ b/T.h @@ -118,16 +118,18 @@ extern T_cache_t *T_cache; #ifdef T_USE_SHARED_MEMORY #define T_SEND() \ - T_cache[T_LOCAL_slot].busy = 1; \ T_cache[T_LOCAL_slot].length = T_LOCAL_size; \ + __sync_synchronize(); \ + T_cache[T_LOCAL_slot].busy = 1; \ T_send(T_LOCAL_buf, T_LOCAL_size) #else /* T_USE_SHARED_MEMORY */ /* when not using shared memory, wait for send to finish */ #define T_SEND() \ - T_cache[T_LOCAL_slot].busy = 1; \ T_cache[T_LOCAL_slot].length = T_LOCAL_size; \ + __sync_synchronize(); \ + T_cache[T_LOCAL_slot].busy = 1; \ T_send(T_LOCAL_buf, T_LOCAL_size); \ while (T_cache[T_LOCAL_slot].busy) usleep(1*1000) diff --git a/tracer/main.c b/tracer/main.c index 18ed8087cc..cf8f8aac85 100644 --- a/tracer/main.c +++ b/tracer/main.c @@ -356,7 +356,8 @@ void wait_message(void) void init_shm(void) { - int s = shm_open(T_SHM_FILENAME, O_RDWR | O_CREAT, 0666); + 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(); } @@ -365,6 +366,12 @@ void init_shm(void) if (T_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_cache, 0x55, T_CACHE_SIZE * sizeof(T_cache_t)); + for (i = 0; i < T_CACHE_SIZE; i++) T_cache[i].busy = 0; } #endif /* T_USE_SHARED_MEMORY */ @@ -555,6 +562,7 @@ no_init_message: while (1) { #ifdef T_USE_SHARED_MEMORY wait_message(); + __sync_synchronize(); #endif #ifdef T_USE_SHARED_MEMORY From 9b0f4913e2d83af960b4d8fd0bb6593e110ef65a Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Mon, 21 Mar 2016 17:42:04 +0100 Subject: [PATCH 25/28] dirty bug... --- tracer/forward.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tracer/forward.c b/tracer/forward.c index 6082d5e7e3..b425e6444b 100644 --- a/tracer/forward.c +++ b/tracer/forward.c @@ -151,6 +151,7 @@ void forward(void *_forwarder, char *buf, int size) new->l = size; new->next = NULL; if (f->head == NULL) f->head = new; + if (f->tail != NULL) f->tail->next = new; f->tail = new; if (pthread_cond_signal(&f->datacond)) abort(); From d37484b5aa673c10fb8a66dca28bea397016c316 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Mon, 11 Apr 2016 10:20:23 +0200 Subject: [PATCH 26/28] put code in the right place for integration into openair --- Makefile => common/utils/T/Makefile | 0 T.c => common/utils/T/T.c | 0 T.h => common/utils/T/T.h | 0 T_defs.h => common/utils/T/T_defs.h | 0 T_messages.txt => common/utils/T/T_messages.txt | 0 generate_Txx.c => common/utils/T/generate_Txx.c | 0 genids.c => common/utils/T/genids.c | 0 main.c => common/utils/T/main.c | 0 {tracer => common/utils/T/tracer}/Makefile | 0 {tracer => common/utils/T/tracer}/database.c | 0 {tracer => common/utils/T/tracer}/defs.h | 0 {tracer => common/utils/T/tracer}/forward.c | 0 {tracer => common/utils/T/tracer}/main.c | 0 {tracer => common/utils/T/tracer}/plot.c | 0 14 files changed, 0 insertions(+), 0 deletions(-) rename Makefile => common/utils/T/Makefile (100%) rename T.c => common/utils/T/T.c (100%) rename T.h => common/utils/T/T.h (100%) rename T_defs.h => common/utils/T/T_defs.h (100%) rename T_messages.txt => common/utils/T/T_messages.txt (100%) rename generate_Txx.c => common/utils/T/generate_Txx.c (100%) rename genids.c => common/utils/T/genids.c (100%) rename main.c => common/utils/T/main.c (100%) rename {tracer => common/utils/T/tracer}/Makefile (100%) rename {tracer => common/utils/T/tracer}/database.c (100%) rename {tracer => common/utils/T/tracer}/defs.h (100%) rename {tracer => common/utils/T/tracer}/forward.c (100%) rename {tracer => common/utils/T/tracer}/main.c (100%) rename {tracer => common/utils/T/tracer}/plot.c (100%) diff --git a/Makefile b/common/utils/T/Makefile similarity index 100% rename from Makefile rename to common/utils/T/Makefile diff --git a/T.c b/common/utils/T/T.c similarity index 100% rename from T.c rename to common/utils/T/T.c diff --git a/T.h b/common/utils/T/T.h similarity index 100% rename from T.h rename to common/utils/T/T.h diff --git a/T_defs.h b/common/utils/T/T_defs.h similarity index 100% rename from T_defs.h rename to common/utils/T/T_defs.h diff --git a/T_messages.txt b/common/utils/T/T_messages.txt similarity index 100% rename from T_messages.txt rename to common/utils/T/T_messages.txt diff --git a/generate_Txx.c b/common/utils/T/generate_Txx.c similarity index 100% rename from generate_Txx.c rename to common/utils/T/generate_Txx.c diff --git a/genids.c b/common/utils/T/genids.c similarity index 100% rename from genids.c rename to common/utils/T/genids.c diff --git a/main.c b/common/utils/T/main.c similarity index 100% rename from main.c rename to common/utils/T/main.c diff --git a/tracer/Makefile b/common/utils/T/tracer/Makefile similarity index 100% rename from tracer/Makefile rename to common/utils/T/tracer/Makefile diff --git a/tracer/database.c b/common/utils/T/tracer/database.c similarity index 100% rename from tracer/database.c rename to common/utils/T/tracer/database.c diff --git a/tracer/defs.h b/common/utils/T/tracer/defs.h similarity index 100% rename from tracer/defs.h rename to common/utils/T/tracer/defs.h diff --git a/tracer/forward.c b/common/utils/T/tracer/forward.c similarity index 100% rename from tracer/forward.c rename to common/utils/T/tracer/forward.c diff --git a/tracer/main.c b/common/utils/T/tracer/main.c similarity index 100% rename from tracer/main.c rename to common/utils/T/tracer/main.c diff --git a/tracer/plot.c b/common/utils/T/tracer/plot.c similarity index 100% rename from tracer/plot.c rename to common/utils/T/tracer/plot.c From ee6789cdde09ffae511c4ca53860487c9774db6e Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Mon, 11 Apr 2016 10:23:15 +0200 Subject: [PATCH 27/28] "make clean" cleans also the tracer --- common/utils/T/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/common/utils/T/Makefile b/common/utils/T/Makefile index 27e1c8a5c0..9694273c19 100644 --- a/common/utils/T/Makefile +++ b/common/utils/T/Makefile @@ -31,3 +31,4 @@ main.o: T.h T_IDs.h T_defs.h clean: rm -f *.o $(PROG) $(GENIDS) core T_IDs.h + cd tracer && make clean From 2bb04f0105db07604744a400fd955ae714a801a6 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Mon, 11 Apr 2016 11:18:26 +0200 Subject: [PATCH 28/28] first version of the generic gui for the tracer --- common/utils/T/tracer/Makefile | 6 +- common/utils/T/tracer/gui/Makefile | 17 ++ common/utils/T/tracer/gui/container.c | 206 ++++++++++++++ common/utils/T/tracer/gui/event.c | 165 ++++++++++++ common/utils/T/tracer/gui/gui.c | 24 ++ common/utils/T/tracer/gui/gui.h | 36 +++ common/utils/T/tracer/gui/gui_defs.h | 178 ++++++++++++ common/utils/T/tracer/gui/init.c | 29 ++ common/utils/T/tracer/gui/label.c | 46 ++++ common/utils/T/tracer/gui/loop.c | 59 ++++ common/utils/T/tracer/gui/test.c | 46 ++++ common/utils/T/tracer/gui/text_list.c | 95 +++++++ common/utils/T/tracer/gui/toplevel_window.c | 88 ++++++ common/utils/T/tracer/gui/widget.c | 216 +++++++++++++++ common/utils/T/tracer/gui/x.c | 284 ++++++++++++++++++++ common/utils/T/tracer/gui/x.h | 47 ++++ common/utils/T/tracer/gui/x_defs.h | 23 ++ common/utils/T/tracer/gui/xy_plot.c | 173 ++++++++++++ 18 files changed, 1737 insertions(+), 1 deletion(-) create mode 100644 common/utils/T/tracer/gui/Makefile create mode 100644 common/utils/T/tracer/gui/container.c create mode 100644 common/utils/T/tracer/gui/event.c create mode 100644 common/utils/T/tracer/gui/gui.c create mode 100644 common/utils/T/tracer/gui/gui.h create mode 100644 common/utils/T/tracer/gui/gui_defs.h create mode 100644 common/utils/T/tracer/gui/init.c create mode 100644 common/utils/T/tracer/gui/label.c create mode 100644 common/utils/T/tracer/gui/loop.c create mode 100644 common/utils/T/tracer/gui/test.c create mode 100644 common/utils/T/tracer/gui/text_list.c create mode 100644 common/utils/T/tracer/gui/toplevel_window.c create mode 100644 common/utils/T/tracer/gui/widget.c create mode 100644 common/utils/T/tracer/gui/x.c create mode 100644 common/utils/T/tracer/gui/x.h create mode 100644 common/utils/T/tracer/gui/x_defs.h create mode 100644 common/utils/T/tracer/gui/xy_plot.c diff --git a/common/utils/T/tracer/Makefile b/common/utils/T/tracer/Makefile index 093acfbe3c..fab5012c28 100644 --- a/common/utils/T/tracer/Makefile +++ b/common/utils/T/tracer/Makefile @@ -10,11 +10,14 @@ CFLAGS += -DT_USE_SHARED_MEMORY LIBS += -lrt PROG=tracer -OBJS=main.o plot.o database.o forward.o +OBJS=main.o plot.o database.o forward.o gui/gui.a $(PROG): $(OBJS) $(CC) $(CFLAGS) -o $(PROG) $(OBJS) $(LIBS) +gui/gui.a: + cd gui && make + %.o: %.c $(CC) $(CFLAGS) -c -o $@ $< @@ -22,3 +25,4 @@ main.o: ../T_IDs.h ../T_defs.h clean: rm -f *.o $(PROG) core + cd gui && make clean diff --git a/common/utils/T/tracer/gui/Makefile b/common/utils/T/tracer/gui/Makefile new file mode 100644 index 0000000000..13820114dd --- /dev/null +++ b/common/utils/T/tracer/gui/Makefile @@ -0,0 +1,17 @@ +CC=gcc +CFLAGS=-Wall -g -pthread + +OBJS=init.o loop.o toplevel_window.o x.o container.o widget.o \ + gui.o label.o event.o xy_plot.o text_list.o + +gui.a: $(OBJS) + ar cr gui.a $(OBJS) + +test: test.o gui.a + $(CC) -o test $(OBJS) test.o -lX11 -pthread -lm + +%.o: %.c + $(CC) $(CFLAGS) -o $@ -c $< + +clean: + rm -f *.a *.o test diff --git a/common/utils/T/tracer/gui/container.c b/common/utils/T/tracer/gui/container.c new file mode 100644 index 0000000000..23f7a42295 --- /dev/null +++ b/common/utils/T/tracer/gui/container.c @@ -0,0 +1,206 @@ +#include "gui.h" +#include "gui_defs.h" +#include +#include + +static void repack(gui *g, widget *_this) +{ +printf("REPACK container %p\n", _this); + struct container_widget *this = _this; + this->hints_are_valid = 0; + return this->common.parent->repack(g, this->common.parent); +} + +static void add_child(gui *g, widget *this, widget *child, int position) +{ +printf("ADD_CHILD container\n"); + widget_add_child_internal(g, this, child, position); +} + +static void compute_vertical_hints(struct gui *g, + struct container_widget *this) +{ + struct widget_list *l; + int cwidth, cheight; + int allocated_width = 0, allocated_height = 0; + + /* get largest width */ + l = this->common.children; + while (l) { + l->item->hints(g, l->item, &cwidth, &cheight); + if (cwidth > allocated_width) allocated_width = cwidth; + allocated_height += cheight; + l = l->next; + } + this->hint_width = allocated_width; + this->hint_height = allocated_height; + this->hints_are_valid = 1; +} + +static void compute_horizontal_hints(struct gui *g, + struct container_widget *this) +{ + struct widget_list *l; + int cwidth, cheight; + int allocated_width = 0, allocated_height = 0; + + /* get largest height */ + l = this->common.children; + while (l) { + l->item->hints(g, l->item, &cwidth, &cheight); + if (cheight > allocated_height) allocated_height = cheight; + allocated_width += cwidth; + l = l->next; + } + this->hint_width = allocated_width; + this->hint_height = allocated_height; + this->hints_are_valid = 1; +} + +static void vertical_allocate(gui *_gui, widget *_this, + int x, int y, int width, int height) +{ +printf("ALLOCATE container vertical %p\n", _this); + int cy = 0; + int cwidth, cheight; + struct gui *g = _gui; + struct container_widget *this = _this; + struct widget_list *l; + + if (this->hints_are_valid == 1) goto hints_ok; + + compute_vertical_hints(g, this); + +hints_ok: + + this->common.x = x; + this->common.y = y; + this->common.width = width; + this->common.height = height; + + /* allocate */ + l = this->common.children; + while (l) { + l->item->hints(g, l->item, &cwidth, &cheight); + l->item->allocate(g, l->item, this->common.x, this->common.y + cy, + //this->hint_width, cheight); + width, cheight); + cy += cheight; + l = l->next; + } + + if (cy != this->hint_height) ERR("reachable?\n"); +} + +static void horizontal_allocate(gui *_gui, widget *_this, + int x, int y, int width, int height) +{ +printf("ALLOCATE container horizontal %p\n", _this); + int cx = 0; + int cwidth, cheight; + struct gui *g = _gui; + struct container_widget *this = _this; + struct widget_list *l; + + if (this->hints_are_valid == 1) goto hints_ok; + + compute_horizontal_hints(g, this); + +hints_ok: + + this->common.x = x; + this->common.y = y; + this->common.width = width; + this->common.height = height; + + /* allocate */ + l = this->common.children; + while (l) { + l->item->hints(g, l->item, &cwidth, &cheight); + l->item->allocate(g, l->item, this->common.x + cx, this->common.y, + cwidth, this->hint_height); + cx += cwidth; + l = l->next; + } + + if (cx != this->hint_width) ERR("reachable?\n"); +} + +static void vertical_hints(gui *_gui, widget *_w, int *width, int *height) +{ +printf("HINTS container vertical %p\n", _w); + struct gui *g = _gui; + struct container_widget *this = _w; + + if (this->hints_are_valid) { + *width = this->hint_width; + *height = this->hint_height; + return; + } + + compute_vertical_hints(g, this); + + *width = this->hint_width; + *height = this->hint_height; +} + +static void horizontal_hints(gui *_gui, widget *_w, int *width, int *height) +{ +printf("HINTS container horizontal %p\n", _w); + struct gui *g = _gui; + struct container_widget *this = _w; + + if (this->hints_are_valid) { + *width = this->hint_width; + *height = this->hint_height; + return; + } + + compute_horizontal_hints(g, this); + + *width = this->hint_width; + *height = this->hint_height; +} + +static void paint(gui *_gui, widget *_this) +{ +printf("PAINT container\n"); + struct gui *g = _gui; + struct widget *this = _this; + struct widget_list *l; + + l = this->children; + while (l) { + l->item->paint(g, l->item); + l = l->next; + } +} + +widget *new_container(gui *_gui, int vertical) +{ + struct gui *g = _gui; + struct container_widget *w; + + glock(g); + + w = new_widget(g, CONTAINER, sizeof(struct container_widget)); + + w->vertical = vertical; + w->hints_are_valid = 0; + + w->common.paint = paint; + w->common.add_child = add_child; + w->common.repack = repack; + + if (vertical) { + w->common.allocate = vertical_allocate; + w->common.hints = vertical_hints; + } else { + w->common.allocate = horizontal_allocate; + w->common.hints = horizontal_hints; + } + + gunlock(g); + + return w; +} diff --git a/common/utils/T/tracer/gui/event.c b/common/utils/T/tracer/gui/event.c new file mode 100644 index 0000000000..fe7f9fbb47 --- /dev/null +++ b/common/utils/T/tracer/gui/event.c @@ -0,0 +1,165 @@ +#include "gui.h" +#include "gui_defs.h" +#include +#include +#include +#include +#include +#include + +/*****************************************************************/ +/* generic functions */ +/*****************************************************************/ + +static void event_list_append(struct gui *g, struct event *e) +{ + struct event_list *new; + + new = calloc(1, sizeof(struct event_list)); + if (new == NULL) OOM; + + new->item = e; + + if (g->queued_events == NULL) { + g->queued_events = new; + new->last = new; + return; + } + + g->queued_events->last->next = new; + g->queued_events->last = new; +} + +static void free_event(struct event *e) +{ + switch (e->type) { + case REPACK: /* nothing */ break; + case DIRTY: /* nothing */ break; + } + free(e); +} + +/*****************************************************************/ +/* sending events */ +/*****************************************************************/ + +static event *new_event_repack(int id) +{ + struct repack_event *ret; + ret = calloc(1, sizeof(struct repack_event)); + if (ret == NULL) OOM; + ret->id = id; + return ret; +} + +static event *new_event_dirty(int id) +{ + struct dirty_event *ret; + ret = calloc(1, sizeof(struct dirty_event)); + if (ret == NULL) OOM; + ret->id = id; + return ret; +} + +void send_event(gui *_gui, enum event_type type, ...) +{ +printf("send_event %d\n", type); + struct gui *g = _gui; + int do_write = 0; + va_list ap; + struct event *e; + + if (g->queued_events == NULL) do_write = 1; + + va_start(ap, type); + + switch (type) { + case REPACK: { + int id; + id = va_arg(ap, int); + e = new_event_repack(id); + break; + } + case DIRTY: { + int id; + id = va_arg(ap, int); + e = new_event_dirty(id); + break; + } + } + + va_end(ap); + + e->type = type; + + event_list_append(g, e); + + if (do_write) { + char c = 1; + if (write(g->event_pipe[1], &c, 1) != 1) + ERR("error writing to pipe: %s\n", strerror(errno)); + } +} + +/*****************************************************************/ +/* processing events */ +/*****************************************************************/ + +static void repack_event(struct gui *g, int id) +{ + struct widget *w = find_widget(g, id); + if (w == NULL) { WARN("widget id %d not found\n", id); return; } + w->repack(g, w); +} + +/* TODO: put that function somewhere else? */ +static struct toplevel_window_widget *get_toplevel_window(struct widget *w) +{ + while (w != NULL) { + if (w->type == TOPLEVEL_WINDOW) + return (struct toplevel_window_widget *)w; + w = w->parent; + } + return NULL; +} + +static void dirty_event(struct gui *g, int id) +{ + struct widget *w = find_widget(g, id); + struct toplevel_window_widget *win; + if (w == NULL) { WARN("widget id %d not found\n", id); return; } + win = get_toplevel_window(w); + if (win == NULL) + { WARN("widget id %d not contained in a window\n", id); return; } + g->xwin = win->x; + w->paint(g, w); + g->xwin = NULL; + g->repainted = 1; +} + +static void process_event(struct gui *g, struct event *e) +{ +printf("processing event type %d\n", e->type); + switch (e->type) { + case REPACK: repack_event(g, ((struct repack_event *)e)->id); break; + case DIRTY: dirty_event(g, ((struct dirty_event *)e)->id); break; + } +} + +/* TODO: events' compression */ +void gui_events(gui *_gui) +{ + struct gui *g = _gui; + +printf("gui_events START: head %p\n", g->queued_events); + + while (g->queued_events) { + struct event_list *cur = g->queued_events; + g->queued_events = cur->next; + if (g->queued_events) g->queued_events->last = cur->last; + process_event(g, cur->item); + free_event(cur->item); + free(cur); + } +printf("gui_events DONE\n"); +} diff --git a/common/utils/T/tracer/gui/gui.c b/common/utils/T/tracer/gui/gui.c new file mode 100644 index 0000000000..55c7a3680a --- /dev/null +++ b/common/utils/T/tracer/gui/gui.c @@ -0,0 +1,24 @@ +#include "gui.h" +#include "gui_defs.h" +#include "x.h" +#include +#include +#include + +void glock(gui *_gui) +{ + struct gui *g = _gui; + if (pthread_mutex_lock(g->lock)) ERR("mutex error\n"); +} + +void gunlock(gui *_gui) +{ + struct gui *g = _gui; + if (pthread_mutex_unlock(g->lock)) ERR("mutex error\n"); +} + +int new_color(gui *_gui, char *color) +{ + struct gui *g = _gui; + return x_new_color(g->x, color); +} diff --git a/common/utils/T/tracer/gui/gui.h b/common/utils/T/tracer/gui/gui.h new file mode 100644 index 0000000000..846b16457d --- /dev/null +++ b/common/utils/T/tracer/gui/gui.h @@ -0,0 +1,36 @@ +#ifndef _GUI_H_ +#define _GUI_H_ + +/* defines the public API of the GUI */ + +typedef void gui; +typedef void widget; + +#define HORIZONTAL 0 +#define VERTICAL 1 + +gui *gui_init(void); + +/* position = -1 to put at the end */ +void widget_add_child(gui *gui, widget *parent, widget *child, int position); + +widget *new_toplevel_window(gui *gui, int width, int height, char *title); +widget *new_container(gui *gui, int vertical); +widget *new_label(gui *gui, const char *text); +widget *new_xy_plot(gui *gui, int width, int height, char *label, + int vruler_width); +widget *new_text_list(gui *_gui, int width, int nlines, int background_color); + +void xy_plot_set_range(gui *gui, widget *this, + float xmin, float xmax, float ymin, float ymax); + +void text_list_add(gui *gui, widget *this, const char *text, int position); + +void gui_loop(gui *gui); + +void glock(gui *gui); +void gunlock(gui *gui); + +int new_color(gui *gui, char *color); + +#endif /* _GUI_H_ */ diff --git a/common/utils/T/tracer/gui/gui_defs.h b/common/utils/T/tracer/gui/gui_defs.h new file mode 100644 index 0000000000..d7032f95da --- /dev/null +++ b/common/utils/T/tracer/gui/gui_defs.h @@ -0,0 +1,178 @@ +#ifndef _GUI_DEFS_H_ +#define _GUI_DEFS_H_ + +/* defines the private API of the GUI */ + +/*************************************************************************/ +/* logging macros */ +/*************************************************************************/ + +#define ERR(...) \ + do { \ + printf("%s:%d:%s: ERROR: ", __FILE__, __LINE__, __FUNCTION__); \ + printf(__VA_ARGS__); \ + abort(); \ + } while (0) + +#define WARN(...) \ + do { \ + printf("%s:%d:%s: WARNING: ", __FILE__, __LINE__, __FUNCTION__); \ + printf(__VA_ARGS__); \ + } while (0) + +#define OOM ERR("out of memory\n") + +/*************************************************************************/ +/* widgets */ +/*************************************************************************/ + +enum widget_type { + TOPLEVEL_WINDOW, CONTAINER, TEXT_LIST, XY_PLOT, BUTTON, LABEL +}; + +struct widget_list; + +struct widget { + enum widget_type type; + int id; + int x; /* allocated x after packing */ + int y; /* allocated y after packing */ + int width; /* allocated width after packing */ + int height; /* allocated height after packing */ + struct widget_list *children; + struct widget *parent; + void (*repack)(gui *g, widget *this); + void (*add_child)(gui *g, widget *this, widget *child, int position); + void (*allocate)(gui *g, widget *this, int x, int y, int width, int height); + void (*hints)(gui *g, widget *this, int *width, int *height); + void (*paint)(gui *g, widget *this); +}; + +struct widget_list { + struct widget *item; + struct widget_list *next; + //struct widget_list *prev; /* unused? */ + struct widget_list *last; /* valid only for the head of the list */ +}; + +struct toplevel_window_widget { + struct widget common; + void *x; /* opaque X data (type x_window), used in x.c */ +}; + +struct container_widget { + struct widget common; + int vertical; + int hints_are_valid; /* used to cache hints values */ + int hint_width; /* cached hint values - invalid if */ + int hint_height; /* repack_was_called == 1 */ +}; + +struct text_list_widget { + struct widget common; + char **text; + int text_count; + int wanted_width; + int wanted_nlines; /* number of lines of text the user wants to see */ + int allocated_nlines; /* actual number of visible lines */ + int starting_line; /* points to the first visible line of text */ + int line_height; + int baseline; + int background_color; +}; + +struct xy_plot_widget { + struct widget common; + float *x; + float *y; + int npoints; + char *label; + int label_width; + int label_height; + int label_baseline; + int vrule_width; /* the width of the vertical ruler text zone */ + float xmin, xmax; + float ymin, ymax; + int wanted_width; + int wanted_height; +}; + +struct button_widget { + struct widget common; +}; + +struct label_widget { + struct widget common; + const char *t; + int color; + int width; /* as given by the graphic's backend */ + int height; /* as given by the graphic's backend */ + int baseline; /* as given by the graphic's backend */ +}; + +/*************************************************************************/ +/* events */ +/*************************************************************************/ + +typedef void event; + +enum event_type { + DIRTY, REPACK +}; + +struct event { + enum event_type type; +}; + +struct event_list { + struct event *item; + struct event_list *next; + struct event_list *last; +}; + +struct dirty_event { + struct event common; + int id; +}; + +struct repack_event { + struct event common; + int id; +}; + +/*************************************************************************/ +/* main structure */ +/*************************************************************************/ + +struct gui { + void *lock; + void *x; /* opaque X data (type x_connection), used in x.c */ + struct widget_list *toplevel; + struct event_list *queued_events; + int event_pipe[2]; + int next_id; /* tells what is the ID of + the next created widget */ + int repainted; /* set to 1 when some widget has + * been repainted (TODO: can be any, + * to be optimized) */ + void *xwin; /* set by a toplevel_window when + * it paints itself, to be used + * by its children */ +}; + +/*************************************************************************/ +/* internal functions */ +/*************************************************************************/ + +widget *new_widget(struct gui *g, enum widget_type type, int size); +void widget_add_child_internal( + gui *_gui, widget *parent, widget *child, int position); + +const char *widget_name(enum widget_type type); + +void send_event(gui *gui, enum event_type type, ...); +void gui_events(gui *gui); + +struct widget *find_widget(struct gui *g, int id); + +#endif /* _GUI_DEFS_H_ */ diff --git a/common/utils/T/tracer/gui/init.c b/common/utils/T/tracer/gui/init.c new file mode 100644 index 0000000000..c708639674 --- /dev/null +++ b/common/utils/T/tracer/gui/init.c @@ -0,0 +1,29 @@ +#include "gui.h" +#include "gui_defs.h" +#include "x.h" +#include +#include +#include +#include +#include +#include + +gui *gui_init(void) +{ + struct gui *ret; + + ret = calloc(1, sizeof(struct gui)); + if (ret == NULL) OOM; + + ret->lock = malloc(sizeof(pthread_mutex_t)); + if (ret->lock == NULL) OOM; + if (pthread_mutex_init(ret->lock, NULL)) + ERR("mutex initialization failed\n"); + + if (pipe(ret->event_pipe)) + ERR("%s\n", strerror(errno)); + + ret->x = x_open(); + + return ret; +} diff --git a/common/utils/T/tracer/gui/label.c b/common/utils/T/tracer/gui/label.c new file mode 100644 index 0000000000..be6c8794a0 --- /dev/null +++ b/common/utils/T/tracer/gui/label.c @@ -0,0 +1,46 @@ +#include "gui.h" +#include "gui_defs.h" +#include "x.h" +#include +#include +#include + +static void paint(gui *_gui, widget *_w) +{ + struct gui *g = _gui; + struct label_widget *l = _w; +printf("PAINT label '%s'\n", l->t); + x_draw_string(g->x, g->xwin, l->color, + l->common.x, l->common.y + l->baseline, l->t); +} + +static void hints(gui *_gui, widget *_w, int *width, int *height) +{ + struct label_widget *l = _w; +printf("HINTS label '%s'\n", l->t); + *width = l->width; + *height = l->height; +} + +widget *new_label(gui *_gui, const char *label) +{ + struct gui *g = _gui; + struct label_widget *w; + + glock(g); + + w = new_widget(g, LABEL, sizeof(struct label_widget)); + + w->t = strdup(label); + if (w->t == NULL) OOM; + w->color = FOREGROUND_COLOR; + + x_text_get_dimensions(g->x, label, &w->width, &w->height, &w->baseline); + + w->common.paint = paint; + w->common.hints = hints; + + gunlock(g); + + return w; +} diff --git a/common/utils/T/tracer/gui/loop.c b/common/utils/T/tracer/gui/loop.c new file mode 100644 index 0000000000..94b7fe54bd --- /dev/null +++ b/common/utils/T/tracer/gui/loop.c @@ -0,0 +1,59 @@ +#include "gui.h" +#include "gui_defs.h" +#include "x.h" +#include +#include +#include +#include +#include +#include + +void gui_loop(gui *_gui) +{ + struct gui *g = _gui; + int xfd; + int eventfd; + int maxfd; + fd_set rd; + + xfd = x_connection_fd(g->x); + eventfd = g->event_pipe[0]; + + if (eventfd > xfd) maxfd = eventfd; + else maxfd = xfd; + + while (1) { + x_flush(g->x); + FD_ZERO(&rd); + FD_SET(xfd, &rd); + FD_SET(eventfd, &rd); + if (select(maxfd+1, &rd, NULL, NULL, NULL) == -1) + ERR("select: %s\n", strerror(errno)); + + glock(g); + + if (FD_ISSET(xfd, &rd)) + x_events(g); + + if (FD_ISSET(eventfd, &rd)) { + char c[256]; + if (read(eventfd, c, 256)); /* for no gcc warnings */ + } + + gui_events(g); + + if (g->repainted) { + struct widget_list *cur; + g->repainted = 0; + cur = g->toplevel; + while (cur) { + struct toplevel_window_widget *w = + (struct toplevel_window_widget *)cur->item; + x_draw(g->x, w->x); + cur = cur->next; + } + } + + gunlock(g); + } +} diff --git a/common/utils/T/tracer/gui/test.c b/common/utils/T/tracer/gui/test.c new file mode 100644 index 0000000000..06e3b6309d --- /dev/null +++ b/common/utils/T/tracer/gui/test.c @@ -0,0 +1,46 @@ +#include "gui.h" + +int main(void) +{ + gui *g; + widget *w, *c1, *c2, *l, *plot, *tl; + int tlcol; + + g = gui_init(); + + c1 = new_container(g, VERTICAL); + c2 = new_container(g, HORIZONTAL); + + l = new_label(g, "this is a good label"); + widget_add_child(g, c2, l, 0); + l = new_label(g, "this is another good label"); + widget_add_child(g, c2, l, -1); + + l = new_label(g, "OH! WHAT A LABEL!"); + widget_add_child(g, c1, l, -1); + + 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_text_list(g, 300, 10, tlcol); + widget_add_child(g, c1, tl, -1); + + text_list_add(g, tl, "hello", -1); + text_list_add(g, tl, "world", -1); + + w = new_toplevel_window(g, 500, 400, "test window"); + widget_add_child(g, w, c1, 0); + + gui_loop(g); + + return 0; +} diff --git a/common/utils/T/tracer/gui/text_list.c b/common/utils/T/tracer/gui/text_list.c new file mode 100644 index 0000000000..89b7e8822d --- /dev/null +++ b/common/utils/T/tracer/gui/text_list.c @@ -0,0 +1,95 @@ +#include "gui.h" +#include "gui_defs.h" +#include "x.h" +#include +#include +#include + +static void paint(gui *_gui, widget *_this) +{ + struct gui *g = _gui; + struct text_list_widget *this = _this; + int i, j; +printf("PAINT text_list %p xywh %d %d %d %d\n", _this, this->common.x, this->common.y, this->common.width, this->common.height); + x_fill_rectangle(g->x, g->xwin, this->background_color, + this->common.x, this->common.y, + this->common.width, this->common.height); + for (i = 0, j = this->starting_line; + i < this->allocated_nlines && j < this->text_count; i++, j++) + x_draw_string(g->x, g->xwin, FOREGROUND_COLOR, + this->common.x, + this->common.y + i * this->line_height + this->baseline, + this->text[j]); +} + +static void hints(gui *_gui, widget *_w, int *width, int *height) +{ + struct text_list_widget *w = _w; + *width = w->wanted_width; + *height = w->wanted_nlines * w->line_height; +printf("HINTS text_list wh %d %d\n", *width, *height); +} + +static void allocate( + gui *gui, widget *_this, int x, int y, int width, int height) +{ + struct text_list_widget *this = _this; + this->common.x = x; + this->common.y = y; + this->common.width = width; + this->common.height = height; + this->allocated_nlines = height / this->line_height; +printf("ALLOCATE text_list %p xywh %d %d %d %d nlines %d\n", this, x, y, width, height, this->allocated_nlines); +} + +widget *new_text_list(gui *_gui, int width, int nlines, int bgcol) +{ + struct gui *g = _gui; + struct text_list_widget *w; + int dummy; + + glock(g); + + w = new_widget(g, TEXT_LIST, sizeof(struct text_list_widget)); + + w->wanted_nlines = nlines; + x_text_get_dimensions(g->x, ".", &dummy, &w->line_height, &w->baseline); + w->background_color = bgcol; + w->wanted_width = width; + + w->common.paint = paint; + w->common.hints = hints; + w->common.allocate = allocate; + + gunlock(g); + + return w; +} + +/*************************************************************************/ +/* public functions */ +/*************************************************************************/ + +void text_list_add(gui *_gui, widget *_this, const char *text, int position) +{ + struct gui *g = _gui; + struct text_list_widget *this = _this; + + glock(g); + + if (position < 0) position = this->text_count; + if (position > this->text_count) position = this->text_count; + + this->text_count++; + this->text = realloc(this->text, this->text_count * sizeof(char *)); + if (this->text == NULL) OOM; + + memmove(this->text + position + 1, this->text + position, + (this->text_count-1 - position) * sizeof(char *)); + + this->text[position] = strdup(text); if (this->text[position] == NULL) OOM; + + send_event(g, DIRTY, this->common.id); + + gunlock(g); +} diff --git a/common/utils/T/tracer/gui/toplevel_window.c b/common/utils/T/tracer/gui/toplevel_window.c new file mode 100644 index 0000000000..b1dd251f6b --- /dev/null +++ b/common/utils/T/tracer/gui/toplevel_window.c @@ -0,0 +1,88 @@ +#include "gui.h" +#include "gui_defs.h" +#include "x.h" +#include +#include + +/**********************************************************************/ +/* callback functions */ +/**********************************************************************/ + +static void repack(gui *g, widget *_this) +{ +printf("REPACK toplevel_window\n"); + struct toplevel_window_widget *this = _this; + if (this->common.children == NULL) ERR("toplevel window has no child\n"); + if (this->common.children->next != NULL) + ERR("toplevel window has too much children\n"); + this->common.children->item->allocate(g, this->common.children->item, + 0 /* x */, 0 /* y */, this->common.width, this->common.height); + send_event(g, DIRTY, this->common.id); +} + +static void add_child(gui *_gui, widget *_this, widget *child, int position) +{ +printf("ADD_CHILD toplevel_window\n"); + struct widget *this = _this; + if (this->children != NULL) { + WARN("toplevel window already has a child\n"); + return; + } + if (position) + WARN("toplevel window doesn't care about 'position' " + "(you passed %d, you should always pass 0)\n", + position); + widget_add_child_internal(_gui, _this, child, 0); /* this does the REPACK */ +} + +/* called when the underlying window is resized by the user or the system */ +static void allocate( + gui *_gui, widget *_this, int x, int y, int width, int height) +{ +printf("ALLOCATE toplevel_window\n"); + struct toplevel_window_widget *this = _this; + this->common.width = width; + this->common.height = height; +// repack(_gui, _this); + send_event(_gui, REPACK, this->common.id); +} + +static void paint(gui *_gui, widget *_this) +{ + struct gui *g = _gui; + struct toplevel_window_widget *this = _this; +printf("PAINT toplevel_window (%d %d)\n", this->common.width, this->common.height); + x_fill_rectangle(g->x, this->x, BACKGROUND_COLOR, + 0, 0, this->common.width, this->common.height); + g->xwin = this->x; + this->common.children->item->paint(_gui, this->common.children->item); + g->xwin = NULL; /* TODO: remove? it's just in case */ +} + +/**********************************************************************/ +/* creation */ +/**********************************************************************/ + +widget *new_toplevel_window(gui *_gui, int width, int height, char *title) +{ + struct gui *g = _gui; + struct toplevel_window_widget *w; + + glock(g); + + w = new_widget(g, TOPLEVEL_WINDOW, sizeof(struct toplevel_window_widget)); + + w->common.width = width; + w->common.height = height; + + w->x = x_create_window(g->x, width, height, title); + + w->common.repack = repack; + w->common.add_child = add_child; + w->common.allocate = allocate; + w->common.paint = paint; + + gunlock(g); + + return w; +} diff --git a/common/utils/T/tracer/gui/widget.c b/common/utils/T/tracer/gui/widget.c new file mode 100644 index 0000000000..8304420aa1 --- /dev/null +++ b/common/utils/T/tracer/gui/widget.c @@ -0,0 +1,216 @@ +#include "gui.h" +#include "gui_defs.h" +#include "x.h" +#include +#include +#include +#include + +static void default_repack(gui *gui, widget *_this); +static void default_allocate( + gui *gui, widget *_this, int x, int y, int width, int height); +static void default_add_child( + gui *_gui, widget *_this, widget *child, int position); +static void default_hints(gui *g, widget *this, int *width, int *height); + +static void toplevel_list_append(struct gui *g, struct widget *e) +{ + struct widget_list *new; + + new = calloc(1, sizeof(struct widget_list)); + if (new == NULL) OOM; + + new->item = e; + + if (g->toplevel == NULL) { + g->toplevel = new; + new->last = new; + return; + } + + g->toplevel->last->next = new; + g->toplevel->last = new; +} + +widget *new_widget(struct gui *g, enum widget_type type, int size) +{ + struct widget *ret; + + //glock(g); + + ret = calloc(1, size); + if (ret == NULL) OOM; + + ret->repack = default_repack; + ret->add_child = default_add_child; + ret->allocate = default_allocate; + ret->hints = default_hints; + /* there is no default paint, on purpose */ + + ret->type = type; + ret->id = g->next_id; + g->next_id++; + ret->width = 0; + ret->height = 0; + + /* add toplevel windows to g->toplevel */ + if (type == TOPLEVEL_WINDOW) + toplevel_list_append(g, ret); + + //gunlock(g); + + return ret; +} + +/*************************************************************************/ +/* internal functions */ +/*************************************************************************/ + +void widget_add_child_internal( + gui *_gui, widget *parent, widget *child, int position) +{ + struct widget *p = parent; + struct widget *c = child; + struct widget_list *new; + struct widget_list *prev, *cur; + int i; + + new = calloc(1, sizeof(struct widget_list)); + if (new == NULL) OOM; + + new->item = c; + c->parent = p; + + prev = NULL; + cur = p->children; + + for (i = 0; position < 0 || i < position; i++) { + if (cur == NULL) break; + prev = cur; + cur = cur->next; + } + + /* TODO: warn/err if i != position+1? */ + + if (prev == NULL) { + /* new is at head */ + new->next = p->children; + if (p->children != NULL) new->last = p->children->last; + else new->last = new; + p->children = new; + goto repack; + } + + if (cur == NULL) { + /* new is at tail */ + prev->next = new; + p->children->last = new; + goto repack; + } + + /* new is between two existing items */ + prev->next = new; + new->next = cur; + +repack: + send_event(_gui, REPACK, p->id); +} + +/*************************************************************************/ +/* default functions */ +/*************************************************************************/ + +static void default_repack(gui *gui, widget *_this) +{ + struct widget *this = _this; + return this->parent->repack(gui, this->parent); +} + +static void default_add_child( + gui *_gui, widget *_this, widget *child, int position) +{ + struct widget *this = _this; + WARN("cannot add child to widget %s\n", widget_name(this->type)); +} + +static void default_allocate( + gui *gui, widget *_this, int x, int y, int width, int height) +{ + struct widget *this = _this; + this->x = x; + this->y = y; + this->width = width; + this->height = height; +} + +static void default_hints(gui *g, widget *this, int *width, int *height) +{ + *width = 1; + *height = 1; +} + +/*************************************************************************/ +/* utils functions */ +/*************************************************************************/ + +void widget_add_child(gui *_gui, widget *parent, widget *child, int position) +{ + struct widget *this = parent; + glock(_gui); + this->add_child(_gui, parent, child, position); + gunlock(_gui); +} + +static const char *names[] = { + "TOPLEVEL_WINDOW", "CONTAINER", "TEXT_LIST", "XY_PLOT", "BUTTON", "LABEL" +}; +const char *widget_name(enum widget_type type) +{ + switch (type) { + default: break; + case TOPLEVEL_WINDOW: + case CONTAINER: + case TEXT_LIST: + case XY_PLOT: + case BUTTON: + case LABEL: + return names[type]; + } + return "UNKNOWN (error)"; +} + +/*************************************************************************/ +/* find a widget */ +/*************************************************************************/ + +/* TODO: optimize traversal and also use a cache */ +struct widget *_find_widget(struct widget *c, int id) +{ + struct widget_list *l; + struct widget *ret; + if (c == NULL) return NULL; + if (c->id == id) return c; + l = c->children; + while (l) { + ret = _find_widget(l->item, id); + if (ret != NULL) return ret; + l = l->next; + } + return NULL; +} + +struct widget *find_widget(struct gui *g, int id) +{ + struct widget_list *l; + struct widget *ret; + + l = g->toplevel; + + while (l) { + ret = _find_widget(l->item, id); + if (ret != NULL) return ret; + l = l->next; + } + + return NULL; +} diff --git a/common/utils/T/tracer/gui/x.c b/common/utils/T/tracer/gui/x.c new file mode 100644 index 0000000000..b498654fdb --- /dev/null +++ b/common/utils/T/tracer/gui/x.c @@ -0,0 +1,284 @@ +#include "x.h" +#include "x_defs.h" +#include "gui_defs.h" +#include +#include +#include +#include + +int x_connection_fd(x_connection *_x) +{ + struct x_connection *x = _x; + return ConnectionNumber(x->d); +} + +static GC create_gc(Display *d, char *color) +{ + GC ret = XCreateGC(d, DefaultRootWindow(d), 0, NULL); + XGCValues gcv; + XColor rcol, scol; + + XCopyGC(d, DefaultGC(d, DefaultScreen(d)), -1L, ret); + if (XAllocNamedColor(d, DefaultColormap(d, DefaultScreen(d)), + color, &scol, &rcol)) { + gcv.foreground = scol.pixel; + XChangeGC(d, ret, GCForeground, &gcv); + } else ERR("X: could not allocate color '%s'\n", color); + + return ret; +} + +int x_new_color(x_connection *_x, char *color) +{ + struct x_connection *x = _x; + x->ncolors++; + x->colors = realloc(x->colors, x->ncolors * sizeof(GC)); + if (x->colors == NULL) OOM; + x->colors[x->ncolors-1] = create_gc(x->d, color); + return x->ncolors - 1; +} + +x_connection *x_open(void) +{ + struct x_connection *ret; + + ret = calloc(1, sizeof(struct x_connection)); + if (ret == NULL) OOM; + + ret->d = XOpenDisplay(0); +printf("XOpenDisplay display %p return x_connection %p\n", ret->d, ret); + if (ret->d == NULL) ERR("error calling XOpenDisplay: no X? you root?\n"); + + x_new_color(ret, "white"); /* background color */ + x_new_color(ret, "black"); /* foreground color */ + + return ret; +} + +x_window *x_create_window(x_connection *_x, int width, int height, + char *title) +{ + struct x_connection *x = _x; + struct x_window *ret; + + ret = calloc(1, sizeof(struct x_window)); + if (ret == NULL) OOM; + + ret->w = XCreateSimpleWindow(x->d, DefaultRootWindow(x->d), 0, 0, + width, height, 0, WhitePixel(x->d, DefaultScreen(x->d)), + WhitePixel(x->d, DefaultScreen(x->d))); + ret->width = width; + ret->height = height; + + XStoreName(x->d, ret->w, title); + + ret->p = XCreatePixmap(x->d, ret->w, width, height, + DefaultDepth(x->d, DefaultScreen(x->d))); + + /* enable backing store */ + { + XSetWindowAttributes att; + att.backing_store = Always; + XChangeWindowAttributes(x->d, ret->w, CWBackingStore, &att); + } + + XSelectInput(x->d, ret->w, + KeyPressMask | + ButtonPressMask | + ButtonReleaseMask | + PointerMotionMask | + ExposureMask | + StructureNotifyMask); + + XMapWindow(x->d, ret->w); + +#if 0 + /* wait for window to be mapped */ +printf("wait for map\n"); + while (1) { + XEvent ev; + //XWindowEvent(x->d, ret->w, StructureNotifyMask, &ev); + XWindowEvent(x->d, ret->w, ExposureMask, &ev); +printf("got ev %d\n", ev.type); + //if (ev.type == MapNotify) break; + if (ev.type == Expose) break; + } +printf("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; +} + +static struct toplevel_window_widget *find_x_window(struct gui *g, Window id) +{ + struct widget_list *cur; + struct toplevel_window_widget *w; + struct x_window *xw; + cur = g->toplevel; + while (cur) { + w = (struct toplevel_window_widget *)cur->item; + xw = w->x; + if (xw->w == id) return w; + cur = cur->next; + } + return NULL; +} + +void x_events(gui *_gui) +{ + struct gui *g = _gui; + struct widget_list *cur; + struct x_connection *x = g->x; + struct toplevel_window_widget *w; + +printf("x_events START\n"); + /* preprocessing (to "compress" events) */ + cur = g->toplevel; + while (cur) { + struct x_window *xw; + w = (struct toplevel_window_widget *)cur->item; + xw = w->x; + xw->redraw = 0; + xw->repaint = 0; + xw->resize = 0; + cur = cur->next; + } + + while (XPending(x->d)) { + XEvent ev; + XNextEvent(x->d, &ev); +printf("XEV %d\n", ev.type); + switch (ev.type) { + case Expose: + if ((w = find_x_window(g, ev.xexpose.window)) != NULL) { + struct x_window *xw = w->x; + xw->redraw = 1; + } + break; + case ConfigureNotify: + if ((w = find_x_window(g, ev.xexpose.window)) != NULL) { + struct x_window *xw = w->x; + xw->resize = 1; + xw->new_width = ev.xconfigure.width; + xw->new_height = ev.xconfigure.height; + if (xw->new_width < 10) xw->new_width = 10; + if (xw->new_height < 10) xw->new_height = 10; +printf("ConfigureNotify %d %d\n", ev.xconfigure.width, ev.xconfigure.height); + } + break; +#if 0 + case MapNotify: + if ((w = find_x_window(g, ev.xexpose.window)) != NULL) { + struct x_window *xw = w->x; + xw->repaint = 1; + } + break; +#endif + default: WARN("TODO: X event type %d\n", ev.type); break; + } + } + + /* postprocessing */ +printf("post processing\n"); + cur = g->toplevel; + while (cur) { + struct toplevel_window_widget *w = + (struct toplevel_window_widget *)cur->item; + struct x_window *xw = w->x; + if (xw->resize) { +printf("resize old %d %d new %d %d\n", xw->width, xw->height, xw->new_width, xw->new_height); + if (xw->width != xw->new_width || xw->height != xw->new_height) { + w->common.allocate(g, w, 0, 0, xw->new_width, xw->new_height); + xw->width = xw->new_width; + xw->height = xw->new_height; + XFreePixmap(x->d, xw->p); + xw->p = XCreatePixmap(x->d, xw->w, xw->width, xw->height, + DefaultDepth(x->d, DefaultScreen(x->d))); + //xw->repaint = 1; + } + } + if (xw->repaint) { + w->common.paint(g, w); + xw->redraw = 1; + } + if (xw->redraw) { + struct x_connection *x = g->x; +printf("XCopyArea w h %d %d\n", xw->width, xw->height); + XCopyArea(x->d, xw->p, xw->w, x->colors[1], + 0, 0, xw->width, xw->height, 0, 0); + } + cur = cur->next; + } +printf("x_events DONE\n"); +} + +void x_flush(x_connection *_x) +{ + struct x_connection *x = _x; + XFlush(x->d); +} + +void x_text_get_dimensions(x_connection *_c, const char *t, + int *width, int *height, int *baseline) +{ + struct x_connection *c = _c; + int dir; + int ascent; + int descent; + XCharStruct overall; + + /* TODO: don't use XQueryTextExtents (X roundtrip) */ + XQueryTextExtents(c->d, XGContextFromGC(c->colors[1]), t, strlen(t), + &dir, &ascent, &descent, &overall); + +//printf("dir %d ascent %d descent %d lbearing %d rbearing %d width %d ascent %d descent %d\n", dir, ascent, descent, overall.lbearing, overall.rbearing, overall.width, overall.ascent, overall.descent); + + *width = overall.width; + *height = ascent + descent; + *baseline = ascent; +} + +/***********************************************************************/ +/* public drawing functions */ +/***********************************************************************/ + +void x_draw_line(x_connection *_c, x_window *_w, int color, + int x1, int y1, int x2, int y2) +{ + struct x_connection *c = _c; + struct x_window *w = _w; + XDrawLine(c->d, w->p, c->colors[color], x1, y1, x2, y2); +} + +void x_draw_rectangle(x_connection *_c, x_window *_w, int color, + int x, int y, int width, int height) +{ + struct x_connection *c = _c; + struct x_window *w = _w; + XDrawRectangle(c->d, w->p, c->colors[color], x, y, width, height); +} + +void x_fill_rectangle(x_connection *_c, x_window *_w, int color, + int x, int y, int width, int height) +{ + struct x_connection *c = _c; + struct x_window *w = _w; + XFillRectangle(c->d, w->p, c->colors[color], x, y, width, height); +} + +void x_draw_string(x_connection *_c, x_window *_w, int color, + int x, int y, const char *t) +{ + struct x_connection *c = _c; + struct x_window *w = _w; + int tlen = strlen(t); + XDrawString(c->d, w->p, c->colors[color], x, y, t, tlen); +} + +void x_draw(x_connection *_c, x_window *_w) +{ + struct x_connection *c = _c; + struct x_window *w = _w; +printf("x_draw XCopyArea w h %d %d display %p window %d pixmap %d\n", w->width, w->height, c->d, (int)w->w, (int)w->p); + XCopyArea(c->d, w->p, w->w, c->colors[1], 0, 0, w->width, w->height, 0, 0); +} diff --git a/common/utils/T/tracer/gui/x.h b/common/utils/T/tracer/gui/x.h new file mode 100644 index 0000000000..41cf65393b --- /dev/null +++ b/common/utils/T/tracer/gui/x.h @@ -0,0 +1,47 @@ +#ifndef _X_H_ +#define _X_H_ + +/* public X interface */ + +#define BACKGROUND_COLOR 0 +#define FOREGROUND_COLOR 1 + +typedef void x_connection; +typedef void x_window; + +x_connection *x_open(void); + +x_window *x_create_window(x_connection *x, int width, int height, + char *title); + +int x_connection_fd(x_connection *x); + +void x_flush(x_connection *x); + +int x_new_color(x_connection *x, char *color); + +/* for x_events, we pass the gui */ +#include "gui.h" +void x_events(gui *gui); + +void x_text_get_dimensions(x_connection *, const char *t, + int *width, int *height, int *baseline); + +/* drawing functions */ + +void x_draw_line(x_connection *c, x_window *w, int color, + int x1, int y1, int x2, int y2); + +void x_draw_rectangle(x_connection *c, x_window *w, int color, + int x, int y, int width, int height); + +void x_fill_rectangle(x_connection *c, x_window *w, int color, + int x, int y, int width, int height); + +void x_draw_string(x_connection *_c, x_window *_w, int color, + int x, int y, const char *t); + +/* this function copies the pixmap to the window */ +void x_draw(x_connection *c, x_window *w); + +#endif /* _X_H_ */ diff --git a/common/utils/T/tracer/gui/x_defs.h b/common/utils/T/tracer/gui/x_defs.h new file mode 100644 index 0000000000..43b99f7cf7 --- /dev/null +++ b/common/utils/T/tracer/gui/x_defs.h @@ -0,0 +1,23 @@ +#ifndef _X_DEFS_H_ +#define _X_DEFS_H_ + +#include + +struct x_connection { + Display *d; + GC *colors; + int ncolors; +}; + +struct x_window { + Window w; + Pixmap p; + int width; + int height; + /* below: internal data used for X events handling */ + int redraw; + int repaint; + int resize, new_width, new_height; +}; + +#endif /* _X_DEFS_H_ */ diff --git a/common/utils/T/tracer/gui/xy_plot.c b/common/utils/T/tracer/gui/xy_plot.c new file mode 100644 index 0000000000..b2775fa054 --- /dev/null +++ b/common/utils/T/tracer/gui/xy_plot.c @@ -0,0 +1,173 @@ +#include "gui.h" +#include "gui_defs.h" +#include "x.h" +#include +#include +#include +#include + +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; + +printf("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); + + /* 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 */ + wanted_plot_width = this->wanted_width; + allocated_plot_width = this->common.width - this->vrule_width; + 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 */ +printf("pre x ticstep %g\n", ticstep); + while (1) { + if (ticstep / (allocated_xmax - allocated_xmin) + * (allocated_plot_width - 1) > 40) break; + ticstep *= 2; + } +printf("post x ticstep %g\n", ticstep); +printf("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; + float 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, v, &vwidth, &dummy, &dummy); + x_draw_string(g->x, g->xwin, 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); +printf("tic k %d val %g x %g\n", k, k * ticstep, x); + } + + /* vertical tics */ + wanted_plot_height = this->wanted_height; + allocated_plot_height = this->common.height - this->label_height * 2; + 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 */ +printf("pre y ticstep %g\n", ticstep); + while (1) { + if (ticstep / (allocated_ymax - allocated_ymin) + * (allocated_plot_height - 1) > 20) break; + ticstep *= 2; + } +printf("post y ticstep %g\n", ticstep); +printf("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; + float y = (k * ticstep - allocated_ymin) / + (allocated_ymax - allocated_ymin) * + (allocated_plot_height - 1); + sprintf(v, "%g", k * ticstep); + x_text_get_dimensions(g->x, v, &vwidth, &dummy, &dummy); + x_draw_line(g->x, g->xwin, FOREGROUND_COLOR, + this->common.x + this->vrule_width, + this->common.y + y, + this->common.x + this->vrule_width + 5, + this->common.y + y); + x_draw_string(g->x, g->xwin, FOREGROUND_COLOR, + this->common.x + this->vrule_width - vwidth - 2, + this->common.y + y - this->label_height / 2 + this->label_baseline, + v); + } + + /* label at bottom, in the middle */ + x_draw_string(g->x, g->xwin, 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); +} + +static void hints(gui *_gui, widget *_w, int *width, int *height) +{ + struct xy_plot_widget *w = _w; + *width = w->wanted_width + w->vrule_width; + *height = w->wanted_height + w->label_height * 2; /* TODO: refine */ +printf("HINTS xy plot wh %d %d (vrule_width %d) (wanted wh %d %d)\n", *width, *height, w->vrule_width, w->wanted_width, w->wanted_height); +} + +widget *new_xy_plot(gui *_gui, int width, int height, char *label, + int vruler_width) +{ + struct gui *g = _gui; + struct xy_plot_widget *w; + + glock(g); + + w = new_widget(g, XY_PLOT, sizeof(struct xy_plot_widget)); + + w->label = strdup(label); if (w->label == NULL) OOM; + /* TODO: be sure calling X there is valid wrt "global model" (we are + * not in the "gui thread") */ + x_text_get_dimensions(g->x, label, &w->label_width, &w->label_height, + &w->label_baseline); +printf("XY PLOT label wh %d %d\n", w->label_width, w->label_height); + + w->wanted_width = width; + w->wanted_height = height; + w->vrule_width = vruler_width; + + w->xmin = -1; + w->xmax = 1; + w->ymin = -1; + w->ymax = 1; + + w->common.paint = paint; + w->common.hints = hints; + + gunlock(g); + + return w; +}