Circular_Buffer

I could add print(ln) to circular arrays, it just wasnt added because it was just implemented in the buffer instead. If i do add it, though, since text has an arbitrary size, you will need the length() method which gives the length of the text in the queue, and use that when dequeuing to a matching char array size. If there is a use for this I will implement it later..

No thats correct, you have a 32 byte buffer, 0-31.
You then have a for loop up to 33 (which includes 0) (34 bytes total)
0 and 1 are overridden.
The head of the first read is pushed 2 places ahead as 0 and 1 are written as 32 and 33 (which the tail resides at (33)).
Therefore, your first byte is 2 and your last byte is 33
:)

The first byte is always the oldest. If you prefer LIFO, you can read from back to front, otherwise default is FIFO, oldest to newest data.
 
Last edited:
No thats correct, you have a 32 byte buffer, 0-31.
You then have a for loop up to 33 (which includes 0) (34 bytes total)
0 and 1 are overridden.
The head of the first read is pushed 2 places ahead as 0 and 1 are written as 32 and 33 (which the tail resides at (33)).
Therefore, your first byte is 2 and your last byte is 33
:)

The first byte is always the oldest. If you prefer LIFO, you can read from back to front, otherwise default is FIFO, oldest to newest data.

Hmm, so I modified the c5 section of the example to obtain a more detailed printout, as follows

Code:
uint8_t idx = 0;
  Serial.printf("Idx\tdata\t\Head Idx\tTail Idx\n");
  while ( c5.size() > 0 ) 
  {
    //Serial.println(c5.read());
    Serial.printf("%d\t%d\t%d\t%d\n", 
        idx, c5.read(), c5.front(), c5.back());
    idx++;
  }

and got the following printout

Code:
Idx	data	Head Idx	Tail Idx
0	2	536897338	536897330
1	3	536897342	536897330
2	4	536897346	536897330
3	5	536897350	536897330
4	6	536897354	536897330
5	7	536897358	536897330
6	8	536897362	536897330
7	9	536897366	536897330
8	10	536897370	536897330
9	11	536897374	536897330
10	12	536897378	536897330
11	13	536897382	536897330
12	14	536897386	536897330
13	15	536897390	536897330
14	16	536897394	536897330
15	17	536897398	536897330
16	18	536897402	536897330
17	19	536897406	536897330
18	20	536897410	536897330
19	21	536897414	536897330
20	22	536897418	536897330
21	23	536897422	536897330
22	24	536897426	536897330
23	25	536897430	536897330
24	26	536897434	536897330
25	27	536897438	536897330
26	28	536897442	536897330
27	29	536897446	536897330
28	30	536897450	536897330
29	31	536897326	536897330
30	32	536897330	536897330
31	33	536897334	536897330

Where the head/tail values appear to be actual RAM addresses rather than relative buffer indices - why is that?

So then I looked at the code a bit, but I got lost pretty quickly ;-(.

So, I went back and modified the example code to show relative element indices rather than RAM addresses, and also printed out several buffer attributes, as shown below:

Code:
  Serial.print("Clearing buffer..."); c5.clear(); Serial.print("Done.\n");
  uint16_t* buffstart = c5.front();
  Serial.printf("Writing 34 values to a 32 position circular buffer...\n");
  Serial.printf("Idx\tdata\t\Rd Ptr\tWr Ptr\tSize\tAvail\tCap\n");
  //for ( uint16_t i = 0; i < 34; i++ ) c5.write(i);
  for (uint16_t i = 0; i < 34; i++)
  {
      c5.write(i);
    Serial.printf("%d\t%d\t%d\t%d\t%d\t%d\t%d\n", 
        i, i, (c5.front() - buffstart) / sizeof(uint16_t),
        (c5.back() - buffstart) / sizeof(uint16_t),
        c5.size(),c5.available(),c5.capacity());
  }
  Serial.printf("Done. \n\n");
  Serial.printf("Reading the above values back out again.......\n");
  Serial.printf("Idx\tdata\t\Rd Ptr\tWr Ptr\tSize\tAvail\tCap\n");
  uint8_t idx = 0;
  while ( c5.size() > 0 ) 
  {
    //Serial.println(c5.read());
      Serial.printf("%d\t%d\t%d\t%d\t%d\t%d\t%d\n",
          idx, c5.read(), (c5.front() - buffstart) / sizeof(uint16_t),
          (c5.back() - buffstart) / sizeof(uint16_t),
          c5.size(), c5.available(), c5.capacity());
      idx++;
  } 
  Serial.printf("Done. \n\n");
  //Serial.println("OK");
  
  while (true)
  {

  }

And this produced the following output:

Code:
Opening port
Port open
----------------------
Clearing buffer...Done.
Writing 34 values to a 32 position circular buffer...
Idx	data	Rd Ptr	Wr Ptr	Size	Avail	Cap
0	0	0	0	1	1	32
1	1	0	1	2	2	32
2	2	0	2	3	3	32
3	3	0	3	4	4	32
4	4	0	4	5	5	32
5	5	0	5	6	6	32
6	6	0	6	7	7	32
7	7	0	7	8	8	32
8	8	0	8	9	9	32
9	9	0	9	10	10	32
10	10	0	10	11	11	32
11	11	0	11	12	12	32
12	12	0	12	13	13	32
13	13	0	13	14	14	32
14	14	0	14	15	15	32
15	15	0	15	16	16	32
16	16	0	16	17	17	32
17	17	0	17	18	18	32
18	18	0	18	19	19	32
19	19	0	19	20	20	32
20	20	0	20	21	21	32
21	21	0	21	22	22	32
22	22	0	22	23	23	32
23	23	0	23	24	24	32
24	24	0	24	25	25	32
25	25	0	25	26	26	32
26	26	0	26	27	27	32
27	27	0	27	28	28	32
28	28	0	28	29	29	32
29	29	0	29	30	30	32
30	30	0	30	31	31	32
31	31	0	31	32	32	32
32	32	1	0	32	32	32
33	33	2	1	32	32	32
Done. 

Reading the above values back out again.......
Idx	data	Rd Ptr	Wr Ptr	Size	Avail	Cap
0	2	3	1	31	31	32
1	3	4	1	30	30	32
2	4	5	1	29	29	32
3	5	6	1	28	28	32
4	6	7	1	27	27	32
5	7	8	1	26	26	32
6	8	9	1	25	25	32
7	9	10	1	24	24	32
8	10	11	1	23	23	32
9	11	12	1	22	22	32
10	12	13	1	21	21	32
11	13	14	1	20	20	32
12	14	15	1	19	19	32
13	15	16	1	18	18	32
14	16	17	1	17	17	32
15	17	18	1	16	16	32
16	18	19	1	15	15	32
17	19	20	1	14	14	32
18	20	21	1	13	13	32
19	21	22	1	12	12	32
20	22	23	1	11	11	32
21	23	24	1	10	10	32
22	24	25	1	9	9	32
23	25	26	1	8	8	32
24	26	27	1	7	7	32
25	27	28	1	6	6	32
26	28	29	1	5	5	32
27	29	30	1	4	4	32
28	30	31	1	3	3	32
29	31	0	1	2	2	32
30	32	1	1	1	1	32
31	33	2	1	0	0	32
Done.

Which leads me to ask the following questions:

  1. 'front()' returns the READ pointer, and 'back()' returns the WRITE pointer. Is this correct?
  2. 'size()' appears to return the number of elements written since the last 'clear()' operation; is this correct?
  3. 'available()' appears to be identical to 'size()'. Why have two functions that return identical results?
  4. 'capacity()' appears to return the original element capacity - correct?

Sorry for all the too-basic questions, but I'm a circular buffer noob ;-)

TIA,

Frank
 
1 is correct, but back is a READ pointer as well. Thats how you pull LIFO.
size and available are the same, due to common usages between programmers, spme may prefer one over the other. Capacity is the size given in the constructor, just for the user to check the size() doesnt exceed capacity() before adding, otherwise oldest entry will be overidden
 
Thanks for the quick response! I'm going to try and use your circular buffer class for my I2C Sniffer project, and I'm sure I'll have more questions ;-).
 
Dont worry, theres more features there than you realize, which makes data entry and data lookups one of the excellent features of circular arrays. :)
 
I created a small program to test the idea of using a circular buffer for my I2C Sniffer program. An ISR that triggers every microsecond from Timer1 reads an 8-bit value from a fixed array containing previously captured I2C bus transitions, and then writes the value to a circular buffer. Writes to the buffer pause when the last byte of the simulated data array is read. Reading and writing are re-enabled every 200 mSec by an interval timer in loop(). Code is shown below:

