diff --git a/common/utils/T/Makefile b/common/utils/T/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..9694273c1965e77e5338ba61871dbe82edb87c14 --- /dev/null +++ b/common/utils/T/Makefile @@ -0,0 +1,34 @@ +CC=gcc +CFLAGS=-Wall -g -pthread -DT_TRACER + +#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 T_defs.h + +clean: + rm -f *.o $(PROG) $(GENIDS) core T_IDs.h + cd tracer && make clean diff --git a/common/utils/T/T_messages.txt b/common/utils/T/T_messages.txt new file mode 100644 index 0000000000000000000000000000000000000000..4c6f6e7aca5fa0f54164ecb4449bcfc6c7fed6d3 --- /dev/null +++ b/common/utils/T/T_messages.txt @@ -0,0 +1,430 @@ +#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 +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 +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 + 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 + 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_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 +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_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 +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 +ID = buf_test diff --git a/common/utils/T/tracer/Makefile b/common/utils/T/tracer/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..fab5012c2862bc56499cdf425f147515700dfa67 --- /dev/null +++ b/common/utils/T/tracer/Makefile @@ -0,0 +1,28 @@ +CC=gcc +CFLAGS=-Wall -g -pthread -DT_TRACER + +#CFLAGS += -O3 -ffast-math -fomit-frame-pointer + +LIBS=-lX11 -lm + +#comment those two lines to NOT use shared memory +CFLAGS += -DT_USE_SHARED_MEMORY +LIBS += -lrt + +PROG=tracer +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 $@ $< + +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/database.c b/common/utils/T/tracer/database.c new file mode 100644 index 0000000000000000000000000000000000000000..59d8cbdc852cca264fe2222bb8792954cd920c0d --- /dev/null +++ b/common/utils/T/tracer/database.c @@ -0,0 +1,325 @@ +#include "defs.h" +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <ctype.h> + +typedef struct { + char *name; + char *desc; + char **groups; + int size; + int id; +} id; + +typedef struct { + char *name; + char **ids; + int size; +} group; + +typedef struct { + char *name; + 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; +} + +int group_cmp(const void *_p1, const void *_p2) +{ + const group *p1 = _p1; + const group *p2 = _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, 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); } + 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->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); +} + +group *get_group(database *r, char *group_name) +{ + group *ret; + + ret = bsearch(&(group){name:group_name}, + 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(&(group){name:group_name}, + 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 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; + 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, i->name); + id_add_group(i, g->name); + + if (end == NULL) break; + end++; + while ((isspace(*end) || *end == ':') && *end != 0) end++; + if (*end == 0) break; + groups = end; + } +} + +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; + int i; + + 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(); } + + 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, i); i++; } + if (!strcmp(name, "GROUP")) add_groups(r, last_id, value); + if (!strcmp(name, "DESC")) add_desc(last_id, 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 %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(" 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); +} + +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 0; + a[i->id] = onoff; + printf("turning %s %s\n", onoff ? "ON" : "OFF", name); + return 1; +} + +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 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) { + for (i = 0; i < d->isize; i++) a[i] = onoff; + printf("turning %s all traces\n", onoff ? "ON" : "OFF"); + return; + } + 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); + } +} diff --git a/common/utils/T/tracer/defs.h b/common/utils/T/tracer/defs.h new file mode 100644 index 0000000000000000000000000000000000000000..69b379ce0b3c3963475622ec3ed6d66b472ed97b --- /dev/null +++ b/common/utils/T/tracer/defs.h @@ -0,0 +1,30 @@ +#ifndef _TRACER_DEFS_H_ +#define _TRACER_DEFS_H_ + +/* types of plots */ +#define PLOT_VS_TIME 0 +#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); +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_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); +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); + +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/common/utils/T/tracer/forward.c b/common/utils/T/tracer/forward.c new file mode 100644 index 0000000000000000000000000000000000000000..b425e6444b929ad60cbfc3f2b4bed2ae6d73a874 --- /dev/null +++ b/common/utils/T/tracer/forward.c @@ -0,0 +1,159 @@ +#include "defs.h" +#include <stdlib.h> +#include <stdio.h> +#include <netinet/ip.h> +#include <arpa/inet.h> +#include <unistd.h> +#include <pthread.h> +#include <string.h> + +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; + 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) +{ +#if 0 + forward_data *f = _f; + do_forward(f, f->sc, f->s, 1); + printf("INFO: forwarder exits\n"); +#endif + 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; + struct sockaddr_in a; + + 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); } + + 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); } + + new_thread(data_sender, f); + + return f; +} + +void forward(void *_forwarder, char *buf, int size) +{ + forward_data *f = _forwarder; + databuf *new; + + new = malloc(sizeof(*new)); if (new == NULL) abort(); + + if (pthread_mutex_lock(&f->datalock)) 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; + if (f->tail != NULL) f->tail->next = new; + f->tail = new; + + if (pthread_cond_signal(&f->datacond)) abort(); + if (pthread_mutex_unlock(&f->datalock)) abort(); +} diff --git a/common/utils/T/tracer/gui/Makefile b/common/utils/T/tracer/gui/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..13820114ddd69e0debe47f2f33aa4db0db98c22e --- /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 0000000000000000000000000000000000000000..23f7a42295dd6f3a0bccaa1262776d79ed06b885 --- /dev/null +++ b/common/utils/T/tracer/gui/container.c @@ -0,0 +1,206 @@ +#include "gui.h" +#include "gui_defs.h" +#include <stdio.h> +#include <stdlib.h> + +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 0000000000000000000000000000000000000000..fe7f9fbb47215c571115b8e3b9396f5d63c81d8f --- /dev/null +++ b/common/utils/T/tracer/gui/event.c @@ -0,0 +1,165 @@ +#include "gui.h" +#include "gui_defs.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> +#include <stdarg.h> + +/*****************************************************************/ +/* 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 0000000000000000000000000000000000000000..55c7a3680aa04b23341cd2d6c123acf6e0a96cfe --- /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 <stdio.h> +#include <stdlib.h> +#include <pthread.h> + +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 0000000000000000000000000000000000000000..846b16457d2e892be9c33716a83254b1e64a032b --- /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 0000000000000000000000000000000000000000..d7032f95daac0c1b0c0fced830d280864b36dd81 --- /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 0000000000000000000000000000000000000000..c708639674f88099dc1cdaf7c6df6ff96fa0ed11 --- /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 <stdio.h> +#include <stdlib.h> +#include <pthread.h> +#include <unistd.h> +#include <errno.h> +#include <string.h> + +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 0000000000000000000000000000000000000000..be6c8794a07af1354382221590f7762655e01c02 --- /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 <stdio.h> +#include <stdlib.h> +#include <string.h> + +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 0000000000000000000000000000000000000000..94b7fe54bd5f1cc436f8d05ebc7f6e51f639c464 --- /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 <sys/select.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <string.h> +#include <unistd.h> + +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 0000000000000000000000000000000000000000..06e3b6309d2b81223675268ca9b92129573daf1d --- /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 0000000000000000000000000000000000000000..89b7e8822d8d427bee2f13bf65ba9f3d75c46a0a --- /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 <stdio.h> +#include <stdlib.h> +#include <string.h> + +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 0000000000000000000000000000000000000000..b1dd251f6b4bd981386e87ca650dea18fad7d60f --- /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 <stdio.h> +#include <stdlib.h> + +/**********************************************************************/ +/* 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 0000000000000000000000000000000000000000..8304420aa13109598ca2fa95cbc049b4e31f6103 --- /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 <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> + +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 0000000000000000000000000000000000000000..b498654fdb4110a8aadac2f3f96969238cbcc716 --- /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 <X11/Xlib.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +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 0000000000000000000000000000000000000000..41cf65393bcdeaafafa1c4413ca65727c69f04cb --- /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 0000000000000000000000000000000000000000..43b99f7cf7ae907f2245b2f51ff9ac96b68b7f30 --- /dev/null +++ b/common/utils/T/tracer/gui/x_defs.h @@ -0,0 +1,23 @@ +#ifndef _X_DEFS_H_ +#define _X_DEFS_H_ + +#include <X11/Xlib.h> + +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 0000000000000000000000000000000000000000..b2775fa054007c7537a6baba6d406c447761b4d5 --- /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 <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <math.h> + +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; +} diff --git a/common/utils/T/tracer/main.c b/common/utils/T/tracer/main.c new file mode 100644 index 0000000000000000000000000000000000000000..cf8f8aac859df410407e9acb21ff93fdbfc3bf54 --- /dev/null +++ b/common/utils/T/tracer/main.c @@ -0,0 +1,582 @@ +#include <stdio.h> +#include <string.h> +#include <netinet/ip.h> +#include <arpa/inet.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <math.h> +#include <pthread.h> + +#include "defs.h" + +#define T_ID(x) x +#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 + +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 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 */ + +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[T_BUFFER_MAX]; \ + 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[T_BUFFER_MAX]; + 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_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; + 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; + 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; + 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); +#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 " + "(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; + } + 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, 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, 0); + } + 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)); + 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: { + 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(); + } + +#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 i; + int s = shm_open(T_SHM_FILENAME, O_RDWR | O_CREAT /*| O_SYNC*/, 0666); + if (s == -1) { perror(T_SHM_FILENAME); abort(); } + if (ftruncate(s, T_CACHE_SIZE * sizeof(T_cache_t))) + { perror(T_SHM_FILENAME); abort(); } + T_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); + + /* 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 */ + +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( +"common options:\n" +" -d <database file> this option is mandatory\n" +" -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 <GROUP or ID> turn log ON for given GROUP or ID\n" +" -off <GROUP or ID> turn log OFF for given GROUP or ID\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" +"\n" +"remote mode options: in this mode you run a local tracer and a remote one\n" +" -r <port> remote side (use given port)\n" +" -l <IP address> <port> local side (forwards packets to remote IP:port)\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; + int do_xforms = 0; + char **on_off_name; + 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; + int port = 2020; +#ifdef T_USE_SHARED_MEMORY + void *f; +#endif + + 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(); + 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; } + 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; } + 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; } + 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]); + 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 (remote_local) goto no_database; + + 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; } + + 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); + 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); + pucch_plot = make_plot(512, 100, "PUCCH 1 energy (SR)", 2, + /* threshold */ + 10240, PLOT_MINMAX, RED, + /* pucch 1 */ + 10240, PLOT_MINMAX, BLUE); + } + +#ifdef T_USE_SHARED_MEMORY + init_shm(); +#endif + s = get_connection("127.0.0.1", port); + + 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(); + 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 (is_on[l]) + if (write(s, &l, sizeof(int)) != sizeof(int)) abort(); + +no_init_message: + + /* read messages */ + while (1) { +#ifdef T_USE_SHARED_MEMORY + wait_message(); + __sync_synchronize(); +#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; +} diff --git a/common/utils/T/tracer/plot.c b/common/utils/T/tracer/plot.c new file mode 100644 index 0000000000000000000000000000000000000000..74473842883c7e968ecf3c84079c4645e18f2467 --- /dev/null +++ b/common/utils/T/tracer/plot.c @@ -0,0 +1,291 @@ +#include "defs.h" +#include <X11/Xlib.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <pthread.h> +#include <math.h> +#include <unistd.h> +#include <sys/select.h> +#include <stdarg.h> + +typedef struct { + 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) +{ + 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]; + int pp; + + 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; + + 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++) { + 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]+ + 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); + } + } + + if (pthread_mutex_unlock(&p->lock)) abort(); + } + + if (redraw) { + redraw = 0; + XCopyArea(p->d, p->px, p->w, DefaultGC(p->d, DefaultScreen(p->d)), + 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); + if (select(maxfd+1, &rset, NULL, NULL, NULL) == -1) abort(); + if (FD_ISSET(p->timer_pipe[0], &rset)) { + char b[512]; + if (read(p->timer_pipe[0], b, 512) <= 0) abort(); + replot = 1; + } + } + + return NULL; +} + +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, + 0, WhitePixel(d, DefaultScreen(d)), WhitePixel(d, DefaultScreen(d))); + 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->width = width; + p->height = height; + 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 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); + 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; + } + va_end(ap); + + p->d = d; + p->w = w; + p->px = pm; + + p->zoom = 1; + p->nplots = nplots; + + pthread_mutex_init(&p->lock, NULL); + + if (pipe(p->timer_pipe)) abort(); + + new_thread(plot_thread, p); + new_thread(timer_thread, p); + + return p; +} + +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->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, int pp) +{ + plot *p = _plot; + if (pthread_mutex_lock(&p->lock)) abort(); + 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, int pp) +{ + plot *p = _plot; + if (pthread_mutex_lock(&p->lock)) abort(); + 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_iq_point_loop(void *_plot, short i, short q, int pp) +{ + plot *p = _plot; + if (pthread_mutex_lock(&p->lock)) abort(); + 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(); +} + +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(); +}