body:
```
#define monitor_pin 14

void setup()
{
  pinMode(monitor_pin , INPUT);
}

void loop()
{
    unsigned long d1 = pulseIn(14, HIGH);
    if (d1>0){//trigger function}
}

```
I know there is a function pulseIn(), but it doesnt really solve my problem. I just want to trigger a function when voltage change from LOW to HIGH/HIGH to LOW. pulseIn() need to wait for the voltage to back to original level which in my case will exceed 3 minutes and cause timeout.

How can  I detect a voltage change other than pulseIn()?

title: How to trigger a function by detecting voltage change?

Answers: 1

body:
You can save the previous state of the pin and then trigger the function when the current state is different from the previous state:

    #define monitor_pin 14
    int previous_state;

    void setup()
    {
      pinMode(monitor_pin , INPUT);
      previous_state = digitalRead(monitor_pin); // Initialize previous state with initial reading of the pin
    }

    void loop()
    {
      int current_state = digitalRead(monitor_pin);
      if(current_state != previous_state){
        // Execute your code here
        previous_state = current_state; // update previous state
      }
    }


body:
I am trying to use the Adafruit MMA8451 accelerometer with an attiny85. The Adafruit library uses Wire which doesn't work on the attiny so I used the ATTinyCore board files which have been modified to use a working version of Wire (github link: https://github.com/SpenceKonde/ATTinyCore).
I'm just trying to get the MMA8451 example to compile but here is the following error output:

```Arduino: 1.8.12 (Windows 10), Board: "ATtiny85/45/25 (No Bootloader), -Os (size, recommended), ATtiny85, 8 MHz (internal), EEPROM retained, RX on PB1, TX on PB (default PB0), B.O.D. Disabled (saves power), Enabled"

C:\Users\sglaw\Documents\Arduino\hardware\ATTinyCore-2.0.0-dev\avr\libraries\SPI\SPI.cpp: In static member function 'static void SPIClass::begin()':

C:\Users\sglaw\Documents\Arduino\hardware\ATTinyCore-2.0.0-dev\avr\libraries\SPI\SPI.cpp:259:5: error: 'USI_SCK_PORT' was not declared in this scope

     USI_SCK_PORT |= _BV(USCK_DD_PIN);   //set the USCK pin as output

     ^~~~~~~~~~~~

C:\Users\sglaw\Documents\Arduino\hardware\ATTinyCore-2.0.0-dev\avr\libraries\SPI\SPI.cpp:259:5: note: suggested alternative: 'USI_CLOCK_PORT'

     USI_SCK_PORT |= _BV(USCK_DD_PIN);   //set the USCK pin as output

     ^~~~~~~~~~~~

     USI_CLOCK_PORT

In file included from c:\users\sglaw\appdata\local\arduino15\packages\arduino\tools\avr-gcc\7.3.0-atmel3.6.1-arduino7\avr\include\avr\io.h:99:0,

                 from C:\Users\sglaw\Documents\Arduino\hardware\ATTinyCore-2.0.0-dev\avr\libraries\SPI\SPI.h:27,

                 from C:\Users\sglaw\Documents\Arduino\hardware\ATTinyCore-2.0.0-dev\avr\libraries\SPI\SPI.cpp:20:

C:\Users\sglaw\Documents\Arduino\hardware\ATTinyCore-2.0.0-dev\avr\libraries\SPI\SPI.cpp:259:25: error: 'USCK_DD_PIN' was not declared in this scope

     USI_SCK_PORT |= _BV(USCK_DD_PIN);   //set the USCK pin as output

                         ^

C:\Users\sglaw\Documents\Arduino\hardware\ATTinyCore-2.0.0-dev\avr\libraries\SPI\SPI.cpp:259:25: note: suggested alternative: 'USI_PIN'

C:\Users\sglaw\Documents\Arduino\hardware\ATTinyCore-2.0.0-dev\avr\libraries\SPI\SPI.cpp:260:5: error: 'USI_DDR_PORT' was not declared in this scope

     USI_DDR_PORT |= _BV(DO_DD_PIN);     //set the DO pin as output

     ^~~~~~~~~~~~

C:\Users\sglaw\Documents\Arduino\hardware\ATTinyCore-2.0.0-dev\avr\libraries\SPI\SPI.cpp:260:5: note: suggested alternative: 'USI_PORT'

     USI_DDR_PORT |= _BV(DO_DD_PIN);     //set the DO pin as output

     ^~~~~~~~~~~~

     USI_PORT

In file included from c:\users\sglaw\appdata\local\arduino15\packages\arduino\tools\avr-gcc\7.3.0-atmel3.6.1-arduino7\avr\include\avr\io.h:99:0,

                 from C:\Users\sglaw\Documents\Arduino\hardware\ATTinyCore-2.0.0-dev\avr\libraries\SPI\SPI.h:27,

                 from C:\Users\sglaw\Documents\Arduino\hardware\ATTinyCore-2.0.0-dev\avr\libraries\SPI\SPI.cpp:20:

C:\Users\sglaw\Documents\Arduino\hardware\ATTinyCore-2.0.0-dev\avr\libraries\SPI\SPI.cpp:260:25: error: 'DO_DD_PIN' was not declared in this scope

     USI_DDR_PORT |= _BV(DO_DD_PIN);     //set the DO pin as output

                         ^

C:\Users\sglaw\Documents\Arduino\hardware\ATTinyCore-2.0.0-dev\avr\libraries\SPI\SPI.cpp:260:25: note: suggested alternative: 'NOT_A_PIN'

C:\Users\sglaw\Documents\Arduino\hardware\ATTinyCore-2.0.0-dev\avr\libraries\SPI\SPI.cpp:261:26: error: 'DI_DD_PIN' was not declared in this scope

     USI_DDR_PORT &= ~_BV(DI_DD_PIN);    //set the DI pin as input

                          ^

Using library Wire at version 2.0.0 in folder: C:\Users\sglaw\Documents\Arduino\hardware\ATTinyCore-2.0.0-dev\avr\libraries\Wire
Using library Adafruit_MMA8451_Library at version 1.2.1 in folder: C:\Users\sglaw\Documents\Arduino\libraries\Adafruit_MMA8451_Library
Using library Adafruit_BusIO at version 1.14.1 in folder: C:\Users\sglaw\Documents\Arduino\libraries\Adafruit_BusIO
Using library Adafruit_Unified_Sensor at version 1.1.7 in folder: C:\Users\sglaw\Documents\Arduino\libraries\Adafruit_Unified_Sensor
Using library SPI at version 2.0.0 in folder: C:\Users\sglaw\Documents\Arduino\hardware\ATTinyCore-2.0.0-dev\avr\libraries\SPI
exit status 1
Error compiling for board ATtiny85/45/25 (No Bootloader).
```

Any help much appreciated

title: Compilation error with MMA8451 accelerometer and attiny85 using ATTinyCore

Answers: 0


body:
I'm trying to figure out how to use interrupts to get BMI270 acceleration data at high rate, but can't find any info on it. Already spent a few hours looking for some sample code and found nothing. Anyone knows where can I find more info or sample code on this?
EDIT:
its the [rev 2][1] and it has a BMI270

  [1]: https://docs.arduino.cc/hardware/nano-33-ble-sense-rev2

title: Arduino Nano 33 BLE Sense's BMI270 accelerometer rev 2

Answers: 0


body:
I am working in an Arduino project in visual studio. I need to get and set time to a RTC clock. That's why I am adding a ds3231 header file in my project from [GitHub][1]. When I want to build "it's showing me linking error.

    cccSeqVu.ltrans0.o*: (.text.startup+0x1ea): undefined reference to DS3231_init(unsigned char)

My code is given below.

       #include <Wire.h>
       #include "ds3231.h"

        void setup(){
            Wire.begin();
            DS3231_init(0x4);
        }

        void loop(){
        }

Can anyone please help me to find out what I have missed.

  [1]: https://github.com/rodan/ds3231

title: Adding RTC Library for Arduino Project in Visual Studio

Answers: 0


body:
Currently I am using `avrdude` and I'm programming my `atmega328p` chip via the `spi` pins by pulling the RESET pin low (spidev programmer).

In my project I'm using predominantly `i2c` and this the only place where `spi` is used. I was wondering whether it is possible to program the chip via the `i2c` protocol and remove the `spi` connections altogether?

My searches were unsuccessful.

title: Is it possible to program an AVR chip (atmega328p) via i2c?

Answers: 2

body:
From section 27.2(*) of the Atmega328xx data sheet (emphasis mine):

> In ATmega88A/88PA/168A/168PA/328/328P the Boot Loader Support provides
> a real Read-While-Write Self- Programming mechanism for downloading
> and uploading program code by the MCU itself. This feature allows
> flexible application software updates controlled by the MCU using a
> Flash-resident Boot Loader program. **The Boot Loader program can use
> any available data interface and associated protocol to read code and
> write (program) that code into the Flash memory,** or read the code from
> the program memory. The program code within the Boot Loader section
> has the capability to write into the entire Flash, including the Boot
> Loader memory. The Boot Loader can thus even modify itself, and it can
> also erase itself from the code if the feature is not needed anymore.
> The size of the Boot Loader memory is configurable with fuses and the
> Boot Loader has two separate sets of Boot Lock bits which can be set
> independently. This gives the user a unique flexibility to select
> different levels of protection.

You may need to re-write the input section of the bootloader, but it sure sounds like Atmel intended it to be doable.

[*] My data-sheet is dated 2018; the relevant section, Section 27, is titled "Boot Loader Support – Read-While-Write Self-Programming", in case a later revision has different section numbers.

body:
Yes, as JRobert pointed out, I have no doubt - it is possible!

You need just 3 things:

 1. a Bootloader that supports uploading the firmware via I2C
 2. an Upload-Software that supports uploading the firmware to the bootloader mentioned in 1.)
 3. an physical connection from the system the upload software is running on to the actual I2C bus of your device

Actually the physical interface is not the problem - there are USB<>I2C interfaces available widely, you can also re-use an arduino itself to be such.

Let's look at the bootloader.

Actually I found a german site that claims having a working [I2C bootloader for Atmega8][1] including an upload tool (use Deepl.com to translate it). It may or may not work for other Atmegas as is.

There is also [another project at github][2].

There will be more if you google for it. Actually I have not investigated any of them.

But chances are good than any of those might work for you.

  [1]: https://old.ethersex.de/index.php/I2C_Bootloader
  [2]: https://github.com/tspspi/ATMega328PBootloaderI2C


body:
I have an Arduino UNO and an ESP32 that need to communicate to each other using SoftwareSerial. The problem I am coming across is that when I call readString and print it out using Serial, it will not give me everything that has been printed out from my ESP32.

I have my Arduino RX Pin hooked up to 4 and TX hooked up to 5
I have my ESP32 RX2 Pin hooked up to 16 and TX2 pin hooked up to 17, with the GND hooked up to directly to the Arduino GND
I am not using any resistors, straight up 5v of pure power

Arduino UNO Code:
```
// C-standard library
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

#include <SoftwareSerial.h>

#define RX_PIN 4
#define TX_PIN 5

SoftwareSerial ardSerial(RX_PIN, TX_PIN);

void setup(void) {
  // Get access to network
  pinMode(RX_PIN, INPUT);
  pinMode(TX_PIN, OUTPUT);
  Serial.begin(9600);
  while(!Serial) {}
  ardSerial.begin(9600);
  while(!ardSerial) {}
}

void loop(void) {
  while (ardSerial.available() > 0) {
    String payload = ardSerial.readString();
    Serial.println(payload);
  }
  delay(1000);

}
```