Code:
/*
    Name:       Teensy_I2C_Sniffer_V6.ino
    Created:	1/4/2020 8:40:20 AM
    Author:     FRANKNEWXPS15\Frank

    This is a port of my Excel VBA code into Arduino/Teensy C++ language.
    It parses the exact same sample data as the Excel program, so it should
    produce the exact same I2C sequences.

    The captured sample data to be parsed is held in the 'simdata' array.

    The original VBA code is saved in 'ExcelVBACode.txt'
*/

/* 'Notes:

    A typical I2C sentence when communicating with a MPU6050 IMU module goes like:
        "I2C(68) wrote 1 byte to 75 - C0 Done."
        "I2C(68) wrote 3 bytes to 72 - C0 0C 10 Done."
        "I2C(68) read 5 bytes from 6A - C0 0C 10 14 03 Done."

    To form a sentence, we need:
        Device addr: 68 in the above examples
        Read/Write direction
        To/From register address:  75, 72 and 6A in the above examples
        Data:  C0, C0 0C 10, and C0 0C 10 14 03 in the above examples
        number of bytes written/read:  1,3 & 5 in the above examples

     Each I2C communication proceeds as follows (assuming a START from an IDLE condition):
         A START or RESTART condition, denoted by SDA & SCL HIGH, followed by SDA LOW, SCL HIGH
         A 7-bit device address, MSB first (0x8/0xC = 1, 0x0/0x4 = 0)
         A R/W bit (0x8/0xC = read, 0x0/0x4 = write)
         An ACK bit (0x8/0xC = NAK, 0x0/0x4 = ACK)
         If the bus direction is WRITE, then
             A register address for read/write
             zero or more additional data bytes
         Else (the bus direction is READ)
            One or more additional data bytes
         Endif
*/

/*
This version adds tonton81's circular buffer class (https://github.com/tonton81/Circular_Buffer)
to simulate real-time processing and display of I2C bus activity.  The sample data is loaded into
a FIFO by an ISR triggered every microsecond by a timer, and then the processing code pulls it out
and parses it as fast as possible.  If this works, then the next version will eliminate the sample
data and connect to a live I2C bus.
*/

#include <TimerOne.h> //needed for ISR
#include "circular_buffer.h"
Circular_Buffer<uint8_t, 2048> cb_trans; //holds transition values from ISR

#define MONITOR_OUT1 2 //so can monitor ISR activity with O'scope
#define MONITOR_OUT2 3 //so can monitor ISR activity with O'scope

const int SIM_DATA_ARRAY_SIZE = 928;
byte simdata[SIM_DATA_ARRAY_SIZE] =
{
    0xc, 0x4, 0x8, 0xc, 0x8, 0xc, 0x0, 0x4, 0x8, 0xc, 0x0,
    0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x8, 0xc, 0x8, 0xc,
    0x8, 0xc, 0x0, 0x4, 0x8, 0xc, 0x0, 0x4, 0x8, 0xc, 0x0, 0x4, 0x0, 0x4, 0xc,
    0x4, 0x8, 0xc, 0x8, 0xc, 0x0, 0x4, 0x8, 0xc, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4,
    0x8, 0xc, 0x0, 0x4, 0x0, 0x4, 0x8, 0xc, 0x8, 0xc, 0x0, 0x4, 0x8, 0xc, 0x0,
    0x4, 0x0, 0x4, 0x0, 0x4, 0x8, 0xc, 0x0, 0x4, 0xc, 0x4, 0x8, 0xc, 0x8, 0xc,
    0x0, 0x4, 0x8, 0xc, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0,
    0x4, 0x8, 0xc, 0x8, 0xc, 0x0, 0x4, 0x8, 0xc, 0x0, 0x4, 0x8, 0xc, 0x0, 0x4,
    0x0, 0x4, 0x0, 0x4, 0xc, 0x4, 0x8, 0xc, 0x8, 0xc, 0x0, 0x4, 0x8, 0xc, 0x0,
    0x4, 0x0, 0x4, 0x0, 0x4, 0x8, 0xc, 0x0, 0x4, 0x8, 0xc, 0x8, 0xc, 0x0, 0x4,
    0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x8, 0xc, 0x0, 0x4, 0xc,
    0x4, 0x8, 0xc, 0x8, 0xc, 0x0, 0x4, 0x8, 0xc, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4,
    0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x8, 0xc, 0x8, 0xc, 0x0, 0x4, 0x8, 0xc, 0x0,
    0x4, 0x8, 0xc, 0x0, 0x4, 0x0, 0x4, 0x8, 0xc, 0x8, 0xc, 0x0, 0x4, 0x0, 0x4,
    0x0, 0x4, 0x8, 0xc, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0xc, 0x4, 0x8,
    0xc, 0x8, 0xc, 0x0, 0x4, 0x8, 0xc, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4,
    0x0, 0x4, 0x0, 0x4, 0x8, 0xc, 0x8, 0xc, 0x8, 0xc, 0x0, 0x4, 0x0, 0x4, 0x8,
    0xc, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0xc, 0x4, 0x8, 0xc, 0x8, 0xc, 0x0, 0x4,
    0x8, 0xc, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x8, 0xc, 0x0, 0x4, 0x0, 0x4, 0x0,
    0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4,
    0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x8, 0xc, 0x8, 0xc, 0x8, 0xc, 0x0, 0x4, 0x0,
    0x4, 0x8, 0xc, 0x0, 0x4, 0xc, 0x4, 0x8, 0xc, 0x8, 0xc, 0x0, 0x4, 0x8, 0xc,
    0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x8, 0xc, 0x8,
    0xc, 0x8, 0xc, 0x0, 0x4, 0x0, 0x4, 0x8, 0xc, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4,
    0xc, 0x4, 0x8, 0xc, 0x8, 0xc, 0x0, 0x4, 0x8, 0xc, 0x0, 0x4, 0x0, 0x4, 0x0,
    0x4, 0x8, 0xc, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4,
    0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x8, 0xc, 0x8,
    0xc, 0x8, 0xc, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x8, 0xc, 0x0, 0x4, 0xc, 0x4,
    0x8, 0xc, 0x8, 0xc, 0x0, 0x4, 0x8, 0xc, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0,
    0x4, 0x0, 0x4, 0x0, 0x4, 0x8, 0xc, 0x8, 0xc, 0x8, 0xc, 0x0, 0x4, 0x0, 0x4,
    0x8, 0xc, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0xc, 0x4, 0x8, 0xc, 0x8, 0xc, 0x0,
    0x4, 0x8, 0xc, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x8, 0xc, 0x0, 0x4, 0x0, 0x4,
    0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0,
    0x4, 0x0, 0x4, 0x8, 0xc, 0x0, 0x4, 0x8, 0xc, 0x0, 0x4, 0x8, 0xc, 0x0, 0x4,
    0x0, 0x4, 0x8, 0xc, 0x0, 0x4, 0xc, 0x4, 0x8, 0xc, 0x8, 0xc, 0x0, 0x4, 0x8,
    0xc, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x8, 0xc,
    0x8, 0xc, 0x8, 0xc, 0x0, 0x4, 0x0, 0x4, 0x8, 0xc, 0x0, 0x4, 0x0, 0x4, 0x0,
    0x4, 0xc, 0x4, 0x8, 0xc, 0x8, 0xc, 0x0, 0x4, 0x8, 0xc, 0x0, 0x4, 0x0, 0x4,
    0x0, 0x4, 0x8, 0xc, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0,
    0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x8, 0xc, 0x8, 0xc,
    0x8, 0xc, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x8, 0xc, 0x0, 0x4, 0xc,
    0x4, 0x8, 0xc, 0x8, 0xc, 0x0, 0x4, 0x8, 0xc, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4,
    0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x8, 0xc, 0x8, 0xc, 0x8, 0xc, 0x0, 0x4, 0x0,
    0x4, 0x8, 0xc, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0xc, 0x4, 0x8, 0xc, 0x8, 0xc,
    0x0, 0x4, 0x8, 0xc, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x8, 0xc, 0x0, 0x4, 0x0,
    0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4,
    0x0, 0x4, 0x8, 0xc, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x8, 0xc, 0x8, 0xc, 0x0,
    0x4, 0x0, 0x4, 0x8, 0xc, 0x0, 0x4, 0xc, 0x4, 0x8, 0xc, 0x8, 0xc, 0x0, 0x4,
    0x8, 0xc, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x8,
    0xc, 0x8, 0xc, 0x8, 0xc, 0x0, 0x4, 0x0, 0x4, 0x8, 0xc, 0x0, 0x4, 0x0, 0x4,
    0x0, 0x4, 0xc, 0x4, 0x8, 0xc, 0x8, 0xc, 0x0, 0x4, 0x8, 0xc, 0x0, 0x4, 0x0,
    0x4, 0x0, 0x4, 0x8, 0xc, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4,
    0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x8, 0xc, 0x8, 0xc, 0x0,
    0x4, 0x0, 0x4, 0x0, 0x4, 0x8, 0xc, 0x0, 0x4, 0x0, 0x4, 0x8, 0xc, 0x0, 0x4,
    0xc, 0x4, 0x8, 0xc, 0x8, 0xc, 0x0, 0x4, 0x8, 0xc, 0x0, 0x4, 0x0, 0x4, 0x0,
    0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x8, 0xc, 0x8, 0xc, 0x8, 0xc, 0x0, 0x4,
    0x0, 0x4, 0x8, 0xc, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0xc, 0x4, 0x8, 0xc, 0x8,
    0xc, 0x0, 0x4, 0x8, 0xc, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x8, 0xc, 0x0, 0x4,
    0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0,
    0x4, 0x0, 0x4, 0x8, 0xc, 0x8, 0xc, 0x8, 0xc, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4,
    0x0, 0x4, 0x0, 0x4, 0x8, 0xc, 0x0, 0x4, 0xc, 0x4, 0x8, 0xc, 0x8, 0xc, 0x0,
    0x4, 0x8, 0xc, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4,
    0x8, 0xc
};

