import the T tracer into openair
This commit is contained in:
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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_ */
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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_ */
|
||||
@@ -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_ */
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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_ */
|
||||
@@ -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_ */
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
Reference in New Issue
Block a user