ESP32 Code
```
#include <stdlib.h>
#include <string.h>

#include <SoftwareSerial.h>

SoftwareSerial ardSerial;

void setup(void) {
  // Begin connections
  Serial.begin(115200);
  while (!Serial) {}

  ardSerial.begin(9600, SWSERIAL_8N1, RX2_PIN, TX2_PIN);
  while (!ardSerial) {}
  return;
}

void loop(void) {
  {
    String spotData = "Huge JSON File that needs transferred";
    ardSerial.print(spotData);
  }

  delay(5000);
}
```

Expected result:
- Able to retrieve every little bit of the JSON file that was printed out

Actual result:
- Only receive like half of the JSON file

title: SoftwareSerial will not read all of the printed string when calling readString()

Answers: 2

body:
I see 2 problems with your code:

- You wrote in the comments, that the JSON file is huge. The Uno has only 2kB of RAM and you are trying to lead the complete file into RAM at once. Such a JSON file from Spotify will easily exceed the 2kB (in fact you have even less, because the Arduino framework and SoftwareSerial also use some of the RAM). So you just cannot handle the complete file at once with an Uno.

- You use `readString()`. This function is sure easy, but also has some pitfalls. It uses the `String` class, which utilizes dynamic memory allocation. It allocates a bigger character array in RAM, if the current array is not big enough. That means, that you would need up to 2 versions of your String fitting into RAM while receiving, leaving only about 1kB. Also it will read from the SoftwareSerial interface, until a timeout is hit (1s by default I think). For building a robust communication between the two devices you should read until you reach a special character, for example via `readStringUntil()`. That special character is often the newline character `'\n'`.

**Possible solution:** First we should talk about the limited RAM problem. As stated above you cannot handle the full file at once. You need to handle it in chunks. Whatever you want to do with the data in the end, the Uno will need some time handling the current chunk of data. So you need to pause the transmission of data at the ESP, until the Uno is ready to receive more. Here you can go two ways:

- Send the data in chunks of predefined size (small enough for the Uno to hold at once in its RAM) and wait a predefined time between each chunk, that is long enough for the Uno to handle every data it might have gotten in that chunk. This is the easiest to program, but will necessarily take more execution time.
- Let the Uno signal to the ESP, that its buffer is full, for example by sending a special character to the ESP. The ESP should then stop sending, until it gets the OK from the Uno to proceed the transmission. To send without loosing data the Uno should probably also send the number of bytes received in that chunk. That way the ESP knows exactly, where in the data String the Uno is currently. This is a bit more difficult, though still easy enough and robust.

To handle the sending in chunks I would use the `write(const uint8_t *buffer, size_t size)` method of SoftwareSerial (actually this function comes from the `Print` class, from which `SoftwareSerial` inherits). The buffer is the pointer to the first element of the current chunk in the `char` array with the data. You can get the `char` array via `spotData.c_str()` and you can get the pointer to the n-th element of it via `&(spotData.c_str()[n])`. The second parameter is the size of the chunk in bytes. This needs to be small enough, that the data will fit into the RAM of the UNO, together with all the RAM needed for processing the data.

On the Uno I would then do the reading bytewise. Something like this:

    char data[BUFFER_SIZE]="";
    int pos=0;

    void loop(){
        if(ardSerial.available()){
            data[pos] = ardSerial.read();
            if(pos == BUFFER_SIZE - 1){
                // Handle chunk of data
                pos = 0; // reset position to reuse buffer
            } else {
                pos++;
            }
        }
    }

I have left out some parts to only demonstrate the principle. Also you need to define `BUFFER_SIZE` yourself, depending on the available RAM.

Obviously this does not implement the second option with the pause signal, which is more complex.

---

Apart from sending and receiving you will need to think about how to process the chunks of data. This depends largely on what exactly you want to do with that data. Just sending them via Serial is easy. Interpreting the data in chunks is more difficult.

body:
There are two ways to implement a parser for a language like JSON or
XML:

1. Have the parser swallow the whole document at once, and produce an
   in-memory representation of the same data.

2. Have the parser return control to the caller for each “event” it
   detects, where an “event” is typically a primitive data item, or the
   start or the end of a container.

Parsers of the first kind are much easier to use, but this can be
expensive in RAM usage if you want to parse a alrge document. The second
kind of parsers are harder to use, but they are able to parse huge
documents using a minimal amount of memory.

On an Arduino, you would typically use ArduinoJson, which is a parser of
the first kind, not ideal for parsing huge documents on little memory. A
quick search for “event driven C++ JSON parser” got me [JsonReader][]. I
did not try it, and do not know whether that would work on Arduino, but
it shows that at least this kind of parsers do exist for JSON in C++.
You may want to search further along this way.

Before you dig into this, however, I suggest you give ArduinoJson a
second chance. ArduinoJson has a couple of tricks that can help dealing
with large documents:

* You can ask it to filter the data as it reads it, in order to only
  keep in memory the items you are actually interested in.

* You can deserialize in chunks, and use the data extracted from one
  chunk at a time.

Both techniques are explained in the tutorial [How to deserialize a very
large document?][tut].

Also, let's not forget the obvious: you should not attempt to store the
raw JSON document in memory. Instead, you should give ArduinoJson a
reference to your stream (namely `ardSerial`), and let it directly pull
the bytes as it parses.

[JsonReader]: https://github.com/xquintana/JsonReader
[tut]: https://arduinojson.org/v6/how-to/deserialize-a-very-large-document/


body:
Just installed Arduino 2.0.3 and I attempted to build a sketch which includes a library that I manually installed in version 1.8.19 and it can't be found:

In my program I have
`#include <DS3231.h>`

Now, attempting to compile it cannot find the library.

What is the path to the basic libraries in Arduino 2.0.3?

title: Just installed Arduino 2.0.3 - what is windows path to associated libraries?

Answers: 1

body:
I found the location by examining the app while it was running.

The associated libraries are at:

`%localappdata%\arduino15\Libraries`

That will look like : `C:\Users\<username>\AppData\Local\Arduino15\libraries`

I created a new folder named `DS3231` dropped in the .cpp, .h and .config files and now my sketch compiles with the `#include <DS3231.h>`

Kind of blows my mind that the Arduino 2.0.3 Libraries are found in a directory named Arduino15.  Is that an old version or something?

Here's what I see in preferences -- don't see a location for user libraries:

[![arduino preferences][1]][1]

The best location will be your sketchbook location + a folder named `libraries`.

For example, in my case my sketchbook location is :

`c:\users\<username>\dev\arduino`

so my library folder should be:

`c:\users\<username>\dev\arduino\libraries`

  [1]: https://i.stack.imgur.com/4Sptg.png


body:
How precisely can an Arduino nano be timed? The project I am working on needs two Arduino nano to work synchronously. Arduino one have to activate a relay after 2700 sec and Arduino two have to activate a second relay after 2700.360 sec (360 milli seconds after )

With the code given below the required accuracy is not achieved.

```
volatile uint32_t ovfCount = 0UL;
volatile uint32_t currentTime = 0UL;
volatile unsigned long time_prev = 0UL;
volatile unsigned long dT = 0UL;

unsigned long delayTime = 2700UL;     //Seconds
unsigned long coilActivateTime = 5UL;  // seconds

volatile unsigned long _waitTime = delayTime * 1000UL + 360UL;
uint32_t _burnTime = coilActivateTime * 1000UL;

volatile bool coilOn_flag = false;

ISR(INT0_vect) {

  EIMSK = 0b00000000;

  TCCR1B = B00011100;
  PORTB ^= (1<<0);
  ovfCount = 0;
  TIFR2 = 0;
  TCNT2 = 0;

}

ISR(TIMER2_OVF_vect) {
  ovfCount++;
}

ISR(TIMER1_OVF_vect) {
  //pass
}

ISR(TIMER1_COMPA_vect) {
  //pass
}

ISR(TIMER1_COMPB_vect) {
  uint8_t tcnt2 = TCNT2;
  uint32_t ovf_count = ovfCount;

  if (bit_is_set(TIFR2, TOV2) && tcnt2 < 128) {
    ovf_count++;
  }

  uint32_t totalCount = ovf_count << 8 | tcnt2;  // raw count
  // uint32_t currentTime = totalCount * 0.004;     // milli second
  currentTime = totalCount * 4UL/1000UL;  // milli second

  if (currentTime >= _waitTime) {
    PORTC ^= (1 << 5);   // relay Switch
    TCCR1A = B00000010;
    TIMSK1 = B00000101;
    PORTB |= (1<<1);
    if (coilOn_flag) {
      TCCR1B = 0;
      PORTB ^= (1 << 1) | (1<<0);
    }
    coilOn_flag = true;
    _waitTime = _burnTime;
    ovfCount = 0;
    TCNT2 = 0;
  }
}

void setup() {
  Serial.begin(115200);
  /*setting the pin directions*/
  DDRB |= (1 << 1) | (1 << 0); // gL, rL
  DDRC |= (1 << 5);  // relay
  DDRD &= B11111011; // interrupt- interrupt

  /* INITIAL STATE SETTING FOR THE PINS */
  PORTB &= B11111100; // rL, gL
  PORTC &= B11011111; // relay

  /* 8Bit Timer*/
  TCCR2A = 0;
  TCCR2B = 0;
  TCCR2A = B00000011;
  TCCR2B = B00001100;
  OCR2A = 250;
  TCNT2 = 0;
  TIFR2 = 0;
  TIMSK2 = B00000001;

  /* 16 bit timer */
  TCCR1A = 0;
  TCCR1B = 0;
  TCCR1A = B10000010;
  // TCCR1B = B00011100;
  TCCR1B = 0;
  ICR1 = 62461;
  OCR1A = 6206;
  OCR1B = 624;
  TCNT1 = 0;
  TIFR1 = 0;
  TIMSK1 = B00000111;

  /* External INTERRUPT */
  EICRA = 0b00000010;
  EIFR = 0;
  EIMSK = 0b00000001;

  PORTB ^= (1<<0);
}

void loop() {

}
```

How to correct the code.?

title: Arduino nano timing precision

Answers: 1

body:
The Arduino Nano is nowhere accurate enough for your application, and
this has nothing to do with your code: it is a hardware limitation. 360
extra milliseconds after 2,700 seconds is a difference of only
133 ppm (parts per million). The Arduino Nano is clocked off a
ceramic resonator, and these time sources carry a typical error of the
order of 1,000 ppm. The best thing the code can do is count the
clock cycles with perfect accuracy, which makes the software timing as
good as the underlying hardware, but never better.

Some options you may try:

1. The one that seems most obvious is to have the first Arduino somehow
   send a trigger signal to the second one when it activates the first
   relay. Or have the second Arduino sense the state of that relay.
   Then, all the second Arduino has to do is wait for 360 ms, which
   it can easily do with reasonable accuracy.

2. If there is no way the Arduinos can communicate, then you could try
   to add external time sources to the Arduinos. Some RTC modules can
   output a 32,768 Hz signal that could be accurate enough for your
   needs. Look for a temperature-compensated RTC, as those are more
   accurate.

3. If you cannot add extra hardware, you could try to calibrate the
   clocks of your Arduinos in order to compensate for their relative
   drift. Keep in mind though that the drift rate is
   temperature-dependent, and wanders randomly even at constant
   temperature. First read the article [Arduino clock frequency
   accuracy][jorisvr], by Joris\_VR, to get an idea of the accuracy you
   could expect from such calibration.

[jorisvr]: http://jorisvr.nl/article/arduino-frequency


body:
I'm trying to upload anything to my Arduino Uno Wifi Rev2, I'm on Arch Linux, but I'm failing with the following error be it via IDEv2 or `arduino-cli`:

