From 2d161e298d7e0605fac08e574f2a03fbd49e58e0 Mon Sep 17 00:00:00 2001 From: rodri Date: Sat, 7 Dec 2024 17:19:48 +0000 Subject: new tool: chrono (wip) --- chrono.c | 255 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ mkfile | 10 +++ nanosec.c | 38 ++++++++++ 3 files changed, 303 insertions(+) create mode 100644 chrono.c create mode 100644 mkfile create mode 100644 nanosec.c diff --git a/chrono.c b/chrono.c new file mode 100644 index 0000000..26750b4 --- /dev/null +++ b/chrono.c @@ -0,0 +1,255 @@ +#include +#include +#include +#include +#include +#include + +#define HZ2MS(hz) (1000/(hz)) + +enum { + Stop, + Pause, + Run, +}; + +typedef struct Stopwatch Stopwatch; +struct Stopwatch +{ + uvlong elapsed; /* in ms */ + char hms[4][4]; + int state; + + void (*start)(Stopwatch*); + void (*stop)(Stopwatch*); + void (*pause)(Stopwatch*); + void (*update)(Stopwatch*, uvlong); + void (*draw)(Stopwatch*, Image*, Point, double); +}; + +char deffont[] = "/lib/font/bit/lucida/unicode.32.font"; + +Image *screenb; +Keyboardctl *kc; +Mousectl *mc; +Channel *drawc; +Stopwatch *chrono; + +uvlong nanosec(void); + +static void +stopwatch_start(Stopwatch *self) +{ + if(self->state == Stop) + self->elapsed = 0; + + self->state = Run; +} + +static void +stopwatch_stop(Stopwatch *self) +{ + if(self->state == Run) + self->state = Stop; +} + +static void +stopwatch_pause(Stopwatch *self) +{ + if(self->state == Run) + self->state = Pause; +} + +static void +stopwatch_update(Stopwatch *self, uvlong dt) +{ + int HMS[4], i; + double t; + + self->elapsed += dt; + t = self->elapsed; + t /= 60*60*1000; HMS[0] = t; t -= HMS[0]; + t *= 60; HMS[1] = t; t -= HMS[1]; + t *= 60; HMS[2] = t; t -= HMS[2]; + t *= 1000; HMS[3] = t; + + for(i = 0; i < nelem(HMS); i++) + snprint(self->hms[i], sizeof self->hms[i], i < 3? "%02d": "%03d", HMS[i]); +} + +static void +stopwatch_draw(Stopwatch *self, Image *dst, Point dp, double scale) +{ + USED(scale); + int i; + + for(i = 0; i < nelem(self->hms); i++){ + if(i > 0) + dp = string(dst, dp, display->white, ZP, font, i < 3? ":": "."); + dp = string(dst, dp, display->white, ZP, font, self->hms[i]); + } +} + +void +timer(void *arg) +{ + Stopwatch *s; + uvlong t0, t1; + uvlong dt; /* in ms */ + + threadsetname("tic-tac"); + + s = arg; + t0 = nanosec(); + for(;;){ + t1 = nanosec(); + dt = (t1 - t0)/1000000ULL; + + if(s->state == Run){ + s->update(s, dt); + nbsend(drawc, nil); + } + + t0 = t1; + sleep(HZ2MS(13)); + } +} + +Stopwatch * +mkstopwatch(void) +{ + Stopwatch *s; + + s = malloc(sizeof *s); + if(s == nil) + sysfatal("malloc: %r"); + + memset(s, 0, sizeof *s); + s->start = stopwatch_start; + s->stop = stopwatch_stop; + s->pause = stopwatch_pause; + s->update = stopwatch_update; + s->draw = stopwatch_draw; + + proccreate(timer, s, mainstacksize); + + return s; +} + +void +rmstopwatch(Stopwatch *s) +{ + free(s); +} + +void +initscreenb(void) +{ + if(screenb != nil) + freeimage(screenb); + + screenb = allocimage(display, rectsubpt(screen->r, screen->r.min), screen->chan, 0, DNofill); + if(screenb == nil) + sysfatal("allocimage: %r"); +} + +void +redraw(void) +{ + draw(screenb, screenb->r, display->black, nil, ZP); + chrono->draw(chrono, screenb, Pt(10, 10), 1); + draw(screen, screen->r, screenb, nil, ZP); + flushimage(display, 1); +} + +void +resize(void) +{ + if(getwindow(display, Refnone) < 0) + sysfatal("resize failed"); + + initscreenb(); + nbsend(drawc, nil); +} + +void +mouse(Mousectl *) +{ + +} + +void +key(Rune r) +{ + switch(r){ + case Kdel: + threadexitsall(nil); + case Kesc: + if(chrono->state == Run) + chrono->pause(chrono); + else if(chrono->state == Pause) + chrono->start(chrono); + break; + case ' ': + if(chrono->state == Run) + chrono->stop(chrono); + else if(chrono->state == Stop) + chrono->start(chrono); + break; + } +} + +void +usage(void) +{ + fprint(2, "usage: %s\n", argv0); + exits("usage"); +} + +void +threadmain(int argc, char *argv[]) +{ + Rune r; + + ARGBEGIN{ + default: usage(); + }ARGEND; + + if(initdraw(nil, deffont, "chrono") < 0) + sysfatal("initdraw: %r"); + if((mc = initmouse(nil, screen)) == nil) + sysfatal("initmouse: %r"); + if((kc = initkeyboard(nil)) == nil) + sysfatal("initkeyboard: %r"); + + initscreenb(); + drawc = chancreate(sizeof(void*), 1); + nbsend(drawc, nil); + chrono = mkstopwatch(); + + enum { MOUSE, RESIZE, KEYS, DRAW, NONE }; + Alt a[] = { + [MOUSE] {mc->c, &mc->Mouse, CHANRCV}, + [RESIZE] {mc->resizec, nil, CHANRCV}, + [KEYS] {kc->c, &r, CHANRCV}, + [DRAW] {drawc, nil, CHANRCV}, + [NONE] {nil, nil, CHANEND} + }; + for(;;) + switch(alt(a)){ + case MOUSE: + mouse(mc); + break; + case RESIZE: + resize(); + break; + case KEYS: + key(r); + break; + case DRAW: + redraw(); + break; + default: + sysfatal("main loop interrupted"); + } +} diff --git a/mkfile b/mkfile new file mode 100644 index 0000000..ae67b34 --- /dev/null +++ b/mkfile @@ -0,0 +1,10 @@ + +#include +#include + +/* + * nsec() is wallclock and can be adjusted by timesync + * so need to use cycles() instead, but fall back to + * nsec() in case we can't + */ +uvlong +nanosec(void) +{ + static uvlong fasthz, xstart; + uvlong x, div; + + if(fasthz == ~0ULL) + return nsec() - xstart; + + if(fasthz == 0){ + if(_tos->cyclefreq){ + cycles(&xstart); + fasthz = _tos->cyclefreq; + } else { + xstart = nsec(); + fasthz = ~0ULL; + fprint(2, "cyclefreq not available, falling back to nsec()\n"); + fprint(2, "you might want to disable aux/timesync\n"); + return 0; + } + } + cycles(&x); + x -= xstart; + + /* this is ugly */ + for(div = 1000000000ULL; x < 0x1999999999999999ULL && div > 1 ; div /= 10ULL, x *= 10ULL); + + return x / (fasthz / div); +} -- cgit v1.2.3