Files
templates/c/logic-scope/include/logic_scope.h
T

61 lines
2.0 KiB
C

#ifndef SET_LOGIC_SCOPE_H
#define SET_LOGIC_SCOPE_H
#include <stdint.h>
#include <string.h>
#include <math.h>
#define LOGIC_SCOPE_MAX 65536u
typedef struct {
uint8_t samples[LOGIC_SCOPE_MAX];
unsigned mode[8]; /* 0 off, 1 logic, 2 PWM envelope */
unsigned count, clock, divider, running, single, generation;
double origin_s;
char status[96];
} LogicScope;
static inline unsigned logic_scope_channels(const LogicScope *s)
{
unsigned n=0;
for (unsigned i=0;i<8;++i) n+=s->mode[i]!=0;
return n;
}
/* Capture the requested interval with the finest representable sample period. */
static inline int logic_scope_plan(double span, unsigned clock, unsigned depth,
unsigned *count, unsigned *divider)
{
if (!isfinite(span) || span<=0 || !clock || depth<2 || depth>LOGIC_SCOPE_MAX) return 0;
double ticks=ceil(span*clock/depth);
ticks=fmax(1,fmin(65536,ticks));
*divider=(unsigned)ticks-1;
*count=(unsigned)fmax(2,fmin(depth,ceil(span*clock/ticks)));
return 1;
}
typedef void (*LogicScopePoint)(void *context, double time, double value);
/* Ignore clipped first/last cycles. A constant level has no measurable period. */
static inline unsigned logic_scope_pwm(const LogicScope *s, unsigned ch,
LogicScopePoint point, void *context)
{
if (ch>=8 || !s->clock || s->count<2) return 0;
unsigned rise=0,fall=0,have_rise=0,have_fall=0,n=0;
unsigned previous=(s->samples[0]>>ch)&1u;
double dt=(s->divider+1.0)/s->clock;
for (unsigned i=1;i<s->count;++i) {
unsigned level=(s->samples[i]>>ch)&1u;
if (level!=previous) {
if (level) {
if (have_rise && have_fall) {
point(context,s->origin_s+(rise+(i-rise)*0.5)*dt,
2.0*(fall-rise)/(i-rise)-1.0);
++n;
}
rise=i; have_rise=1; have_fall=0;
} else if (have_rise) { fall=i; have_fall=1; }
}
previous=level;
}
return n;
}
#endif