WhitehawkTailor / I2C-sniffer

This code catches I2C communication by running on an ESP32 board that are connected to I2C BUS lines as a passive listener.
GNU General Public License v3.0
25 stars 16 forks source link

Extracting data from output #1

Open ITstreet1 opened 2 years ago

ITstreet1 commented 2 years ago

I tried this sniffer and it works just fine.

My question is: If I get say, this line in the output buffer S0100000W+00001000+s I can see that on the 0100000 address I have 00001000 data. How to take this data for this specific address and do something with it? Maybe send to a server. Do anything.

The reason is, if there are multiple I2C devices, and I want to monitor only specific. So if I get a bunch of those readings and want to filter all of them and take only this one, cut everything and send this 00001000 to a server.

Any help would be appreciated.

WhitehawkTailor commented 2 years ago

Hi,

this is a very simple solution that displays the traffic only. There is no logic implemented in the code to process the communication. In order to implement the functionality you need to process the communication flow by separating the address part and the data part. Having the address information it can be decided if it is the one you are interested. For the observed address you can get the data sent by or read by the Master. This data can be processed or transfered to other devices via any connection (other serial, WiFi, Bluetooth).

In my code the processDataBuffer() is the place that processes the communication flow. My code just prints out the characters. This is the place that can be extended with the additional code to identify the address and process the data. The message exchange character series can be processed with a regexp expression (sorry I am not an expert in this), or with a string processing solution implemented by you. this could go like: create one string from the character flow from S to s split the string to address and data. first part from S to W/R is the address decide if the address is the one that you need if so then process the data part from + to + and send it out.

I hope this pseudo code can help you.

ITstreet1 commented 2 years ago

I know the logic I need, but not how to achieve it. :) I tried to "fix" a line or two, but just broke everything. It is hard to follow the logic all the way. Maybe not to you.

ITstreet1 commented 2 years ago

I wonder, could it be packed in some sort of a string or so? So it could be sent to a server as it is.

WhitehawkTailor commented 2 years ago

There is a simple solution and a difficult. Simple solution just send data are in the buffer as string to a server when processDataBuffer() is being called. This does not assure that the string will contain accomplished I2C communication. It may happen that the sting will contain one and a half message. In this case on the receiver server you have to implement the logic to understand the messages and process them.

Difficult solution is to put the complete command into a sting when all the character is read from the I2C line. This requires more logic implementation into processDataBuffer().

Would the simple solution be enough for you?

ITstreet1 commented 2 years ago

I have modified your sketch to filter specific I2C address, so in the output, I get only an array of bytes I need. That part is OK. As an output, I get what I expect. It is ok to send it as it is on a server. When in a database, I can process it as I want.

Some solution to send it as simple as it can be, would be nice.

Later, I could post it here so you can give it a touch or two to make it useful for others.

WhitehawkTailor commented 2 years ago

That is nice from you. When you think just send it over and I will extend the project with it. Thx

ITstreet1 commented 2 years ago
/**
 * @AUTHOR Ákos Szabó (Whitehawk Tailor) - aaszabo@gmail.com
 * 
 * This is an I2C sniffer that logs traffic on I2C BUS.
 * 
 * It is not part of the I2C BUS. It is neither a Master, nor a Slave and puts no data to the lines.
 * It just listens and logs the communication.
 * 
 * Two pins as imput are attached to SDC and SDA lines.
 * Since the I2C communications runs on 400kHz so,
 * the tool that runs this program should be fast.
 * This was tested on an ESP32 bord Heltec WiFi Lora32 v2
 * ESP32 core runs on 240MHz.
 * It means there are 600 ESP32 cycles during one I2C clock tick.
 *
 * 
 * The program uses interrupts to detect
 * the raise edge of the SCL - bit transfer 
 * the falling edge of SDA if SCL is HIGH- START
 * the raise edge of SDA if SCL id HIGH - STOP 
 * 
 * In the interrupt routines there is just a few line of code
 * that mainly sets the status and stores the incoming bits.
 * Otherwise the program gets timeout panic in interrupt handler and
 * restart the CPU.
 * 
 */

//#include <Arduino.h>

//#define I2CTEST  //use it to  run a blinking LED test on SDA and SCL pins

#define PIN_SDA 12  //BLUE
#define PIN_SCL 13  //Yellow

#define I2C_IDLE 0
//#define I2C_START 1
#define I2C_TRX 2
//#define I2C_RESP 3
//#define I2C_STOP 4

bool stampaj = 1;

// Promeniti u trazenu adresu
//pcf8574 - S0100000
//bilo -S1101101
const volatile byte adresa[] = "S0100000";//Adresa I2C uredjaja, slovo S na pocetku ne brisati
//

static volatile byte i2cStatus = I2C_IDLE;//Status of the I2C BUS
static uint32_t lastStartMillis = 0;//stoe the last time
static volatile byte dataBuffer[9600];//Array for storing data of the I2C communication
static volatile uint16_t bufferPoiW=0;//points to the first empty position in the dataBufer to write
static uint16_t bufferPoiR=0;//points to the position where to start read from
static volatile byte bitCount = 0;//counter of bit appeared on the BUS
static volatile uint16_t byteCount =0;//counter of bytes were writen in one communication.
static volatile byte i2cBitD =0;//Container of the actual SDA bit
static volatile byte i2cBitD2 =0;//Container of the actual SDA bit
static volatile byte i2cBitC =0;//Container of the actual SDA bit
static volatile byte i2cClk =0;//Container of the actual SCL bit
static volatile byte i2cAck =0;//Container of the last ACK value
static volatile byte i2cCase =0;//Container of the last ACK value
static volatile uint16_t falseStart = 0;//Counter of false start events
//static volatile byte respCount =0;//Auxiliary variable to help detect next byte instead of STOP
//these variables just for statistic reasons
static volatile uint16_t sclUpCnt = 0;//Auxiliary variable to count rising SCL
static volatile uint16_t sdaUpCnt = 0;//Auxiliary variable to count rising SDA
static volatile uint16_t sdaDownCnt = 0;//Auxiliary variable to count falling SDA

////////////////////////////
//// Interrupt handlers
/////////////////////////////

/**
 * Rising SCL makes reading the SDA
 * 
 */
void IRAM_ATTR i2cTriggerOnRaisingSCL() 
{
  sclUpCnt++;

  //is it a false trigger?
  if(i2cStatus==I2C_IDLE)
  {
    falseStart++;
    //return;//this is not clear why do we have so many false START
  }

  //get the value from SDA
  i2cBitC =  digitalRead(PIN_SDA);

  //decide wherewe are and what to do with incoming data
  i2cCase = 0;//normal case

  if(bitCount==8)//ACK case
    i2cCase = 1;

  if(bitCount==7 && byteCount==0 )// R/W if the first address byte
    i2cCase = 2;

  bitCount++;

  switch (i2cCase)
  {
    case 0: //normal case
      dataBuffer[bufferPoiW++] = '0' + i2cBitC;//48
    break;//end of case 0 general
    case 1://ACK
      if(i2cBitC)//1 NACK SDA HIGH
        {
          dataBuffer[bufferPoiW++] = '-';//45
        }
        else//0 ACK SDA LOW
        {
          dataBuffer[bufferPoiW++] = '+';//43
        } 
      byteCount++;
      bitCount=0;
    break;//end of case 1 ACK
    case 2:
      if(i2cBitC)
      {
        dataBuffer[bufferPoiW++] = 'R';//82
      }
      else
      {
        dataBuffer[bufferPoiW++] = 'W';//87
      }
    break;//end of case 2 R/W

  }//end of switch

}//END of i2cTriggerOnRaisingSCL() 

