Think: NR with different number of slots per frame depending on mu. The name 'subframes_per_frame' is a bit ambiguous. It is valid for LTE, but for NR it should be 'slots_per_frame'. For example, for sub-carrier spacing of 30KHz, we have 20 slots per frame, so in this case subframes_per_frame = 20. In reality whatever the numerology, there is always 10 subframes per frame in NR. But how to name this variable which is used both for LTE and NR cases? 'subframes_or_slots_per_frame'? It's a bit long and also ambiguous. Conclusion: no big deal I think. 'subframes_per_frame' and so be it.
132 lines
3.6 KiB
C
132 lines
3.6 KiB
C
#include "view.h"
|
|
#include "../utils.h"
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <pthread.h>
|
|
#include <stdarg.h>
|
|
#include <string.h>
|
|
#include <math.h>
|
|
|
|
struct scrolltti {
|
|
view common;
|
|
gui *g;
|
|
widget *w;
|
|
widget *throughput_textarea;
|
|
int plot;
|
|
float refresh_rate;
|
|
pthread_mutex_t lock;
|
|
int subframes_per_frame;
|
|
unsigned long *data;
|
|
unsigned long total; /* sum data[0..n] to have smoother value printed */
|
|
float *xout;
|
|
float *yout;
|
|
int insert_point;
|
|
int next_tick_frame;
|
|
int next_tick_subframe;
|
|
};
|
|
|
|
/* this array is used to get Y range 1000, 2000, 5000, 10000, ... */
|
|
static int tolog[11] = { -1, 1, 2, 5, 5, 5, 10, 10, 10, 10, 10 };
|
|
|
|
static void *scrolltti_thread(void *_this)
|
|
{
|
|
struct scrolltti *this = _this;
|
|
int i;
|
|
int p;
|
|
float max, mlog;
|
|
char o[64];
|
|
|
|
while (1) {
|
|
if (pthread_mutex_lock(&this->lock)) abort();
|
|
/* TODO: optimize */
|
|
p = this->insert_point;
|
|
max = 0;
|
|
for (i = 0; i < this->subframes_per_frame * 100; i++) {
|
|
this->xout[i] = i;
|
|
this->yout[i] = this->data[p];
|
|
if (this->data[p] > max) max = this->data[p];
|
|
p = (p + 1) % (this->subframes_per_frame * 100);
|
|
}
|
|
bps(o, this->total/(this->subframes_per_frame * 100.), "b/s");
|
|
textarea_set_text(this->g, this->throughput_textarea, o);
|
|
/* for Y range we want 1000, 2000, 5000, 10000, 20000, 50000, etc. */
|
|
if (max < 1000) max = 1000;
|
|
mlog = pow(10, floor(log10(max)));
|
|
max = tolog[(int)ceil(max/mlog)] * mlog;
|
|
xy_plot_set_range(this->g, this->w, 0, this->subframes_per_frame * 100, 0, max);
|
|
xy_plot_set_points(this->g, this->w, this->plot,
|
|
this->subframes_per_frame * 100, this->xout, this->yout);
|
|
if (pthread_mutex_unlock(&this->lock)) abort();
|
|
sleepms(1000/this->refresh_rate);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void clear(view *this)
|
|
{
|
|
/* TODO */
|
|
}
|
|
|
|
static void insert(struct scrolltti *this, double value)
|
|
{
|
|
this->total -= this->data[this->insert_point];
|
|
this->data[this->insert_point] = value;
|
|
this->total += this->data[this->insert_point];
|
|
this->insert_point = (this->insert_point + 1) % (this->subframes_per_frame * 100);
|
|
}
|
|
|
|
static void next_subframe(struct scrolltti *this)
|
|
{
|
|
this->next_tick_subframe++;
|
|
if (this->next_tick_subframe == this->subframes_per_frame) {
|
|
this->next_tick_subframe = 0;
|
|
this->next_tick_frame++;
|
|
this->next_tick_frame %= 1024;
|
|
}
|
|
}
|
|
|
|
static void append(view *_this, int frame, int subframe, double value)
|
|
{
|
|
struct scrolltti *this = (struct scrolltti *)_this;
|
|
|
|
if (pthread_mutex_lock(&this->lock)) abort();
|
|
while (this->next_tick_frame != frame || this->next_tick_subframe != subframe) {
|
|
insert(this, 0);
|
|
next_subframe(this);
|
|
}
|
|
insert(this, value);
|
|
next_subframe(this);
|
|
if (pthread_mutex_unlock(&this->lock)) abort();
|
|
}
|
|
|
|
view *new_view_scrolltti(float refresh_rate, gui *g, widget *w, int color,
|
|
widget *throughput_textarea, int subframes_per_frame)
|
|
{
|
|
struct scrolltti *ret = calloc(1, sizeof(struct scrolltti));
|
|
if (ret == NULL) abort();
|
|
|
|
ret->common.clear = clear;
|
|
ret->common.append = (void (*)(view *, ...))append;
|
|
|
|
ret->refresh_rate = refresh_rate;
|
|
ret->g = g;
|
|
ret->w = w;
|
|
ret->throughput_textarea = throughput_textarea;
|
|
ret->plot = xy_plot_new_plot(g, w, color);
|
|
|
|
ret->subframes_per_frame = subframes_per_frame;
|
|
ret->data = calloc(subframes_per_frame * 100, sizeof(unsigned long));
|
|
if (ret->data == NULL) abort();
|
|
ret->xout = calloc(subframes_per_frame * 100, sizeof(float));
|
|
if (ret->xout == NULL) abort();
|
|
ret->yout = calloc(subframes_per_frame * 100, sizeof(float));
|
|
if (ret->yout == NULL) abort();
|
|
|
|
if (pthread_mutex_init(&ret->lock, NULL)) abort();
|
|
|
|
new_thread(scrolltti_thread, ret);
|
|
|
|
return (view *)ret;
|
|
}
|