//#define PARSE_LOOP_DEBUG
//#define GET_8BIT_DATABYTE_DEBUG
const int BUFFER_CHECK_INTERVAL_MSEC = 200;
#pragma region PROCESSING_VARIABLES
uint8_t devAddr;
uint8_t regAddr;

//added for bus direction labels
enum BUSDIR
{
    WRITE,
    READ,
    UNKNOWN = -1
} RWDir;
BUSDIR BusDir = BUSDIR::UNKNOWN;

int ACKNAKFlag; //can be negative
uint8_t databyte_array[2048]; //holds multiple databytes for later output sentence construction
uint16_t databyte_idx = 0; //index into databyte_array FIFO
uint16_t numbytes = 0; //number of data bytes extracted from data stream
#pragma endregion ProcVars

#pragma region ISR_VARS
uint16_t  write_index = 0;
uint16_t  read_index = 0;
uint8_t   current_portb = 0xFF;
uint8_t   last_portb = 0xFF;
bool bBufferFull = false;
elapsedMillis mSecSinceLastBufferCheck;
uint8_t* frontptr = 0;
#pragma endregion ISRVars



//-------------------------------------------------------------------------------
//--------------------------------    ISR    ------------------------------------
//-------------------------------------------------------------------------------
//01/04/2020 modified to 'capture' data from simdata[]
void capture_data(void)
{
    last_portb = current_portb;
    current_portb = simdata[read_index]; //pull one transition value from simdata
    read_index++;

    if (last_portb != current_portb && !bBufferFull)
    {
        cb_trans.write(current_portb); //add current transition value to FIFO
        digitalWriteFast(MONITOR_OUT1, !digitalReadFast(MONITOR_OUT1));
    }
    
    //pause writing to cb_trans circular buffer
    if (read_index >= SIM_DATA_ARRAY_SIZE)
    {
        bBufferFull = true;
        read_index = 0;
        digitalWriteFast(MONITOR_OUT1, LOW);
    }
}

void setup()
{
    Serial.begin(1); //rate value ignored
    unsigned long now = millis();
    int idx = 0;
    while (!Serial && (millis() - now) < 3000)
    {
        delay(500);
        idx++;
    }
    Serial.printf("Serial available after %lu mSec\n", millis() - now);

    pinMode(MONITOR_OUT1, OUTPUT);
    pinMode(MONITOR_OUT2, OUTPUT);
    pinMode(LED_BUILTIN, OUTPUT);
    Timer1.initialize(1); // run every mico second
    Timer1.attachInterrupt(capture_data);

    frontptr = cb_trans.front();

    mSecSinceLastBufferCheck = 0;
}

void loop()
{
    if (mSecSinceLastBufferCheck > BUFFER_CHECK_INTERVAL_MSEC)
    {
        Serial.printf("%lu: cb_trans contains = %d elements\n", millis(), cb_trans.back()- frontptr);
        mSecSinceLastBufferCheck -= BUFFER_CHECK_INTERVAL_MSEC;
        cb_trans.clear();
        read_index = 0;
        bBufferFull = false;
        digitalWriteFast(MONITOR_OUT2, !digitalReadFast(MONITOR_OUT2));
    }
}

A partial output is as follows:

Code:
Opening port
Port open
Serial available after 1000 mSec
1501: cb_trans contains = 1854 elements
1701: cb_trans contains = 1852 elements
1901: cb_trans contains = 1852 elements
2101: cb_trans contains = 1852 elements
2301: cb_trans contains = 1852 elements
2501: cb_trans contains = 1852 elements
2701: cb_trans contains = 1852 elements
2901: cb_trans contains = 1852 elements
3101: cb_trans contains = 1852 elements
3301: cb_trans contains = 1852 elements
3501: cb_trans contains = 1852 elements
3701: cb_trans contains = 1852 elements
3901: cb_trans contains = 1852 elements
4101: cb_trans contains = 1852 elements
4301: cb_trans contains = 1852 elements
4501: cb_trans contains = 1852 elements

Port closed

I was a bit surprised to see that the number of elements in the circular buffer was almost exactly TWICE the value I expected. The simdata[] array contains 928 8-bit values, and the circular buffer is defined as containing uint8_t elements, so I don't understand the x2 factor.

What am I doing wrong here?

TIA,

Frank
 
Have you checked .size() for number of elements? Perhaps your calculation is wrong, try size() to confirm

back() and front(), by the way show the byte in either head or tail of the queue

In printf, also, %d is signed, try %u?
 
Tonton81,

OK, size() returns 928, as expected. Changing the %d to %u for front()-frontptr doesn't change anything. Maybe

Code:
Circular_Buffer<uint8_t, 2048> cb_trans; //holds transition values from ISR

is really defined as

Code:
Circular_Buffer<uint8_16, 2048> cb_trans;

under the hood?
 
Tonton81,

OK, size() returns 928, as expected. Changing the %d to %u for front()-frontptr doesn't change anything. Maybe

Code:
Circular_Buffer<uint8_t, 2048> cb_trans; //holds transition values from ISR

is really defined as

Code:
Circular_Buffer<uint8_16, 2048> cb_trans;

under the hood?
 
Changed the print line to

Code:
        Serial.printf("%lu: cb_trans contains = %d elements\n", millis(), cb_trans.size());

And now I get for output:

Code:
Opening port
Port open
5701: cb_trans contains = 928 elements
5901: cb_trans contains = 927 elements
6101: cb_trans contains = 928 elements
6301: cb_trans contains = 928 elements
6501: cb_trans contains = 928 elements
6701: cb_trans contains = 928 elements
6901: cb_trans contains = 928 elements
7101: cb_trans contains = 928 elements
7301: cb_trans contains = 928 elements
7501: cb_trans contains = 928 elements
7701: cb_trans contains = 928 elements
7901: cb_trans contains = 927 elements
8101: cb_trans contains = 928 elements
8301: cb_trans contains = 928 elements
8501: cb_trans contains = 928 elements
8701: cb_trans contains = 928 elements
8901: cb_trans contains = 927 elements
9101: cb_trans contains = 928 elements
9301: cb_trans contains = 928 elements
9501: cb_trans contains = 928 elements
9701: cb_trans contains = 928 elements
9901: cb_trans contains = 928 elements
10101: cb_trans contains = 928 elements
10301: cb_trans contains = 928 elements
10501: cb_trans contains = 928 elements
10701: cb_trans contains = 928 elements
10901: cb_trans contains = 928 elements
11101: cb_trans contains = 928 elements
11301: cb_trans contains = 928 elements
11501: cb_trans contains = 928 elements
11701: cb_trans contains = 927 elements

Port closed

Not quite sure why I occasionally get 927 elements, as the 200 mSec interval time is much much longer than the time required to read & write all 928 elements.

If I reduce the interval time to zero, I get

Code:
Opening port
Port open
Serial available after 1000 mSec
1300: cb_trans contains = 0 elements
1300: cb_trans contains = 0 elements
1300: cb_trans contains = 0 elements
1300: cb_trans contains = 0 elements
1300: cb_trans contains = 0 elements
1300: cb_trans contains = 0 elements
1300: cb_trans contains = 0 elements
1300: cb_trans contains = 0 elements
1300: cb_trans contains = 0 elements
1300: cb_trans contains = 0 elements
1300: cb_trans contains = 0 elements
1300: cb_trans contains = 0 elements
1300: cb_trans contains = 0 elements
1303: cb_trans contains = 1856 elements
1304: cb_trans contains = 2048 elements
1305: cb_trans contains = 2048 elements
1307: cb_trans contains = 2048 elements
1308: cb_trans contains = 2048 elements
1310: cb_trans contains = 2048 elements
1311: cb_trans contains = 2048 elements
1312: cb_trans contains = 2048 elements