/**
 * This is for recognizing I2C START and STOP
 * This is called when the SDA line is changing
 * It is decided inside the function wheather it is a rising or falling change.
 * If SCL is on High then the falling change is a START and the rising is a STOP.
 * If SCL is LOW, then this is the action to set a data bit, so nothing to do.
 */
void IRAM_ATTR i2cTriggerOnChangeSDA()
{
  //make sure that the SDA is in stable state
  do
  {
    i2cBitD =  digitalRead(PIN_SDA);
    i2cBitD2 =  digitalRead(PIN_SDA);
  } while (i2cBitD!=i2cBitD2);

  //i2cBitD =  digitalRead(PIN_SDA);

  if(i2cBitD)//RISING if SDA is HIGH (1)
  {

    i2cClk = digitalRead(PIN_SCL);
    if(i2cStatus=!I2C_IDLE && i2cClk==1)//If SCL still HIGH then it is a STOP sign
    {     
      //i2cStatus = I2C_STOP;
      i2cStatus = I2C_IDLE;
      bitCount = 0;
      byteCount = 0;
      bufferPoiW--;
      dataBuffer[bufferPoiW++] = 's';//115
      dataBuffer[bufferPoiW++] = '\n'; //10
    }
    sdaUpCnt++;
  }
  else //FALLING if SDA is LOW
  {

    i2cClk = digitalRead(PIN_SCL);
    if(i2cStatus==I2C_IDLE && i2cClk)//If SCL still HIGH than this is a START
    {
      i2cStatus = I2C_TRX;
      //lastStartMillis = millis();//takes too long in an interrupt handler and caused timeout panic and CPU restart
      bitCount = 0;
      byteCount =0;
      dataBuffer[bufferPoiW++] = 'S';//83 STOP
      //i2cStatus = START;    
    }
    sdaDownCnt++;
  }
}//END of i2cTriggerOnChangeSDA()

////////////////////////////////
//// Functions
////////////////////////////////

/**
 * Reset all important variable
 */
void resetI2cVariable()
{
  i2cStatus = I2C_IDLE;
  bufferPoiW=0;
  bufferPoiR=0;
  bitCount =0;
  falseStart = 0;
}//END of resetI2cVariable()

/**
* @DESC Write out the buffer to the serial console
*
*/
void processDataBuffer()
{
  if(bufferPoiW == bufferPoiR)//There is nothing to say
    return;

  uint16_t pw = bufferPoiW;
  //print out falseStart
  Serial.printf("\nSCL up: %d SDA up: %d SDA down: %d false start: %d\n", sclUpCnt, sdaUpCnt, sdaDownCnt, falseStart);

  //Adres filter
  for(int i=bufferPoiR; i< (bufferPoiR+8); i++)
  {
    if (dataBuffer[i] != adresa[i]) stampaj=0;
  }

  //print out the content of the buffer
  if (stampaj)
  {
    for(int i=bufferPoiR; i< pw; i++)
    {
      Serial.write(dataBuffer[i]);
      bufferPoiR++;  
    } 
  }
  stampaj=1;  

  //if there is no I2C action in progress and there wasn't during the Serial.print then buffer was printed out completly and can be reset.
  if(i2cStatus == I2C_IDLE && pw==bufferPoiW)
  {
    bufferPoiW =0;
    bufferPoiR =0;
  } 
}//END of processDataBuffer()

/////////////////////////////////
////  MAIN entry point of the program
/////////////////////////////////
void setup() 
{

  #ifdef I2CTEST
  pinMode(PIN_SCL, OUTPUT);   
    pinMode(PIN_SDA, OUTPUT); 
  #else
  //Define pins for SCL, SDA
  pinMode(PIN_SCL, INPUT_PULLUP);   
    pinMode(PIN_SDA, INPUT_PULLUP);
  //pinMode(PIN_SCL, INPUT);   
    //pinMode(PIN_SDA, INPUT);

    //reset variables
    resetI2cVariable();

    //Atach interrupt handlers to the interrupts on GPIOs
    attachInterrupt(PIN_SCL, i2cTriggerOnRaisingSCL, RISING); //trigger for reading data from SDA
  attachInterrupt(PIN_SDA, i2cTriggerOnChangeSDA, CHANGE); //for I2C START and STOP
  #endif
  Serial.begin(115200);
}//END of setup

/**
 * LOOP
 */
void loop() 
{

  #ifdef I2CTEST
  digitalWrite(PIN_SCL, HIGH);   //13 SARGA
    digitalWrite(PIN_SDA, HIGH);  //12 KEK
  delay(500);
  digitalWrite(PIN_SCL, HIGH);   //13 SARGA
    digitalWrite(PIN_SDA, LOW); //12 KEK
  delay(500);
  #else

    //if it is in IDLE, then write out the databuffer to the serial consol
    if(i2cStatus == I2C_IDLE)
  {
    processDataBuffer();
        Serial.print("\rStart delay    ");    
        delay(5000);
        Serial.print("\rEnd delay    ");
    delay(500);
  }

  #endif

}//END of loop

Here you are.

You may notice a new const volatile byte adresa[ ] There one should put the I2C address that needs, and as output, there will be ONLY data from that address. This works.

In a processDataBuffer function, you will notice all the logic I implemented. It is only basic. Check if there are data with that address, if there is, print it. If not, move on.

ITstreet1 commented 2 years ago

I connected basic PCF8574 with two LEDs on Nano. With ESP32 and ISO1540 I get the expected data. This is the form:

S0100000W+10001000+s S0100000W+00001000+s S0100000W+10001000+s S0100000W+10000000+s S0100000W+10001000+s S0100000W+00001000+s

This should be packed in something like this as a String:

S0100000W+10001000+sS0100000W+00001000+sS0100000W+10001000+sS0100000W+10000000+sS0100000W+10001000+sS0100000W+00001000+s

ITstreet1 commented 2 years ago

If I change byte adresa [ ] from 0100000 to something else, I get nothing.

On a server, I can easily cut it into pieces and do whatever I want. But first things first. Let's send it.

WhitehawkTailor commented 2 years ago

thanx for the code. But let me notice that this is not a perfect code. You cannot be sure this will work in any cases. You will experience data loss. It works if you are lucky and all the circumstances are good.

The implemented logic to follow the communication uses interrupts. That is why the main loop does nothing but process the buffer. The buffer is written by the routines called by the interrupts.

So here is the thing. When processDataBuffer() is called from the main loop you cannot be sure that there is a whole complete message in it. It may happened the message has only a few bytes of an address like this: S010000 And when the processDataBuffer() is called again then you will see the second part of it only, because former processDataBuffer() cleaned it up: 0W+10001000+s In neither case your address checking will find it as a proper address.

In case when there is rare communication and only one or none happens during the delayed loop, then you are lucky and your code works in most of the time. It can happen that the processDataBuffer() is called by the main loop in the middle of an I2C message then again you will see only part of a communication message. Your experience will be that some messages are missing.

To handle all of this makes it so difficult, if you want to implement the logic in the processDataBuffer(). The challenge is to process the data only in case that contains full I2C messages. Or in case there are multiple messages and a part as well, then process full messages only and leave the half in the array.

ITstreet1 commented 2 years ago

I noticed all the issues a time or two you mention. It is fair enough.

On a server, everything can be cut into pieces. And nothing is important that much. If you know what to expect, everything that is not a match, just cut off.

The main goal should be to send it to a server. And that is a little bit tricky for me. If you have a solution to take the data from a buffer, no matter what is in it, and put it in a String...

WhitehawkTailor commented 2 years ago

What is the protocol that the destination server expects? Is it an HTTP request or any API that needs data in XML or JSON? What is the transfer type? Is it WiFi?

ITstreet1 commented 2 years ago

HTTPGet request ESP32. SQL PHP

I think if it could be packed in a String, it would be more than enough.