> avrdude: usbdev_open(): cannot open device: Permission denied
>
> avrdude: jtag3_open_common(): Did not find any device matching VID 0x03eb and PID list: 0x2145

The device permissions:

    crw-rw-rw- 166,0 root uucp  9 Jan 23:22 /dev/ttyACM0

My udev rule:

    KERNEL=="ttyACM[0-9]",MODE="0666",GROUP="uucp",TAG+="uaccess"

`lsusb`:

    Bus 001 Device 005: ID 03eb:2145 Atmel Corp. ATMEGA328P-XMINI (CDC ACM)

First two entries from `udevadm info -a -n /dev/ttyACM0`:

      looking at device '/devices/pci0000:00/0000:00:14.0/usb1/1-3/1-3:1.1/tty/ttyACM0':
        KERNEL=="ttyACM0"
        SUBSYSTEM=="tty"
        DRIVER==""
        ATTR{power/control}=="auto"
        ATTR{power/runtime_active_time}=="0"
        ATTR{power/runtime_status}=="unsupported"
        ATTR{power/runtime_suspended_time}=="0"

      looking at parent device '/devices/pci0000:00/0000:00:14.0/usb1/1-3/1-3:1.1':
        KERNELS=="1-3:1.1"
        SUBSYSTEMS=="usb"
        DRIVERS=="cdc_acm"
        ATTRS{authorized}=="1"
        ATTRS{bAlternateSetting}==" 0"
        ATTRS{bInterfaceClass}=="02"
        ATTRS{bInterfaceNumber}=="01"
        ATTRS{bInterfaceProtocol}=="01"
        ATTRS{bInterfaceSubClass}=="02"
        ATTRS{bNumEndpoints}=="01"
        ATTRS{bmCapabilities}=="6"
        ATTRS{iad_bFirstInterface}=="01"
        ATTRS{iad_bFunctionClass}=="02"
        ATTRS{iad_bFunctionProtocol}=="01"
        ATTRS{iad_bFunctionSubClass}=="02"
        ATTRS{iad_bInterfaceCount}=="02"
        ATTRS{physical_location/dock}=="no"
        ATTRS{physical_location/horizontal_position}=="left"
        ATTRS{physical_location/lid}=="no"
        ATTRS{physical_location/panel}=="top"
        ATTRS{physical_location/vertical_position}=="upper"
        ATTRS{supports_autosuspend}=="1"