So size() is clearly working properly, and the time stamps show that it only takes 3-4 mSec to fill the 2048-element (still not sure if they are 8 or 16-bit elements though) circular buffer.

So, assuming that my 928-transition (414 8-bit bytes) is representative of a typical I2C burst, and my intended application only produces one burst every 200 mSec, I should have essentially infinite time to decode the transitions & print results - yay!

Frank


Frank
 
Sorry == forgot to mention that for the 'zero interval' output I also commented out the 'cb_trans.clear()' call to let the FIFO contents build up to max capacity.

Frank
 
The type for the buffer, is guarenteed to be the type you used in the template constructor. uint8_t, it is impossible for the compiler to generate a different type than the one you specified to the template parameter. Even though it wasn't mentioned, I'm currently now working with a circular array of 74 uint64_t's, 64 levels :)
 
Front and back are just a pointer in CBA. Example:

cb_trans.front()[2];

This basically gives you the data stored in indice 2 of the front of the queue. Same goes for back(). This is just a pointer, basically, to your array in the front or end of the queue.

I use the back() method to compare data on canbus between the last stored frame and the one that just came in. After the comparison, if data I choose to compare is different, then the new frame is stored in the list.
 
I understand they are just pointers, but why is there a difference of 1852 between the front and back pointers of a 928-byte 8-bit-per-element circular buffer? The inference is that it takes 2 pointer locations to store one 8-bit byte, which doesn't make a whole lot of sense.
 
I'm trying to use cb.ReadBytes() in a function, but it doesn't seem to be working the way I would expect. Here's the function

Code:
//uint8_t Get7BitDeviceAddr(byte * simdata, uint16_t & readidx)
uint8_t Get7BitDeviceAddr(Circular_Buffer<uint8_t, 2048>& cb)
{
    //Purpose: Construct a 7-bit address starting from next FIFO element
    //Inputs:
    //  cb = reference to cb_trans FIFO
    //Outputs:
    //  returns the address as an 8-bit value with the MSB = 0, or 0x0 if unsuccessful
    //  the 14 transitions associated with the 7-bit address removed from FIFO
    //Plan:
    //  Step1: Convert a pair of FIFO elements into a 0 or 1
    //  Step2: Add the appropriate value to an ongoing sum
    //  Step3: return the total.
    //Notes:
    //  A '0' is coded as a 0x0 followed by a 0x4
    //  A '1' is coded as a 0x8 followed by a 0xC

    uint8_t devAddr = 0x0; //failure return value

    //devAddr is exactly 7 bits long, so 8 bits with MSB = 0
    uint8_t data[2]; //holds one transition pair
    for (size_t i = 0; i < 7; i++)
    {

        //cb.readBytes(data, 2);
        data[0] = cb.read();
        data[1] = cb.read();
        Serial.printf("data[0] = %x, data[1] = %x\n", data[0], data[1]);

        if (data[0] == 0x8 && data[1] == 0xC)
        {
            Serial.printf("Get7BitDeviceAddr: '1' found at i = %d, adding %x to devAddr to get %x\n",
                i, 1 << (7 - i), devAddr + (1 << (7 - i)));

            devAddr += (1 << (7 - i)); //add 2^(7-i) to sum
        }
    }

    devAddr = devAddr >> 1; //divide result by 2 to get 7-bit addr from 8 bits
    return devAddr;
}