WhitehawkTailor commented 2 years ago

then the processDataBuffer() should be modified to check if the buffer contains whole S...s pieces and send them via a HTTP GET message. One question that need to be checked is the frequency of I2C message. If I2C messages come too frequently then you have to have a buffer big enough to store messages temporarily. Second question is how frequently the server can be requested with the GET message. This to timing question will define the delay in the main loop and the size of the buffer to store I2C messages temporarily.

ITstreet1 commented 2 years ago

I would try to go no matter if any garbage in or not. Is it whole or not. That could be easily filtered on the server. It is not that important if something is missing. As for time, I think, some say 10 sec or so. Maybe more, it doesn't matter that much. Let's try it as is.

Later I will add some other I2C devices, just to see how it works. Or some other I2C expander with 2 ports.

To be honest my goal is to monitor some devices that do things in a loop. So if not good in the first reading, it will be in second. Or third.

WhitehawkTailor commented 2 years ago

In this case it is easy, just make the main loop to send out whatever is in the dataBuffer as a string. For this you just have to modify the processDataBuffer() to put everything into a message string from the dataBuffer and send it out.

ITstreet1 commented 2 years ago

I know that, but not sure how. I am messing up pretty much with putting buffer in a String. Didn't move an inch. Not sure how to modify it.

That is why I am here.

WhitehawkTailor commented 2 years ago

I made some modification to make available the sending. Please check parts in the code that is marked with v1.1 and see the descriptions. I am not sure if it works, because I don't have the setup assembled to test it. You have to extend this code with the communication, like access WiFi, send an HTTP request, etc.

Here is the modified code: `/**

include

//#define I2CTEST //use it to run a blinking LED test on SDA and SCL pins

define PIN_SDA 12 //BLUE

define PIN_SCL 13 //Yellow

define I2C_IDLE 0

//#define I2C_START 1

define I2C_TRX 2

//#define I2C_RESP 3 //#define I2C_STOP 4

static volatile byte i2cStatus = I2C_IDLE;//Status of the I2C BUS static uint32_t lastStartMillis = 0;//stoe the last time static volatile byte dataBuffer[9600];//Array for storing data of the I2C communication static volatile uint16_t bufferPoiW=0;//points to the first empty position in the dataBufer to write static uint16_t bufferPoiR=0;//points to the position where to start read from static volatile byte bitCount = 0;//counter of bit appeared on the BUS static volatile uint16_t byteCount =0;//counter of bytes were writen in one communication. static volatile byte i2cBitD =0;//Container of the actual SDA bit static volatile byte i2cBitD2 =0;//Container of the actual SDA bit static volatile byte i2cBitC =0;//Container of the actual SDA bit static volatile byte i2cClk =0;//Container of the actual SCL bit static volatile byte i2cAck =0;//Container of the last ACK value static volatile byte i2cCase =0;//Container of the last ACK value static volatile uint16_t falseStart = 0;//Counter of false start events //static volatile byte respCount =0;//Auxiliary variable to help detect next byte instead of STOP //these variables just for statistic reasons static volatile uint16_t sclUpCnt = 0;//Auxiliary variable to count rising SCL static volatile uint16_t sdaUpCnt = 0;//Auxiliary variable to count rising SDA static volatile uint16_t sdaDownCnt = 0;//Auxiliary variable to count falling SDA

//v1.1 //Store the begining of the communication string. Modify it according to your setup. String msgToServer = "http://192.168.0.19:5544/I2cServer?ADDR=0100000&data=";

//////////////////////////// //// Interrupt handlers /////////////////////////////

/**

}//END of i2cTriggerOnRaisingSCL()

/**

//////////////////////////////// //// Functions ////////////////////////////////

/**

/**

/**

/**

}

///////////////////////////////// //// MAIN entry point of the program ///////////////////////////////// void setup() {

#ifdef I2CTEST
pinMode(PIN_SCL, OUTPUT);   
pinMode(PIN_SDA, OUTPUT);   
#else
//Define pins for SCL, SDA
pinMode(PIN_SCL, INPUT_PULLUP);   
pinMode(PIN_SDA, INPUT_PULLUP);
//pinMode(PIN_SCL, INPUT);   
//pinMode(PIN_SDA, INPUT);

//reset variables
resetI2cVariable();

//Atach interrupt handlers to the interrupts on GPIOs
attachInterrupt(PIN_SCL, i2cTriggerOnRaisingSCL, RISING); //trigger for reading data from SDA
attachInterrupt(PIN_SDA, i2cTriggerOnChangeSDA, CHANGE); //for I2C START and STOP
#endif
Serial.begin(115200);

}//END of setup

/**

}//END of loop `

WhitehawkTailor commented 2 years ago

I hope it helps you. Good luck!

ITstreet1 commented 2 years ago

Nagyon köszönöm!

I will try it and let you know.