I feel like I've tried everything so far:
 - `sudo chmod a+rw /dev/ttyACM0`
 - `sudo usermod -a -G uucp $USER`
 - adding udev rule with all different configs (although if chown/chmod doesn't work what will it change??)
 - changing ownership to my user...
 - I checked the process for the IDE to make sure it runs on my user and it does
 - After all these steps I always either restarted and/or reloaded everything with `sudo udevadm control --reload-rules && sudo udevadm trigger`
 - Went through plethora of similar topics, no clues

I feel like I must be doing something awfully stupid here, it doesn't make any sense to me why it wouldn't work even after I chown'ed it to my user...

Answers: 1

body:
Looking at the board definition for the UNO WIFI R2, it doesn't use the serial port for upload. It's using an mdbg chip that it speaks to over a non-cdcacm USB protocol. Getting yourself into the group-owner for the serial device is good for communicating to the board through the serial monitor though.

The megaavr board package seems to [come with a file][1] for creating your udev rules that you should find at:
```sh
"${USER}/.arduino15/packages/arduino/hardware/megaavr/1.8.8/scripts/create_dfu_udev_rule"
```

The 1.8.8 subdirectory of megaavr is current as of writing. It will no doubt change. I still have 1.8.7 on my system.

Running it should create the necessary udev rule for allowing avrdude to speak directly to the USB device. Specifically they're adding this:
```txt
SUBSYSTEM=="usb", ATTR{idVendor}=="03eb", ATTR{idProduct}=="2145", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1"
```

They seem to be creating a udev rule for the tty device as well, though that shouldn't strictly be necessary given what you've already done with becoming a member of the serial device's group. Basically you're doing it by becoming a member of the owning group where what they did was just open the device up to RW permissions for everyone.

  [1]: https://github.com/arduino/ArduinoCore-megaavr/blob/1.8.8/scripts/create_dfu_udev_rule


body:
I'm working on a low power device that implements an ESP8266 MCU and uses it's deep sleep feature. The firmware uses the Arduino C++ library.

Part of the functionality requires knowing the time. To do this, I am using `configTime` to get the time (i.e. NTP). But, to reduce power consumption, I only connect to WiFi every 24 hours. The ESP8266 wakes every hour (to decide if it should do something or go back to sleep). To keep time, I record the last known unix timestamp to RTC memory and upon waking add the amount of time that the device was told to deep sleep (i.e. 1 hour).

The flaw in this design: Part of the requirement is that the user needs to be able to wake the device manually with a button press and interrupt the normal sleep pattern, but if the device is woken with the reset button, it adds an hour to the time and the time becomes completely inaccurate (because an hour was added, even though it could be seconds since deep sleep started).

Is there a way, using the ESP8266 API, to tell how long the device was *actually* in deep sleep? That way, on wake, instead of blindly adding 1 hour to the RTC-saved unix timestamp, I can add the amount of time that the MCU was in deep sleep. The [datasheet][1] seems to only mention the RTC a few times in not much detail.

If no firmware solution exists, what hardware solution could I use?

Thinking out loud: I think a compromise could be to detect if the reset button was pressed (latch/flip flop/register, maybe?). In this case I still wouldn't be able to tell how long the MCU was asleep, but at least I'd be able to tell if I should add time. I found that `system_get_rst_info` is based on how the device went to sleep (i.e. if woken from deep sleep by pressing the reset button, the reason is `REANSON_DEEP_SLEEP_AWAKE`), so I couldn't see how to make use of that in this case. I suppose I could add an external RTC, negating the need to calculate how long the MCU was in deep sleep, and just use that external IC for time keeping.

Edit: Apparently, [`rtctime.dsleep()`][2] provides time keeping across deep sleep, but it's [LUA only][3] so not useful to me. The [source][4] is written in C, but I can't see anything that would help.

> Time is kept across the deep sleep. I.e. rtctime.get() will keep working (provided time was available before the sleep).

  [1]: https://www.espressif.com/sites/default/files/documentation/0a-esp8266ex_datasheet_en.pdf
  [2]: https://nodemcu.readthedocs.io/en/release/modules/rtctime/#rtctimedsleep
  [3]: https://www.esp8266.com/viewtopic.php?p=67168
  [4]: https://github.com/nodemcu/nodemcu-firmware/blob/release/app/modules/rtctime.c

title: Is it possible to know how long an ESP8266 was in deep sleep?

Answers: 2

body: save timestamp in NVRAM, the time before sleep. once wakeup, simply subtract the the data saved in NVRAM from the current time.

body:
I believe the answer is **no** (you cannot tell exactly how long an ESP8266 was asleep), given these constraints:

 1. If an external RTC cannot be used.
 2. If the MCU does not connect to Wi-Fi every time it wakes.
 3. If the MCU can be woken arbitrarily by the user pressing the reset button.

In other words, if the ESP8266 does not connect to Wi-Fi every time it wakes, you can only estimate the time based on how long it *should* have been in deep sleep, but you can't know for sure without either going online or using an external RTC.


body:
I have been trying to develop multi cpp project in platformio and whenever I define ESPAsyncWebServer class object with the extern in defines.h and declare it in main.cpp I am getting scarry looking error 'HTTP_DELETE' conflicts with a previous declaration But when I define ESPAsyncWebServer class object without the extern in main.cpp instead I am not getting any error. Can you help in this regard?

main.cpp:
```
#include "defines.h"
#include <AsyncMQTT_ESP32.h>
#include <WebServer_ESP32_W5500.h>

AsyncMqttClient mqttClient;
TimerHandle_t mqttReconnectTimer;
TimerHandle_t wifiReconnectTimer;

/* ESPAsyncWebServer */
WiFiClient clientWiFi;
AsyncWebServer serverAsyncWeb(80);
AsyncWebSocket WebSocketAsync("/ws");
/* Processors */

String prc(const String &var)
{
  return String();
}

/* Processors End */
void allAsyncWebServer()
{
  serverAsyncWeb.on("/", HTTP_GET, [](AsyncWebServerRequest *request)
                    { request->send(SPIFFS, "/index.htm", String(), false, prc); }); /// log
}

/* allAsyncWebServer End */

/* WebSocketAsync */

void AsyncWebSocketEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len)
{
  switch (type)
  {
  case WS_EVT_CONNECT:
    Serial.printf("WebSocket client #%u connected from %s\n", client->id(), client->remoteIP().toString().c_str());
    break;
  case WS_EVT_DISCONNECT:
    Serial.printf("WebSocket client #%u disconnected\n", client->id());
    break;
  case WS_EVT_DATA:
    // handleWebSocketMessage(arg, data, len);
    break;
  case WS_EVT_PONG:
  case WS_EVT_ERROR:
    break;
  }
}

byte mac[][NUMBER_OF_MAC] =
{
  { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0x01 },
  { 0xDE, 0xAD, 0xBE, 0xEF, 0xBE, 0x02 },
  { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0x03 },
  { 0xDE, 0xAD, 0xBE, 0xEF, 0xBE, 0x04 },
  { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0x05 },
  { 0xDE, 0xAD, 0xBE, 0xEF, 0xBE, 0x06 },
  { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0x07 },
  { 0xDE, 0xAD, 0xBE, 0xEF, 0xBE, 0x08 },
  { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0x09 },
  { 0xDE, 0xAD, 0xBE, 0xEF, 0xBE, 0x0A },
  { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0x0B },
  { 0xDE, 0xAD, 0xBE, 0xEF, 0xBE, 0x0C },
  { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0x0D },
  { 0xDE, 0xAD, 0xBE, 0xEF, 0xBE, 0x0E },
  { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0x0F },
  { 0xDE, 0xAD, 0xBE, 0xEF, 0xBE, 0x10 },
  { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0x11 },
  { 0xDE, 0xAD, 0xBE, 0xEF, 0xBE, 0x12 },
  { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0x13 },
  { 0xDE, 0xAD, 0xBE, 0xEF, 0xBE, 0x14 },
};

// Select the IP address according to your local network
IPAddress myIP(192, 168, 2, 232);
IPAddress myGW(192, 168, 2, 1);
IPAddress mySN(255, 255, 255, 0);

// Google DNS Server IP
IPAddress myDNS(8, 8, 8, 8);

extern "C"
{
#include "freertos/FreeRTOS.h"
#include "freertos/timers.h"
}

const char *PubTopic = "async-mqtt/ESP32_W5500_Pub"; // Topic to publish

// ESP32_W5500 ETH;

void connectToWifi()
{
  Serial.println("Connecting to Wi-Fi...");
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
}

void connectToMqtt()
{
  Serial.println("Connecting to MQTT...");
  mqttClient.connect();
}

void WiFiEvent(WiFiEvent_t event)
{
  switch (event)
  {
#if USING_CORE_ESP32_CORE_V200_PLUS

  case ARDUINO_EVENT_WIFI_READY:
    Serial.println("WiFi ready");
    break;

  case ARDUINO_EVENT_WIFI_STA_START:
    Serial.println("WiFi STA starting");
    break;

  case ARDUINO_EVENT_WIFI_STA_CONNECTED:
    Serial.println("WiFi STA connected");
    break;

  case ARDUINO_EVENT_WIFI_STA_GOT_IP6:
  case ARDUINO_EVENT_WIFI_STA_GOT_IP:
    Serial.println("WiFi connected");
    Serial.print("IP address: ");
    Serial.println(WiFi.localIP());
    connectToMqtt();
    break;

  case ARDUINO_EVENT_WIFI_STA_LOST_IP:
    Serial.println("WiFi lost IP");
    break;

  case ARDUINO_EVENT_WIFI_STA_DISCONNECTED:
    Serial.println("WiFi lost connection");
    xTimerStop(mqttReconnectTimer, 0); // ensure we don't reconnect to MQTT while reconnecting to Wi-Fi
    xTimerStart(wifiReconnectTimer, 0);
    break;
#else

  case SYSTEM_EVENT_STA_GOT_IP:
    Serial.println("WiFi connected");
    Serial.println("IP address: ");
    Serial.println(WiFi.localIP());
    connectToMqtt();
    break;

  case SYSTEM_EVENT_STA_DISCONNECTED:
    Serial.println("WiFi lost connection");
    xTimerStop(mqttReconnectTimer, 0); // ensure we don't reconnect to MQTT while reconnecting to Wi-Fi
    xTimerStart(wifiReconnectTimer, 0);
    break;
#endif

  default:
    break;
  }
}

void ETH_event(WiFiEvent_t event)
{
  switch (event)
  {
#if USING_CORE_ESP32_CORE_V200_PLUS

  case ARDUINO_EVENT_ETH_START:
    Serial.println("ETH starting");
    break;

  case ARDUINO_EVENT_ETH_CONNECTED:
    Serial.println("ETH connected");
    break;

  case ARDUINO_EVENT_ETH_GOT_IP:
    Serial.println("ETH got IP");
    Serial.print("IP address: ");
    Serial.println(ETH.localIP());
    connectToMqtt();
    break;

  case ARDUINO_EVENT_ETH_DISCONNECTED:
    Serial.println("ETH lost connection");

    // ensure we don't reconnect to MQTT when no ETH
    xTimerStop(mqttReconnectTimer, 0);

    break;

  case ARDUINO_EVENT_ETH_STOP:
    Serial.println("ETH stops");

    // ensure we don't reconnect to MQTT when no ETH
    xTimerStop(mqttReconnectTimer, 0);

    break;
#else

  case SYSTEM_EVENT_ETH_CONNECTED:
    erial.println(F("ETH Connected"));
    break;

  case SYSTEM_EVENT_ETH_GOT_IP:
    Serial.println("ETH connected");
    Serial.println("IP address: ");
    Serial.println(ETH.localIP());
    connectToMqtt();
    break;

  case SYSTEM_EVENT_ETH_DISCONNECTED:
  case SYSTEM_EVENT_ETH_STOP:
    Serial.println("ETH lost connection");

    // ensure we don't reconnect to MQTT when no ETH
    xTimerStop(mqttReconnectTimer, 0);

    break;
#endif

  default:
    break;
  }
}

void printSeparationLine()
{
  Serial.println("************************************************");
}

void onMqttConnect(bool sessionPresent)
{
  Serial.print("Connected to MQTT broker: ");
  Serial.print(MQTT_HOST);
  Serial.print(", port: ");
  Serial.println(MQTT_PORT);
  Serial.print("PubTopic: ");
  Serial.println(PubTopic);

  printSeparationLine();
  Serial.print("Session present: ");
  Serial.println(sessionPresent);

  uint16_t packetIdSub = mqttClient.subscribe(PubTopic, 2);
  Serial.print("Subscribing at QoS 2, packetId: ");
  Serial.println(packetIdSub);

  mqttClient.publish(PubTopic, 0, true, "ESP32_W5500 Test");
  Serial.println("Publishing at QoS 0");

  uint16_t packetIdPub1 = mqttClient.publish(PubTopic, 1, true, "test 2");
  Serial.print("Publishing at QoS 1, packetId: ");
  Serial.println(packetIdPub1);

  uint16_t packetIdPub2 = mqttClient.publish(PubTopic, 2, true, "test 3");
  Serial.print("Publishing at QoS 2, packetId: ");
  Serial.println(packetIdPub2);

  printSeparationLine();
}

void onMqttDisconnect(AsyncMqttClientDisconnectReason reason)
{
  (void)reason;

  Serial.println("Disconnected from MQTT.");

  if (ESP32_W5500_isConnected())
  {
    xTimerStart(mqttReconnectTimer, 0);
  }
}

void onMqttSubscribe(const uint16_t &packetId, const uint8_t &qos)
{
  Serial.println("Subscribe acknowledged.");
  Serial.print("  packetId: ");
  Serial.println(packetId);
  Serial.print("  qos: ");
  Serial.println(qos);
}

void onMqttUnsubscribe(const uint16_t &packetId)
{
  Serial.println("Unsubscribe acknowledged.");
  Serial.print("  packetId: ");
  Serial.println(packetId);
}

void onMqttMessage(char *topic, char *payload, const AsyncMqttClientMessageProperties &properties,
                   const size_t &len, const size_t &index, const size_t &total)
{
  (void)payload;

  Serial.println("Publish received.");
  Serial.print("  topic: ");
  Serial.println(topic);
  Serial.print("  qos: ");
  Serial.println(properties.qos);
  Serial.print("  dup: ");
  Serial.println(properties.dup);
  Serial.print("  retain: ");
  Serial.println(properties.retain);
  Serial.print("  len: ");
  Serial.println(len);
  Serial.print("  index: ");
  Serial.println(index);
  Serial.print("  total: ");
  Serial.println(total);
}

void onMqttPublish(const uint16_t &packetId)
{
  Serial.println("Publish acknowledged.");
  Serial.print("  packetId: ");
  Serial.println(packetId);
}

void setup()
{
  #define FORMAT_SPIFFS_IF_FAILED false
  Serial.begin(115200);
  if (!SPIFFS.begin(FORMAT_SPIFFS_IF_FAILED))
  {
    Serial.println(F("W0")); // W0: SPIFFS Mount Failed
    return;
  }

  while (!Serial && millis() < 5000)
    ;

  Serial.print("\nStarting FullyFeature_ESP32_W5500 on ");
  Serial.print(BOARD_NAME);
  Serial.println(" with " + String(SHIELD_TYPE));
  Serial.println(WEBSERVER_ESP32_W5500_VERSION);
  // Serial.println(ASYNC_MQTT_GENERIC_VERSION);

  AMQTT_LOGWARN(F("Default SPI pinout:"));
  AMQTT_LOGWARN1(F("SPI_HOST:"), ETH_SPI_HOST);
  AMQTT_LOGWARN1(F("MOSI:"), MOSI_GPIO);
  AMQTT_LOGWARN1(F("MISO:"), MISO_GPIO);
  AMQTT_LOGWARN1(F("SCK:"), SCK_GPIO);
  AMQTT_LOGWARN1(F("CS:"), CS_GPIO);
  AMQTT_LOGWARN1(F("INT:"), INT_GPIO);
  AMQTT_LOGWARN1(F("SPI Clock (MHz):"), SPI_CLOCK_MHZ);
  AMQTT_LOGWARN(F("========================="));
  wifiReconnectTimer = xTimerCreate("wifiTimer", pdMS_TO_TICKS(2000), pdFALSE, (void *)0,
                                    reinterpret_cast<TimerCallbackFunction_t>(connectToWifi));
  mqttReconnectTimer = xTimerCreate("mqttTimer", pdMS_TO_TICKS(2000), pdFALSE, (void *)0,
                                    reinterpret_cast<TimerCallbackFunction_t>(connectToMqtt));

  WiFi.onEvent(WiFiEvent);

  mqttClient.onConnect(onMqttConnect);
  mqttClient.onDisconnect(onMqttDisconnect);
  mqttClient.onSubscribe(onMqttSubscribe);
  mqttClient.onUnsubscribe(onMqttUnsubscribe);
  mqttClient.onMessage(onMqttMessage);
  mqttClient.onPublish(onMqttPublish);

  // mqttClient.setServer(MQTT_HOST, MQTT_PORT);

  ///////////////////////////////////

  // To be called before ETH.begin()
  WiFi.onEvent(ETH_event);

  // start the ethernet connection and the server:
  // Use DHCP dynamic IP and random mac
  uint16_t index = millis() % NUMBER_OF_MAC;

  // bool begin(int MISO_GPIO, int MOSI_GPIO, int SCLK_GPIO, int CS_GPIO, int INT_GPIO, int SPI_CLOCK_MHZ,
  //            int SPI_HOST, uint8_t *W5500_Mac = W5500_Default_Mac);
  // ETH.begin( MISO_GPIO, MOSI_GPIO, SCK_GPIO, CS_GPIO, INT_GPIO, SPI_CLOCK_MHZ, ETH_SPI_HOST );
  //  ETH.begin( MISO_GPIO, MOSI_GPIO, SCK_GPIO, CS_GPIO, INT_GPIO, SPI_CLOCK_MHZ, ETH_SPI_HOST, mac[index] );
  //  byte esp32Mac[] = WiFi.macAddress();
  Serial.print("WiFi.macAddress(): ");
  Serial.println(WiFi.macAddress());
  uint8_t baseMac[6];
  esp_read_mac(baseMac, ESP_MAC_WIFI_STA);
  // ETH.begin(MISO_GPIO, MOSI_GPIO, SCK_GPIO, CS_GPIO, INT_GPIO, SPI_CLOCK_MHZ, ETH_SPI_HOST, baseMac);
  test();
  Serial.print("index: ");
  Serial.println(index);
  Serial.print("ETH.macAddress(): ");
  Serial.println(ETH.macAddress());
  // Static IP, leave without this line to get IP via DHCP
  // bool config(IPAddress local_ip, IPAddress gateway, IPAddress subnet, IPAddress dns1 = 0, IPAddress dns2 = 0);
  // ETH.config(myIP, myGW, mySN, myDNS);

  ESP32_W5500_waitForConnect();
  connectToWifi();

  allAsyncWebServer();    // Enable ESP Asynchronous Servers
  serverAsyncWeb.begin(); // Start ESP Asynchronous Server
  /* Initiallize AsyncWebSocket */
  WebSocketAsync.onEvent(AsyncWebSocketEvent);
  serverAsyncWeb.addHandler(&WebSocketAsync);
  ///////////////////////////////////
}

void loop()
{
}
```
define.h:
```
/****************************************************************************************************************************
  defines.h
  AsyncMqttClient_Generic is a library for ESP32, ESP8266, Protenta_H7, STM32F7, etc. with current AsyncTCP support

  Based on and modified from :

  1) async-mqtt-client (https://github.com/marvinroger/async-mqtt-client)

  Built by Khoi Hoang https://github.com/khoih-prog/AsyncMqttClient_Generic
 ***************************************************************************************************************************************/

#ifndef defines_h
#define defines_h
#include <Arduino.h>
#include <WiFi.h>
#include <ESPAsyncWebServer.h>
#include <AsyncTCP.h>
#include <Update.h>
#include <ESPmDNS.h>
#include <SPIFFS.h>

#include "Test.h"
#include <AsyncMQTT_ESP32.hpp>
#include <WebServer_ESP32_W5500.hpp>
#include "w5500/esp32_w5500.h"
// Debug Level from 0 to 4
#define _ETHERNET_WEBSERVER_LOGLEVEL_       1
#define _ASYNC_MQTT_LOGLEVEL_               1

//////////////////////////////////////////////////////////

// Optional values to override default settings
// Don't change unless you know what you're doing
//#define ETH_SPI_HOST        SPI3_HOST
//#define SPI_CLOCK_MHZ       25

// Must connect INT to GPIOxx or not working
// #define INT_GPIO            21  //4

// #define MISO_GPIO           19
// #define MOSI_GPIO           23
// #define SCK_GPIO            18
// #define CS_GPIO             22  //5

//////////////////////////////////////////////////////////

// #include <WebServer_ESP32_W5500.h>

/////////////////////////////////////////////

// Enter a MAC address and IP address for your controller below.
extern AsyncMqttClient mqttClient;
extern TimerHandle_t mqttReconnectTimer;
extern TimerHandle_t wifiReconnectTimer;
// extern ESP32_W5500 ETH;

// // extern WiFiClient clientWiFi;
// extern AsyncWebServer serverAsyncWeb;
// extern AsyncWebSocket WebSocketAsync;

#define NUMBER_OF_MAC      20

#define WIFI_SSID         "Digisol"
#define WIFI_PASSWORD     "12345678"

#define MQTT_HOST IPAddress(192, 168, 1, 2)
// #define MQTT_HOST         "broker.emqx.io"        // Broker address
#define MQTT_PORT 1883

#endif    //defines_h
```
Test.h:
```
#ifndef Test_H
#define Test_H
void test();
#endif
```
Test.cpp:
```
#include "defines.h"
void test()
{
    uint8_t baseMac[6];
    esp_read_mac(baseMac, ESP_MAC_WIFI_STA);
    mqttClient.setServer(MQTT_HOST, MQTT_PORT);
    ETH.begin(MISO_GPIO, MOSI_GPIO, SCK_GPIO, CS_GPIO, INT_GPIO, SPI_CLOCK_MHZ, ETH_SPI_HOST, baseMac);
}
```
Error:
```
In file included from C:/Users/shubh/.platformio/packages/framework-arduinoespressif32/libraries/WebServer/src/HTTP_Method.h:4,
                 from C:/Users/shubh/.platformio/packages/framework-arduinoespressif32/libraries/WebServer/src/WebServer.h:30,
                 from .pio/libdeps/esp32dev/WebServer_ESP32_W5500/src/WebServer_ESP32_W5500.hpp:33,
                 from include/defines.h:24,
                 from src/Test.cpp:1:
C:/Users/shubh/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/nghttp/port/include/http_parser.h:95:6: error: 'HTTP_DELETE' conflicts with a previous declaration
   XX(0,  DELETE,      DELETE)       \
      ^
C:/Users/shubh/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/nghttp/port/include/http_parser.h:138:45: note: in definition of macro 'XX'
 #define XX(num, name, string) HTTP_##name = num,
                                             ^~~
C:/Users/shubh/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/nghttp/port/include/http_parser.h:139:3: note: in expansion of macro 'HTTP_METHOD_MAP'
   HTTP_METHOD_MAP(XX)
   ^~~~~~~~~~~~~~~
In file included from include/defines.h:16,
                 from src/Test.cpp:1:
.pio/libdeps/esp32dev/ESP Async WebServer/src/ESPAsyncWebServer.h:64:3: note: previous declaration 'WebRequestMethod HTTP_DELETE'
   HTTP_DELETE  = 0b00000100,
   ^~~~~~~~~~~
In file included from C:/Users/shubh/.platformio/packages/framework-arduinoespressif32/libraries/WebServer/src/HTTP_Method.h:4,
                 from C:/Users/shubh/.platformio/packages/framework-arduinoespressif32/libraries/WebServer/src/WebServer.h:30,
                 from .pio/libdeps/esp32dev/WebServer_ESP32_W5500/src/WebServer_ESP32_W5500.hpp:33,
                 from include/defines.h:24,
                 from src/Test.cpp:1:
C:/Users/shubh/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/nghttp/port/include/http_parser.h:96:6: error: 'HTTP_GET' conflicts with a previous declaration
   XX(1,  GET,         GET)          \
      ^
C:/Users/shubh/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/nghttp/port/include/http_parser.h:138:45: note: in definition of macro 'XX'
 #define XX(num, name, string) HTTP_##name = num,
                                             ^~~
C:/Users/shubh/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/nghttp/port/include/http_parser.h:139:3: note: in expansion of macro 'HTTP_METHOD_MAP'
   HTTP_METHOD_MAP(XX)
   ^~~~~~~~~~~~~~~
In file included from include/defines.h:16,
                 from src/Test.cpp:1:
.pio/libdeps/esp32dev/ESP Async WebServer/src/ESPAsyncWebServer.h:62:3: note: previous declaration 'WebRequestMethod HTTP_GET'
   HTTP_GET     = 0b00000001,
   ^~~~~~~~
In file included from C:/Users/shubh/.platformio/packages/framework-arduinoespressif32/libraries/WebServer/src/HTTP_Method.h:4,
                 from C:/Users/shubh/.platformio/packages/framework-arduinoespressif32/libraries/WebServer/src/WebServer.h:30,
                 from .pio/libdeps/esp32dev/WebServer_ESP32_W5500/src/WebServer_ESP32_W5500.hpp:33,
                 from include/defines.h:24,
                 from src/Test.cpp:1:
C:/Users/shubh/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/nghttp/port/include/http_parser.h:97:6: error: 'HTTP_HEAD' conflicts with a previous declaration
   XX(2,  HEAD,        HEAD)         \
      ^
C:/Users/shubh/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/nghttp/port/include/http_parser.h:138:45: note: in definition of macro 'XX'
 #define XX(num, name, string) HTTP_##name = num,
                                             ^~~
C:/Users/shubh/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/nghttp/port/include/http_parser.h:139:3: note: in expansion of macro 'HTTP_METHOD_MAP'
   HTTP_METHOD_MAP(XX)
   ^~~~~~~~~~~~~~~
In file included from include/defines.h:16,
                 from src/Test.cpp:1:
.pio/libdeps/esp32dev/ESP Async WebServer/src/ESPAsyncWebServer.h:67:3: note: previous declaration 'WebRequestMethod HTTP_HEAD'
   HTTP_HEAD    = 0b00100000,
   ^~~~~~~~~
In file included from C:/Users/shubh/.platformio/packages/framework-arduinoespressif32/libraries/WebServer/src/HTTP_Method.h:4,
                 from C:/Users/shubh/.platformio/packages/framework-arduinoespressif32/libraries/WebServer/src/WebServer.h:30,
                 from .pio/libdeps/esp32dev/WebServer_ESP32_W5500/src/WebServer_ESP32_W5500.hpp:33,
                 from include/defines.h:24,
                 from src/Test.cpp:1:
C:/Users/shubh/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/nghttp/port/include/http_parser.h:98:6: error: 'HTTP_POST' conflicts with a previous declaration
   XX(3,  POST,        POST)         \
      ^
C:/Users/shubh/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/nghttp/port/include/http_parser.h:138:45: note: in definition of macro 'XX'
 #define XX(num, name, string) HTTP_##name = num,
                                             ^~~
C:/Users/shubh/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/nghttp/port/include/http_parser.h:139:3: note: in expansion of macro 'HTTP_METHOD_MAP'
   HTTP_METHOD_MAP(XX)
   ^~~~~~~~~~~~~~~
In file included from include/defines.h:16,
                 from src/Test.cpp:1:
.pio/libdeps/esp32dev/ESP Async WebServer/src/ESPAsyncWebServer.h:63:3: note: previous declaration 'WebRequestMethod HTTP_POST'
   HTTP_POST    = 0b00000010,
   ^~~~~~~~~
In file included from C:/Users/shubh/.platformio/packages/framework-arduinoespressif32/libraries/WebServer/src/HTTP_Method.h:4,
                 from C:/Users/shubh/.platformio/packages/framework-arduinoespressif32/libraries/WebServer/src/WebServer.h:30,
                 from .pio/libdeps/esp32dev/WebServer_ESP32_W5500/src/WebServer_ESP32_W5500.hpp:33,
                 from include/defines.h:24,
                 from src/Test.cpp:1:
C:/Users/shubh/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/nghttp/port/include/http_parser.h:99:6: error: 'HTTP_PUT' conflicts with a previous declaration
   XX(4,  PUT,         PUT)          \
      ^
C:/Users/shubh/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/nghttp/port/include/http_parser.h:138:45: note: in definition of macro 'XX'
 #define XX(num, name, string) HTTP_##name = num,
                                             ^~~
C:/Users/shubh/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/nghttp/port/include/http_parser.h:139:3: note: in expansion of macro 'HTTP_METHOD_MAP'
   HTTP_METHOD_MAP(XX)
   ^~~~~~~~~~~~~~~
In file included from include/defines.h:16,
                 from src/Test.cpp:1:
.pio/libdeps/esp32dev/ESP Async WebServer/src/ESPAsyncWebServer.h:65:3: note: previous declaration 'WebRequestMethod HTTP_PUT'
   HTTP_PUT     = 0b00001000,
   ^~~~~~~~
In file included from C:/Users/shubh/.platformio/packages/framework-arduinoespressif32/libraries/WebServer/src/HTTP_Method.h:4,
                 from C:/Users/shubh/.platformio/packages/framework-arduinoespressif32/libraries/WebServer/src/WebServer.h:30,
                 from .pio/libdeps/esp32dev/WebServer_ESP32_W5500/src/WebServer_ESP32_W5500.hpp:33,
                 from include/defines.h:24,
                 from src/Test.cpp:1:
C:/Users/shubh/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/nghttp/port/include/http_parser.h:139:3: note: in expansion of macro 'HTTP_METHOD_MAP'
   HTTP_METHOD_MAP(XX)
   ^~~~~~~~~~~~~~~
In file included from include/defines.h:16,
                 from src/main.cpp:1:
.pio/libdeps/esp32dev/ESP Async WebServer/src/ESPAsyncWebServer.h:68:3: note: previous declaration 'WebRequestMethod HTTP_OPTIONS'
   HTTP_OPTIONS = 0b01000000,
   ^~~~~~~~~~~~
In file included from C:/Users/shubh/.platformio/packages/framework-arduinoespressif32/libraries/WebServer/src/HTTP_Method.h:4,
                 from C:/Users/shubh/.platformio/packages/framework-arduinoespressif32/libraries/WebServer/src/WebServer.h:30,
                 from .pio/libdeps/esp32dev/WebServer_ESP32_W5500/src/WebServer_ESP32_W5500.hpp:33,
                 from include/defines.h:24,
                 from src/main.cpp:1:
C:/Users/shubh/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/nghttp/port/include/http_parser.h:128:6: error: 'HTTP_PATCH' conflicts with a previous declaration
   XX(28, PATCH,       PATCH)        \
      ^~
C:/Users/shubh/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/nghttp/port/include/http_parser.h:138:45: note: in definition of macro 'XX'
 #define XX(num, name, string) HTTP_##name = num,
                                             ^~~
C:/Users/shubh/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/nghttp/port/include/http_parser.h:139:3: note: in expansion of macro 'HTTP_METHOD_MAP'
   HTTP_METHOD_MAP(XX)
   ^~~~~~~~~~~~~~~
In file included from include/defines.h:16,
                 from src/main.cpp:1:
.pio/libdeps/esp32dev/ESP Async WebServer/src/ESPAsyncWebServer.h:66:3: note: previous declaration 'WebRequestMethod HTTP_PATCH'
   HTTP_PATCH   = 0b00010000,
   ^~~~~~~~~~
Compiling .pio\build\esp32dev\liba04\AsyncMQTT_ESP32\AsyncMqttClient\Packets\ConnAckPacket.cpp.o
Compiling .pio\build\esp32dev\liba04\AsyncMQTT_ESP32\AsyncMqttClient\Packets\Out\Connect.cpp.o
*** [.pio\build\esp32dev\src\Test.cpp.o] Error 1
*** [.pio\build\esp32dev\src\main.cpp.o] Error 1
=========================== [FAILED] Took 10.22 seconds ===========================
```

title: object of "ESPAsyncWebServer" causing conflict

Answers: 0


body:
I have written this code:

    char message[4];
    memcpy(message, &delta, 4);

    Wire.write(message, 4);

When I try to compile I get this warning:

    warning: invalid conversion from ‘char*’ to ‘const uint8_t* {aka const unsigned char*}’ [-fpermissive]
       Wire.write(message, 4);
                            ^

Also followed by this note:

    In file included from main.ino:5:0:
    /usr/share/arduino/libraries/Wire/Wire.h:61:20: note:   initializing argument 1 of ‘virtual size_t TwoWire::write(const uint8_t*, size_t)’
         virtual size_t write(const uint8_t *, size_t);
                        ^

I do not understand what is wrong?

title: Wire.write invalid conversion from ‘char*’ to ‘const uint8_t*

Answers: 1

body:
Try

    Wire.write((const uint8_t*) message, 4);

I.e., cast it to the correct type, uint8_t and char are the same (at least on Arduino and for this example, as you do not char about unsigned/signed values).

(see also the comment of the busybee below, for using the cleaner C++ cast).


body:
When I need to send multiple bytes via Wire, for example a long int, I cast it to a byte array and specify a length

    long int i;
    Wire.write((byte*)&i, 4);

But if I want to send bytes from more than 1 variable I need to create a buffer

    byte i;
    byte j;
    byte message[2] = {i, j};
    Wire.write(message, 2);

If I want to send them without copying the data I can put them in a struct

    struct message {
      byte i;
      byte j;
    };
    Wire.write((byte*)&message, 2);

But this would require me to refactor existing code.

Is there any c voodoo that I can perform to send bytes of different places of my code over Wire without copying them in a buffer and without refactoring the code?

title: How to send multiple bytes with Wire without copying

Answers: 4

body:
```
// Written by Nick Gammon
// May 2012

template <typename T> unsigned int I2C_writeAnything (const T& value)
  {
  Wire.write((byte *) &value, sizeof (value));
  return sizeof (value);
  }  // end of I2C_writeAnything

template <typename T> unsigned int I2C_readAnything(T& value)
  {
    byte * p = (byte*) &value;
    unsigned int i;
    for (i = 0; i < sizeof value; i++)
          *p++ = Wire.read();
    return i;
  }  // end of I2C_readAnything
```

Then in the body of your code you can:

```
I2C_writeAnything(message);
```

Similarly your other end can `I2C_readAnything`.

There is a small amount of refactoring required, changing the function call.

body:
No, you cannot.

C does not guarantee any allocation properties of variables. Even if you write one variable definition right after another, both variables can have addresses assigned that have other memory in between.

So, if you want a "packet" sent via `Wire` that contains values of multiple variables, you need to fill a buffer with these values.

Even though C maintains the order of members of a structure, please be aware that depending on the target's architecture there can be gaps between the members for alignment. However, some compilers have language extensions to tackle this issue.

body:
No, this function overwrite of `Wire.write()` is meant for buffers, meaning connected spaces in memory, which can be covered by simply incrementing the buffer. That is not the case for distinct variables.

But that begs the question, why you want to do that in one call to `Wire.write()` in the first place. This function does **not** do any communication on the I2C lines, it just **writes to the libraries internal buffer**. The data gets actually send in `Wire.endTransmission()` or in the onRequest interrupts in the background (depending on where you have those write statements). Thus you already have a buffer and don't need another one. Just call `Wire.write()` multiple times, once for each variable. That will build up the data sequentially inside the internal buffer.

body:
As @chrisl said, there is an internal buffer so the best I can do is just use multiple `Wire.write` calls, but in my case that wasn't working. I got only the last written value or rubbish data.

I dug through the source of the Wire library and found that [the version in github](https://github.com/arduino/ArduinoCore-avr/blob/8b327d7bede1c1245db99daeba4e168c92c11194/libraries/Wire/src/utility/twi.c#L342) (as of this writing) makes it possible to use multiple writes by appending to the buffer:

    // set length and copy data into tx buffer
    for(i = 0; i < length; ++i){
      twi_txBuffer[twi_txBufferLength+i] = data[i];
    }
    twi_txBufferLength += length;

But the one I have installed locally looks like this:

    // set length and copy data into tx buffer
    twi_txBufferLength = length;
    for(i = 0; i < length; ++i){
      twi_txBuffer[i] = data[i];
    }

So that explains a lot.

In case someone else also has this problem, you just need to update.

I was even too lazy to update, so I just replaced the function. Probably not the best decision, but it works!

Thanks!


body:
I have 3 devices:
- An [UNO](https://auseparts.com.au/SainSmart-UNO-ATMEGA328P-PU-ATMEGA8U2-Microcontroller) (non-genuine)

[![UNO][1]][1]

- An [SMS hat/shield device `SIM7600G-H`](https://core-electronics.com.au/sim7600g-h-m2-4g-hat-for-raspberry-pi-lte-cat4-high-speed-4g3g2g-gnss-global-band-1.html) to communicate with via UART

[![SMS Device][2]][2]

- A [USB UART controller](https://core-electronics.com.au/usb-to-ttl-uart-rs232-serial-converter-module-pl2303hx-au-local-shipping.html) for debugging purposes

[![UART USB][3]][3]

---

I'm using the UNO to talk to the SMS device via UART at `9600` baud to send and receive SMS commands. I need the hardware port open to debug, and I am trying to use a software port to talk to the SMS device via it's TX RX pins.

But I cannot get the software port to talk to the SMS device at all.

This is the success I've had trying to talk to and from devices. The bold boxes are needed to be solved for this setup to work. ✅ = working coms, ❌ = nothing on coms at all. Read left to right, **HAT serial (SMS DEVICE)** can communicate with UNO hardware serial.

[![Connection matrix][4]][4]

And I'm using this code to just relay inputs and outputs between the hardware and software ports for testing.

```cpp
// Must be same on mock and serial
const int baud = 9600;

// Communication with mock hat
SoftwareSerial mockPort(2, 3);

void setup()
{
  Serial.begin(baud);

  while (!Serial)
  {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  mockPort.begin(baud);
  Serial.println("Mock port has started @ " + String(baud));
}

void loop()
{

  while (mockPort.available() > 0)
  {
    char inByte = mockPort.read();
    // and send to the hardware serial port:
    Serial.write(inByte);
  }

  // while there is data coming in FROM SERIAL, read it and send it back to mock
  while (Serial.available() > 0)
  {
    char inByte = Serial.read();
    // and send to the mock serial port:
    mockPort.write(inByte);
  }
}
```

Why can't I communicate to the SMS device with the software ports? (or the USB UART as well?) When testing, I can see the UNO's RX light turn on, but I never receive any data back from the SMS device (the serial monitor is just black).

---

Notes:

- I've tried the AltSoftSerial library as well
- I've set the SMS hat's baud rate default to `9600`
- I've tried different communication pins
- I've got the TX pins on RX pins and vice versa

  [1]: https://i.stack.imgur.com/4QNLxs.png
  [2]: https://i.stack.imgur.com/A9I7Fs.png
  [3]: https://i.stack.imgur.com/WIQjYs.png
  [4]: https://i.stack.imgur.com/ojMCll.png

title: Cannot communicate with software serial on particular devices (SIM7600G-H)

Answers: 1

body: The `TX` and `RX` labels mirror the Raspberry Pi. So I swapped the `RX` and `TX` wires to connect as `RX`->`RX` and `TX`->`TX` and now it works


body:
Hello dear Arduino SE community.

I have 5 sensors. I read 4 of them with an NI USB-6009 DAQ board and I read the fifth one with an Arduino UNO R3. Though, with the fifth sensor not only I read a signal from it, but I also send a signal to it.

Both the Arduino and the NI board are connected to a computer via two different USB ports and send the signals to the computer simultaneously. Also - simultaneously - the Arduino sends a signal to the fifth sensor.

I noticed a strange behavior with the signal from one of the sensors read by the NI board. It starts with giving me a signal that is clearly wrong and over the course of, approximately, 5 minutes gradually changes to a correct reading.

That hadn't happened when I didn't have Arduino connected to the computer at the same time.

Thus, I'm wondering if it is possible that an Arduino and an NI board can interfere with each other's signals when connected to the computer simultaneously. If it is possible, is it something widespread and is there a working solution?

Thank you in advance.
Ivan

P.S. I deliberately don't provide the specs of my system because the point of my question is not to resolve the issue but to learn if what I described is possible theoretically and if such cases have been encountered.

title: Can an Arduino and an NI USB-6009 DAQ board interfere with each other's signals when they are simultaneously reading signals from different sensors?

Answers: 1

body:
I have found a solution to my problem.

The sensor that was giving me the wrong signal was plugged to the same electrical circuit with "heavy" equipment (two DC laboratory power supplies). It is well known that one shouldn't do it because "heavy" equipment sends noise back to the circuit which, ultimately, causes noise in the signal generated by the sensor.

Thus, my issue had nothing to do with the Arduino interfering with the USB-6009 through the computer.

To make sure, I disconnected the Arduino from the computer and still got the same wrong signal from the problematic sensor. Then, I plugged the problematic sensor to another electrical circuit, connected the Arduino back to the computer and got the right signal.

Thus, I conclude that one can safely use an Arduino and a USB-6009 with the same computer.


body:
I'm making little project on my arduino nano using OLED display. I want to make 'boot screen'. If I will turn on device then Image1 should appear, wait few sec then Image2 should apear and then the main screen wich is showing the readings from sensor. Main screen is showing after 14sec; thats kinda good news but why this part is not working?
```
void boot (void) {
  if (actualScreen == 0) {
    u8g.drawBitmapP( 0, 0, 128/8, 64, bootoli_dash_bootscreen);
    delay(7000);
    actualScreen=1;
  };
  if (actualScreen == 1) {
    u8g.drawBitmapP( 0, 0, 128/8, 64, bootgoFast);
    delay(7000);
    actualScreen=2;
  };
```
Full code:
```#include "U8glib.h"
#include <OneWire.h>
#include <DallasTemperature.h>
#define SCREEN_WIDTH 128 // OLED display width,  in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
#define ONE_WIRE_BUS 6

// Setup a oneWire instance to communicate with any OneWire device
OneWire oneWire(ONE_WIRE_BUS);
// Pass oneWire reference to DallasTemperature library
DallasTemperature sensors(&oneWire);
U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_DEV_0 | U8G_I2C_OPT_NO_ACK | U8G_I2C_OPT_FAST); // Fast I2C / TWI

// 'oil_bar', 128x39px
const unsigned char oil_bar [] PROGMEM = {
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc,
 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,
 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,
 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x20, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
 0x00, 0x20, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
 0x00, 0x20, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
 0x00, 0x20, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00,
 0x1f, 0x9f, 0xc0, 0x00, 0x3f, 0xbf, 0x80, 0x01, 0x9f, 0x9f, 0xc0, 0x03, 0x7f, 0x7f, 0x00, 0x00,
 0x18, 0x18, 0xc0, 0x00, 0x31, 0xb1, 0x80, 0x03, 0x31, 0x98, 0xc0, 0x06, 0x67, 0x63, 0x00, 0x00,
 0x18, 0x18, 0xc0, 0x00, 0x21, 0x31, 0x80, 0x03, 0x31, 0x90, 0xc0, 0x06, 0xc6, 0x63, 0x00, 0x00,
 0x10, 0x31, 0x80, 0x00, 0x63, 0x21, 0x80, 0x07, 0x31, 0xb1, 0x80, 0x0e, 0x06, 0xc2, 0x00, 0x00,
 0x30, 0x31, 0x80, 0x00, 0x63, 0x63, 0x00, 0x02, 0x63, 0x31, 0x80, 0x04, 0x0c, 0xc6, 0x00, 0x00,
 0x3f, 0xb1, 0x80, 0x00, 0x7f, 0x63, 0x00, 0x06, 0x63, 0x31, 0x80, 0x0c, 0x18, 0xc6, 0x00, 0x00,
 0x33, 0xa1, 0x80, 0x00, 0x3e, 0x63, 0x00, 0x06, 0x63, 0x61, 0x00, 0x0c, 0x30, 0xc6, 0x00, 0x00,
 0x23, 0x63, 0x00, 0x00, 0x06, 0xc3, 0x00, 0x06, 0x43, 0x63, 0x00, 0x0c, 0x61, 0x84, 0x00, 0x00,
 0x63, 0x63, 0x00, 0x00, 0x06, 0xc6, 0x00, 0x04, 0xc6, 0x63, 0x00, 0x08, 0xc1, 0x8c, 0x00, 0x00,
 0x63, 0x63, 0x00, 0x00, 0x06, 0xc6, 0x00, 0x0c, 0xc6, 0x63, 0x00, 0x19, 0xc1, 0x8c, 0x00, 0x00,
 0x7e, 0x7f, 0x00, 0x00, 0xfc, 0xfe, 0x00, 0x0c, 0xfe, 0xfe, 0x00, 0x1b, 0xf1, 0xfc, 0x00, 0x00,
 0x7e, 0x7e, 0x00, 0x01, 0xfc, 0xfc, 0x00, 0x0c, 0xfc, 0x7e, 0x00, 0x1b, 0xf1, 0xf8, 0x00, 0x00
};

// 'oil_peak', 88x18px
const unsigned char oil_peak [] PROGMEM = {
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xe0, 0x01, 0xf8, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00,
 0x00, 0x0f, 0xe0, 0x81, 0xf8, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x02, 0x00, 0x08, 0x6d, 0x80, 0x40,
 0x00, 0x00, 0x00, 0x62, 0x00, 0x02, 0x00, 0x18, 0xcd, 0x80, 0xc0, 0x00, 0x00, 0x00, 0x46, 0x00,
 0x02, 0x00, 0x18, 0xc1, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x06, 0x0c, 0x18, 0xc9, 0x00,
 0xdf, 0xbf, 0xe7, 0xc0, 0xc4, 0xfb, 0xe6, 0xcc, 0x30, 0x9b, 0x00, 0x99, 0x32, 0x26, 0xc0, 0xfc,
 0x99, 0x27, 0x80, 0x31, 0x9b, 0x01, 0x9b, 0x22, 0x64, 0xc1, 0xf9, 0x99, 0x67, 0x00, 0x31, 0x92,
 0x01, 0x9f, 0x66, 0x6c, 0xc1, 0x81, 0xf3, 0xee, 0x00, 0x21, 0x96, 0x01, 0xb0, 0x66, 0x6c, 0x81,
 0x81, 0x06, 0x6f, 0x00, 0x7f, 0x36, 0x03, 0x30, 0x44, 0x4d, 0x81, 0x03, 0x06, 0x4b, 0x0c, 0x3f,
 0x36, 0x03, 0x3c, 0x44, 0xcf, 0x03, 0x03, 0xc7, 0xc9, 0x8c, 0x00, 0x00, 0x02, 0x00, 0x00, 0x18,
 0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x80,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

// 'oli_dash_bootscreen', 128x64px
const unsigned char bootoli_dash_bootscreen [] PROGMEM = {
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80,
 0x01, 0x9e, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00,
 0x01, 0x1c, 0x40, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x1c, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00,
 0x00, 0x1c, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x3c, 0x38, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00,
 0x00, 0x3c, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x3c, 0x38, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00,
 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x78, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00,
 0x00, 0x38, 0xc3, 0xbe, 0xf3, 0xbe, 0xf0, 0x7f, 0x38, 0xf3, 0xfe, 0x3f, 0x87, 0xe0, 0xfe, 0x00,
 0x00, 0x79, 0xc7, 0x9f, 0xf3, 0x9f, 0xf9, 0xff, 0x7f, 0xf3, 0xff, 0x7f, 0xdf, 0xf3, 0xfe, 0x00,
 0x00, 0x79, 0xc7, 0x1f, 0xf3, 0x9f, 0xfb, 0xfe, 0x7f, 0xe1, 0xff, 0x7f, 0xdf, 0xf7, 0xfe, 0x00,
 0x00, 0x71, 0xc7, 0x1c, 0x77, 0x9c, 0x73, 0x8e, 0x79, 0xf1, 0xce, 0xe3, 0xdc, 0x77, 0x1c, 0x00,
 0x00, 0x73, 0xc7, 0x1c, 0x77, 0x1c, 0x77, 0x8e, 0x70, 0xf3, 0xcc, 0xe3, 0x9c, 0xf7, 0x1c, 0x00,
 0x00, 0xf3, 0x8f, 0x38, 0xf7, 0x3c, 0x77, 0x1c, 0xf0, 0xe3, 0x80, 0xff, 0xbf, 0xef, 0x1c, 0x00,
 0x00, 0xf3, 0x8e, 0x38, 0xe7, 0x38, 0xf7, 0x1c, 0xe1, 0xe3, 0x81, 0xff, 0x3f, 0xee, 0x3c, 0x00,
 0x00, 0xe3, 0x8e, 0x38, 0xee, 0x38, 0xe7, 0x1c, 0xe1, 0xe3, 0x81, 0xc0, 0x38, 0x0e, 0x38, 0x00,
 0x00, 0xe7, 0x8e, 0x38, 0xee, 0x38, 0xef, 0x1d, 0xe1, 0xe7, 0x01, 0xc0, 0x78, 0x0e, 0x38, 0x00,
 0x01, 0xe7, 0x9e, 0x71, 0xee, 0x78, 0xef, 0x39, 0xff, 0xc7, 0x01, 0xc0, 0x78, 0x1f, 0x78, 0x00,
 0x01, 0xe7, 0xfc, 0x71, 0xce, 0x71, 0xcf, 0xf9, 0xff, 0xc7, 0x01, 0xf8, 0x7f, 0x0f, 0xf0, 0x00,
 0x01, 0xc7, 0xfc, 0x71, 0xdc, 0x71, 0xc7, 0xf9, 0xff, 0x87, 0x01, 0xfc, 0x3f, 0x07, 0xf0, 0x00,
 0x03, 0xc0, 0x10, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x03, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

// 'goFast', 128x64px
const unsigned char bootgoFast [] PROGMEM = {
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x01, 0xff, 0xfc, 0x3f, 0xff, 0xe0, 0x00, 0x3f, 0xff, 0x8f, 0xe0, 0x3f, 0xff, 0xf3, 0xff, 0xf8,
 0x01, 0xff, 0xff, 0x1f, 0xff, 0xf8, 0x00, 0x1f, 0xff, 0x07, 0xe0, 0x3f, 0xff, 0xf7, 0xff, 0xf8,
 0x00, 0xff, 0xff, 0x8f, 0xff, 0xf8, 0x00, 0x1f, 0xff, 0x03, 0xe0, 0x1f, 0xff, 0xe7, 0xff, 0xf8,
 0x00, 0xff, 0xff, 0x0f, 0xff, 0xf8, 0x00, 0x1f, 0xfe, 0x03, 0xe0, 0x0f, 0xff, 0xe7, 0xff, 0xf8,
 0x00, 0xf8, 0x1f, 0x0f, 0x81, 0xf8, 0x00, 0x1f, 0x00, 0x07, 0xe0, 0x0f, 0x80, 0x06, 0x3e, 0x18,
 0x00, 0xf8, 0x1f, 0x0f, 0x81, 0xf0, 0x00, 0x1f, 0x00, 0x07, 0xe0, 0x1f, 0x80, 0x0c, 0x3e, 0x10,
 0x00, 0xf8, 0x1f, 0x1f, 0x01, 0xf0, 0x00, 0x3f, 0x00, 0x0f, 0xe0, 0x1f, 0x00, 0x08, 0x7e, 0x00,
 0x01, 0xf0, 0x3f, 0x1f, 0x01, 0xf0, 0x00, 0x3e, 0x00, 0x0f, 0xe0, 0x1f, 0x00, 0x00, 0x7c, 0x00,
 0x01, 0xf0, 0x3e, 0x1f, 0x01, 0xf0, 0x00, 0x3e, 0x00, 0x1f, 0xe0, 0x1f, 0x00, 0x00, 0x7c, 0x00,
 0x01, 0xf0, 0x3e, 0x1f, 0x03, 0xe0, 0x00, 0x3e, 0x00, 0x1f, 0xe0, 0x1f, 0x80, 0x00, 0x7c, 0x00,
 0x03, 0xf0, 0x00, 0x3e, 0x03, 0xe0, 0x00, 0x7e, 0x00, 0x3f, 0xe0, 0x1f, 0xc0, 0x00, 0xf8, 0x00,
 0x03, 0xe0, 0x00, 0x3e, 0x03, 0xe0, 0x00, 0x7c, 0x00, 0x3d, 0xe0, 0x0f, 0xe0, 0x00, 0xf8, 0x00,
 0x03, 0xe0, 0x00, 0x3e, 0x07, 0xe0, 0x00, 0x7f, 0xe0, 0x7d, 0xe0, 0x07, 0xf0, 0x00, 0xf8, 0x00,
 0x03, 0xe7, 0xfc, 0x7e, 0x07, 0xc0, 0x00, 0x7f, 0xc0, 0x79, 0xe0, 0x07, 0xf0, 0x00, 0xf8, 0x00,
 0x07, 0xc7, 0xfc, 0x7c, 0x07, 0xc0, 0x00, 0xff, 0xc0, 0xf9, 0xe0, 0x03, 0xf8, 0x01, 0xf0, 0x00,
 0x07, 0xcf, 0xf8, 0x7c, 0x07, 0xc0, 0x00, 0xff, 0x80, 0xf1, 0xe0, 0x01, 0xfc, 0x01, 0xf0, 0x00,
 0x07, 0xcf, 0xf8, 0x7c, 0x0f, 0xc0, 0x00, 0xf8, 0x01, 0xf1, 0xe0, 0x00, 0xfe, 0x01, 0xf0, 0x00,
 0x07, 0xc0, 0xf8, 0xf8, 0x0f, 0x80, 0x00, 0xf8, 0x01, 0xe1, 0xe0, 0x00, 0x7e, 0x01, 0xf0, 0x00,
 0x0f, 0x81, 0xf0, 0xf8, 0x0f, 0x80, 0x01, 0xf0, 0x03, 0xff, 0xe0, 0x00, 0x3f, 0x03, 0xe0, 0x00,
 0x0f, 0x81, 0xf0, 0xf8, 0x0f, 0x80, 0x01, 0xf0, 0x03, 0xff, 0xe0, 0x00, 0x3e, 0x03, 0xe0, 0x00,
 0x0f, 0x81, 0xf0, 0xf8, 0x1f, 0x00, 0x01, 0xf0, 0x07, 0xff, 0xe0, 0x00, 0x3e, 0x03, 0xe0, 0x00,
 0x1f, 0x81, 0xf1, 0xf0, 0x1f, 0x00, 0x01, 0xf0, 0x07, 0xff, 0xe0, 0x00, 0x3e, 0x07, 0xe0, 0x00,
 0x1f, 0x03, 0xe1, 0xf0, 0x1f, 0x00, 0x03, 0xe0, 0x0f, 0x83, 0xe0, 0x00, 0x3e, 0x07, 0xc0, 0x00,
 0x1f, 0x03, 0xe1, 0xf0, 0x1f, 0x00, 0x03, 0xe0, 0x0f, 0x81, 0xe0, 0x00, 0x7c, 0x07, 0xc0, 0x00,
 0x1f, 0xff, 0xe1, 0xff, 0xfe, 0x00, 0x03, 0xe0, 0x1f, 0x01, 0xe3, 0xff, 0xfc, 0x07, 0xc0, 0x00,
 0x1f, 0xff, 0xe1, 0xff, 0xfe, 0x00, 0x03, 0xe0, 0x1f, 0x01, 0xe7, 0xff, 0xfc, 0x0f, 0x80, 0x00,
 0x1f, 0xff, 0xc1, 0xff, 0xfe, 0x00, 0x07, 0xc0, 0x3e, 0x01, 0xe7, 0xff, 0xf8, 0x0f, 0x80, 0x00,
 0x0f, 0xff, 0x80, 0xff, 0xf8, 0x00, 0x07, 0xc0, 0x3e, 0x01, 0xef, 0xff, 0xf0, 0x0f, 0x80, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x0f, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x1e, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x1c, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x18, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x10, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x20, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

int peakValue = 0;
int actualScreen = 0; // 0- boot screen, 1- GoFast screen, 2- wsaźnik temperatury
void boot (void) {
  if (actualScreen == 0) {
    u8g.drawBitmapP( 0, 0, 128/8, 64, bootoli_dash_bootscreen);
    delay(7000);
    actualScreen=1;
  };
  if (actualScreen == 1) {
    u8g.drawBitmapP( 0, 0, 128/8, 64, bootgoFast);
    delay(7000);
    actualScreen=2;
  };

}

void setup() {
  sensors.begin();
  u8g.setFont(u8g_font_tpssb);
  u8g.setColorIndex(1);  // set the color to white
 Serial.begin(9600);
}

void loop() {
  int analogValue = analogRead(A0); // odczyt z czujnika w postaci wartości liczbowej
  sensors.requestTemperatures(); // prosi o odczyt z czujnika

 int temperature = sensors.getTempCByIndex(0); // temperatura w stopniach celsjusza

 if (temperature>peakValue) {
    peakValue=temperature;
    };
 Serial.print("Peak:");
 Serial.println(temperature);
  Serial.print("Analog");
  Serial.println(analogValue);
  delay(3000);

  u8g.firstPage();
  do {
    boot();
    if(actualScreen == 2){
      if (temperature<40){
    u8g.drawBox(2, 3, 0, 16); // rysuje box
   };

      u8g.setColorIndex(1); // white color
      u8g.drawBitmapP( 0, 0, 128/8, 39, oil_bar);                 // wyswietla górny pasek
      u8g.drawBitmapP( 0, 46, 88/8, 18, oil_peak);              // wyświetla oil peak
      u8g.setColorIndex(1);
   if(temperature>40)  {
          u8g.drawBox(2, 3, map(temperature, 784, 115, 55, 125), 16);    // actual gauge fill, remapped from 784-115 to 0-125 (maximum rectangle size)
   };
    }
  } while ( u8g.nextPage() );

}
```
**Wokwi project**: https://wokwi.com/projects/353820351118650369

title: Problem with switching screens using U8glib

Answers: 0


body:
Consider this code:

    void loop() {
        digitalWrite(pinTest, HIGH);
        digitalWrite(pinTest, LOW);
    }

On an Arduino Mega 2560, running 16MHz (=0.06us), I would expect the width of the pulse to be somewhere around 0.1us.

However, when measuring with my oscilloscope, I get around 4us high and 5-6 us low. I understand it could take some cycles to run the `digitalWrite` code, but this seems quite a lot.

How is that difference explained?

title: How to increase pinout switching?

Answers: 2

body:
I fixed it by using assembly code to run the program. Because I am using Linux, I couldn't use Atmel Studio, but you can easily use AVR assembly with `arduino-cli`.

Make your `.ino` like this:

    extern "C" void myAssemblyMain();

    void setup() {
        myAssemblyMain();
    }
    void loop() {
    }

then add a `pulse.S` file with the assembly code:

    #define __SFR_OFFSET 0

    #include "avr/io.h"

    .global myAssemblyMain

    myAssemblyMain:
      sbi   DDRA, 0     ; Set PA0 as output

    blink:
      sbi   PINA, 0     ; Toggle PINB
      jmp   blink

Using this code, I get a ~400ns pulse. Which is more than enough for my needs.

body:
You do not need to go all the way down to assembly in order to get that
speed. You can do direct port access from your `.ino` file:

```c++
void setup() {
    DDRA |= _BV(PA0);  // pin 22 = PA0 as output
    for (;;) {
        PINA |= _BV(PA0);  // toggle PA0
    }
}

void loop(){}
```

This compiles to something that is almost equivalent to your assembly
code. Actually, it is a bit faster, as it uses `rjmp` instead of the
slower `jmp` instruction.

**Edit**: A few notes

1. As pointed out by timemage in a comment, you can save another CPU
   cycle by writing `PINA =` instead of `PINA |=`.

2. This code, as well as your two examples, will exhibit a glitch every
   1,024 µs. This is caused by the periodic timer interrupt used
   by the Arduino core for timekeeping (`millis()`, `micros()` and
   `delay()`). You can avoid the glitch by disabling interrupts before
   going into the tight loop. Alternatively, if you do not use the
   Arduino core at all, you can define a function called `main()`
   instead of `setup()` and `loop()`: this will completely remove the
   Arduino core initialization for your compiled program.

3. `arduino-cli` is useful for sparing you the complexity of the Arduino
   build system (automatic installation of the cores and libraries,
   libraries in multiple places that depend on the core you use...). If
   you do not use the Arduino core, `arduino-cli` is of little use: a
   very simple Makefile that calls `avr-gcc` and `avrdude` is all you
   need for basic AVR development.


body:
https://github.com/espressif/arduino-esp32/tree/master/libraries/HTTPUpdate

I found out that this library can read x-MD5 header but looks like it's going through with the update no matter what MD5 I set. I thought it's for verifying the update, I do md5sum of my bin file on the server and then ESP32 checks the hash of downloaded bin to confirm the file wasn't corrupted during download. Am I wrong here? What's the purpose of this x-MD5 header if not for this?

If it has another purpose, how do I make sure that the bin with the update wasn't corrupted during download so I don't brick ESP32?

title: ESP32 HTTP Update and x-MD5 header

Answers: 0


body: I am using Arduino IDE 2.0.3.  When compiling code if there is an error it shows on a black background with a red font, that is hard for me to read.  Can I change either the background or the font?  Looking within the IDE I don't see how and not seeing anything on the internet.  TIA

title: Arduino Output Panel Font Color Change

Answers: 1

body: Thank you dankeboy36 for pointing out "Themes".  Fixed it right up.


body:
I am trying to control a servo motor with the following code:

```c
#include <Servo.h>

Servo servo;

int const inputPin = 3;

void setup() {
  Serial.begin(9600);
  servo.attach(9);
  pinMode(inputPin, INPUT);
  servo.write(0);
}

void loop() {
  if (digitalRead(inputPin)) {
    Serial.println("HIGH");
    servo.write(40);
  } else {
    Serial.println("LOW");
    servo.write(0);
  }
}
```

It takes input from pin 3 and controls the servo with pin 9. When pin 3 is connected to a pushbutton, as shown in the following image, it works exactly as expected; for as long as the button is held down, the servo stays at 40° and when the button is released the servo returns to 0°.

It's a little difficult to see in the images, but the resistor on row 24 is connected to ground, not power.
[![enter image description here][1]][1]

However, if I replace the button with an Adafruit RF M4 Receiver, as shown in the following image, the servo behaves differently. When I hold the button on the remote down, the servo attempts to move to 40°, but returns to 0° before trying again. From the serial output, I can see that the pin is in fact oscillating between HIGH and LOW.
[![Circuit with receiver][2]][2]

If I remove the commands to the servo and just use the buttons to control the serial output, the code behaves correctly. With both the pushbutton and the RF M4 Receiver, the output says HIGH when the button is held down and LOW when it is released. So the issue only occurs when I use both the receiver and a servo motor, but not one or the other.
```c
int const inputPin = 3;

void setup() {
  Serial.begin(9600);
  pinMode(inputPin, INPUT);
}

void loop() {
  if (digitalRead(inputPin)) {
    Serial.println("HIGH");
  } else {
    Serial.println("LOW");
  }
}
```

I am using an Arduino Uno R3, [this receiver](https://www.adafruit.com/product/1096), and [this remote](https://www.adafruit.com/product/1095).

Edit: The schematic, as requested. I'm new to Arduino, so I apologize if the schematic is a little sloppy.

<!-- Begin schematic: In order to preserve an editable schematic, please
     don't edit this section directly.
     Click the "edit" link below the image in the preview instead. -->

![schematic](https://i.stack.imgur.com/L5WtY.png)

<!-- End schematic -->

  [1]: https://i.stack.imgur.com/2O56Z.jpg
  [2]: https://i.stack.imgur.com/rquY5.jpg

title: Unable to use RF M4 Receiver with servo motor

Answers: 0


body:
I'm unsure how this will be handled by the Arduino compiler. If anyone can explain what and why, I'd appreciate it. This is obviously very simplified, but it does contain the actual issue.

At the module level I have this `union`. I understand that this is strictly speaking not correct C++, but it does work for me, at least when used directly and not passed as a argument to a function.

      union _TAT {          // access as bytes or uint32
        uint32_t wide = 0;
        uint8_t bytes[4];
      };

      _TAT oneTAT;        // a variable of _TAT

Suppose I also have a function that works on these:

      void fix_Term(_TAT atat) {
        atat.wide = 0;
        atat.bytes[3] = 17;
      }

...and I invoke it with:

      fix_Term(oneTAT);

As I understand it, passing `AnArray[]` is equivalent to passing `*AnArray`, so the function might/should see `atat.bytes[3]` as a pointer to that byte of the variable. But what about `atat.wide`? I haven't explicitly passed `oneTAT` by reference, so...?

What might actually happen here? It does compile without complaint but I can't test it because the hardware it depends on isn't available yet. Besides, even if it works, I'd like to know why.

And of course, if it's just wrong, how do I best accomplish passing and modifying a variable like this?

title: How does Arduino handle passing this union?

Answers: 2

body:
Yes passing `AnArray[]` is equivalent to passing `*AnArray`. **But** declaring `uint8_t *anarray1` is _not_ equivalent to declaring `uint8_t anarray2[4]` in a struct/class/union definition. The former includes a pointer to a byte in the struct, the later actually includes 4 bytes in the struct. So in the later case, `anarray2` already points to data, and using `variable.anarray2[0]` correctly gets you the value in the structure, while calling `variable.anarray1[0]` would result in undefined behavior, because the pointer just points anywhere.

So your code is compiling and executing without error, but since you're passing the union by value, the effect of your `fix_term` function is discarded, much like if you had passed in an ordinary value type instead (such as int).

body:
It is confusing in C and C++ that arrays are passed as pointers but an instance of class, struct or union is always passed by value (so as a copy) including the arrays which are part of the memory space of the structure as in the case of your union.

If you want to pass by reference, declare the function's parameter as a reference 'type'. For example `void fix_Term(_TAT& atat) {`.