With the code as shown above (readBytes() commented out, replaced by two calls to read(), I get the following (correct) output:

Code:
Opening port
Port open
Serial available after 1000 mSec
1501: cb_trans contains = 928 elements
1501: In DecodeAndPrintFIFOContents()
Start sequence found, FIFO size = 926
First 20 elements in the FIFO are
0: 8
1: c
2: 8
3: c
4: 0
5: 4
6: 8
7: c
8: 0
9: 4
10: 0
11: 4
12: 0
13: 4
14: 0
15: 4
16: 0
17: 4
18: 0
19: 4
data[0] = 8, data[1] = c
Get7BitDeviceAddr: '1' found at i = 0, adding 80 to devAddr to get 80
data[0] = 8, data[1] = c
Get7BitDeviceAddr: '1' found at i = 1, adding 40 to devAddr to get c0
data[0] = 0, data[1] = 4
data[0] = 8, data[1] = c
Get7BitDeviceAddr: '1' found at i = 3, adding 10 to devAddr to get d0
data[0] = 0, data[1] = 4
data[0] = 0, data[1] = 4
data[0] = 0, data[1] = 4
devAddr = 68, FIFO size = 912

However, if I comment out the two calls to read() and uncomment the call to readBytes(), I get the following output:

Code:
Opening port
Port open
Serial available after 1000 mSec
1501: cb_trans contains = 928 elements
1501: In DecodeAndPrintFIFOContents()
Start sequence found, FIFO size = 926
First 20 elements in the FIFO are
0: 8
1: c
2: 8
3: c
4: 0
5: 4
6: 8
7: c
8: 0
9: 4
10: 0
11: 4
12: 0
13: 4
14: 0
15: 4
16: 0
17: 4
18: 0
19: 4
data[0] = c, data[1] = 4
data[0] = c, data[1] = 4
data[0] = c, data[1] = 4
data[0] = c, data[1] = 4
data[0] = c, data[1] = 4
data[0] = c, data[1] = 4
data[0] = c, data[1] = 4
devAddr = 0, FIFO size = 912

What am I doing wrong here?

Frank
 
can you post a full sketch i can load it to a standalone teensy to test? Last post is a snippet

EDIT, nevermind, I see the issue with readBytes. That will need to be fixed.
 
Last edited:
Ok try the patch

https://github.com/tonton81/Circular_Buffer

Test example:

Code:
#include "circular_buffer.h"


Circular_Buffer<uint8_t, 32> c5;

void setup() {
  Serial.begin(1);
  delay(500);
  Serial.println("----------------------");


  for ( uint16_t i = 0; i < 34; i++ ) c5.write(i);

  if ( 1 ) {
    Serial.println(c5.read());
    Serial.println(c5.read());
  }
  else {
    uint8_t data[2];
    c5.readBytes(data, 2);
    Serial.println(data[0]);
    Serial.println(data[1]);
  }

}

void loop() {

}

Change the if value to 0 or 1 to try both ways
 
It appears that peekbytes() might have an issue too. Here's my (somewhat messy, sorry) code in its entirety:

Code:
/*
    Name:       Teensy_I2C_Sniffer_V6.ino
    Created:	1/4/2020 8:40:20 AM
    Author:     FRANKNEWXPS15\Frank

    This is a port of my Excel VBA code into Arduino/Teensy C++ language.
    It parses the exact same sample data as the Excel program, so it should
    produce the exact same I2C sequences.

    The captured sample data to be parsed is held in the 'simdata' array.

    The original VBA code is saved in 'ExcelVBACode.txt'
*/

/* 'Notes:

    A typical I2C sentence when communicating with a MPU6050 IMU module goes like:
        "I2C(68) wrote 1 byte to 75 - C0 Done."
        "I2C(68) wrote 3 bytes to 72 - C0 0C 10 Done."
        "I2C(68) read 5 bytes from 6A - C0 0C 10 14 03 Done."

    To form a sentence, we need:
        Device addr: 68 in the above examples
        Read/Write direction
        To/From register address:  75, 72 and 6A in the above examples
        Data:  C0, C0 0C 10, and C0 0C 10 14 03 in the above examples
        number of bytes written/read:  1,3 & 5 in the above examples

     Each I2C communication proceeds as follows (assuming a START from an IDLE condition):
         A START or RESTART condition, denoted by SDA & SCL HIGH, followed by SDA LOW, SCL HIGH
         A 7-bit device address, MSB first (0x8/0xC = 1, 0x0/0x4 = 0)
         A R/W bit (0x8/0xC = read, 0x0/0x4 = write)
         An ACK bit (0x8/0xC = NAK, 0x0/0x4 = ACK)
         If the bus direction is WRITE, then
             A register address for read/write
             zero or more additional data bytes
         Else (the bus direction is READ)
            One or more additional data bytes
         Endif
*/

/*
This version adds tonton81's circular buffer class (https://github.com/tonton81/Circular_Buffer)
to simulate real-time processing and display of I2C bus activity.  The sample data is loaded into
a FIFO by an ISR triggered every microsecond by a timer, and then the processing code pulls it out
and parses it as fast as possible.  If this works, then the next version will eliminate the sample
data and connect to a live I2C bus.
*/

#include <TimerOne.h> //needed for ISR
#include "circular_buffer.h"
Circular_Buffer<uint8_t, 2048> cb_trans; //holds transition values from ISR

#define MONITOR_OUT1 2 //so can monitor ISR activity with O'scope
#define MONITOR_OUT2 3 //so can monitor ISR activity with O'scope

const int SIM_DATA_ARRAY_SIZE = 928;
byte simdata[SIM_DATA_ARRAY_SIZE] =
{
    0xc, 0x4, 0x8, 0xc, 0x8, 0xc, 0x0, 0x4, 0x8, 0xc, 0x0,
    0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x8, 0xc, 0x8, 0xc,
    0x8, 0xc, 0x0, 0x4, 0x8, 0xc, 0x0, 0x4, 0x8, 0xc, 0x0, 0x4, 0x0, 0x4, 0xc,
    0x4, 0x8, 0xc, 0x8, 0xc, 0x0, 0x4, 0x8, 0xc, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4,
    0x8, 0xc, 0x0, 0x4, 0x0, 0x4, 0x8, 0xc, 0x8, 0xc, 0x0, 0x4, 0x8, 0xc, 0x0,
    0x4, 0x0, 0x4, 0x0, 0x4, 0x8, 0xc, 0x0, 0x4, 0xc, 0x4, 0x8, 0xc, 0x8, 0xc,
    0x0, 0x4, 0x8, 0xc, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0,
    0x4, 0x8, 0xc, 0x8, 0xc, 0x0, 0x4, 0x8, 0xc, 0x0, 0x4, 0x8, 0xc, 0x0, 0x4,
    0x0, 0x4, 0x0, 0x4, 0xc, 0x4, 0x8, 0xc, 0x8, 0xc, 0x0, 0x4, 0x8, 0xc, 0x0,
    0x4, 0x0, 0x4, 0x0, 0x4, 0x8, 0xc, 0x0, 0x4, 0x8, 0xc, 0x8, 0xc, 0x0, 0x4,
    0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x8, 0xc, 0x0, 0x4, 0xc,
    0x4, 0x8, 0xc, 0x8, 0xc, 0x0, 0x4, 0x8, 0xc, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4,
    0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x8, 0xc, 0x8, 0xc, 0x0, 0x4, 0x8, 0xc, 0x0,
    0x4, 0x8, 0xc, 0x0, 0x4, 0x0, 0x4, 0x8, 0xc, 0x8, 0xc, 0x0, 0x4, 0x0, 0x4,
    0x0, 0x4, 0x8, 0xc, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0xc, 0x4, 0x8,
    0xc, 0x8, 0xc, 0x0, 0x4, 0x8, 0xc, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4,
    0x0, 0x4, 0x0, 0x4, 0x8, 0xc, 0x8, 0xc, 0x8, 0xc, 0x0, 0x4, 0x0, 0x4, 0x8,
    0xc, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0xc, 0x4, 0x8, 0xc, 0x8, 0xc, 0x0, 0x4,
    0x8, 0xc, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x8, 0xc, 0x0, 0x4, 0x0, 0x4, 0x0,
    0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4,
    0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x8, 0xc, 0x8, 0xc, 0x8, 0xc, 0x0, 0x4, 0x0,
    0x4, 0x8, 0xc, 0x0, 0x4, 0xc, 0x4, 0x8, 0xc, 0x8, 0xc, 0x0, 0x4, 0x8, 0xc,
    0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x8, 0xc, 0x8,
    0xc, 0x8, 0xc, 0x0, 0x4, 0x0, 0x4, 0x8, 0xc, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4,
    0xc, 0x4, 0x8, 0xc, 0x8, 0xc, 0x0, 0x4, 0x8, 0xc, 0x0, 0x4, 0x0, 0x4, 0x0,
    0x4, 0x8, 0xc, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4,
    0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x8, 0xc, 0x8,
    0xc, 0x8, 0xc, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x8, 0xc, 0x0, 0x4, 0xc, 0x4,
    0x8, 0xc, 0x8, 0xc, 0x0, 0x4, 0x8, 0xc, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0,
    0x4, 0x0, 0x4, 0x0, 0x4, 0x8, 0xc, 0x8, 0xc, 0x8, 0xc, 0x0, 0x4, 0x0, 0x4,
    0x8, 0xc, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0xc, 0x4, 0x8, 0xc, 0x8, 0xc, 0x0,
    0x4, 0x8, 0xc, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x8, 0xc, 0x0, 0x4, 0x0, 0x4,
    0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0,
    0x4, 0x0, 0x4, 0x8, 0xc, 0x0, 0x4, 0x8, 0xc, 0x0, 0x4, 0x8, 0xc, 0x0, 0x4,
    0x0, 0x4, 0x8, 0xc, 0x0, 0x4, 0xc, 0x4, 0x8, 0xc, 0x8, 0xc, 0x0, 0x4, 0x8,
    0xc, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x8, 0xc,
    0x8, 0xc, 0x8, 0xc, 0x0, 0x4, 0x0, 0x4, 0x8, 0xc, 0x0, 0x4, 0x0, 0x4, 0x0,
    0x4, 0xc, 0x4, 0x8, 0xc, 0x8, 0xc, 0x0, 0x4, 0x8, 0xc, 0x0, 0x4, 0x0, 0x4,
    0x0, 0x4, 0x8, 0xc, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0,
    0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x8, 0xc, 0x8, 0xc,
    0x8, 0xc, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x8, 0xc, 0x0, 0x4, 0xc,
    0x4, 0x8, 0xc, 0x8, 0xc, 0x0, 0x4, 0x8, 0xc, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4,
    0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x8, 0xc, 0x8, 0xc, 0x8, 0xc, 0x0, 0x4, 0x0,
    0x4, 0x8, 0xc, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0xc, 0x4, 0x8, 0xc, 0x8, 0xc,
    0x0, 0x4, 0x8, 0xc, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x8, 0xc, 0x0, 0x4, 0x0,
    0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4,
    0x0, 0x4, 0x8, 0xc, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x8, 0xc, 0x8, 0xc, 0x0,
    0x4, 0x0, 0x4, 0x8, 0xc, 0x0, 0x4, 0xc, 0x4, 0x8, 0xc, 0x8, 0xc, 0x0, 0x4,
    0x8, 0xc, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x8,
    0xc, 0x8, 0xc, 0x8, 0xc, 0x0, 0x4, 0x0, 0x4, 0x8, 0xc, 0x0, 0x4, 0x0, 0x4,
    0x0, 0x4, 0xc, 0x4, 0x8, 0xc, 0x8, 0xc, 0x0, 0x4, 0x8, 0xc, 0x0, 0x4, 0x0,
    0x4, 0x0, 0x4, 0x8, 0xc, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4,
    0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x8, 0xc, 0x8, 0xc, 0x0,
    0x4, 0x0, 0x4, 0x0, 0x4, 0x8, 0xc, 0x0, 0x4, 0x0, 0x4, 0x8, 0xc, 0x0, 0x4,
    0xc, 0x4, 0x8, 0xc, 0x8, 0xc, 0x0, 0x4, 0x8, 0xc, 0x0, 0x4, 0x0, 0x4, 0x0,
    0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x8, 0xc, 0x8, 0xc, 0x8, 0xc, 0x0, 0x4,
    0x0, 0x4, 0x8, 0xc, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0xc, 0x4, 0x8, 0xc, 0x8,
    0xc, 0x0, 0x4, 0x8, 0xc, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x8, 0xc, 0x0, 0x4,
    0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0,
    0x4, 0x0, 0x4, 0x8, 0xc, 0x8, 0xc, 0x8, 0xc, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4,
    0x0, 0x4, 0x0, 0x4, 0x8, 0xc, 0x0, 0x4, 0xc, 0x4, 0x8, 0xc, 0x8, 0xc, 0x0,
    0x4, 0x8, 0xc, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4,
    0x8, 0xc
};

#define PARSE_LOOP_DEBUG
//#define GET_8BIT_DATABYTE_DEBUG
const int BUFFER_CHECK_INTERVAL_MSEC = 200;
//const int BUFFER_CHECK_INTERVAL_MSEC = 5;
#pragma region PROCESSING_VARIABLES
uint8_t devAddr;
uint8_t regAddr;

//added for bus direction labels
enum BUSDIR
{
    WRITE,
    READ,
    UNKNOWN = -1
} RWDir;
BUSDIR BusDir = BUSDIR::UNKNOWN;

int ACKNAKFlag; //can be negative
uint8_t databyte_array[2048]; //holds multiple databytes for later output sentence construction
uint16_t databyte_idx = 0; //index into databyte_array
uint16_t numbytes = 0; //number of data bytes extracted from data stream
uint8_t killbuff[2]; //used to consume start/stop bytes

#pragma endregion ProcVars

#pragma region ISR_VARS
uint16_t  write_index = 0;
uint16_t  read_index = 0;
uint8_t   current_portb = 0xFF;
uint8_t   last_portb = 0xFF;
bool bBufferFull = false;
elapsedMillis mSecSinceLastBufferCheck;
#pragma endregion ISRVars

int DecodeAndPrintFIFOContents(Circular_Buffer<uint8_t, 2048>& cb); //need forward reference here


//-------------------------------------------------------------------------------
//--------------------------------    ISR    ------------------------------------
//-------------------------------------------------------------------------------
//01/04/2020 modified to 'capture' data from simdata[]
void capture_data(void)
{
    if (!bBufferFull) //for debug - writes only one set of data to FIFO
    {
        last_portb = current_portb;
        current_portb = simdata[read_index]; //pull one transition value from simdata
        read_index++;

        if (last_portb != current_portb && !bBufferFull)
        {
            cb_trans.write(current_portb); //add current transition value to FIFO
            digitalWriteFast(MONITOR_OUT1, !digitalReadFast(MONITOR_OUT1));
        }
    
        //pause writing to cb_trans circular buffer
        if (read_index >= SIM_DATA_ARRAY_SIZE)
        {
            bBufferFull = true;
            read_index = 0;
            digitalWriteFast(MONITOR_OUT1, LOW);
        }
    }
}

void setup()
{
    Serial.begin(1); //rate value ignored
    unsigned long now = millis();
    int idx = 0;
    while (!Serial && (millis() - now) < 3000)
    {
        delay(500);
        idx++;
    }
    Serial.printf("Serial available after %lu mSec\n", millis() - now);

    pinMode(MONITOR_OUT1, OUTPUT);
    pinMode(MONITOR_OUT2, OUTPUT);
    pinMode(LED_BUILTIN, OUTPUT);
    Timer1.initialize(1); // run every mico second
    Timer1.attachInterrupt(capture_data);

    mSecSinceLastBufferCheck = 0;
}

void loop()
{
    if (mSecSinceLastBufferCheck > BUFFER_CHECK_INTERVAL_MSEC)
    {
        Serial.printf("%lu: cb_trans contains = %d elements\n", millis(), cb_trans.size());
        mSecSinceLastBufferCheck -= BUFFER_CHECK_INTERVAL_MSEC;
        DecodeAndPrintFIFOContents(cb_trans); //decode and print everything captured so far
        //cb_trans.clear();
        read_index = 0;
        bBufferFull = false;
        digitalWriteFast(MONITOR_OUT2, !digitalReadFast(MONITOR_OUT2));
        while (true)
        {

        }
    }
}

void PrintNextFIFOBytes(Circular_Buffer<uint8_t, 2048>& cb, uint8_t numbytes)
{
    Serial.printf("Next %d FIFO Bytes: ", numbytes);
    for (size_t i = 0; i < numbytes-1; i++)
    {
        Serial.printf("%x,", cb.peek(i));
    }
    Serial.printf("%x\n", cb.peek(numbytes-1));
}
bool IsStart(Circular_Buffer<uint8_t, 2048>& cb)
{
    bool result = false;

    uint8_t data[2]; data[0] = data[1] = 0;
    //DEBUG!!
    Serial.printf("IsStart() just before cb.peekBytes(data, 2): data[0] = %x,data[1] = %x, size = %d, idx = %d\n",
        data[0],data[1], cb.size(), SIM_DATA_ARRAY_SIZE - cb.size());
    PrintNextFIFOBytes(cb, 10);
    //DEBUG!!
    cb.peekBytes(data, 2);
    //DEBUG!!
    Serial.printf("IsStart() just after cb.peekBytes(data, 2): data[0] = %x,data[1] = %x, size = %d, idx = %d\n",
        data[0],data[1], cb.size(), SIM_DATA_ARRAY_SIZE - cb.size());
    PrintNextFIFOBytes(cb, 10);
    //DEBUG!!
    if (data[0] == 0xC && data[1] == 0x4)
    {
        Serial.printf("Start detected at size = %d, data idx = %d\n", cb.size(), SIM_DATA_ARRAY_SIZE - cb.size());
        result = true;
    }

    return result;
}

bool IsStop(Circular_Buffer<uint8_t, 2048>& cb)
{
    bool result = false;

    uint8_t data[2];
    cb.peekBytes(data, 2);
    if (data[0] == 0x4 && data[1] == 0xC)
    {
        //cb.readBytes(data, 2); //consume these bytes
        result = true;
    }

    return result;

}

uint8_t Get7BitDeviceAddr(Circular_Buffer<uint8_t, 2048>& cb)
{
    //Purpose: Construct a 7-bit address starting from next FIFO element
    //Inputs:
    //  cb = reference to cb_trans FIFO
    //Outputs:
    //  returns the address as an 8-bit value with the MSB = 0, or 0x0 if unsuccessful
    //  the 14 transitions associated with the 7-bit address removed from FIFO
    //Plan:
    //  Step1: Convert a pair of FIFO elements into a 0 or 1
    //  Step2: Add the appropriate value to an ongoing sum
    //  Step3: return the total.
    //Notes:
    //  A '0' is coded as a 0x0 followed by a 0x4
    //  A '1' is coded as a 0x8 followed by a 0xC

    uint8_t devAddr = 0x0; //failure return value

    //devAddr is exactly 7 bits long, so 8 bits with MSB = 0
    uint8_t data[2]; //holds one transition pair
    for (size_t i = 0; i < 7; i++)
    {

        cb.readBytes(data, 2);
        //data[0] = cb.read();
        //data[1] = cb.read();
        //Serial.printf("data[0] = %x, data[1] = %x\n", data[0], data[1]);

        if (data[0] == 0x8 && data[1] == 0xC)
        {
            //Serial.printf("Get7BitDeviceAddr: '1' found at i = %d, adding %x to devAddr to get %x\n",
                //i, 1 << (7 - i), devAddr + (1 << (7 - i)));

            devAddr += (1 << (7 - i)); //add 2^(7-i) to sum
        }
    }

    devAddr = devAddr >> 1; //divide result by 2 to get 7-bit addr from 8 bits
    return devAddr;
}

int GetReadWriteFlag(Circular_Buffer<uint8_t, 2048>& cb)
{
    //Purpose: decode R/W byte pair
    //Inputs:
    //  cb = reference to cb_trans FIFO
    //Outputs:
    //  readidx = if successful, points to next byte pair in simdata
    //  returns 1 for Read (0x8/0xC), 0 for Write (0x0/0x4), -1 for failure
    //Notes:
    //  

    int result = 0;
    uint8_t data[2];
    data[0] = cb.read();
    data[1] = cb.read();
    //Serial.printf("data[0] = %x, data[1] = %x\n", data[0], data[1]);

    if (data[0] == 0x8 && data[1] == 0xC)
    {
        result = 1; //read detected
    }

    //else if (simdata[readidx] == 0x0 && simdata[readidx + 1] == 0x4)
    else if (data[0] == 0x0 && data[1] == 0x4)
    {
        result = 0; //write detected
    }
    else
    {
        result = -1; //failed to detect read or write
    }

    return result;
}

int GetACKNAKFlag(Circular_Buffer<uint8_t, 2048>& cb)
{
    //Purpose: decode ACK/NAK byte pair
    //Inputs:
    //  cb = reference to cb_trans circular buffer holding transition values
    //Outputs:
    //  returns 1 for NAK (0x8/0xC), 0 for ACK (0x0/0x4), -1 for failure
    //Notes:
    //  this code is identical to the code for GetReadWriteFlag, so use it instead 

     return GetReadWriteFlag(cb_trans);

}
int Get8BitDataByte(Circular_Buffer<uint8_t, 2048>& cb)
{
    //Purpose: Construct a 8-bit data byte starting from dataidx
    //Inputs:
    //  cb = reference to cb_trans circular buffer holding transition values
    //Outputs:
    //  returns the address as an 8-bit value, or -1 if unsuccessful
    //  dataidx = pointer to next simdata entry
    //Plan:
    //  Step1: Convert a pair of simdata entries into a 0 or 1
    //  Step2: Add the appropriate value to an ongoing sum
    //  Step3: return the total.
    //Notes:
    //  A '0' is coded as a 0x0 followed by a 0x4
    //  A '1' is coded as a 0x8 followed by a 0xC
    //  12/29/19 - changed return val to int, so can return -1 when a 'short byte' is detected

    int dataval = 0x0; 

    Serial.printf("Get8BitDataByte: cb.size = %d, index = %d\n",
        cb.size(), SIM_DATA_ARRAY_SIZE-cb.size());
    PrintNextFIFOBytes(cb, 20);

    //8 bits with MSB = 0
    int numbytes = 0;
    uint8_t data[2]; //holds one transition pair

    for (size_t i = 0; i < 8; i++)
    {
        cb.readBytes(data, 2);
        //Serial.printf("data[0] = %x, data[1] = %x\n", data[0], data[1]);

        if (data[0] == 0x0 && data[1] == 0x4)
        {
            numbytes++;
        }

        
        else if (data[0] == 0x8 && data[1] == 0xC)
        {
#ifdef GET_8BIT_DATABYTE_DEBUG
            Serial.printf("Get8BitDataByte: '1' found at i = %d, adding %x to devAddr to get %x\n",
                i, 1 << (7 - i), dataval + (1 << (7 - i)));
#endif
            dataval += (1 << (7 - i)); //add 2^(8-i) to sum
            numbytes++;
        }
    }

#ifdef GET_8BIT_DATABYTE_DEBUG
    Serial.printf("Get8BitDataByte: numbytes = %d\n", numbytes);
#endif
    if (numbytes != 8)
    {
        dataval = -1; //error return value
    }

    return dataval;
}

int GetDataBytes(Circular_Buffer<uint8_t, 2048>& cb, uint8_t* databytes)
{
    //Notes:
    //  01/01/2020: removed databyteidx from sig - always starts at zero

    uint16_t numbytes = 0;
    uint16_t databyte_idx = 0;

    bool StartFlag = false;
    bool StopFlag = false;
    int dataval;

    do
    {
        dataval = Get8BitDataByte(cb);
//DEBUG!!
        Serial.printf("GetDataBytes() just after Get8BitDataByte(): datval = %x, size = %d, idx = %d\n", 
            dataval, cb.size(), SIM_DATA_ARRAY_SIZE-cb.size());
        PrintNextFIFOBytes(cb, 10);
//DEBUG!!

        //watch out for 'short byte' reads
        if (dataval >= 0)
        {
            uint8_t databyte = (uint8_t)dataval;
            databyte_array[databyte_idx] = databyte;
            databyte_idx++;
            numbytes++;
        }

        ACKNAKFlag = GetACKNAKFlag(cb_trans);
//DEBUG!!
        Serial.printf("GetDataBytes() just after GetACKNAKFlag(): ACKNAK = %d, size = %d, idx = %d\n", 
            ACKNAKFlag, cb.size(), SIM_DATA_ARRAY_SIZE-cb.size());
        PrintNextFIFOBytes(cb, 10);
//DEBUG!!
        StartFlag = IsStart(cb_trans);
//DEBUG!!
        Serial.printf("GetDataBytes() just after IsStart(): StartFlag = %d, size = %d, idx = %d\n", 
            StartFlag, cb.size(), SIM_DATA_ARRAY_SIZE-cb.size());
        PrintNextFIFOBytes(cb, 10);
//DEBUG!!
        StopFlag = IsStop(cb_trans);

#ifdef PARSE_LOOP_DEBUG
        Serial.printf("IsStart %d, IsStop  %d, next two bytes are %x, %x, data idx = %d\n",
            StartFlag, StopFlag, cb.peek(0), cb.peek(1), SIM_DATA_ARRAY_SIZE-cb.size());
#endif

    } while (!StartFlag && !StopFlag && cb_trans.size() > 0);

    return numbytes;
}

void OutputFormattedSentence(int RW, uint8_t dev, uint8_t reg, uint8_t numbytes, uint8_t* bytearray, uint16_t startidx)
{
    Serial.printf("I2C(%x) %s %d bytes %s %x... ",
        dev, (RW == 0 ? "writing" : "reading"), numbytes - startidx, (RW == 0 ? "to" : "from"), reg);
    for (size_t i = startidx; i < numbytes; i++)
    {
        Serial.printf("%x ", bytearray[i]);
    }

    Serial.printf(". Done\n");

}

int DecodeAndPrintFIFOContents(Circular_Buffer<uint8_t, 2048>& cb)
{
    //Purpose:  decode and print I2C conversation held in cb_trans FIFO
    //Inputs:  
    //  cb = 2048 element FIFO
    //Outputs:
    //  returns number of bytes processed, or -1 for failure
    //  outputs structured I2C sentence to serial monitor
    //Plan:
    //  Step1: Determine if there is anything to do (have to have more than one transition in FIFO)
    //  Step2: Parse transitions into I2C sentence structure
    //  Step3: Output sentence to serial monitor

    if (cb.size() < 2)
    {
        return 0;
    }


    Serial.printf("%lu: In DecodeAndPrintFIFOContents()\n", millis());

    while (cb.size() > 0)
    {
#ifdef PARSE_LOOP_DEBUG
        Serial.printf("At top of while (cb.size() > 0): size = %d\n", cb.size());
        Serial.printf("Next two bytes in FIFO are %x, %x\n", cb.peek(0), cb.peek(1));
#endif
        //Find a START sequence (0xC followed by 0x4)
        while (!IsStart(cb))
        {
            Serial.printf("looking for start...\n");
        }
        cb.readBytes(killbuff,2); //01/05/20 moved START byte consume out of IsStart()


    #ifdef PARSE_LOOP_DEBUG
        Serial.printf("Start sequence found, FIFO size = %d\n", cb.size());
        PrintNextFIFOBytes(cb_trans, 20);
    #endif

        if (cb.size() > 14)//14 entries required for 7-bit address
        {
            //Get 7-bit device address
            devAddr = Get7BitDeviceAddr(cb);
    #ifdef PARSE_LOOP_DEBUG
            Serial.printf("devAddr = %x, FIFO size = %d\n", devAddr, cb.size());
            PrintNextFIFOBytes(cb_trans, 20);
    #endif
        }

        //get read/write flag  1 = Read, 0 = Write, -1 = error
        BusDir = (BUSDIR)GetReadWriteFlag(cb);

    #ifdef PARSE_LOOP_DEBUG
        Serial.printf("BusDir = %s\n", ((BusDir == BUSDIR::WRITE) ? "WRITE" : "READ"));
        PrintNextFIFOBytes(cb_trans, 20);
    #endif

        //get ACK/NAK flag
        ACKNAKFlag = GetACKNAKFlag(cb);
    #ifdef PARSE_LOOP_DEBUG
        Serial.printf("ACKNAK = %s\n", (ACKNAKFlag == 0) ? "ACK" : "NAK");
    #endif

        numbytes = GetDataBytes(cb, databyte_array); //terminates on a START, but the start bytes are not consumed
    #ifdef PARSE_LOOP_DEBUG
        Serial.printf("Got %d bytes from GetDataBytes()\n", numbytes);
        PrintNextFIFOBytes(cb_trans, 20);
    #endif

        while (true)
        {

        }
        //If the bus direction is WRITE, then extract
        //    A register address for read / write
        //    zero or more additional data bytes
        if (BusDir == BUSDIR::WRITE)
        {
            regAddr = databyte_array[0];
    #ifdef PARSE_LOOP_DEBUG
            Serial.printf("regAddr = %x, cb size = %d\n", regAddr, cb.size());
    #endif

            //check for additional data
            if (numbytes > 1)
            {
    #ifdef PARSE_LOOP_DEBUG
                Serial.printf("Additional data found!\n");
                for (size_t i = 0; i < numbytes; i++)
                {
                    Serial.printf("data[%d] = %x\n", i, databyte_array[i]);
                }
    #endif
                //1st byte is register addr, subsequent bytes are data
                OutputFormattedSentence(BusDir, devAddr, regAddr, numbytes, databyte_array, 1);
            }
        }
        else  //all bytes are data
        {
#ifdef PARSE_LOOP_DEBUG
            Serial.printf("In data block:  got %d bytes of data\n", numbytes);
            for (size_t i = 0; i < numbytes; i++)
            {
                Serial.printf("data[%d] = %x\n", i, databyte_array[i]);
            }
#endif
            OutputFormattedSentence(BusDir, devAddr, regAddr, numbytes, databyte_array, 0);
        }
    #ifdef PARSE_LOOP_DEBUG
        Serial.printf("At end of while (cb.size() > 0): size = %d\n", cb.size());
        Serial.printf("Next two bytes in FIFO are %x, %x\n", cb.peek(0), cb.peek(1));
    #endif

    }//while (cb.size() > 0)

    return 1;
}

I have a function IsStart() that looks for the byte pair [c,4]. In this function I use peekbytes(cb,2) to look at (but not consume) the first two bytes of the FIFO, and use them for the match. However, it appears that peekbytes() may be skipping two bytes. If I replace peekBytes() with two calls to peek(), I get the expected results.

Here's an edited output showing just the few relevant lines: The first set below is with peekBytes(data,2):

Code:
Get8BitDataByte: cb.size = 908, index = 20
Next 20 FIFO Bytes: 0,4,8,c,8,c,8,c,0,4,8,c,0,4,8,c,0,4,0,4
GetDataBytes() just after Get8BitDataByte(): datval = 75, size = 892, idx = 36
Next 10 FIFO Bytes: 0,4,0,4,c,4,8,c,8,c
GetDataBytes() just after GetACKNAKFlag(): ACKNAK = 0, size = 890, idx = 38
Next 10 FIFO Bytes: 0,4,c,4,8,c,8,c,0,4
[COLOR="#FF0000"]IsStart() just before cb.peekBytes(data, 2): data[0] = 0,data[1] = 0, size = 890, idx = 38
Next 10 FIFO Bytes: 0,4,c,4,8,c,8,c,0,4
IsStart() just after cb.peekBytes(data, 2): data[0] = c,data[1] = 4, size = 890, idx = 38
Next 10 FIFO Bytes: 0,4,c,4,8,c,8,c,0,4
[/COLOR]

And after replacing peekBytes(data,2) with two peek() calls:

Code:
Get8BitDataByte: cb.size = 908, index = 20
Next 20 FIFO Bytes: 0,4,8,c,8,c,8,c,0,4,8,c,0,4,8,c,0,4,0,4
GetDataBytes() just after Get8BitDataByte(): datval = 75, size = 892, idx = 36
Next 10 FIFO Bytes: 0,4,0,4,c,4,8,c,8,c
GetDataBytes() just after GetACKNAKFlag(): ACKNAK = 0, size = 890, idx = 38
Next 10 FIFO Bytes: 0,4,c,4,8,c,8,c,0,4
[COLOR="#FF0000"]IsStart() just before cb.peekBytes(data, 2): data[0] = 0,data[1] = 0, size = 890, idx = 38
Next 10 FIFO Bytes: 0,4,c,4,8,c,8,c,0,4
IsStart() just after cb.peekBytes(data, 2): data[0] = 0,data[1] = 4, size = 890, idx = 38
Next 10 FIFO Bytes: 0,4,c,4,8,c,8,c,0,4
[/COLOR]

You can see in the highlighted lines that peek(0) & peek(1) pick out the correct bytes, but peekByte(data,2) skips the first two bytes in the FIFO, loading the 3rd and 4th ones into data[0] and data[1] instead.

If this is indeed a problem with peekBytes() and not just my fevered imagination, then it may be that other multiple-byte versions of FIFO operations could use another look

Frank
 
Thank you, I will check into that and fix it when I get back home
readBytes is good now?
 
Last edited:
Ok, I corrected the offset needed of memmove on peekBytes, and readded it to readBytes, both function correctly. It's been updated on github, let me know if you still have issues :)

My last example posted earlier works for testing readBytes and peekBytes
 
The Teensy I2C sniffer project now works properly with tonton81's circular buffer library (although without the latest peekBytes() fix - I'm still using peek()). Here's the output from just one pass through the simulated burst data