ITstreet1 commented 2 years ago
String getStringFromDataBuffer()
{
String ret = "";
if(bufferPoiW == bufferPoiR)//There is nothing to say
return;

Can't compile. This return;

ITstreet1 commented 2 years ago

Maybe the problem is with copy-paste, as you can see. When copying the code, first paste it, then select all of it, and click insert code or ctrl+e. When inserting the code in those ```` it always messes up.

Or maybe better, add a new file in the repo.

Besides, this code you posted is not the one I modified with selecting the I2C address.

WhitehawkTailor commented 2 years ago

The compiler is right (of course :). The return should give back a String, since the value type of the function is String. So the proper line is: return null; or return "";

ITstreet1 commented 2 years ago

Boldog új évet!

No back to the problem. return null; trow this error: 'null' was not declared in this scope

return ""; Compiles.

ITstreet1 commented 2 years ago
/**

    @author Ákos Szabó (Whitehawk Tailor) - aaszabo@gmail.com
    This is an I2C sniffer that logs traffic on I2C BUS.
    IDE: Visual Studio Code + PlatformIO
    Platform: Arduino for ESP32
    Board: Heltec WiFi Lora32 v2
    GPIO12 SDA
    GPIO13 SCL
    This is not connecting to the BUS as an I2C device. It is neither a Master, nor a Slave.
    It just listens and logs the communication.
    The application does not interrupt the I2C communication.
    Two pins as input are attached to SDC and SDA lines.
    Since the I2C communications runs on 400kHz so,
    the tool that runs this program should be fast.
    This was tested on an ESP32 bord Heltec WiFi Lora32 v2
    ESP32 core runs on 240MHz.
    It means there are 600 ESP32 cycles during one I2C clock tick.
    The program uses interrupts to detect
    the raise edge of the SCL - bit transfer
    the falling edge of SDA if SCL is HIGH- START
    the raise edge of SDA if SCL id HIGH - STOP
    In the interrupt routines there is just a few line of code
    that mainly sets the status and stores the incoming bits.
    Otherwise the program gets timeout panic in interrupt handler and
    restart the CPU.
    v1.0
    Basic operation and put message to eh serial output
    v1.1
    See additional parts marked with the version title v1.1
    The additionals makes possible to send the logged I2C communication content to a server via HTTP request.
    */

#include <Arduino.h>
#include <WiFi.h>
#include <HTTPClient.h>
//#define I2CTEST //use it to run a blinking LED test on SDA and SCL pins

#define PIN_SDA 12 //BLUE
#define PIN_SCL 13 //Yellow

#define I2C_IDLE 0
//#define I2C_START 1
#define I2C_TRX 2
//#define I2C_RESP 3
//#define I2C_STOP 4

static volatile byte i2cStatus = I2C_IDLE;//Status of the I2C BUS
static uint32_t lastStartMillis = 0;//stoe the last time
static volatile byte dataBuffer[9600];//Array for storing data of the I2C communication
static volatile uint16_t bufferPoiW=0;//points to the first empty position in the dataBufer to write
static uint16_t bufferPoiR=0;//points to the position where to start read from
static volatile byte bitCount = 0;//counter of bit appeared on the BUS
static volatile uint16_t byteCount =0;//counter of bytes were writen in one communication.
static volatile byte i2cBitD =0;//Container of the actual SDA bit
static volatile byte i2cBitD2 =0;//Container of the actual SDA bit
static volatile byte i2cBitC =0;//Container of the actual SDA bit
static volatile byte i2cClk =0;//Container of the actual SCL bit
static volatile byte i2cAck =0;//Container of the last ACK value
static volatile byte i2cCase =0;//Container of the last ACK value
static volatile uint16_t falseStart = 0;//Counter of false start events
//static volatile byte respCount =0;//Auxiliary variable to help detect next byte instead of STOP
//these variables just for statistic reasons
static volatile uint16_t sclUpCnt = 0;//Auxiliary variable to count rising SCL
static volatile uint16_t sdaUpCnt = 0;//Auxiliary variable to count rising SDA
static volatile uint16_t sdaDownCnt = 0;//Auxiliary variable to count falling SDA

//v1.1
//Store the begining of the communication string. Modify it according to your setup.
String msgToServer = "http://192.168.0.19:5544/I2cServer?ADDR=0100000&data=";
const char* ssid = "ssid";
const char* password = "pass";
const int deviceID = 1;

////////////////////////////
//// Interrupt handlers
/////////////////////////////

/**

    This is the rising SCL interrupt handler
    Rising SCL makes reading the SDA

*/
void IRAM_ATTR i2cTriggerOnRaisingSCL()
{
sclUpCnt++;

//is it a false trigger?
if(i2cStatus==I2C_IDLE)
{
  falseStart++;
  //return;//this is not clear why do we have so many false START
}

//get the value from SDA
i2cBitC =  digitalRead(PIN_SDA);

//decide wherewe are and what to do with incoming data
i2cCase = 0;//normal case

if(bitCount==8)//ACK case
  i2cCase = 1;

if(bitCount==7 && byteCount==0 )// R/W if the first address byte
  i2cCase = 2;

bitCount++;

switch (i2cCase)
{
  case 0: //normal case
    dataBuffer[bufferPoiW++] = '0' + i2cBitC;//48
  break;//end of case 0 general
  case 1://ACK
    if(i2cBitC)//1 NACK SDA HIGH
      {
        dataBuffer[bufferPoiW++] = '-';//45
      }
      else//0 ACK SDA LOW
      {
        dataBuffer[bufferPoiW++] = '+';//43
      } 
    byteCount++;
    bitCount=0;
  break;//end of case 1 ACK
  case 2:
    if(i2cBitC)
    {
      dataBuffer[bufferPoiW++] = 'R';//82
    }
    else
    {
      dataBuffer[bufferPoiW++] = 'W';//87
    }
  break;//end of case 2 R/W

}//end of switch

}//END of i2cTriggerOnRaisingSCL()

/**

    This is the SDA interrupt handler

    This is for recognizing I2C START and STOP

    This is called when the SDA line is changing

    It is decided inside the function wheather it is a rising or falling change.

    If SCL is on High then the falling change is a START and the rising is a STOP.

    If SCL is LOW, then this is the action to set a data bit, so nothing to do.
    */
    void IRAM_ATTR i2cTriggerOnChangeSDA()
    {
    //make sure that the SDA is in stable state
    do
    {
    i2cBitD = digitalRead(PIN_SDA);
    i2cBitD2 = digitalRead(PIN_SDA);
    } while (i2cBitD!=i2cBitD2);

    if(i2cBitD)//RISING if SDA is HIGH (1)
    {

     i2cClk = digitalRead(PIN_SCL);
     if(i2cStatus=!I2C_IDLE && i2cClk==1)//If SCL still HIGH then it is a STOP sign
     {      
      //i2cStatus = I2C_STOP;
      i2cStatus = I2C_IDLE;
      bitCount = 0;
      byteCount = 0;
      bufferPoiW--;
      dataBuffer[bufferPoiW++] = 's';//115
      dataBuffer[bufferPoiW++] = '\n'; //10
     }
     sdaUpCnt++;

    }
    else //FALLING if SDA is LOW
    {

     i2cClk = digitalRead(PIN_SCL);
     if(i2cStatus==I2C_IDLE && i2cClk)//If SCL still HIGH than this is a START
     {
      i2cStatus = I2C_TRX;
      //lastStartMillis = millis();//takes too long in an interrupt handler and caused timeout panic and CPU restart
      bitCount = 0;
      byteCount =0;
      dataBuffer[bufferPoiW++] = 'S';//83 STOP
      //i2cStatus = START;    
     }
     sdaDownCnt++;

    }
    }//END of i2cTriggerOnChangeSDA()

////////////////////////////////
//// Functions
////////////////////////////////

/**

    Reset all important variable
    */
    void resetI2cVariable()
    {
    i2cStatus = I2C_IDLE;
    bufferPoiW=0;
    bufferPoiR=0;
    bitCount =0;
    falseStart = 0;
    }//END of resetI2cVariable()

/**

    @desc Write out the buffer to the serial console

*/
void processDataBuffer()
{
if(bufferPoiW == bufferPoiR)//There is nothing to say
return;

uint16_t pw = bufferPoiW;
//print out falseStart
Serial.printf("\nprocessDataBuffer\nSCL up: %d SDA up: %d SDA down: %d false start: %d\n", sclUpCnt, sdaUpCnt, sdaDownCnt, falseStart);
//print out the content of the buffer 
for(int i=bufferPoiR; i< pw; i++)
{
  Serial.write(dataBuffer[i]);
  bufferPoiR++;   
}

//if there is no I2C action in progress and there wasn't during the Serial.print then buffer was printed out completly and can be reset.
if(i2cStatus == I2C_IDLE && pw==bufferPoiW)
{
  bufferPoiW =0;
  bufferPoiR =0;
} 

}//END of processDataBuffer()

/**

    v1.1
    @desc This method returns a String that contains everything that is available in the dataBuffer
    This function also resets the buffer, so this and processDataBuffer cannot be used in the same time.
    @ret String value. Returns the whole content of the dataBuffer as a string.

*/
String getStringFromDataBuffer()
{
String ret = "";
if(bufferPoiW == bufferPoiR)//There is nothing to say
return "";

uint16_t pw = bufferPoiW;
//print out falseStart
Serial.printf("\ngetStringFromDataBuffer\nSCL up: %d SDA up: %d SDA down: %d false start: %d\n", sclUpCnt, sdaUpCnt, sdaDownCnt, falseStart);
//print out the content of the buffer 
for(int i=bufferPoiR; i< pw; i++)
{
  ret += (char)dataBuffer[i];   
  bufferPoiR++;   
}

//if there is no I2C action in progress and there wasn't during the Serial.print then buffer was printed out completly and can be reset.
if(i2cStatus == I2C_IDLE && pw==bufferPoiW)
{
  bufferPoiW =0;
  bufferPoiR =0;
}

return ret;

}//END of processDataBuffer()

/**

    v1.1
    This is an empty method.
    Write here any communication with a server

*/
void sendMsgOut(String argStr){
  argStr.replace(" ","");
  Serial.println();
  Serial.println(argStr);
  Serial.println();
}

/////////////////////////////////
//// MAIN entry point of the program
/////////////////////////////////
void setup(){
Serial.begin(115200);
#ifdef I2CTEST
pinMode(PIN_SCL, OUTPUT);   
pinMode(PIN_SDA, OUTPUT); 
#else
//Define pins for SCL, SDA
pinMode(PIN_SCL, INPUT_PULLUP);   
pinMode(PIN_SDA, INPUT_PULLUP);
//pinMode(PIN_SCL, INPUT);   
//pinMode(PIN_SDA, INPUT);

//reset variables
resetI2cVariable();

//Atach interrupt handlers to the interrupts on GPIOs
attachInterrupt(PIN_SCL, i2cTriggerOnRaisingSCL, RISING); //trigger for reading data from SDA
attachInterrupt(PIN_SDA, i2cTriggerOnChangeSDA, CHANGE); //for I2C START and STOP
#endif

WiFi.begin(ssid, password);
  Serial.println("Connecting");
  while(WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("Connected to WiFi network with IP Address: ");
  Serial.println(WiFi.localIP());

}//END of setup

/**

    LOOP

    v1.0

    @desc Writes I2C mcommunication to the serial if there is any.

    v1.1

    @desc uses sendMsgOut to send I2C mcommunication to the specified server and format given by the msgToServer variable
    */
    void loop()
    {

    #ifdef I2CTEST //do this in case it is testing the lines
    digitalWrite(PIN_SCL, HIGH); //13 Yellow
    digitalWrite(PIN_SDA, HIGH); //12 Blue
    delay(500);
    digitalWrite(PIN_SCL, HIGH); //13 Yellow
    digitalWrite(PIN_SDA, LOW); //12 Blue
    delay(500);
    #else
    //if it is in IDLE, then write out the databuffer to the serial consol
    if(i2cStatus == I2C_IDLE)
    {
    //v1.0
    //processDataBuffer();

      //v1.1
      //Get the content of the dataBuffer as a string and put it into a message
      //Send out the message
      //make sure that the msgToServer string variable is set properly above in the global variable section.
      sendMsgOut( msgToServer + getStringFromDataBuffer());

      //Delay the loop
         Serial.print("\rStart delay    ");   
         delay(5000);
         Serial.print("\rEnd delay    ");
         delay(500);
     }

    #endif

}//END of loop
ITstreet1 commented 2 years ago

Ok, so this code compiles. Problem is, there are empty spaces that I couldn't remove with replace() function.

Empty space in a string is not a valid URL. %20 is or no delimiter at all. How to remove that empty space? Or replace it?

ITstreet1 commented 2 years ago

You may notice I added some WiFi code. Not all.

WhitehawkTailor commented 2 years ago

I put this version into the code base as main-send.cpp Can you send me few examples of string with empty characters. Where the empty characters come from? Is it in the I2C communication or somewhere else?

ITstreet1 commented 2 years ago

My bad expression. Sorry. It is New Line that causes the problem. I just edited it.

Stay tuned! More tests coming.

ITstreet1 commented 2 years ago

OK. So I made a few tests. The changes I made in pull-request are ok. That, as it is works. I can send the data to a server. There is one issue. The leading S has disappeared somehow. It doesn't change anything as it is in the database and there I can do what I want.

Now the hard part... My first sketch somewhere above has the part that filters the I2C addresses and prints only the one I need. Here we have a sketch that doesn't filter it. When I tried to merge them together, I get a non-working sketch. It doesn't print/sends the output. Although it is the same setup. Just as it didn't find the data with the selected address.

ITstreet1 commented 2 years ago
/**

    @author Ákos Szabó (Whitehawk Tailor) - aaszabo@gmail.com
    This is an I2C sniffer that logs traffic on I2C BUS.
    IDE: Visual Studio Code + PlatformIO
    Platform: Arduino for ESP32
    Board: Heltec WiFi Lora32 v2
    GPIO12 SDA
    GPIO13 SCL
    This is not connecting to the BUS as an I2C device. It is neither a Master, nor a Slave.
    It just listens and logs the communication.
    The application does not interrupt the I2C communication.
    Two pins as input are attached to SDC and SDA lines.
    Since the I2C communications runs on 400kHz so,
    the tool that runs this program should be fast.
    This was tested on an ESP32 bord Heltec WiFi Lora32 v2
    ESP32 core runs on 240MHz.
    It means there are 600 ESP32 cycles during one I2C clock tick.
    The program uses interrupts to detect
    the raise edge of the SCL - bit transfer
    the falling edge of SDA if SCL is HIGH- START
    the raise edge of SDA if SCL id HIGH - STOP
    In the interrupt routines there is just a few line of code
    that mainly sets the status and stores the incoming bits.
    Otherwise the program gets timeout panic in interrupt handler and
    restart the CPU.
    v1.0
    Basic operation and put message to eh serial output
    v1.1
    See additional parts marked with the version title v1.1
    The additionals makes possible to send the logged I2C communication content to a server via HTTP request.
    v1.2
    Adding WIFI comunication for sending data to a server
    Few minor bugs fix
    */

#include <Arduino.h>
#include <WiFi.h>
#include <HTTPClient.h>
//#define I2CTEST //use it to run a blinking LED test on SDA and SCL pins

#define PIN_SDA 12 //BLUE
#define PIN_SCL 13 //Yellow

#define I2C_IDLE 0
//#define I2C_START 1
#define I2C_TRX 2
//#define I2C_RESP 3
//#define I2C_STOP 4

//v1.2
bool filterToPrint = 1;
const volatile byte addressFilter[] = "S0100000";//I2C addres to filter. Lettter S on the begining must stay
//
static volatile byte i2cStatus = I2C_IDLE;//Status of the I2C BUS
static uint32_t lastStartMillis = 0;//stoe the last time
static volatile byte dataBuffer[9600];//Array for storing data of the I2C communication
static volatile uint16_t bufferPoiW=0;//points to the first empty position in the dataBufer to write
static uint16_t bufferPoiR=0;//points to the position where to start read from
static volatile byte bitCount = 0;//counter of bit appeared on the BUS
static volatile uint16_t byteCount =0;//counter of bytes were writen in one communication.
static volatile byte i2cBitD =0;//Container of the actual SDA bit
static volatile byte i2cBitD2 =0;//Container of the actual SDA bit
static volatile byte i2cBitC =0;//Container of the actual SDA bit
static volatile byte i2cClk =0;//Container of the actual SCL bit
static volatile byte i2cAck =0;//Container of the last ACK value
static volatile byte i2cCase =0;//Container of the last ACK value
static volatile uint16_t falseStart = 0;//Counter of false start events
//static volatile byte respCount =0;//Auxiliary variable to help detect next byte instead of STOP
//these variables just for statistic reasons
static volatile uint16_t sclUpCnt = 0;//Auxiliary variable to count rising SCL
static volatile uint16_t sdaUpCnt = 0;//Auxiliary variable to count rising SDA
static volatile uint16_t sdaDownCnt = 0;//Auxiliary variable to count falling SDA

//v1.1
//Store the begining of the communication string. Modify it according to your setup.
//String msgToServer = "http://192.168.0.19:5544/I2cServer?ADDR=0100000&data=";
//v1.2
String msgToServer = "http://somesite.com/index.php?deviceID=1&data=";
const char* ssid = "ssid";
const char* password = "pass";
const int deviceID = 1;

////////////////////////////
//// Interrupt handlers
/////////////////////////////

/**

    This is the rising SCL interrupt handler
    Rising SCL makes reading the SDA

*/
void IRAM_ATTR i2cTriggerOnRaisingSCL()
{
sclUpCnt++;

//is it a false trigger?
if(i2cStatus==I2C_IDLE)
{
  falseStart++;
  //return;//this is not clear why do we have so many false START
}

//get the value from SDA
i2cBitC =  digitalRead(PIN_SDA);

//decide wherewe are and what to do with incoming data
i2cCase = 0;//normal case

if(bitCount==8)//ACK case
  i2cCase = 1;

if(bitCount==7 && byteCount==0 )// R/W if the first address byte
  i2cCase = 2;

bitCount++;

switch (i2cCase)
{
  case 0: //normal case
    dataBuffer[bufferPoiW++] = '0' + i2cBitC;//48
  break;//end of case 0 general
  case 1://ACK
    if(i2cBitC)//1 NACK SDA HIGH
      {
        dataBuffer[bufferPoiW++] = '-';//45
      }
      else//0 ACK SDA LOW
      {
        dataBuffer[bufferPoiW++] = '+';//43
      } 
    byteCount++;
    bitCount=0;
  break;//end of case 1 ACK
  case 2:
    if(i2cBitC)
    {
      dataBuffer[bufferPoiW++] = 'R';//82
    }
    else
    {
      dataBuffer[bufferPoiW++] = 'W';//87
    }
  break;//end of case 2 R/W

}//end of switch

}//END of i2cTriggerOnRaisingSCL()

/**

    This is the SDA interrupt handler

    This is for recognizing I2C START and STOP

    This is called when the SDA line is changing

    It is decided inside the function wheather it is a rising or falling change.

    If SCL is on High then the falling change is a START and the rising is a STOP.

    If SCL is LOW, then this is the action to set a data bit, so nothing to do.
    */
    void IRAM_ATTR i2cTriggerOnChangeSDA()
    {
    //make sure that the SDA is in stable state
    do
    {
    i2cBitD = digitalRead(PIN_SDA);
    i2cBitD2 = digitalRead(PIN_SDA);
    } while (i2cBitD!=i2cBitD2);

    if(i2cBitD)//RISING if SDA is HIGH (1)
    {

     i2cClk = digitalRead(PIN_SCL);
     if(i2cStatus=!I2C_IDLE && i2cClk==1)//If SCL still HIGH then it is a STOP sign
     {      
      //i2cStatus = I2C_STOP;
      i2cStatus = I2C_IDLE;
      bitCount = 0;
      byteCount = 0;
      bufferPoiW--;
      dataBuffer[bufferPoiW++] = 's';//115
      dataBuffer[bufferPoiW++] = '\n'; //10
     }
     sdaUpCnt++;

    }
    else //FALLING if SDA is LOW
    {

     i2cClk = digitalRead(PIN_SCL);
     if(i2cStatus==I2C_IDLE && i2cClk)//If SCL still HIGH than this is a START
     {
      i2cStatus = I2C_TRX;
      //lastStartMillis = millis();//takes too long in an interrupt handler and caused timeout panic and CPU restart
      bitCount = 0;
      byteCount =0;
      dataBuffer[bufferPoiW++] = 'S';//83 STOP
      //i2cStatus = START;    
     }
     sdaDownCnt++;

    }
    }//END of i2cTriggerOnChangeSDA()

////////////////////////////////
//// Functions
////////////////////////////////

/**

    Reset all important variable
    */
    void resetI2cVariable()
    {
    i2cStatus = I2C_IDLE;
    bufferPoiW=0;
    bufferPoiR=0;
    bitCount =0;
    falseStart = 0;
    }//END of resetI2cVariable()

/**

    @desc Write out the buffer to the serial console

*/
void processDataBuffer()
{
if(bufferPoiW == bufferPoiR)//There is nothing to say
return;

uint16_t pw = bufferPoiW;
//print out falseStart
Serial.printf("\nprocessDataBuffer\nSCL up: %d SDA up: %d SDA down: %d false start: %d\n", sclUpCnt, sdaUpCnt, sdaDownCnt, falseStart);
//print out the content of the buffer 
for(int i=bufferPoiR; i< pw; i++){
  Serial.write(dataBuffer[i]);
  bufferPoiR++;   
}

//if there is no I2C action in progress and there wasn't during the Serial.print then buffer was printed out completly and can be reset.
if(i2cStatus == I2C_IDLE && pw==bufferPoiW)
{
  bufferPoiW =0;
  bufferPoiR =0;
} 

}//END of processDataBuffer()

/**

    v1.1
    @desc This method returns a String that contains everything that is available in the dataBuffer
    This function also resets the buffer, so this and processDataBuffer cannot be used in the same time.
    @ret String value. Returns the whole content of the dataBuffer as a string.
    v1.2
    Added filtering the byte array

*/
String getStringFromDataBuffer()
{
String ret = "";
if(bufferPoiW == bufferPoiR)//There is nothing to say
return "";

uint16_t pw = bufferPoiW;
//print out falseStart
Serial.printf("\ngetStringFromDataBuffer\nSCL up: %d SDA up: %d SDA down: %d false start: %d\n", sclUpCnt, sdaUpCnt, sdaDownCnt, falseStart);
//print out the content of the buffer 
//address filter
  for(int i=bufferPoiR; i< (bufferPoiR+8); i++){
    if (dataBuffer[i] != addressFilter[i]) filterToPrint=0;    
    }
    if (filterToPrint){
      for(int i=bufferPoiR; i< pw; i++){
        ret += (char)dataBuffer[i];   
        bufferPoiR++;   
      }
    }
filterToPrint = 1;

//if there is no I2C action in progress and there wasn't during the Serial.print then buffer was printed out completly and can be reset.
if(i2cStatus == I2C_IDLE && pw==bufferPoiW)
{
  bufferPoiW =0;
  bufferPoiR =0;
}

return ret;

}//END of processDataBuffer()

/**

    v1.1
    This is an empty method.
    Write here any communication with a server
    v1.2 
    wifi support
*/
void sendMsgOut(String argStr){
  argStr.replace("\n","");
  Serial.println();
  Serial.println(argStr);
  Serial.println();

  if(WiFi.status()== WL_CONNECTED){
      HTTPClient http;
      http.begin(argStr);
      int httpResponseCode = http.GET();
      if (httpResponseCode>0) {
        Serial.print("HTTP Response code: ");
        Serial.println(httpResponseCode);
        String payload = http.getString();
        Serial.println(payload);
      }
  }
}

/////////////////////////////////
//// MAIN entry point of the program
/////////////////////////////////
void setup(){
Serial.begin(115200);
#ifdef I2CTEST
pinMode(PIN_SCL, OUTPUT);   
pinMode(PIN_SDA, OUTPUT); 
#else
//Define pins for SCL, SDA
pinMode(PIN_SCL, INPUT_PULLUP);   
pinMode(PIN_SDA, INPUT_PULLUP);
//pinMode(PIN_SCL, INPUT);   
//pinMode(PIN_SDA, INPUT);

//reset variables
resetI2cVariable();

//Atach interrupt handlers to the interrupts on GPIOs
attachInterrupt(PIN_SCL, i2cTriggerOnRaisingSCL, RISING); //trigger for reading data from SDA
attachInterrupt(PIN_SDA, i2cTriggerOnChangeSDA, CHANGE); //for I2C START and STOP
#endif

WiFi.begin(ssid, password);
  Serial.println("Connecting");
  while(WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("Connected to WiFi network with IP Address: ");
  Serial.println(WiFi.localIP());

}//END of setup

/**

    LOOP

    v1.0

    @desc Writes I2C mcommunication to the serial if there is any.

    v1.1

    @desc uses sendMsgOut to send I2C mcommunication to the specified server and format given by the msgToServer variable
    */
    void loop()
    {

    #ifdef I2CTEST //do this in case it is testing the lines
    digitalWrite(PIN_SCL, HIGH); //13 Yellow
    digitalWrite(PIN_SDA, HIGH); //12 Blue
    delay(500);
    digitalWrite(PIN_SCL, HIGH); //13 Yellow
    digitalWrite(PIN_SDA, LOW); //12 Blue
    delay(500);
    #else
    //if it is in IDLE, then write out the databuffer to the serial consol
    if(i2cStatus == I2C_IDLE)
    {
    //v1.0
    //processDataBuffer();

      //v1.1
      //Get the content of the dataBuffer as a string and put it into a message
      //Send out the message
      //make sure that the msgToServer string variable is set properly above in the global variable section.
      sendMsgOut( msgToServer + getStringFromDataBuffer());

      //Delay the loop
         Serial.print("\rStart delay    ");   
         delay(5000);
         Serial.print("\rEnd delay    ");
         delay(500);
     }

    #endif

}//END of loop
ITstreet1 commented 2 years ago

I commented changes to the main sketch

WhitehawkTailor commented 2 years ago

Now this is the debug challenge :) Put Serial.println("Loop"); and Serial.println("getString"); and Serial.println("sendMsg"); etc. to the beginning of corresponding functions. It will show the process during the operation.

Also write out the content of the buffer after this line: uint16_t pw = bufferPoiW; like this for(int i=bufferPoiR; i< pw; i++) { Serial.write(dataBuffer[i]);
}

Send me the log from the console of couple message. Is there any message at all? Does it contain the function entries at all? Is there any I2C content? Is there a valid I2C address that you expect?

ITstreet1 commented 2 years ago

I added print on Loop and sendMsg. getString is a function from the ESP32 library. It just returns a response code, in this case, 200. This means everything is ok. And in the database I have entries. Empty entries.

I added print dataBuffer also.

This is the output:


Start delay    
End delay    Loop

getStringFromDataBuffer
SCL up: 6025 SDA up: 68 SDA down: 94 false start: 5999
sendMsg

http://somesite.com/index.php?deviceID=1&data=

HTTP Response code: 200

Start delay    
End delay    Loop

getStringFromDataBuffer
SCL up: 6120 SDA up: 89 SDA down: 125 false start: 6083
sendMsg

http://somesite.com/index.php?deviceID=1&data=

HTTP Response code: 200

Messages are ok, as I had previous entries from the pull-request code. When I upload that sketch, everything is fine. There is a mess with this I2C address filter. And I made it as I did on the original sketch, I posted above. Then, it worked just fine.

WhitehawkTailor commented 2 years ago

I meant the sendMsgOut and the getStringFromDataBuffer() to extend with a print not the ESP32 library function. Anyway, it seems to work. Why there is no I2C data added to the HTTP request. It is empty now.

Is it done, or you need more help on this?

ITstreet1 commented 2 years ago

Ok. There is huge progress!

I can sniff only the data from a specific address. Problem was, leading S somehow disappeared. So, I had to modify addressFilter, and to change: for(int i=bufferPoiR; i< (bufferPoiR+7); i++) because there is one byte less.

Now it works as it should.

Next things: -To add a few I2C devices and check how it works with more I2C addresses. -To sniff some I2C devices with more ports. Say MCP23017 or so.

This will be great piece of software, when finished. :)

ITstreet1 commented 2 years ago

There a some problems. As I said, I made this setup: Arduino Nano over PCF8574 blinks two LEDs (P3 and P7). It can be clearly seen on output, besides the I2C address. ESP32 dev kit over Mikroelektronika I2C Isolator ISO1540 is connected as in your example.

While I use this setup and the last sketch, everything goes fine. I2C data is in the database. I can select the I2C address as I want.

Issue nr1: As I mention, leading S somehow disappears. I fixed it, and I mention it also.

Issue nr2: No matter of selected address, the data has been sent to the server. This should be fixed also, so it sends data only if there is something on that address.

Issue nr3: This is a big one. I added an Oled display on Nano and just print and clear Hello every second. This resets the ESP32. I get this:

SCL up: 1 SDA up: 0 SDA down: 0 false start: 1
0
Start delay    Guru Meditation Error: Core  1 panic'ed (IllegalInstruction). Exception was unhandled.
Memory dump at 0x4008112c: 20c0fcb6 00198200 8080881b
Core  1 register dump:
PC      : 0x40081130  PS      : 0x00060031  A0      : 0x400843bc  A1      : 0x3ffbee40  
A2      : 0x0000000d  A3      : 0x3ffc3784  A4      : 0x00000000  A5      : 0x00002000  
A6      : 0x3ffbee68  A7      : 0x00000001  A8      : 0x800d1174  A9      : 0x3ffc3749  
A10     : 0x00000000  A11     : 0x3ffc1154  A12     : 0x00060023  A13     : 0x3ffc4f5c  
A14     : 0x00000000  A15     : 0x00000000  SAR     : 0x0000001d  EXCCAUSE: 0x00000000  
EXCVADDR: 0x00000000  LBEG    : 0x00000000  LEND    : 0x00000000  LCOUNT  : 0x00000000  

Backtrace:0x4008112d:0x3ffbee400x400843b9:0x3ffbee60 0x400ebc73:0x3ffc4e80 0x400d7d36:0x3ffc4ea0 0x40088d59:0x3ffc4ec0 

ELF file SHA256: 0000000000000000

Rebooting...
ets Jun  8 2016 00:22:57

rst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0030,len:1284
load:0x40078000,len:12836
load:0x40080400,len:3032
entry 0x400805e4
ITstreet1 commented 2 years ago

There is an additional issue. When starting/resetting ESP32, I had to disconnect VCC from the IS1540 (https://www.mikroe.com/i2c-isolator-click). Otherwise, it goes through continuous resetting. When it boots, I connect VCC from ESP to ISO1540. I think the solution would be to add a MOSFET and in setup() power up the ISO1540.

WhitehawkTailor commented 2 years ago

The first seems the same that I had. It was because the interrupt handler takes too long. Or it can arise if you over access an array and write to a position that is not reserved.

The second I think is because ESP32 is overloaded with the ISO1540 or other elements. Do not attache anything to ESP32 power output. Everything has to have its own power source.

ITstreet1 commented 2 years ago

https://www.ti.com/lit/ds/symlink/iso1540.pdf?ts=1641889238249&ref_url=https%253A%252F%252Fwww.ti.com%252Fproduct%252FISO1540

We are talking about milliamps. I don't think ISO1540 is overloading ESP32 that much. But...

Not sure about the third issue. I have a PCA9535. It has two ports. Just to see how it works.

ITstreet1 commented 2 years ago

Tests go further... I have a board, some sort of a display, with 4 PCA9535 on it which drive LEDs. Four times 16 channels. Every IC has two ports.

Issue nr1: When I let one of them blink two LEDs, it looks fine. When I let 2 PCA9535 blink two LEDs each, this is ok. But my filter loop is obviously wrong. If I choose one address, the sketch will print everything if that address is in the buffer, not only the part with that specific address.

Issue nr2: When I let all 4 ICs blink all channels, I get nothing, so I think the buffer is not big enough. What value should I put instead of 9600 that is right now? Try and guess or not?

WhitehawkTailor commented 2 years ago

You mean there is some module with microcontroller (call it A) that is connected to 4 PCA9535 (call them B, C, D, E) via I2C BUS. Your I2C sniffer (call it F) also connected to the lines. And now A communicates with B, C, D, E and F listens to the communication.

issue nr1 The logic of your address identification makes the program to display the whole buffer if it starts with the given address. More precisely your address identificator works well in just some cases. If this is your code still: for(int i=bufferPoiR; i< (bufferPoiR+8); i++){ if (dataBuffer[i] != addressFilter[i]) filterToPrint=0;
} if (filterToPrint){ for(int i=bufferPoiR; i< pw; i++){ ret += (char)dataBuffer[i];
bufferPoiR++;
} }

Then it works only if the buffer starts with the address, because you use i variable to read the addressFilter too. This should start from 0 always, but if bufferPoi not 0, then i will start with other number than 0. This could be a fix: for(int i=bufferPoiR, int k=0; i< (bufferPoiR+8); i++){ if (dataBuffer[i] != addressFilter[k++]) filterToPrint=0;
}

issue nr2 I think it is not the question of buffer size. Let's have the first issue fixed and it will fix the second one too. I hope :)

ITstreet1 commented 2 years ago

Using your original sketch, while there is data on all 4 ICs, I have readings. But I also get this after a minute or two:

Guru Meditation Error: Core  1 panic'ed (StoreProhibited). Exception was unhandled.

Core  1 register dump:
PC      : 0x4008123d  PS      : 0x00060031  A0      : 0x400843bc  A1      : 0x3ffbee40  
A2      : 0x0000000c  A3      : 0x3ffc3778  A4      : 0x00000000  A5      : 0x00001000  
A6      : 0x00060123  A7      : 0x3ffc1154  A8      : 0x800d1174  A9      : 0x3ffc3778  
A10     : 0x0000002d  A11     : 0x3ffc1154  A12     : 0x3ffb27e0  A13     : 0x3ffb27c0  
A14     : 0x3ffc3908  A15     : 0x00000031  SAR     : 0x00000004  EXCCAUSE: 0x0000001d  
EXCVADDR: 0x800d1174  LBEG    : 0x4008629d  LEND    : 0x400862ad  LCOUNT  : 0xffffffff  

Backtrace:0x4008123a:0x3ffbee400x400843b9:0x3ffbee60 0x4000bfed:0x3ffb26a0 0x4008a641:0x3ffb26b0 0x40088a1c:0x3ffb26d0 0x400d348c:0x3ffb2710 0x400d3b11:0x3ffb2760 0x400d2104:0x3ffb2790 0x400d1605:0x3ffb27c0 0x400d10a2:0x3ffb27e0 0x400d10ea:0x3ffb2800 0x400d1cd9:0x3ffb2820 

ELF file SHA256: 0000000000000000

Rebooting...
ets Jun  8 2016 00:22:57

rst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0030,len:1284
load:0x40078000,len:12836
load:0x40080400,len:3032
entry 0x400805e4

It starts again with readings and eventually gets this again.

From time to time I get this also:

1111111R-11111111-11111111-11111111-11111111-11111111-11111111-111S0100111W+00000011+s

As for your snipet suggestion, it can not compile. I get this:

 error: 'i' was not declared in this scope
   for(int i=bufferPoiR, int k=0; i< (bufferPoiR+8); i++){
WhitehawkTailor commented 2 years ago

I am sure the issue is the overwritten buffer. Display the bufferPoiR and bufferPoiW at the beginning of the getStringFromDataBuffer() every time when you enter. Modify the Serial.printf in getStringFromDataBuffer() with this line:

Serial.printf("\ngetStringFromDataBuffer\nSCL up: %d SDA up: %d SDA down: %d false start: %d poiW: %d poiR: %d\n", sclUpCnt, sdaUpCnt, sdaDownCnt, falseStart, bufferPoiW, bufferPoiR);

The suggested part above works well if you remove the "int" part for k:

for(int i=bufferPoiR, k=0; i< (bufferPoiR+8); i++) { if (dataBuffer[i] != addressFilter[k++]) filterToPrint=0; }

Anyway this is not a perfect solution. You said that you don§t want to process the data on the ESP32 side and everything should be send up no matter what is the content. So if you remove the address filtering and you always send up everything what you actually have in the buffer than your problem will disappear on the ESP32 side.

So modify the checking part and remove the address filter:

for(int i=bufferPoiR; i< (bufferPoiR+8); i++){ if (dataBuffer[i] != addressFilter[i]) filterToPrint=0;
} if (filterToPrint){ for(int i=bufferPoiR; i< pw; i++){ ret += (char)dataBuffer[i];
bufferPoiR++;
} } filterToPrint = 1;

to this

  for(int i=bufferPoiR; i< pw; i++)
  {
    ret += (char)dataBuffer[i];   
    bufferPoiR++;   
  }

Let's see if crash will disappear or not.

WhitehawkTailor commented 2 years ago

Also here is a useful string tokenizer finction for Arduino that can help. With this you can slice the buffer data at every start that is an S. You can check this for more: https://www.best-microcontroller-projects.com/arduino-strtok.html

Make sure only whole messages will processed. If you takes a message that starts with S, but not all the bits are in the buffer when you starts the process then you will end up with broken messages and will louse them.

ITstreet1 commented 2 years ago

Your basic sketch reboots the ESP32 when all PCA9535 communicates with an Arduino.

Guru Meditation Error: Core  1 panic'ed (StoreProhibited). Exception was unhandled.

Core  1 register dump:
PC      : 0x4008120b  PS      : 0x00060031  A0      : 0x400853bc  A1      : 0x3ffbee40  
A2      : 0x0000000c  A3      : 0x3ffc3778  A4      : 0x00000000  A5      : 0x00001000  
A6      : 0x00000000  A7      : 0x00000000  A8      : 0x00000000  A9      : 0x00000052  
A10     : 0x00000000  A11     : 0x00002623  A12     : 0x00000000  A13     : 0x3ffc4f5c  
A14     : 0x00000000  A15     : 0x00000000  SAR     : 0x0000001d  EXCCAUSE: 0x0000001d  
EXCVADDR: 0x00000052  LBEG    : 0x00000000  LEND    : 0x00000000  LCOUNT  : 0x00000000  

Backtrace:0x40081208:0x3ffbee400x400853b9:0x3ffbee60 0x400ebc73:0x3ffc4e80 0x400d7d36:0x3ffc4ea0 0x40088d59:0x3ffc4ec0 

ELF file SHA256: 0000000000000000

Rebooting...
ets Jun  8 2016 00:22:57

rst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0030,len:1284
load:0x40078000,len:12836
load:0x40080400,len:3032
entry 0x400805e4

I am trying to monitor some systems where there are those ICs I mention, but also some other devices on motherboard as well. I am waiting for some adapter to arrive so I can connect ISO1540 and ESP32 to the motherboard itself and see how it would work.

With that adapter, I will have ESP32 and ISO1540 soldered on a PCB, so no wires, or any possibility to cause problems other than the data and communication itself. Right now, I have 12 Dupont wires. The problem could cause everything.

ITstreet1 commented 2 years ago

After a while, it spits this:

1111111R-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-111111
Start delay    
End delay    
SCL up: 12475 SDA up: 178 SDA down: 178 false start: 12436
11-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-111
Start delay    
End delay    
SCL up: 14323 SDA up: 178 SDA down: 178 false start: 14284
11111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-111111
Start delay    
End delay    
SCL up: 16039 SDA up: 178 SDA down: 178 false start: 16000
11-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-111
Start delay    
End delay    
SCL up: 17887 SDA up: 178 SDA down: 178 false start: 17848
11111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-111111
Start delay    
End delay    
SCL up: 19537 SDA up: 178 SDA down: 178 false start: 19498
11-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-
Start delay    
End delay    
SCL up: 21385 SDA up: 178 SDA down: 178 false start: 21346
11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-111
Start delay    
End delay    
SCL up: 23299 SDA up: 178 SDA down: 178 false start: 23260
11111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-
Start delay    
End delay    
SCL up: 24949 SDA up: 178 SDA down: 178 false start: 24910
11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-111
Start delay    
End delay    
SCL up: 26863 SDA up: 178 SDA down: 178 false start: 26824
11111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-
Start delay    
End delay    
SCL up: 28513 SDA up: 178 SDA down: 178 false start: 28474
11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-111
Start delay    
End delay    
SCL up: 30313 SDA up: 257 SDA down: 261 false start: 30259
11111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-11111111-111111S0100011W+00000010+s
ITstreet1 commented 2 years ago

If needed, I can send you the sketch that blinks those LEDs.

WhitehawkTailor commented 2 years ago

which code do you run that produces this output? Is it the origin code, or some modified?

ITstreet1 commented 2 years ago

Basic sketch from here.