#ifndef SET_LOGIC_SCOPE_H #define SET_LOGIC_SCOPE_H #include #include #include #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; unsigned trigger_mode, trigger_channel; /* FREE, RISE, FALL, HIGH, LOW */ unsigned stream, stream_rate; /* Separate acquisition mode; rate 0 follows timebase. */ uint64_t stream_samples; 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;icount;++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