Code:
Opening port
Port open
Port open
Serial available after 2500 mSec
3001: cb_trans contains = 928 elements
I2C(68) reading 1 bytes from 75... 68 . Done
I2C(68) reading 1 bytes from 6a... c0 . Done
I2C(68) writing 1 bytes to 6a... c4 . Done
I2C(68) reading 2 bytes from 72... 0 1c . Done
I2C(68) reading 2 bytes from 72... 0 38 . Done
I2C(68) reading 2 bytes from 72... 0 54 . Done
I2C(68) reading 2 bytes from 72... 0 70 . Done
I2C(68) reading 2 bytes from 72... 0 8c . Done
I2C(68) reading 2 bytes from 72... 0 c4 . Done
I2C(68) reading 2 bytes from 72... 0 e0 . Done
3003: cb_trans contains = 0 elements

So it takes a stock Teensy 3.2 about 3 mSec to parse and print results for a 928-byte I2C 'burst', so it should be able to keep up with a burst interval down to 10 mSec or so (my application uses a burst interval of 200 mSec).

Frank
 
tonton81,

Have you verified that cb.remove(element) actually removes the element? Here's a partial output from my current program, where I parse through a capture buffer to remove invalid bytes, and I have included the function that executes the parsing algorithm

Code:
Code:
uint16_t RemoveInvalidBytes(Circular_Buffer<uint8_t, 2048>& cb)
{
    uint8_t previous_byte, current_byte;

    Serial.printf("cb_trans contains %d elements\n", cb.size());
    PrintNextFIFOBytes(cb, cb.size());

    uint16_t cullcount = 0;
    //OK, now go back through the array, excising invalid sequences
    uint rawidx = 0;
    for (uint16_t i = 0; i < cb.size();) //i gets incremented internally
    {
        previous_byte = cb.peek(i); //get the first byte
        current_byte = cb.peek(i+1); //get the next byte
        bool validpair =
            (
            (previous_byte == 0xC && current_byte == 0x4) //START or RESTART
                || (previous_byte == 0x4 && current_byte == 0xC) //STOP
                || (previous_byte == 0x0 && current_byte == 0x4) //0 OR ACK
                || (previous_byte == 0x8 && current_byte == 0xC) //1 or NAK
                );

        Serial.printf("idx %d: Considering dp = %x, dc = %x: validity = %d\n",
            rawidx, previous_byte, current_byte, validpair);
        if (validpair)
        {
            i += 2;
        }
        else
        {
            uint8_t rembyte = cb.peek(i);
            if (cb.remove(i))
            {
                Serial.printf("successfully removed item %d = %x, leaving %d bytes\n", i, rembyte,cb.size());
            }
            else
            {
                Serial.printf("Failed to remove item %d = %x\n", i, rembyte);
            }
            PrintNextFIFOBytes(cb, 10);
            bool res = cb.remove(i); //remove invalid byte
            cullcount++;
            i++;
        }
    }

    return cullcount;
}

