diff --git a/c/logic-scope/README.md b/c/logic-scope/README.md index 96c4403..1c4e30c 100644 --- a/c/logic-scope/README.md +++ b/c/logic-scope/README.md @@ -19,3 +19,5 @@ Its `tests/test_logic_scope.c` checks the capture plan, phase-shifted PWM, constant inputs, menu selection, retained snapshots, and renderer bounds. `include/scope_decoders.h` contains the portable DSView catalogue/configuration/annotation model; the isolated ARM adapter is in `tools/scope-decoders`. The framebuffer UI and UIO acquisition live in the Zynq board project. + +`include/logic_stream.h` assembles contiguous stream blocks into bounded windows, checks block sequence, preserves trigger edges across block boundaries, and stops after one window in SINGLE. FREE/RISE/FALL/HIGH/LOW use an explicitly selected D0-D7 input. Frame publication is independent of how many windows the display renders. The board integration owns DMA acknowledgement, overflow handling and exclusive UIO access. diff --git a/c/logic-scope/include/logic_scope.h b/c/logic-scope/include/logic_scope.h index a6069d7..5cf8f6b 100644 --- a/c/logic-scope/include/logic_scope.h +++ b/c/logic-scope/include/logic_scope.h @@ -9,6 +9,9 @@ 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; diff --git a/c/logic-scope/include/logic_stream.h b/c/logic-scope/include/logic_stream.h new file mode 100644 index 0000000..21fbb36 --- /dev/null +++ b/c/logic-scope/include/logic_stream.h @@ -0,0 +1,37 @@ +#ifndef SET_LOGIC_STREAM_H +#define SET_LOGIC_STREAM_H +#include "logic_scope.h" +typedef struct { uint8_t pending[LOGIC_SCOPE_MAX]; unsigned filled,target,previous,have_previous,triggered,sequence; } LogicStream; +static inline unsigned logic_stream_divider(double span,unsigned rate) { + static const unsigned fixed[]={0,1000,100,20,10}; + if(rate>0&&rate<5)return fixed[rate]; + double value=ceil(span*100000000.0/LOGIC_SCOPE_MAX); + return !isfinite(value)||value<10?10:value>65535?65535:(unsigned)value; +} +static inline void logic_stream_reset(LogicStream *state,unsigned target) { + memset(state,0,sizeof(*state));state->target=target<1?1:target>LOGIC_SCOPE_MAX?LOGIC_SCOPE_MAX:target; +} +static inline int logic_stream_match(unsigned mode,unsigned previous,unsigned current,unsigned valid,unsigned channel) { + unsigned mask=1u<<(channel&7),a=previous&mask,b=current&mask; + return !mode || (mode==1&&valid&&!a&&b)||(mode==2&&valid&&a&&!b)||(mode==3&&b)||(mode==4&&!b); +} +/* Sequence continuity is checked before touching the displayed frame. */ +static inline int logic_stream_feed(LogicStream *state,LogicScope *scope,unsigned sequence,const uint8_t *bytes,unsigned count) { + if(sequence!=state->sequence)return -1; + ++state->sequence;scope->stream_samples+=count;int updated=0; + unsigned i=0; + while(itriggered&&itriggered=logic_stream_match(scope->trigger_mode,state->previous,current,state->have_previous,scope->trigger_channel); + if(!state->triggered){state->previous=current;state->have_previous=1;++i;} + } + if(i==count)break; + unsigned take=state->target-state->filled;if(take>count-i)take=count-i; + memcpy(state->pending+state->filled,bytes+i,take);state->filled+=take;i+=take; + state->previous=bytes[i-1];state->have_previous=1; + if(state->filled==state->target){memcpy(scope->samples,state->pending,state->target);scope->count=state->target;scope->origin_s=0;++scope->generation;updated=1;state->filled=0;state->triggered=0; + if(scope->single){scope->single=scope->running=0;break;} + } + }return updated; +} +#endif