ERIS CORE
eris_analyze_scope.cpp
Go to the documentation of this file.
1 /* Audio Library for Teensy 3.X
2  * Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com
3  *
4  * Development of this audio library was funded by PJRC.COM, LLC by sales of
5  * Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop
6  * open source software by purchasing Teensy or other PJRC products.
7  *
8  * Permission is hereby granted, free of charge, to any person obtaining a copy
9  * of this software and associated documentation files (the "Software"), to deal
10  * in the Software without restriction, including without limitation the rights
11  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12  * copies of the Software, and to permit persons to whom the Software is
13  * furnished to do so, subject to the following conditions:
14  *
15  * The above copyright notice, development funding notice, and this permission
16  * notice shall be included in all copies or substantial portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24  * THE SOFTWARE.
25  */
26 
27 
28 /**
29  * @file eris_analyze_scope.cpp
30  * @author Brian Monkaba (brian.monkaba@gmail.com)
31  * @brief
32  * @version 0.1
33  * @date 2021-08-24
34  *
35  * @copyright portions Copyright (c) 2021
36  *
37  */
38 
39 
40 #include <Arduino.h>
41 #include <arm_math.h>
42 #include "eris_analyze_scope.h"
43 
44 
45 #define SCOPE_MAX_TRIGGER_WAIT 800
46 
47 #define STATE_IDLE 0 // doing nothing
48 #define STATE_WAIT_TRIGGER 1 // looking for trigger condition
49 #define STATE_DELAY 2 // waiting from trigger to print
50 #define STATE_PRINTING 3 // printing data
51 
53 {
54  audio_block_t *block;
55  audio_block_t *blockb; //2nd channel (optional)
56  bool isDualChannel;
57 
58  uint32_t offset;
59  uint32_t remain;
60 
61  //capture only if channel 0 is connected
62  block = receiveReadOnly(0);
63  if (!block){
64  blockb = receiveReadOnly(1);
65  if (blockb) release(blockb);
66  return;
67  }
68 
69  blockb = receiveReadOnly(1);
70  if (!blockb) {
71  isDualChannel = false;
72  } else isDualChannel = true;
73 
74  offset = 0;
75  while (offset < AUDIO_BLOCK_SAMPLES) {
76  remain = AUDIO_BLOCK_SAMPLES - offset;
77  switch (state) {
78  case STATE_WAIT_TRIGGER:
79  // TODO: implement this....
80  offset = AUDIO_BLOCK_SAMPLES;
81  break;
82 
83  case STATE_DELAY:
84  //Serial.printf("STATE_DELAY, count = %u\n", count);
85  if (remain < count) {
86  count -= remain;
87  offset = AUDIO_BLOCK_SAMPLES;
88  } else {
89  offset += count;
90  count = mem_length;
91  state = STATE_PRINTING;
92  }
93  break;
94 
95  case STATE_PRINTING:
96  //wait for the zero crossing on ch1
97  if (count == mem_length){
98  dot = 0;
99  dotAvg = 0;
100  dotAvgSlow = 0;
101  dotDelta = 0;
102  dotDeltaMACD = 0;
103  dotAccel = 0;
104  dotMACD = 0;
105  edgeCount = 0;
106  edgeCount_ch2 = 0;
107  peakValue = 0;
108  edgeTimer=0;
109  edgeDelay=0;
110  edgeTimer2=0;
111  edgeDelay2=0;
112 
113  bool found = false;
114  for(int16_t i=1;i < AUDIO_BLOCK_SAMPLES-h_div;i++){
115  if(trigger_wait_count > SCOPE_MAX_TRIGGER_WAIT){
116  //force the trigger
117  found=true;
118  edgeTimer=0;
119  edgeTimer2=0;
120  break;
121  }
122  if (block->data[i] > 0 && block->data[i-1] < 0){
123  offset = i;
124  if(isDualChannel){
125  if (blockb->data[i] > 0 || 1){
126  found = true;
127  }
128  }else found = true;
129  if (found){
130  edgeTimer=0;
131  edgeTimer2=0;
132  break;
133  }
134  }
135  }
136  //skip to the next block
137  if(!found) {offset = AUDIO_BLOCK_SAMPLES;};
138 
139  }
140 
141  while ((offset < AUDIO_BLOCK_SAMPLES) && (count > 0)){
142  edgeTimer++;
143  edgeTimer2++;
144  //for every sample
145  if ((offset >= h_div) && block->data[offset] <= 0 && block->data[offset-h_div] >0){
146  if((edgeCount > 0) && (edgeTimer > 20)){
147  if (edgeDelay==0){edgeDelay = edgeTimer;
148  } else {
150  }
151  }
152  edgeTimer=0;
153  }
154  if (isDualChannel && (offset >= h_div) && blockb->data[offset] <= 0 && blockb->data[offset-h_div] >0){
155  if((edgeCount_ch2 > 0) && (edgeTimer2 > 20)){
156  if (edgeDelay2==0){edgeDelay2 = edgeTimer2;
157  } else {
159  }
160  }
161  edgeTimer2=0;
162  }
163 
164  h_div_count++;
165  //for the captured samples
166  if(h_div_count==h_div){
167  h_div_count=0;
168  count--;
169  _memory[0][mem_length - count - 1 ] = block->data[offset];
170  peakValue = max(peakValue,abs(block->data[offset]));
171  if (isDualChannel){
172  _memory[1][mem_length - count - 1 ] = blockb->data[offset];
173  //peakValue = max(peakValue,abs(blockb->data[offset]));
174  if ((offset >= h_div) && (blockb->data[offset] <= -10 ) && (blockb->data[offset-h_div] > 10)){
175  edgeCount_ch2++;
176  }
177  }else _memory[1][mem_length - count - 1 ] = 0;
178 
179  if ((offset >= h_div) && (block->data[offset] <= -10 ) && (block->data[offset-h_div] > 10)){
180  edgeCount++;
181  }
182  }
183  offset++;
184  }
185 
186 
187  if (count == 0){
188  //Serial.println(edgeCount);
189  //only update the values if data is available
190  if(peakValue >0){
191  if((edgeCount < 8) && (auto_h_div < 16)) auto_h_div++;
192  if((edgeCount > 11) && (auto_h_div > 1)) auto_h_div--;
193  //calculate the dot product if dual channel
194  if (isDualChannel ){
195  q63_t lastDelta;
196  lastDelta= dotDelta;
197  dotLast = dot/1000000;
198  arm_dot_prod_q15(&_memory[0][0],&_memory[1][0],mem_length,&dot);
199  dot = dot /1000000;
200  dotDelta = ((dot) - (dotLast));
201  dotAccel = ((dotDelta)-(lastDelta));
202  dotAvg = (dotAvg/2) + (dot/2);
203  dotAvgSlow = (dotAvg/2) + (dotAvgSlow/2);
204  dotMACD = ((dotAvg) - (dotAvgSlow));
205  //(dotMACD>0)?:dotMACD*=-1;
207  memcpy(&memory[1],&_memory[1],sizeof(_memory[1]));
208  }
209  //buffered outputs
210  memcpy(&memory[0],&_memory[0],sizeof(_memory[0]));
213  dot_output=dot;
224  }
225  isAvailable = true;
226  if (autoTrigger){
227  trigger();
228  }else state = STATE_IDLE;
229  trigger_wait_count = 0;
230  }
231  break;
232 
233  default: // STATE_IDLE
234  offset = AUDIO_BLOCK_SAMPLES;
235  break;
236  }
237  }
238  release(block);
239  if(isDualChannel) release(blockb);
240 }
241 
242 
243 int16_t erisAudioAnalyzeScope::read(int8_t channel, uint16_t mem_index){
244  if (mem_index > mem_length) return 0;
245  return memory[channel][mem_index];
246 }
247 
249 {
250  h_div = auto_h_div;
251  if (count ==0){ //ignore external trigger requests if already capturing
252  if (delay_length > 0) {
254  state = STATE_DELAY;
255  } else {
256  count = mem_length;
257  state = STATE_PRINTING;
258  }
259  }
260 }
261 
263  if (isAvailable){
264  isAvailable = false;
265  trigger();
266  return true;
267  }
268  return false;
269 }
270 
static void release(audio_block_t *block)
audio_block_t * receiveReadOnly(unsigned int index=0)
volatile uint32_t edgeCount_output
volatile int32_t dotMACD_output
volatile int16_t peakValue_output
volatile q63_t dotLast_output
virtual void update(void)
volatile int32_t dotAvgSlow_output
volatile uint32_t edgeDelay_output
volatile int32_t dotAccel_output
int16_t read(int8_t channel, uint16_t mem_index)
volatile int32_t dotDelta_output
volatile uint32_t edgeDelay2_output
volatile int32_t dotDeltaMACD_output
volatile uint32_t edgeCount_ch2_output
volatile int32_t dotAvg_output
int16_t data[AUDIO_BLOCK_SAMPLES]
Definition: AudioStream.h:78