And the (partial) output:

Code:
Next 20 FIFO Bytes: c,4,0,8,c,8,c,8,0,4,0,8,c,8,0,4,0,4,8,c
cb_trans contains 165 elements
Next 165 FIFO Bytes: c,4,0,8,c,8,c,8,0,4,0,8,c,8,0,4,0,4,8,c,8,0,4,0,4,8,0,4,8,c,8,c,8,c,0,4,0,4,8,c,0,4,0,4,0,4,c,4,0,8,c,8,c,0,4,0,8,c,0,4,0,4,8,c,8,c,0,4,0,4,0,4,0,4,0,4,0,4,0,c,8,0,4,0,4,0,4,0,4,0,4,8,c,0,4,8,c,0,4,0,4,8,c,8,0,4,c,4,0,8,c,8,c,8,0,4,0,8,c,8,0,4,0,4,0,8,c,8,0,4,0,4,8,0,4,8,c,8,c,0,4,8,c,0,4,8,c,0,4,0,4,0,4,c,4,0,8,c,8,c,0,4,8,c,0
idx 0: Considering dp = c, dc = 4: validity = 1
idx 0: Considering dp = 0, dc = 8: validity = 0
Failed to remove item 2 = 0
Next 10 FIFO Bytes: c,4,0,8,c,8,c,8,0,4
idx 0: Considering dp = 8, dc = c: validity = 1
idx 0: Considering dp = 8, dc = c: validity = 1
idx 0: Considering dp = 8, dc = 0: validity = 0
Failed to remove item 7 = 8
Next 10 FIFO Bytes: c,4,0,8,c,8,c,8,0,4
idx 0: Considering dp = 0, dc = 4: validity = 1
idx 0: Considering dp = 0, dc = 8: validity = 0
Failed to remove item 10 = 0
Next 10 FIFO Bytes: c,4,0,8,c,8,c,8,0,4
idx 0: Considering dp = 8, dc = c: validity = 1
idx 0: Considering dp = 8, dc = 0: validity = 0
Failed to remove item 13 = 8

Am I doing something wrong with the 'cb.remove(i)' call?

Frank
 
Cb.remove is a unique feature implemented specifically for circular arrays, not circular buffers. The function only processes on circular arrays, and exits on buffers. It's used to drop an entire array out of a queue of arrays that match,provided the queue slot is specified. I do believe that is only specifically used when a user is manually running list() and removing an item line from the queue. A similar automatic find and remove version is findRemove, where it searches for indice matches before wiping the array out of the queue. Only one library has ever used this, Canquitto, although hasn't been used since in the updated version of that library
 
Back
Top