text:
Use an LDR to run a sketch
This may sound like a simple question but I have tried to find the right solution but all I find is the usual make an led blink and even I can code that nugget
I am quite new to programming arduino but am a dab hand with a soldering iron.
What I would like to do is combine the attributes of an LDR to allow a lighting sketch to run if it is dark and go off in daylight, but all I seem to find is turn a pin high or low, this is no good as I already have a sketch I would like to run
I am using WS2811 led nodes housed in pinspot style housings so the sketch would need to check the light level and if it is below a set value run the rest of the sketch then check every hour to see if the light level has changed to be above a set level  if it is go into a check loop until the light level falls again to below the set value can anyone point me in the right direction I would be grateful for any assistance
Thanks
Dave

Can you show us the "lighting" sketch you written?

It sounds like you need to put your light code in an if statement that checks the light level.  I know I’ve seen this project done over and over so I don’t believe you can’t find an example.  If you find one that just sets a pin high or low in response to the ldr then you’re almost there.  Just take out the line that turns the pin high or low and replace with code that turns your led strip on or off.  It’s really just that simple.

the function that reads the value of an LDR and the function that turns on the lights are two completely separate functions ... the LDR function raises a flag that says light on ... it does nothing else .... the light function turns on the light if it sees the flag .... it does nothing else .... the light on flag could also be raised by a pushbutton being pressed or by a timer or by sound detector hearing noise, etc.

You're unlikely to find exactly what you want as existing code example. Break it into parts and solve it in parts.
You can't "Run a sketch" based on reading a value of an LDR. You can write a new sketch that reads an LDR, and calls a function if it's dark, or a different function if it is light. You will need to refactor your code from your other sketch into functions that you can integrate into your new combined sketch that uses the LDR. That means doing some original programming, not "finding the right solution" ready-made on the internet.
First, how do you use an LDR to determine if it's light or dark? Answer, use an analog input. Build a voltage divider with the LDR and a similar sized resistor, and feed the output into an analog pin. Say the LDR is between +5V and the pin, so more light results in higher voltage, hence a larger value.
Log the output of the LDR to the console in a loop, and decide on your threshold values for light and dark. Make the threshold value a constant. Let's call it DARK.
Now write a loop function. It might look something like this:
int lightValue;
#define ldr_pin xxx //your pin number
#define threshold xxx //your threshold value

void setup() {
   //set the ldr pin as an analog input
}

void loop() {
   lightValue = analogRead(ldr_pin);
   if (lightValue <= threshold) {
      doNightStuff();
   } else {
      stopDoingStuff();
   }
}

Edit:
As mentioned by Edgar, the code above will be subject to "jitter", where it will rapidly switch back and forth between the dark and light states.
The solution is to add a buffer range where once it's in one state, it doesn't change states until it leaves the buffer range.
The if statement might look like this:
#define buffer 5

if ((lightValue +buffer) <= threshold)
    doNightStuff();
else if ((lightValue -buffer) >= threshold)
    stopDoingStuff();

It would be still better with two thresholds that provide some hysteresis.

Fair point, but I think that might be beyond the OP's current level of understanding.

You are probably right. OTOH, without hysteresis, the OP is likely to be coming back here pretty soon. :-)

if you power the LDR with an INPUT_PULLUP pin instead of VIN, you don't need a fixed resistor to form your divider, just plug the other LDR lead into the analog input. This won't give you full range, but it's more than enough resolution to distinguish dark from light.

simple adding of hysteresis, replace all loop code but first line: if ((lightValue +5) <= threshold) doNightStuff(); if ((lightValue -5) >= threshold) stopDoingStuff(); Adjust as needed.

@ Duncan C
think i have a solution not sure if it's your way but it does work so not bad for a newbie lol
//
//  "Pacifica"
//  Gentle, blue-green ocean waves.
//  December 2019, Mark Kriegsman and Mary Corey March.
//  For Dan.
//  Thanks for the sketch i have added a daylight sensor so they now go off in daylight Dave Cowell June 2020

int lightValue;  //new code dc

#define FASTLED_ALLOW_INTERRUPTS 0
#include <FastLED.h>
FASTLED_USING_NAMESPACE

#define ldr_pin             A0   //new dc
#define Threshold_dark      100  //new dc
#define Threshold_light     1000  //new dc
#define DATA_PIN            7
#define NUM_LEDS            28
#define MAX_POWER_MILLIAMPS 500
#define LED_TYPE            WS2811
#define COLOR_ORDER         RGB

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

CRGB leds[NUM_LEDS];

void setup() {

  analogRead (A0);  //new dc

  delay( 3000); // 3 second delay for boot recovery, and a moment of silence
  FastLED.addLeds<LED_TYPE,DATA_PIN,COLOR_ORDER>(leds, NUM_LEDS)
        .setCorrection( TypicalLEDStrip );
  FastLED.setMaxPowerInVoltsAndMilliamps( 5, MAX_POWER_MILLIAMPS);
}

void loop(){

 lightValue = analogRead (ldr_pin);  //new dc

 if (lightValue <= Threshold_dark){    // new dc

    EVERY_N_MILLISECONDS(20)
    pacifica_loop();
    FastLED.show();

 }else { (lightValue = Threshold_light);  // New dc

 {                                         // New dc

 for (int i = 0; i <NUM_LEDS;i++){         // New dc

      memset (leds,0,NUM_LEDS*3);          // New dc

                FastLED.show();             // New dc

                FastLED.delay (100);         // New dc

 }         // New dc
  }        // New dc
   }       // New dc
    }      // New dc

//////////////////////////////////////////////////////////////////////////
//
// The code for this animation is more complicated than other examples, and
// while it is "ready to run", and documented in general, it is probably not
// the best starting point for learning.  Nevertheless, it does illustrate some
// useful techniques.
//
//////////////////////////////////////////////////////////////////////////
//
// In this animation, there are four "layers" of waves of light.
//
// Each layer moves independently, and each is scaled separately.
//
// All four wave layers are added together on top of each other, and then
// another filter is applied that adds "whitecaps" of brightness where the
// waves line up with each other more.  Finally, another pass is taken
// over the led array to 'deepen' (dim) the blues and greens.
//
// The speed and scale and motion each layer varies slowly within independent
// hand-chosen ranges, which is why the code has a lot of low-speed 'beatsin8' functions
// with a lot of oddly specific numeric ranges.
//
// These three custom blue-green color palettes were inspired by the colors found in
// the waters off the southern coast of California, https://goo.gl/maps/QQgd97jjHesHZVxQ7
//
CRGBPalette16 pacifica_palette_1 =
    { 0x000507, 0x000409, 0x00030B, 0x00030D, 0x000210, 0x000212, 0x000114, 0x000117,
      0x000019, 0x00001C, 0x000026, 0x000031, 0x00003B, 0x000046, 0x14554B, 0x28AA50 };
CRGBPalette16 pacifica_palette_2 =
    { 0x000507, 0x000409, 0x00030B, 0x00030D, 0x000210, 0x000212, 0x000114, 0x000117,
      0x000019, 0x00001C, 0x000026, 0x000031, 0x00003B, 0x000046, 0x0C5F52, 0x19BE5F };
CRGBPalette16 pacifica_palette_3 =
    { 0x000208, 0x00030E, 0x000514, 0x00061A, 0x000820, 0x000927, 0x000B2D, 0x000C33,
      0x000E39, 0x001040, 0x001450, 0x001860, 0x001C70, 0x002080, 0x1040BF, 0x2060FF };

void pacifica_loop()
{
  // Increment the four "color index start" counters, one for each wave layer.
  // Each is incremented at a different speed, and the speeds vary over time.
  static uint16_t sCIStart1, sCIStart2, sCIStart3, sCIStart4;
  static uint32_t sLastms = 0;
  uint32_t ms = GET_MILLIS();
  uint32_t deltams = ms - sLastms;
  sLastms = ms;
  uint16_t speedfactor1 = beatsin16(3, 179, 269);
  uint16_t speedfactor2 = beatsin16(4, 179, 269);
  uint32_t deltams1 = (deltams * speedfactor1) / 256;
  uint32_t deltams2 = (deltams * speedfactor2) / 256;
  uint32_t deltams21 = (deltams1 + deltams2) / 2;
  sCIStart1 += (deltams1 * beatsin88(1011,10,13));
  sCIStart2 -= (deltams21 * beatsin88(777,8,11));
  sCIStart3 -= (deltams1 * beatsin88(501,5,7));
  sCIStart4 -= (deltams2 * beatsin88(257,4,6));

  // Clear out the LED array to a dim background blue-green
  fill_solid( leds, NUM_LEDS, CRGB( 2, 6, 10));

  // Render each of four layers, with different scales and speeds, that vary over time
  pacifica_one_layer( pacifica_palette_1, sCIStart1, beatsin16( 3, 11 * 256, 14 * 256), beatsin8( 10, 70, 130), 0-beat16( 301) );
  pacifica_one_layer( pacifica_palette_2, sCIStart2, beatsin16( 4,  6 * 256,  9 * 256), beatsin8( 17, 40,  80), beat16( 401) );
  pacifica_one_layer( pacifica_palette_3, sCIStart3, 6 * 256, beatsin8( 9, 10,38), 0-beat16(503));
  pacifica_one_layer( pacifica_palette_3, sCIStart4, 5 * 256, beatsin8( 8, 10,28), beat16(601));

  // Add brighter 'whitecaps' where the waves lines up more
  pacifica_add_whitecaps();

  // Deepen the blues and greens a bit
  pacifica_deepen_colors();
}

// Add one layer of waves into the led array
void pacifica_one_layer( CRGBPalette16 & p, uint16_t cistart, uint16_t wavescale, uint8_t bri, uint16_t ioff)
{
  uint16_t ci = cistart;
  uint16_t waveangle = ioff;
  uint16_t wavescale_half = (wavescale / 2) + 20;
  for( uint16_t i = 0; i < NUM_LEDS; i++) {
    waveangle += 250;
    uint16_t s16 = sin16( waveangle ) + 32768;
    uint16_t cs = scale16( s16 , wavescale_half ) + wavescale_half;
    ci += cs;
    uint16_t sindex16 = sin16( ci) + 32768;
    uint8_t sindex8 = scale16( sindex16, 240);
    CRGB c = ColorFromPalette( p, sindex8, bri, LINEARBLEND);
    leds[i] += c;
  }
}

// Add extra 'white' to areas where the four layers of light have lined up brightly
void pacifica_add_whitecaps()
{
  uint8_t basethreshold = beatsin8( 9, 55, 65);
  uint8_t wave = beat8( 7 );

  for( uint16_t i = 0; i < NUM_LEDS; i++) {
    uint8_t threshold = scale8( sin8( wave), 20) + basethreshold;
    wave += 7;
    uint8_t l = leds[i].getAverageLight();
    if( l > threshold) {
      uint8_t overage = l - threshold;
      uint8_t overage2 = qadd8( overage, overage);
      leds[i] += CRGB( overage, overage2, qadd8( overage2, overage2));
    }
  }
}

// Deepen the blues and greens
void pacifica_deepen_colors()
{
  for( uint16_t i = 0; i < NUM_LEDS; i++) {
    leds[i].blue = scale8( leds[i].blue,  145);
    leds[i].green= scale8( leds[i].green, 200);
    leds[i] |= CRGB( 2, 5, 7);
  }
  {

  }
}


text:
How to run my buzzer for few more seconds after switching off
This is a basic level lazer alarm project. When anyone crosed or kept their hands on the lazer. buzzer starts working but when they took their hand from lazer light buzzer stops. But i want even after taking hands my buzzer should work for few (15-30) seconds .so please help me by giving idea..

Please don’t write answers in the comments. It bypasses our quality measures by not having voting (both up and down) available on comments, as well as having other problems detailed on meta. Comments are for clarifying and improving the question; please don’t use them for other purposes. Existing answers-in-comments have been deleted. I notice a proper answer has been given by DragonflyRobotics.

If you are using a digital buzzer, you can do:
digitalWrite(buzzerPin,HIGH);
delay(1000);
digitalWrite(buzzerPin,LOW);

source: Stack Exchange

license: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/4.0/

sort: votes


text:
Unable to send UDP packets while performing OTA update on the esp8266
I am sending specific UDP packets with my esp8266 every 5s, I have added an OTA update command, and added the update_progress callback aiming to send it back to my laptop, using a serial terminal I noticed that regular packets, as well as the progress packet, are not sent during the update, everything gets back after. Is the esp able to send and receive packets simultaneously?, is there any interference or the OTA update process causes an interruption?
Hardware: ESP8266MOD Nodemcu
Software: VS code with portable Arduino 1.8.9, espcore 2.6.3

esp8266 ArduinoOTA library has
  WiFiUDP::stopAll();
  WiFiClient::stopAll();

to ensure undisturbed OTA upload

Any way to trick it to enable UDP, or sweep between TCP(for OTA) and UDP, I am using the ESP8266httpUpdate library and it disables all wifi clients except TCP, commenting that section did nothing

@AlaeddineSalem, you can try to remove the lines from the library

all_licenses: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/4.0/


text:
Am not able to call C++ function pointers from inline assembly
Due to some curiosity, I was trying to use some assembly with my Arduino MEGA 2560.
I am not able to invoke a function from a c++ function pointer array.
When I uncomment the call function, func_a runs. However, when I almost reproduce the assembly, it doesnt work.
Example:
extern "C" void __attribute__ ((used, noinline, noreturn)) func_a();

typedef void (*volatile func_ptr)();

func_ptr tasks[MAX_TASKS] = {&func_a};

extern "C"
void __attribute__ ((used, noinline)) call(func_ptr *ptr) {
    (*ptr)();
}

void __attribute__ ((noreturn, used)) setup() {

    // call(tasks);

    asm volatile (
    "lds r26, (tasks)\n"
    "lds r27, (tasks + 1)\n"

    "ld r30, X+\n"
    "ld r31, X\n"

    "eijmp\n"
    );
}

Generated assembly recovered from avr-objdump
000001c6 <setup>:
 1c6:   a0 91 00 02     lds r26, 0x0200 ; 0x800200 <tasks>
 1ca:   b0 91 01 02     lds r27, 0x0201 ; 0x800201 <tasks+0x1>
 1ce:   ed 91           ld  r30, X+
 1d0:   fc 91           ld  r31, X
 1d2:   19 94           eijmp
 1d4:   08 95           ret

000001d6 <call>:
 1d6:   dc 01           movw    r26, r24
 1d8:   ed 91           ld  r30, X+
 1da:   fc 91           ld  r31, X
 1dc:   19 94           eijmp

An specific resources I should refer for things like this?
If it matters, I'm using platformio on a linux system for compilation.

It seems you got confused by the pointer indirections, which is
confounded by the implicit indirections made by the compiler.
Here:
extern "C"
void __attribute__ ((used, noinline)) call(func_ptr *ptr) {
    (*ptr)();
}

The parameter ptr is not a function pointer: it's a pointer to a
function pointer. You have to dereference it twice in order to get the
function: (**ptr)();. Note that the compiler implicitly dereferences a
function pointer if you call it like a function: that's why you get no
error by explicitly dereferencing the pointer only once. In the
generated assembly, the lines
ld  r30, X+
ld  r31, X

dereference ptr in order to get the address of the function to call.
You probably wanted to write
extern "C"
void __attribute__ ((used, noinline)) call(func_ptr ptr) {
    ptr();
}

And then use it as:
call(tasks[0]);

If you just call(tasks), the array identifier decays to pointer, and
the compiler handles this as a shortcut for call(&tasks[0]);, which
turns out to be compatible with your initial implementation of call().
Now, in your inline assembly you have
lds r26, (tasks)
lds r27, (tasks + 1)

The assembly treats tasks as a symbol representing the address of
the tasks array. The linker replaces those symbols by the actual
address (0x0200). Those instructions read the RAM at this and the
following address. These slots of RAM hold the first item of the array,
namely &func_a. So now you have this address in the X register pair.
No need to read RAM again: you can movw r30, r26 and do the indirect
jump. Or, better yet, load into Z to begin with:
lds r30, (tasks)
lds r31, (tasks + 1)
eijmp

See also Majenko's answer: here I am assuming EIND is somehow
correctly set up to begin with. On an Uno, you would just use ijmp
instead of eijmp and not worry about EIND.

That kindof eplained things. When I used (tasks) in the asm, I expected it to load the address of the first element of the array and not the value pointed to by it. Im not sure how to do that. Maybe I will have to understand the extended asm syntax.

@darkspine: You can load the address of tasks with, e.g., ldi r26, lo8(tasks)\n ldi r27, hi8(tasks). Unlike lds, the ldi instruction does not access the RAM, as the address is known at build time and filled-in by the linker.

I will start off by saying that I am no expert in AVR assembly, so I have no idea if any of this is actually correct. However from reading the various documents on the subject I have gleaned:

On the ATMega2560 EIJMP uses a combination of both the Z register and the EIND register to form a full address.

That means that as well as setting up the Z register for the lower 16 bits of the address you also have to set up the EIND register for the upper 5 bits of the address.

Indirect jump to the address pointed to by the Z (16 bits) Pointer Register in the Register File and the EIND Register in the I/O space. This instruction allows for indirect jumps to the entire 4M (words) Program memory space.

It then goes on to show an example:
ldi r16,$05 ; Set up EIND and Z-pointer
out EIND,r16
ldi r30,$00
ldi r31,$10
eijmp ; Jump to $051000

How you determine what the EIND register should be? Well, in general you don't. You wouldn't use EIJMP. From what I understand for functions outside the lower 64kwords of address space the compiler builds a "jump table" which is stored in the lower area of memory. You jump to the entry in that table with IJMP and that table then jumps to the final destination with EIJMP for you.
Doing this kind of jumping in assembly isn't really a nice thing to try and figure out. It's messy. Better to let the compiler do it for you and use C rather than assembly.  The AVR-GCC guys put a lot of work into making function pointers work correctly (from what I have read it wasn't easy even for them), and you're just re-inventing the wheel.
At the very least you should implement your code 100% in C to begin with then look at the compiled output to see how the compiler thinks it should be done.

I switched to eijmp because thats what gcc was using. The problem turned out to be that tasks is dereferenced when using it in the asm.
Also, thanks for the document, Its much more verbose than the ATMega2560 datasheet.


text:
ESP8266 NODEMCU V3 web server with MAX7219 and DS3231 RTC
I am using ESP8266 NodeMCU with MAX7219 and a DS3231 teal time clock. I want to display the time and some text. The display is made of 4 FC16 modules which are made of 4 8x8 MAX7219 led matrix modules so it would be a 32x32 led matrix diplay divided in 4 rows.
I am displaying the time hh:mm on the last row and text on the first 3 rows.
With ESP8266 I connected to my wi-fi and I created a web server which says "Hello World!"
So my question is: how do I upload my code to the web server so I can change the text remotely?
I found this tutorial https://maker.pro/esp8266/tutorial/how-to-build-an-led-matrix-display-with-a-nodemcu-esp8266 that shows how to change the text on one row of display but I don't want something that fancy. I just want my code uploaded and to be able to change in the code.
#include "RTClib.h"
#include <MD_Parola.h>
#include <MD_MAX72xx.h>
#include <SPI.h>
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>

ESP8266WebServer server;

// Define the number of devices we have in the chain and the hardware interface
// NOTE: These pin numbers will probably not work with your hardware and may
// need to be adapted
#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
#define MAX_DEVICES 12
#define NUM_ZONES 3

int CS_PIN = D4;
int CLK_PIN = D5;
int DATA_PIN = D7;

// Hardware SPI connection
MD_Parola P = MD_Parola(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);
// Arbitrary output pins
// MD_Parola P = MD_Parola(HARDWARE_TYPE, DATA_PIN, CLK_PIN, CS_PIN, MAX_DEVICES);

RTC_DS3231 rtc;
#define SPEED_TIME  25
#define PAUSE_TIME  1000

uint8_t lastUpdateMin = 0;
uint8_t lastUpdateHour = 0;

// Global variable
const char  *pc[NUM_ZONES] =
{
  "TIME", //0
  "ROOM", //1
  "SUBJECT", //2
  //"GRADE",//3
};

void setup(void)
{
  Serial.begin(115200);
  Serial.println();

  WiFi.begin("ssid", "password");

  Serial.print("Connecting");
  while (WiFi.status() != WL_CONNECTED)
  {
    delay(500);
    Serial.print(".");
  }
  Serial.println();

  Serial.print("Connected, IP address: ");
  Serial.println(WiFi.localIP());
  server.on("/", []() {
    server.send(200, "text/plain", "Hello World!");
  });
  server.begin();

  P.begin();
  if (! rtc.begin()) {
    Serial.println("Couldn't find RTC");
    while (1);
  }

  if (rtc.lostPower()) {
    Serial.println("RTC lost power, lets set the time!");
    //     If the RTC have lost power it will set the RTC to the date & time this sketch was compiled in the following line
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
  }

  P.begin(3);
  P.setZone(0, 0, 3); // Modules 0-3 in zone 0
  P.setZone(1, 4, 7); // Modules 4-7 in zone 1
  P.setZone(2, 8, 11); // Modules 8-11 in zone 2
  // P.setZone(3, 12, 15); // Modules 12-15 in zone 3
}

void loop(void)
{
  server.handleClient();
  DateTime now = rtc.now();
  if (lastUpdateMin != now.minute()) { // change every minute
    lastUpdateMin = now.minute();
    char buffer[] = "hh:mm";  // hours and minutes
    P.displayZoneText(0, now.toString(buffer), PA_CENTER, 0, 0, PA_PRINT, PA_NO_EFFECT);
  }
  if (lastUpdateHour != now.hour()) {   // change every hour
    lastUpdateHour = now.hour();
    P.displayZoneText(1, pc[1], PA_CENTER, 0, 0, PA_PRINT, PA_NO_EFFECT);  // 2nd row
    P.displayZoneText(2, pc[2], PA_CENTER, 0, 0, PA_PRINT, PA_NO_EFFECT);   // 3rd row
    //   P.displayZoneText(3, pc[3], PA_CENTER, 0, 0, PA_PRINT, PA_NO_EFFECT); // 4th row
  }
  P.displayAnimate();
}

if you want to upload the sketch over WiFi, use the ArduinoOTA library. you don't need a webserver for that. see the example in the IDE Examples menu.

you want to send text to be shown over http? just take a GET param in your server.on and feed it to the P.displayZoneText function

I want things to work the other way around. From the web server I want to be able to change the text zones in my code.

In that case add a PUT or POST param in your server.on. When you want a website to type the data in, you could rely or HTML forms (I think) and/or javascript to send a post request to the server, when the submit button is clicked


text:
Fail to convert time_T from past to tm struct
Continuing a Question asked few days ago, answered by Edgar, a new question has rised:
My goal was using a past time_t value, and convert it into a struct tm variable in order to  use it, part as a Char to print a readable text and some for logic queries.
At start NTP is configured as:
void myIOT32::startNTP(const int gmtOffset_sec = 2 * 3600, const int daylightOffset_sec = 3600, const char *ntpServer = "pool.ntp.org")
{
  configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
}

and every-time I need to get epoch and or struct tm of current time I call this function
void myIOT32::getTime()
{
  int a = 0;
  while (a < 3)
  {
    if (getLocalTime(&timeinfo))
    {
      delay(100);
      time(&epoch_time);
    }
    a++;
  }

BUT, when using the following function I get not GMT (+3) reference as needed :
struct tm *myIOT32::convEpoch(time_t in_time)
{
  struct tm *convTime = gmtime(&in_time);
  //char time_char[40];
  //sprintf(time_char, "%04d-%02d-%02d %02d:%02d:%02d", convTime->tm_year + 1900, convTime->tm_mon + 1, convTime->tm_mday,
          convTime->tm_hour, convTime->tm_min, convTime->tm_sec);
  return convTime;
}

Meaning I get to correct epoch time, but strcut tm is 3 hrs earlier ( and no, I do not want to hard-code +3... )

the Arduino and the NTP server don't know the time zone you are in. so create a constant and put it at the beginning of your sketch (yes, hardcode). why do you use the C time library? the TimeLib is much simpler to use

@Juraj - even tough it was config at the beginning when start NTP was executed ?

@Juraj  and the reason I do not want to hard code +3, is daylight saving...

in Europe it looks like we have only a few changes to/from DST before us. the date can be calculated. https://github.com/jandrassy/Regulator/blob/104421279aef672362bcff0baf7447410bc2b590/Regulator/Modbus.ino#L94

@Juraj Yes... that was my fallback. By the way, you asked about the reason not using TimeLib... since in example called "simpleTime" for ESP32 used dates that way ( and not as in ESP8266), so I guessed it is a compatibility issue.

replacing gmtime(&timeinfo) with localtime(&timeinfo) in myIOT32::convEpoch passes definition of time-zone as needed.
for more information in this cpluspls site


text:
Having trouble with sprintf function and string class
in my code, I was using string class to make an array to store my menu items
String menu[2] = {{"Menu 1"}, {"Menu2"}};

How do I convert this into char arrays and how do I call them?
Example:
Serial.println(menu[0]);

Sounds like you're looking for menu[0].c_str()

const char* menu[2] = {"Menu 1", "Menu2"};

By the way, you can access a string.  You call a function.  You don't call a string.

Create them as char arrays like this:
const char* menu[2] = {"Menu 1", "Menu 2"};

and use them like this:
Serial.println(menu[0]);

Strictly speaking it's an array of char*, not an array of char. And you should handle "Menu 1" as a const char*, to allow the compiler inhibit you doing nonsense. And avoid warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]

Edited for the const.

It is an array of char*.  And each one of those pointers points to a char array, not a String.  My point there was to distinguish between char array and String object.

Agreed. Even the warning text calls "hello" a string constant. But string (string literals aka const char array) and Arduino String Objects are so different that we should avoid using the term string completely.


text:
How to write analog signals to control throttle of the ship?
I am using teensy 2.0 as DAC. I am trying to write signals on rudder and throttle of the ship via relay. How can I write these analog signals? Should I specify voltage for every pin?
Here is my code:
int Rudder_p= 21; //Digital Write
int Rudder_s= 20; //Digital Write
int Throttle_p= 19; //Analog write
int Throttle_s= 18; //Analog write
int Throttle_T= 17; //Digital Write

void setup() {
  Serial.begin(9600);
  pinMode(Realy1,OUTPUT);
  pinMode(Rudder_p,INPUT);
  pinMode(Rudder_s,INPUT);
  pinMode(Throttle_p,OUTPUT);
  pinMode(Throttle_s,OUTPUT);
  pinMode(Throttle_T,INPUT);

  if (Serial.available() > 0) {
    incomingByte = Serial.read();
  }
}

// the loop routine runs over and over again forever:
void loop() {

  //Relay
  digitalWrite(Relay1,HIGH);
  delay(500);
  digitalWrite(Relay1,LOW);
  delay(500);

   //I am missing logic here:

  // read the input on analog pin 21
  int Value = analogWrite(F0);
  delay(1);        // delay in between reads for stability
}

You don't use an analog signal to control a relay.

I am using digital signal to control relay. But I need to be able to write analog write to control throttle and rudders. Each of them has reference voltage 5V and signal voltage between 0.5-4.5 VDC. I don't know how to use analogWrite() while setting up these voltages.

Do you really need an analog voltage, or a PWM signal? Normally throttle and rudders are controlled via servos, which need a PWM like signal, not an analog signal

https://www.arduino.cc/reference/en/language/functions/analog-io/analogwrite/


text:
current reading is not a sine like a voltage wave

I am working on a power meter project with ZMPT101B and SCT013. I want to see the phase difference between voltage and current in the serial plotter but the results are like this? Why do you think the current reading is not a sine like a voltage wave?]
2]2

because there is only a little load

When you look closely, the current is oscillating too. The signal is just too small to see it here. You should try to scale it up and/or make a measurement with more resolution

Current is only a sine wave with a purely resistive load. With other loads current changes all the time depending on what the load(s) is(/are) doing.

@Majenko and isn't it true that there is no such thing as a purely resistive load? There's always going to be some inductive and capacitive component, albeit a small one.

@DuncanC Often too small to measure though, at least with crude sensors like the SCT013, which itself will be an inductive load, thus changing your measurements by doing the measuring. But yes, it's impossible to get 100% pure resistive.

And doesn't the presence of capacitance and inductance in the circuit mean that the current graph is often visibly distorted from a pure sine wave?


text:
How to use a USB host shield with different HID Joysticks
I bought a Sparkfun USB host shield a while ago and have been using it using my Logitech Extreme 3D Pro Joystick. There is some example code for that one which makes it nice and easy to work with. There is also some example code for a generic USB HID Joystick.
My goal is to be able to use any joystick I want with the shield. All the channels on each of my flight sticks are being detected but they all have issues like they are mapped wrongly and don't have a full range of motion.
I understand I need to use USBHID_desc to get the USB HID Descriptor (unique for each joystick right?) and plug those numbers somewhere into the USBHIDJoystick code, but I don't know where to put this information.
My problem boils down to how should I use the data recovered from the USBHID_desc program.
Any help would be appreciated as I'm at a bit of a loss
Thanks
Report Descriptor for Random Flight Stick
Start
0000: 05 01 09 04 A1 01 09 01 A1 00 05 01 09 30 09 31
0010: 15 00 26 FF 03 35 00 46 FF 03 65 00 75 0A 95 02
0020: 81 02 09 35 09 32 15 00 26 FF 01 35 00 46 FF 01
0030: 65 00 75 09 95 02 81 02 75 01 95 02 81 01 09 39
0040: 15 01 25 08 35 00 46 3B 01 65 14 75 08 95 01 81
0050: 02 05 09 19 01 29 06 15 00 25 01 35 00 45 01 75
0060: 01 95 06 81 02 75 01 95 0A 81 01 C0 C0
Usage Page Gen Desktop Ctrls(01)
Usage Game Pad
Collection Application
Usage Pointer
Collection Physical
Usage Page Gen Desktop Ctrls(01)
Usage X
Usage Y
Logical Min(00)
Logical Max(FF03)
Physical Min(00)
Physical Max(FF03)
Unit(00)
Report Size(0A)
Report Count(02)
Input(00000010)
Usage Rz
Usage Z
Logical Min(00)
Logical Max(FF01)
Physical Min(00)
Physical Max(FF01)
Unit(00)
Report Size(09)
Report Count(02)
Input(00000010)
Report Size(01)
Report Count(02)
Input(00000001)
Usage Hat Switch
Logical Min(01)
Logical Max(08)
Physical Min(00)
Physical Max(3B01)
Unit(14)
Report Size(08)
Report Count(01)
Input(00000010)
Usage Page Button(09)
Usage Min(01)
Usage Max(06)
Logical Min(00)
Logical Max(01)
Physical Min(00)
Physical Max(01)
Report Size(01)
Report Count(06)
Input(00000010)
Report Size(01)
Report Count(0A)
Input(00000001)
End Collection
End Collection Game Pad Pointer X Y(02)(08)
 Rz Z(00)(E3)
(00)(00)
 Hat Switch(00)
 Btn0001
(00) Btn0002
(01) Btn0003
(00) Btn0004
(00) Btn0005
(00) Btn0006
(00)
(00)(00)(00)(00)(00)(00)(00)(00)(00)(00)

USB HID Joystick .INO
#include <usbhid.h>
#include <hiduniversal.h>
#include <usbhub.h>

// Satisfy IDE, which only needs to see the include statment in the ino.
#ifdef dobogusinclude
#include <spi4teensy3.h>
#endif
#include <SPI.h>

#include "hidjoystickrptparser.h"

USB Usb;
USBHub Hub(&Usb);
HIDUniversal Hid(&Usb);
JoystickEvents JoyEvents;
JoystickReportParser Joy(&JoyEvents);

void setup() {
        Serial.begin(115200);
#if !defined(__MIPSEL__)
        while (!Serial); // Wait for serial port to connect - used on Leonardo, Teensy and other boards with built-in USB CDC serial connection
#endif
        Serial.println("Start");

        if (Usb.Init() == -1)
                Serial.println("OSC did not start.");

        delay(200);

        if (!Hid.SetReportParser(0, &Joy))
                ErrorMessage<uint8_t > (PSTR("SetReportParser"), 1);
}

void loop() {
        Usb.Task();
}

USB HID Joystick .cpp
#include "hidjoystickrptparser.h"

JoystickReportParser::JoystickReportParser(JoystickEvents *evt) :
joyEvents(evt),
oldHat(0xDE),
oldButtons(0) {
        for (uint8_t i = 0; i < RPT_GEMEPAD_LEN; i++)
                oldPad[i] = 0xD;
}

void JoystickReportParser::Parse(USBHID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf) {
        bool match = true;

        // Checking if there are changes in report since the method was last called
        for (uint8_t i = 0; i < RPT_GEMEPAD_LEN; i++)
                if (buf[i] != oldPad[i]) {
                        match = false;
                        break;
                }

        // Calling Game Pad event handler
        if (!match && joyEvents) {
                joyEvents->OnGamePadChanged((const GamePadEventData*)buf);

                for (uint8_t i = 0; i < RPT_GEMEPAD_LEN; i++) oldPad[i] = buf[i];
        }

        uint8_t hat = (buf[5] & 0xF);

        // Calling Hat Switch event handler
        if (hat != oldHat && joyEvents) {
                joyEvents->OnHatSwitch(hat);
                oldHat = hat;
        }

        uint16_t buttons = (0x0000 | buf[6]);
        buttons <<= 4;
        buttons |= (buf[5] >> 4);
        uint16_t changes = (buttons ^ oldButtons);

        // Calling Button Event Handler for every button changed
        if (changes) {
                for (uint8_t i = 0; i < 0x0C; i++) {
                        uint16_t mask = (0x0001 << i);

                        if (((mask & changes) > 0) && joyEvents) {
                                if ((buttons & mask) > 0)
                                        joyEvents->OnButtonDn(i + 1);
                                else
                                        joyEvents->OnButtonUp(i + 1);
                        }
                }
                oldButtons = buttons;
        }
}

void JoystickEvents::OnGamePadChanged(const GamePadEventData *evt) {
        Serial.print("X1: ");
        PrintHex<uint8_t > (evt->X, 0x80);
        Serial.print("\tY1: ");
        PrintHex<uint8_t > (evt->Y, 0x80);
        Serial.print("\tX2: ");
        PrintHex<uint8_t > (evt->Z1, 0x80);
        Serial.print("\tY2: ");
        PrintHex<uint8_t > (evt->Z2, 0x80);
        Serial.print("\tRz: ");
        PrintHex<uint8_t > (evt->Rz, 0x80);
        Serial.println("");
}

void JoystickEvents::OnHatSwitch(uint8_t hat) {
        Serial.print("Hat Switch: ");
        PrintHex<uint8_t > (hat, 0x80);
        Serial.println("");
}

void JoystickEvents::OnButtonUp(uint8_t but_id) {
        Serial.print("Up: ");
        Serial.println(but_id, DEC);
}

void JoystickEvents::OnButtonDn(uint8_t but_id) {
        Serial.print("Dn: ");
        Serial.println(but_id, DEC);
}

USB HID Joystick .h
#if !defined(__HIDJOYSTICKRPTPARSER_H__)
#define __HIDJOYSTICKRPTPARSER_H__

#include <usbhid.h>

struct GamePadEventData {
        uint8_t X, Y, Z1, Z2, Rz;
};

class JoystickEvents {
public:
        virtual void OnGamePadChanged(const GamePadEventData *evt);
        virtual void OnHatSwitch(uint8_t hat);
        virtual void OnButtonUp(uint8_t but_id);
        virtual void OnButtonDn(uint8_t but_id);
};

#define RPT_GEMEPAD_LEN     5

class JoystickReportParser : public HIDReportParser {
        JoystickEvents *joyEvents;

        uint8_t oldPad[RPT_GEMEPAD_LEN];
        uint8_t oldHat;
        uint16_t oldButtons;

public:
        JoystickReportParser(JoystickEvents *evt);

        virtual void Parse(USBHID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf);
};

#endif // __HIDJOYSTICKRPTPARSER_H__

Edit of the current problem:
(This was fixed with a bit of trial and error in the packed struct)
X: 512 Y: 512 Hat Switch: 0 Twist: 768 Slider: 108 Buttons A: 0 Buttons B: 0
X: 512 Y: 512 Hat Switch: 0 Twist: 256 Slider: 108 Buttons A: 0 Buttons B: 0
X: 512 Y: 512 Hat Switch: 0 Twist: 768 Slider: 108 Buttons A: 0 Buttons B: 0
X: 512 Y: 512 Hat Switch: 0 Twist: 256 Slider: 108 Buttons A: 0 Buttons B: 0
X: 512 Y: 512 Hat Switch: 0 Twist: 768 Slider: 108 Buttons A: 0 Buttons B: 0
X: 512 Y: 512 Hat Switch: 0 Twist: 256 Slider: 108 Buttons A: 0 Buttons B: 0
X: 512 Y: 512 Hat Switch: 0 Twist: 768 Slider: 108 Buttons A: 0 Buttons B: 0
X: 512 Y: 512 Hat Switch: 0 Twist: 256 Slider: 108 Buttons A: 0 Buttons B: 0
X: 512 Y: 512 Hat Switch: 0 Twist: 768 Slider: 108 Buttons A: 0 Buttons B: 0
X: 512 Y: 512 Hat Switch: 0 Twist: 256 Slider: 108 Buttons A: 0 Buttons B: 0
X: 512 Y: 512 Hat Switch: 0 Twist: 768 Slider: 108 Buttons A: 0 Buttons B: 0

Edit for if statement issue:
Below is a section of the what my issue pretty much goes down to.
Now, I am assuming here that structs act in a similar way to dictionaries in python which I think is a massive simplification as they also seem to work as a class? Anyway, I was working on a way to have a first struct with the data for a specific joystick in, then using the data from that first to fill the second that will be used multiple times in the code but I think that is a worse method then what I have below and I couldn't get it to work anyway.
.cpp
#include "le3dp_rptparser.h"
#define __HIDJOYSTICKRPTPARSER_H__

#include <usbhid.h>

struct LogitechGamePro
{
  union { //axes and hut switch
    uint32_t axes;
    struct {
      uint32_t x : 10;
      uint32_t y : 10;
      uint32_t twist : 9;
      uint32_t slider : 10;
    };
  };
  uint8_t hat;
  uint8_t buttons_a;
  uint8_t buttons_b;
};

struct GamePadEventData
{
  union { //axes and hut switch
    uint32_t axes;
    struct {
      uint32_t x : 10;
      uint32_t y : 10;
      uint32_t twist : 9;
      uint32_t slider : 10;
    };
  };
  uint8_t hat;
  uint8_t buttons_a;
  uint8_t buttons_b;
};

JoystickReportParser::JoystickReportParser(JoystickEvents *evt) :
    joyEvents(evt)
{}

void JoystickReportParser::Parse(USBHID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf)
{

    bool match = true;

    // Checking if there are changes in report since the method was last called
    for (uint8_t i=0; i<RPT_GAMEPAD_LEN; i++) {
        if( buf[i] != oldPad[i] ) {
            match = false;
            break;
        }
  }
    // Calling Game Pad event handler
    if (!match && joyEvents) {
        joyEvents->OnGamePadChanged((const GamePadEventData*)buf);

        for (uint8_t i=0; i<RPT_GAMEPAD_LEN; i++) oldPad[i] = buf[i];
    }

}

void JoystickEvents::OnGamePadChanged(const GamePadEventData *evt)
{
    Serial.print("X: ");
    PrintHex<uint16_t>(evt->x, 0x80);
    Serial.print(" Y: ");
    PrintHex<uint16_t>(evt->y, 0x80);
    Serial.print(" Hat Switch: ");
    PrintHex<uint8_t>(evt->hat, 0x80);
    Serial.print(" Twist: ");
    PrintHex<uint8_t>(evt->twist, 0x80);
    Serial.print(" Slider: ");
    PrintHex<uint8_t>(evt->slider, 0x80);
  Serial.print(" Buttons A: ");
    PrintHex<uint8_t>(evt->buttons_a, 0x80);
    Serial.print(" Buttons B: ");
    PrintHex<uint8_t>(evt->buttons_b, 0x80);
    Serial.println("");
}

.h
#if !defined(__HIDJOYSTICKRPTPARSER_H__)
#define __HIDJOYSTICKRPTPARSER_H__

#include <usbhid.h>

struct GamePadEventData {};

struct ST290 {};
struct LogitechGamePro {};

class JoystickEvents
{
public:
    virtual void OnGamePadChanged(const GamePadEventData *evt);
};

#define RPT_GAMEPAD_LEN sizeof(GamePadEventData)/sizeof(uint8_t)

class JoystickReportParser : public HIDReportParser
{
    JoystickEvents      *joyEvents;

  uint8_t oldPad[RPT_GAMEPAD_LEN];

public:
    JoystickReportParser(JoystickEvents *evt);

    virtual void Parse(USBHID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf);
};

#endif // __HIDJOYSTICKRPTPARSER_H__

Error from Example code 2:
sketch\le3dp_rptparser.cpp: In member function 'virtual void JoystickReportParser::Parse(USBHID*, bool, uint8_t, uint8_t*)':
le3dp_rptparser.cpp:36:54: error: no matching function for call to 'JoystickEvents::OnGamePadChanged(GamePadEventData&)'
             joyEvents->OnGamePadChanged(currentValues);
                                                      ^
In file included from sketch\le3dp_rptparser.cpp:1:0:
sketch\le3dp_rptparser.h:43:15: note: candidate: virtual void JoystickEvents::OnGamePadChanged(const GamePadEventData*)
  virtual void OnGamePadChanged(const GamePadEventData *evt);
               ^~~~~~~~~~~~~~~~
sketch\le3dp_rptparser.h:43:15: note:   no known conversion for argument 1 from 'GamePadEventData' to 'const GamePadEventData*'
sketch\le3dp_rptparser.cpp: At global scope:
le3dp_rptparser.cpp:46:6: error: prototype for 'void JoystickEvents::OnGamePadChanged(GamePadEventData*)' does not match any in class 'JoystickEvents'
 void JoystickEvents::OnGamePadChanged(GamePadEventData *evt)
      ^~~~~~~~~~~~~~
In file included from sketch\le3dp_rptparser.cpp:1:0:
le3dp_rptparser.h:43:15: error: candidate is: virtual void JoystickEvents::OnGamePadChanged(const GamePadEventData*)
  virtual void OnGamePadChanged(const GamePadEventData *evt);
               ^~~~~~~~~~~~~~~~
exit status 1
no matching function for call to 'JoystickEvents::OnGamePadChanged(GamePadEventData&)'

Reading and understanding a report descriptor can be a bit of a black art at times. They're quite cryptic when you first look at them, but actually they make perfect sense.
If you think of each entry (except "input" or "output") as setting some configuration value, and the "input" and "output" entries as using those configuration values, it makes more sense.
Since you are only working with gamepads and joysticks (essentially the same thing) much of the descriptor can be ignored (however you sill have to parse it to get to the other stuff).  So let's take your example descriptor a line (or group of lines) at a time and see what they all mean, and what they mean to you.
Usage Page Gen Desktop Ctrls(01)
Usage Game Pad
Collection Application
Usage Pointer
Collection Physical
Usage Page Gen Desktop Ctrls(01)

You don't much care about these from a data perspective, but they do define what the following data is interpreted as. This tells you that "The following data is for configuring the pointer aspect (direction, not mouse pointer) of a game pad.
Usage X
Usage Y

These are the parameters that we are now configuring (joystick X and Y movement). We group them together because they have common settings and parameters. Those parameters are coming up.
Logical Min(00)
Logical Max(FF03)
Physical Min(00)
Physical Max(FF03)

This is the range of the values that we are going to be reporting, and what that range means. In this case there is a 1:1 mapping between the values the joystick reports (Logical) and what those values map to (Physical). We see a better usage of this later on.  The numbers are "little endian", which means that "FF03" is actually "0x03FF", so the joystick reports values between 0 and 1023.
Unit(00)

This defines the physical units of the value being reported. In this case there are no units. Again we see a better usage of this later on.
Report Size(0A)
Report Count(02)

Now we get into the nitty gritty of the data being sent.  This tells us that each report value is 0x0A (10) bits in size, and there are 2 of them. That's 1 report for the X value of 10 bits, and 1 report for the Y value of 10 bits (in that order, since that is the order of the "Usage" lines above).
So so far we have 20 bits of data in our report that are laid out in bytes as:
XXXXXXXX
YYYYYYXX
....YYYY

There's 4 bits not filled in our bytes yet, but don't worry, they're coming soon. Next comes the "Input" entry:
Input(00000010)

This is where it actually creates the data in the report according to the settings we have set above.  The 00000010 tells us that it's a variable data value that is being sent.
Now we have another similar chunk for the Z (throttle) and Rz (rotational Z) values:
Usage Rz
Usage Z
Logical Min(00)
Logical Max(FF01)
Physical Min(00)
Physical Max(FF01)
Unit(00)
Report Size(09)
Report Count(02)
Input(00000010)

This is almost the same as above, but the numbers are different.  We have 2 usages of Rz and Z (in that order), and they report values between 0 and 0x01FF (511).  Again there are no units to these numbers.  The report size is 9 bits (by the way, 29-1 is 511), and there are two reports, one for Rz and one for Z.
So lets feed these into our bytes, 9 bits of z (I'll use "z" for Rz) and 9 for Z:
XXXXXXXX
YYYYYYXX
zzzzYYYY
ZZZzzzzz
..ZZZZZZ

You see we still have two bits unused in our bytes. HID reports don't like unused bits, so we need to pad those out before moving on to a new area of interest:
Report Size(01)
Report Count(02)
Input(00000001)

Here we're defining a report size of 1 bit and there's two reports. That's 2 bits. These are our padding bits to fill out those extra two bits above. You see the Input entry has a different number with it.  00000001 tells us that this is constant data. It's nothing that will ever change - just padding.
So now our HID report looks like:
XXXXXXXX
YYYYYYXX
zzzzYYYY
ZZZzzzzz
00ZZZZZZ

Now we move on to the "Hat switch", which is somewhat similar, but not quite:
Usage Hat Switch
Logical Min(01)
Logical Max(08)
Physical Min(00)
Physical Max(3B01)
Unit(14)
Report Size(08)
Report Count(01)
Input(00000010)

Here we have 1 report of 8 bits. We're sending a value between 1 and 8 for the 8 directions of the hat switch (you can only have 1 direction at a time), and we're using an entire byte to send that value in. It sounds wasteful, given that we only need 4 bits to represent the number 8, but remember we would have to pad the other 4 bits with a constant value to bring it up to a round byte. So it's simpler to just use the whole byte in this instance and save having to have a padding section in the descriptor.
You notice that the logical and physical min and max differ in this section. That shows you what you would map the logical values to in a "real world" situation.  In this case the values 1-8 map to the real values 0-315 (0x01b3). It's up to you if you actually do that mapping or not. What are those numbers though? Well, if you divide 315 by 8 (the number of hat positions) you get 45. And each hat position is a 45° increment. So they must map to degrees. And look, "Unit" hs a value of 0x14 in it. If we look that up we see that 0x14 corresponds to "English Rotational Angular Position", or "degrees" in normal speech.
We can now add that to our report format:
XXXXXXXX
YYYYYYXX
zzzzYYYY
ZZZzzzzz
00ZZZZZZ
HHHHHHHH

And finally we have 6 buttons:
Usage Page Button(09)
Usage Min(01)
Usage Max(06)
Logical Min(00)
Logical Max(01)
Physical Min(00)
Physical Max(01)
Report Size(01)
Report Count(06)
Input(00000010)

There is no "Button 1" etc usage in HID, but you can define a range for the usage, which is what has been done here. Basically since we're in the "buttons" usage page we define a range of 1-6 for the buttons - so there's button 1 to button 6 inclusive.
Each button is either 0 or 1 (not pressed, or pressed), and that's the same "In the real world".  Each button has a 1 bit report, since that's all you need, and there are 6 reports, one for each button.
Again we're only using 6 out of the 8 bits of a byte for this, so we pad it out with two more constant bits:
Report Size(01)
Report Count(0A)
Input(00000001)

So if we now add those buttons we get our final report format:
XXXXXXXX
YYYYYYXX
zzzzYYYY
ZZZzzzzz
00ZZZZZZ
HHHHHHHH
00654321

So you have 7 bytes of data that you then have to split up and recombine in the right way with all sorts of bit shifting and masking to extract the real values. And of course this varies from joystick to joystick.
As you can guess writing a parser not only for the HID descriptor itself, but to extract the data in accordance with that descriptor, will be quite a task. Some joysticks will have the values all packed together, some won't. Some will need to have things read in one order, and some in another. Some will have more buttons, or more axes of motion than others.
You can read the HID 1.11 specification here which will tell you all about how the raw numbers map to the different things.
The existing parser code is looking for things in hard coded positions in the data coming in and is doing it in very basic ways. It doesn't honour the report descriptor in any way, and instead just takes each byte as an axis.
You would need to re-write that entire Parse() function (or create a child class that overrides it) to use the information you have parsed from the report descriptor to extract the values from the data bytes in the right way. Given the myriad ways it could be done you will have quite a task ahead of you. It would be easier to just support specific joysticks and hard-code the options for them, maybe make a separate subclass for each joystick each with its own overridden Parse() function. It's up to you to then use the different classes in your code as you need.

To address your other problems:

In the header file have the definitions for your structs:

struct LogitechGamePro
{
  union { //axes and hut switch
    uint32_t axes;
    struct {
      uint32_t x : 10;
      uint32_t y : 10;
      uint32_t twist : 9;
      uint32_t slider : 10;
    };
  };
  uint8_t hat;
  uint8_t buttons_a;
  uint8_t buttons_b;
};

struct GamePadEventData
{
  union { //axes and hut switch
    uint32_t axes;
    struct {
      uint32_t x : 10;
      uint32_t y : 10;
      uint32_t twist : 9;
      uint32_t slider : 10;
    };
  };
  uint8_t hat;
  uint8_t buttons_a;
  uint8_t buttons_b;
};

In the .cpp file use those for casting and population:

void JoystickReportParser::Parse(USBHID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf)
{

    struct GamePadEventData currentValues;

    bool match = true;

    // Checking if there are changes in report since the method was last called
    for (uint8_t i=0; i<RPT_GAMEPAD_LEN; i++) {
        if( buf[i] != oldPad[i] ) {
            match = false;
            break;
        }
    }
    // Calling Game Pad event handler
    if (!match && joyEvents) {
        // if (joystick is the logitech game pro) {
            // Overlay the struct on top of the data by casting it to
            // a new variable
            struct LogitechGamePro *jsdata = (LogitechGamePro *)buf;

            // Copy values from the temporary overlaid struct into
            // a real variable of the right type for the callback
            currentValues.x = jsdata->x;
            currentValues.y = jsdata->y;
            currentValues.z = jsdata->z;
            // etc

            // Call the callback with that real variable
            joyEvents->OnGamePadChanged(&currentValues);
        // } else if (joystick is some other joystick) {
        //     do the same as above with a different joystick struct
        // } ... etc ...

        for (uint8_t i=0; i<RPT_GAMEPAD_LEN; i++) oldPad[i] = buf[i];
    }

}

thanks so much, this helped me to actually understand the report desc. It's unfortunate that I don't have the coding skills to rewrite the parse function to use the report descriptor.
For changing the specific options for each joystick, I assume I would need to change the struct GamePadEventData?
would I do something like this: (from example)
uint32_t x : 10;
uint32_t y : 10;
and change the numbers after?
I am probably wrong but do those numbers after correspond to the range of each axis? (mins/maxs),  Thanks again

Yep, using a packed struct like that is a good way of extracting the data.

Hello, I used the struct and it is almost working perfectly. The only issue is that the twist is flickering between 256 and 768. I have edited a sample in my original question from the serial monitor. It happens whenever the slide isn't at the 0 and happens much more quickly when the slide is in motion. Any advice is appreciated thankyou

Okay, I sorted the problem out. For anyone wondering I had the packed struct a bit wrong. Trial and error for about a minute sorted it for me but you could do it with the report descriptor instead.

My issue is now selecting between structs. My original plan was to have an array for each joystick type and then selecting which array to use to fill in the numbers for the struct. Unfortunately, the order of each axis matters so that's a no go. I am not great at c but know the basics. How would you suggest changing between packed structs? Thanks

You would probably want a big if-then-else (or a switch/case) to overlay the struct over the byte array of the incoming data (cast it), then copy the values from the struct into some standard other struct / array to use later in your program.

Ah okay thankyou, that clears it up.

Hey, I'm trying to wrap the struct in an if statement but its just giving me expected unqualified-id before 'if' Any ideas?
Thanks

Not without seeing your code.

good point, I'll edit it into the question with a more details

I added a section of a simple version of what I'm trying to do with some details of another way I went about it.

@VosemMedia There's nothing wrong with that snippet. It compiles fine. And it's a perfectly valid way of doing it.

It doesn't seem to compile for me, probably because its in a header file? I moved the header/cpp to the top of the ino and it still didn't compile. I added a larger portion of my code in. Thanks

Your if must be inside a function. Executable code outside a function is not valid C.

hmm interesting, thankyou. I added in a void function (edited in the original question) and now it's giving me 'GamePadEventData' does not name a type from the .cpp file. Any further ideas? I don't know why putting it in a function/if statement is bringing these problems. Thanks again

Your structure only exists within the scope it is defined in: in this case the function you just wrapped it in.

so I should put everything in that file into a single function?

You should put things in the areas where they are needed. You should first define multiple structs with different names. Then in your packet decoder you cast your incoming data to one of the structs depending on which joystick is connected. Then you copy your data from that cast variable struct to your live data struct. It's those last bits that go in the if, not the definition of the struct.

So in my .h file, I should declare multiple structs for each type of joystick, then where and how should I move the data from the selected struct (e.g logitech joystick) into the live struct. Should I do it in the cpp file? if so, should I wrap all of the areas that require the struct in a single function? Thanks

Yes, do it in the CPP file. In the parse function. Use casting of the data array: if (joystick == LOGITECH_GAME_PRO) {struct LogitechGamePro *jsdata = (struct LogitechGamePro *)data; mydata.x = jsdata->x; ... } for example.

Thanks for the code, I have a couple of questions. If I declare my structs in the CPP file and change the data in the live struct in a CPP function, how will the .h functions get access to it? It's giving me a gamepaddata does not give a type, presumably because it's not defined in the .h file. How can the .h get access to it defined in the cpp? Also, from your code, would I edit to to look something like struct GamePadEventData (the live one) *jsdata = (struct LogitechGamePro (the one we want to chage the live one to) *)data; mydata.x = jsdata->x;  and also add more eg mydata.y = ...

No. GamePadEventData is the struct that would define the variable you want to copy to (mydata in that example).

Ah okay that makes more sense, so the mydata is an example struct which you copy to. I am still getting virtual void OnGamePadChanged(const GamePadEventData *evt); exit status 1 'GamePadEventData' does not name a type from the header. It's because I am declaring the structs in the CPP. What do you reccomend? Thanks

Declare the structs in the .h file (that is, just the struct foo {...}; portion). Use the structs in the CPP file as variable types.

Okay, I removed all the nonsense I had before and am trying to get the bare bones working. I removed the casting of structs because that's a separate problem that ill tackle after this first one. I declared the structs in the .h like you recommended but populated them in the .cpp (as you can see in the code I edited in). Unfortunately, I am getting a redeclaration error (in the .cpp) because I have previously created them in the .h. I would have thought, just removing the struct variable type would have sorted it but I don't think you can do that in C. Thanks

Your empty structs in the .h should be the full structs that are currently in the .cpp. The structs in the .cpp should not exist.

I have edited in some example code to the end of my answer.

Thankyou for all that example code, I think i'm finally wrapping my head around it all. its bringing up one error, no matching function for call to 'JoystickEvents::OnGamePadChanged(GamePadEventData&)' from the line joyEvents->OnGamePadChanged(currentValues); thanks. I also added in the full error into the bottom of my question

Probably needs to be a pointer actually...

Thank you so much, that got it working perfectly. I know the question was super old when I put a new comment and I would have understanded if you just ignored it. Cheers for helping me this has sorted all of my issues :)

Glad to be of help.


text:
Mega: attachInterrupt on pin 18/19/20/21 not working
Task:
I'm trying to create a fan-control with the arduino mega. I'm generating a PWM signal on pin 6 and 7 and want to use interrups to measure the rpm of the fans.
Problem:
On pin 2 and 3 everything wors fine, but I cannot get it working on any of pins 18-21. The numbers are jumping around wildly. BUT: The numbers are correct on 0% and 100% duty!
What I've aleady tried:

Changed my timer from 1 to 4 (currently it's 4)
Replaced the display to get rid of U8g2lib.
Changing connection order of the signal cables (and thus the connected fan).
Check the signal with an digital oscilloscope (looks fine on all ports)
Set the global ISR variables to volatile and byte to prevent update hazards.
Bang my head on the table.

Nothing solved my problem. What am I missing?
    #include <Arduino.h>
    #include <U8g2lib.h>
    #include <Bounce2.h>

    #ifdef U8X8_HAVE_HW_SPI
    #include <SPI.h>
    #endif
    #ifdef U8X8_HAVE_HW_I2C
    #include <Wire.h>
    #endif

    U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/U8X8_PIN_NONE);

    #define PIN_CONTROL_S 6
    #define PIN_CONTROL_L 7
    #define PIN_SENSE_1 18
    #define PIN_SENSE_2 19
    #define PIN_SENSE_3 3
    #define PIN_SENSE_4 2
    #define PIN_BUTTON 22

    #define UPDATE_CYCLE 1000 // Refresh interval of the display/measurement.
    #define SIGNAL_PER_RND 2  // 2 Signals per revolution
    #define DUTY_INC 10       // Increate of the duty in % per button press
    #define PWM_MAX 320       // PWM mode counts up 320 then down 320 counts (25kHz)
    #define lineOffset 10     // Offset (y) per line on display

    word duty = 0;  // 0-100 duty cycle
    word dutyS = 0; // 0-320 = 0-100% duty cycle for small fans
    word dutyL = 0; // 0-320 = 0-100% duty cycle for large fans

    volatile byte counterFan1 = 0;
    volatile byte counterFan2 = 0;
    volatile byte counterFan3 = 0;
    volatile byte counterFan4 = 0;

    unsigned long lastDraw = 0;

    Bounce btnBouncer = Bounce(PIN_BUTTON, 50);

    void setupPwm() {
        // Steuerung
        pinMode(PIN_CONTROL_S, OUTPUT);
        pinMode(PIN_CONTROL_L, OUTPUT);

        // Sensoren
        pinMode(PIN_SENSE_1, INPUT_PULLUP);
        pinMode(PIN_SENSE_2, INPUT_PULLUP);
        pinMode(PIN_SENSE_3, INPUT_PULLUP);
        pinMode(PIN_SENSE_4, INPUT_PULLUP);

        // Clear timer register
        TCCR4A = 0;
        TCCR4B = 0;
        TCCR4C = 0;
        TCNT4 = 0;

        TCCR4A |= _BV(WGM41);  // Set PWM mode, phase correct. TOP is ICR1.  (Mode 10)
        TCCR4B |= _BV(WGM43);  // Start BOTTOM, TOP from OCR1x to OCR1x.

        TCCR4B |= _BV(CS40);   // Prescaler 1:1

        TCCR4A |= _BV(COM4A1); // High output OC1A on compareMatch when up-counting / low when down-counting
        TCCR4A |= _BV(COM4B1); // High output OC1B on compareMatch when up-counting / low when down-counting

        OCR4A = dutyS;         // set initial duty
        OCR4B = dutyL;         // set initial duty

        ICR4 = PWM_MAX; // TOP for TCNTx. 320 => @16Mhz CPU -> 25kHz PWM
    }

    void setupDisplay() {
        u8g2.begin();
        u8g2.setFont(u8g2_font_6x10_tf);
        u8g2.setFontRefHeightExtendedText();
        u8g2.setDrawColor(1);
        u8g2.setFontPosTop();
        u8g2.setFontDirection(0);
    }

    void attachInterrups() {
        attachInterrupt(digitalPinToInterrupt(PIN_SENSE_1), isrFan1, RISING);
        attachInterrupt(digitalPinToInterrupt(PIN_SENSE_2), isrFan2, RISING);
        attachInterrupt(digitalPinToInterrupt(PIN_SENSE_3), isrFan3, RISING);
        attachInterrupt(digitalPinToInterrupt(PIN_SENSE_4), isrFan4, RISING);
    }

    void detachInterrups() {
        detachInterrupt(digitalPinToInterrupt(PIN_SENSE_1));
        detachInterrupt(digitalPinToInterrupt(PIN_SENSE_2));
        detachInterrupt(digitalPinToInterrupt(PIN_SENSE_3));
        detachInterrupt(digitalPinToInterrupt(PIN_SENSE_4));
    }

    void setup() {
        setupDisplay();
        setupPwm();
        attachInterrups();

        pinMode(PIN_BUTTON, INPUT_PULLUP);
    }

    void draw(void) {
        char output[22]; // One line of the display can show 21 characters.
        float uPerSekS1 = counterFan1; // * 60000 / measureDuration / SIGNAL_PER_RND;
        float uPerSekS2 = counterFan2; // * 60000 / measureDuration / SIGNAL_PER_RND;
        float uPerSekL1 = counterFan3; // * 60000 / measureDuration / SIGNAL_PER_RND;
        float uPerSekL2 = counterFan4; // * 60000 / measureDuration / SIGNAL_PER_RND;
        int y = 0;

        sprintf(output, "Duty    :    %3d", duty);
        u8g2.drawStr(0, y, output);

        y += lineOffset;
        sprintf(output, "U/sec S1: %6d", (int) uPerSekS1);
        u8g2.drawStr(0, y, output);

        y += lineOffset;
        sprintf(output, "U/sec S2: %6d", (int) uPerSekS2);
        u8g2.drawStr(0, y, output);

        y += lineOffset;
        sprintf(output, "U/sec L1: %6d", (int) uPerSekL1);
        u8g2.drawStr(0, y, output);

        y += lineOffset;
        sprintf(output, "U/sec L2: %6d", (int) uPerSekL2);
        u8g2.drawStr(0, y, output);
    }

    void measure() {
        unsigned long measureDuration = millis() - lastDraw;
        if (measureDuration >= UPDATE_CYCLE) {
            // Deactivate interrupt while we are calculating
            detachInterrups();

            u8g2.clearBuffer();
            draw();
            u8g2.sendBuffer();

            // reset state
            counterFan1 = 0;
            counterFan2 = 0;
            counterFan3 = 0;
            counterFan4 = 0;
            lastDraw = millis();

            // Reactivate interrupt
            attachInterrups();
        }
    }

    void loop() {
        measure();
        btnBouncer.update();
        if (btnBouncer.fell()) {
            // Button was pressed. Increase duty.
            if (duty > 90) {
                duty = 0;
            } else {
                duty += DUTY_INC;
            }

            dutyS = duty * PWM_MAX / 100;
            dutyL = duty * PWM_MAX / 100;

            OCR4A = dutyS;
            OCR4B = dutyL;
        }
    }

    void isrFan1() {
        counterFan1++;
    }

    void isrFan2() {
        counterFan2++;
    }

    void isrFan3() {
        counterFan3++;
    }

    void isrFan4() {
        counterFan4++;
    }

Edit:
I've tried my best to create a readable circuit diagram. The 4-pin connectors represent the fans.

Ok, maybe it is an electronical issue? I just double checked my statements and connected the oscilloscope simultaneously to the arduino and it looked like the osci is stabilizint the results...
I'm using a 5KΩ pull up resistance. Is that ok?

I can't understand what the duty cycle has to do with reading the pulses. What happens if you unplug 6 and 7 and turn the fans with your hand? Are you sure the 8 bit counters do not overflow when the fan turns fast?

@EdgarBonet If i unplugg 6/7 the fans will go up to 100%. I've forgotten to mention I'm using 4pin PC fans. They are connected to 12V and get regulated by the 25KHz PWM I'm generatingion the third pin. The fourth pin is the signal pin with two signals per round.

@EdgarBonet  ...and 8 bit are not overflowing. The measurement interval is currently 1 sec, and I get up to 50 signals per measurement cycle.

what is wired to interrupt pins and how?

Ok, I did not solve the problem regarding pin 18-21, but I found an other solution: using PinChangeInterrupts and the PinChangeInterrupt libary
I did not change anything about my hardware setup, excep moving the wires from pin 18/19 to A8/A9. I've changed my code to use PinChangeInterrups for two of the fans, maybe I'll change all 4 fans.
Here is the new code:
#include <Arduino.h>
#include <U8g2lib.h>
#include <Bounce2.h>
#include <PinChangeInterrupt.h>

#ifdef U8X8_HAVE_HW_SPI
#include <SPI.h>
#endif
#ifdef U8X8_HAVE_HW_I2C
#include <Wire.h>
#endif

U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/U8X8_PIN_NONE);

#define PIN_CONTROL_S 6
#define PIN_CONTROL_L 7

//#define PIN_SENSE_1 18
//#define PIN_SENSE_2 19
#define PIN_SENSE_1 A8
#define PIN_SENSE_2 A9

#define PIN_SENSE_3 3
#define PIN_SENSE_4 2
#define PIN_BUTTON 22

#define UPDATE_CYCLE 1000 // Refresh interval of the display/measurement.
#define SIGNAL_PER_RND 2  // 2 Signals per revolution
#define DUTY_INC 10       // Increate of the duty in % per button press
#define PWM_MAX 320       // PWM mode counts up 320 then down 320 counts (25kHz)
#define lineOffset 10     // Offset (y) per line on display

word duty = 0;  // 0-100 duty cycle
word dutyS = 0; // 0-320 = 0-100% duty cycle for small fans
word dutyL = 0; // 0-320 = 0-100% duty cycle for large fans

volatile byte counterFan1 = 0;
volatile byte counterFan2 = 0;
volatile byte counterFan3 = 0;
volatile byte counterFan4 = 0;

unsigned long measureDuration;
unsigned long lastDraw = 0;

Bounce btnBouncer = Bounce(PIN_BUTTON, 50);

void setupPwm() {
    // Steuerung
    pinMode(PIN_CONTROL_S, OUTPUT);
    pinMode(PIN_CONTROL_L, OUTPUT);

    // Sensoren
    pinMode(PIN_SENSE_1, INPUT_PULLUP);
    pinMode(PIN_SENSE_2, INPUT_PULLUP);
    pinMode(PIN_SENSE_3, INPUT_PULLUP);
    pinMode(PIN_SENSE_4, INPUT_PULLUP);

    // Clear timer register
    TCCR4A = 0;
    TCCR4B = 0;
    TCCR4C = 0;
    TCNT4 = 0;

    TCCR4A |= _BV(WGM41);  // Set PWM mode, phase correct. TOP is ICR1.  (Mode 10)
    TCCR4B |= _BV(WGM43);  // Start BOTTOM, TOP from OCR1x to OCR1x.

    TCCR4B |= _BV(CS40);   // Prescaler 1:1

    TCCR4A |= _BV(COM4A1); // High output OC1A on compareMatch when up-counting / low when down-counting
    TCCR4A |= _BV(COM4B1); // High output OC1B on compareMatch when up-counting / low when down-counting

    OCR4A = dutyS;         // set initial duty
    OCR4B = dutyL;         // set initial duty

    ICR4 = PWM_MAX; // TOP for TCNTx. 320 => @16Mhz CPU -> 25kHz PWM
}

void setupDisplay() {
    u8g2.begin();
    u8g2.setFont(u8g2_font_6x10_tf);
    u8g2.setFontRefHeightExtendedText();
    u8g2.setDrawColor(1);
    u8g2.setFontPosTop();
    u8g2.setFontDirection(0);
}

void attachInterrups() {
//    attachInterrupt(digitalPinToInterrupt(PIN_SENSE_1), isrFan1, RISING);
    attachPCINT(digitalPinToPCINT(PIN_SENSE_1), isrFan1, RISING);

//    attachInterrupt(digitalPinToInterrupt(PIN_SENSE_2), isrFan2, RISING);
    attachPCINT(digitalPinToPCINT(PIN_SENSE_2), isrFan2, RISING);

    attachInterrupt(digitalPinToInterrupt(PIN_SENSE_3), isrFan3, RISING);
    attachInterrupt(digitalPinToInterrupt(PIN_SENSE_4), isrFan4, RISING);
}

void detachInterrups() {
//    detachInterrupt(digitalPinToInterrupt(PIN_SENSE_1));
    detachPinChangeInterrupt(digitalPinToPCINT(PIN_SENSE_1));

//    detachInterrupt(digitalPinToInterrupt(PIN_SENSE_2));
    detachPinChangeInterrupt(digitalPinToPCINT(PIN_SENSE_2));

    detachInterrupt(digitalPinToInterrupt(PIN_SENSE_3));
    detachInterrupt(digitalPinToInterrupt(PIN_SENSE_4));
}

void setup() {
//    cli();
    setupDisplay();
    setupPwm();
    attachInterrups();

    pinMode(PIN_BUTTON, INPUT_PULLUP);
//    sei();
}

void draw() {
    char output[22]; // One line of the display can show 21 characters.
    float uPerSekS1 = counterFan1 * 60000 / measureDuration / SIGNAL_PER_RND;
    float uPerSekS2 = counterFan2 * 60000 / measureDuration / SIGNAL_PER_RND;
    float uPerSekL1 = counterFan3 * 60000 / measureDuration / SIGNAL_PER_RND;
    float uPerSekL2 = counterFan4 * 60000 / measureDuration / SIGNAL_PER_RND;
    int y = 0;

    sprintf(output, "Duty    :    %3d", duty);
    u8g2.drawStr(0, y, output);

    y += lineOffset;
    sprintf(output, "U/sec S1: %6d", (int) uPerSekS1);
    u8g2.drawStr(0, y, output);

    y += lineOffset;
    sprintf(output, "U/sec S2: %6d", (int) uPerSekS2);
    u8g2.drawStr(0, y, output);

    y += lineOffset;
    sprintf(output, "U/sec L1: %6d", (int) uPerSekL1);
    u8g2.drawStr(0, y, output);

    y += lineOffset;
    sprintf(output, "U/sec L2: %6d", (int) uPerSekL2);
    u8g2.drawStr(0, y, output);
}

void measure() {
    measureDuration = millis() - lastDraw;
    if (measureDuration >= UPDATE_CYCLE) {
        // Deactivate interrupt while we are calculating
        detachInterrups();

        u8g2.clearBuffer();
        draw();
        u8g2.sendBuffer();

        // reset state
        counterFan1 = 0;
        counterFan2 = 0;
        counterFan3 = 0;
        counterFan4 = 0;
        lastDraw = millis();

        // Reactivate interrupt
        attachInterrups();
    }
}

void loop() {
    measure();
    btnBouncer.update();
    if (btnBouncer.fell()) {
        // Button was pressed. Increase duty.
        if (duty > 90) {
            duty = 0;
        } else {
            duty += DUTY_INC;
        }

        dutyS = duty * PWM_MAX / 100;
        dutyL = duty * PWM_MAX / 100;

        OCR4A = dutyS;
        OCR4B = dutyL;
    }
}

void isrFan1() {
    counterFan1++;
}

void isrFan2() {
    counterFan2++;
}

void isrFan3() {
    counterFan3++;
}

void isrFan4() {
    counterFan4++;
}


text:
Serial Interrupt
I want to create a simple program, that responds to me sending a character over the Arduino IDE console. I am using an arduino UNO. Here is my program:
volatile bool MeasReceived=false;

ISR(PCINT2_vect){
  PCICR = 0b00000000;    // turn off port d
  MeasReceived=true;
}

void setup() {
  Serial.begin(9600);
  Serial.flush();

  Serial.print("Hello PC");
  delay(1000);
  cli();
  PCICR |= 0b00000100;    // turn on port d
  PCMSK2 |= 0b0000001;    // turn on pins PD0 , PCINT16
  sei();

}

void loop() {

  if(MeasReceived==true){
    MeasReceived=false;
    inByte = Serial.read();

    if(inByte=='A'){   //A: PC requests measurement data from Arduino
       Serial.print('B');
    }
    else{
      Serial.print(inByte);
    }
  }
  PCICR = 0b00000001; // re-enable port d
}

What I do is that I set the RX pin as a pin change interrupt. After that, I send a character through the console, for example 'A'. The ISR kicks in, firstly disabling the interrupt, and after that, the flag is set true. That way, I enter the part of the code where I do the Serial.read() command, to find what character was sent to me via the console.
The problem is that, no matter the character I send, the result is always 255. That means that the value of inByte, after the Serial.read() is always 255. What goes wrong?
EDIT: Original question answered by me below. However, one interesting thing occured in the new code posted below. If I put the Arduino to sleep (powerDown Mode), and try to wake it up with the serial interrupt, if I send only one character, then the arduino does wake up, but does not enter the ISR! If I send two characters, then the ISR is accessed and the flags set, with the program working fine. Here is the code, to reproduce the issue:
volatile bool MeasReceived=false;
uint8_t inByte;

ISR(PCINT2_vect){
  PCMSK2 = 0b00000000;    // turn off port d
  MeasReceived=true;
}

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);

  Serial.begin(9600);
  Serial.flush();
  Serial.print("Hello PC");
  delay(1000);

  cli();
  PCICR = 0b00000100;    // turn on port d
  PCMSK2 = 0b00000001;    // turn on pins PD0 , PCINT16
  sei();
}

void loop() {

  if(MeasReceived==true){
    MeasReceived=false;
    delay(2000);
    inByte = Serial.read();

    if(inByte=='A'){   //A: PC requests measurement data from Arduino
       Serial.print('B');
    }
    else{
      Serial.print(inByte);
    }
    PCMSK2 = 0b00000001;

  }

  set_sleep_mode(SLEEP_MODE_PWR_DOWN);    //Set power down mode
  sleep_bod_disable();  //disable brown-out detection
  digitalWrite(LED_BUILTIN, LOW);
  sleep_enable();
  sleep_cpu();
  sleep_disable();
  digitalWrite(LED_BUILTIN, HIGH);
  delay(1000);
  //int i=Serial.available();
  //Serial.print(i);
  delay(1000);

}

So, by sending one character, the Arduino wakes up, the LED shines, and after the two seconds, Arduino goes back to sleep, never entering the ISR and as a result not setting the flag. Furthermore, having sent one character, if I uncomment the Serial.available() printing, it prints "0"!
If I send two characters, the Arduino wakes up, and the program works fine.

have you seen this? ... https://www.arduino.cc/reference/en/language/functions/communication/serial/serialevent/

and this .. https://stackoverflow.com/questions/53104440/how-to-implement-interrupt-for-serial-usart-communication-for-atmega328p-arduino

Why do you want to use the pin change interrupt here? I don't see  why this should be done, since the Serial (UART) interface has its own interrupts.

@chrisl I need the best possible power saving, which is given by PWR_DWN mode. In order to wake up from that mode, I need to use pin change interrupt to my UART RX.

Your diagnostic about the interrupt handled too fast is correct. When a
byte arrives at the serial port, the start bit will trigger the
interrupt, but the byte is only available for reading once the UART
receives the stop bit, which is about one millisecond later.

to disable/re-enable the pin-change interrupt, the right way seems to
be to use the PCMSK register and not the PCICR.

The canonical procedure for enabling any edge-triggered interrupt is
to first clear the interrupt flag, then set the interrupt enable bit.
Note that the interrupt flag is cleared by writing a logic one to it.
For the PCINT2 interrupt that would be:
PCIFR =  _BV(PCIF2);  // clear interrupt flag
PCICR |= _BV(PCIE2);  // enable interrupt

This being said, there is no point in using a pin change interrupt in
the first place. You can instead use the canonical idiom
if (Serial.available() > 0) {
    char inByte = Serial.read();
    // ...
}

If you plan to sleep, you will likely want to do it with the serial port
enabled, in order for it not to miss the start bit. This means you will
use the IDLE sleep mode. Then, when the serial port receives a full
byte, it will wake up the CPU with its own interrupt, so you do not have
to take care of this yourself.

Edit 1: The simplest way to put the CPU to sleep until the next
interrupt is received is to call sleep_mode() at the end of loop(),
e.g.:
// Sleep until the next character is received.
set_sleep_mode(SLEEP_MODE_IDLE);
if (!Serial.available()) {
    sleep_bod_disable();
    sleep_mode();
}

There is, however, a race condition here: if the interrupt fires after
you test Serial.available() but before going to sleep, you will sleep
instead of handling the received character. The solution to this problem
is to do the test with interrupts disabled and then enable them right
before issuing the sleep instruction, as explained in the
documentation of the avr-libc:
set_sleep_mode(SLEEP_MODE_IDLE);
cli();
if (!Serial.available()) {
    sleep_enable();
    sleep_bod_disable();
    sei();
    sleep_cpu();
    sleep_disable();
}
sei();

Edit 2: answering the questions in the comments.

Pin change interrupt allows you to sleep deeper than IDLE, but if you
do so, the UART will be stopped and it will miss the start bit, which
could throw off its timing. I would rather stick with IDLE and use the
power_*_disable() functions to turn off the unneeded peripherals.

I have a theory, though I don't know if it's valid. Look at the
schematic of the PCINT detection. If the clock is stopped, a
change in the pin level will make the XOR gate switch to 1, which
presumably wakes up the MCU, but that will not be recorded by the
downstream flip-flops, which rely on the clock. If the pin returns to
its original level before the clock restarts (which takes some time when
coming out of PWR_DOWN), then the flip-flops never see the pin change
condition, and the interrupt flag does not rise.

Edit 3: I made a test that confirms that, when waking up from
PWR_DOWN by a pulse-triggered PCINT event, the ISR does not run if
the pulse is too short. The setup involves two Arduinos:

the “tester” Arduino:

sends pulses of various lengths through digital 8 = PB0
forwards on TX the data received on RX

the “DUT” Arduino:

sleeps in PWR_DOWN mode
wakes up by pin change interrupt on digital 8 = PB0 = PCINT0
reports whether the ISR ran on the serial port

The connections are:
DUT   Tester    PC
───────────────────
        USB --- USB
GND --- GND
+5V --- +5V
  8 --- 8
 TX --- RX

The “tester” program:
const uint32_t PULSE_PERIOD = 500;  // pulses every 500 ms

void setup() {
    DDRB |= _BV(PB0);  // digital 8 = PB0 as output
    Serial.begin(9600);
    Serial.println("Tester: ready");
}

void loop() {
    // Forward the serial communication.
    while (Serial.available())
        Serial.write(Serial.read());

    // Periodically send a pulse.
    static uint32_t last_pulse_time;
    if (millis() - last_pulse_time >= PULSE_PERIOD) {
        last_pulse_time += PULSE_PERIOD;

        // Send a pulse of 2^n microseconds.
        static uint8_t n = 0;
        uint16_t length = 1U << n;
        Serial.print("Tester: sending pulse of ");
        Serial.print(length);
        Serial.println(" us");
        Serial.flush();
        uint32_t now = millis();
        while (millis() == now) ;  // wait for the tick
        PORTB |= _BV(PB0);
        delayMicroseconds(length);
        PORTB &= ~_BV(PB0);

        // Next pulse size.
        if (++n >= 16) n = 0;
    }
}

The “DUT” program:
#include <avr/sleep.h>

// The PCINT ISR only sets a flag.
volatile bool isr_ran;
ISR(PCINT0_vect) { isr_ran = true; }

void setup() {
    // Setup interrupt.
    PCMSK0 = _BV(PCINT0);  // sense PCINT0 = PB0
    PCIFR |= _BV(PCIF0);   // clear interrupt flag
    PCICR  = _BV(PCIE0);   // enable PCINT0 interrupt

    // Avoid other interrupts.
    TIMSK0 = 0;         // avoid timer interrupt
    PORTD |= _BV(PD0);  // pull RX high to prevent USART_RX interrupt
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);

    Serial.begin(9600);
    Serial.println("DUT: ready");
}

void loop() {
    loop_until_bit_is_clear(PINB, PB0);  // wait for LOW input
    Serial.println("DUT: going to sleep");
    Serial.flush();
    isr_ran = false;
    sleep_mode();
    Serial.print("DUT: woke up, ISR ran: ");
    Serial.println(isr_ran ? "YES" : "NO");
}

And the results:
DUT: going to sleep
Tester: sending pulse of 1 us
DUT: woke up, ISR ran: NO
DUT: going to sleep
Tester: sending pulse of 2 us
...
Tester: sending pulse of 1024 us
DUT: woke up, ISR ran: NO
DUT: going to sleep
Tester: sending pulse of 2048 us
DUT: woke up, ISR ran: YES
DUT: going to sleep
Tester: sending pulse of 4096 us
DUT: woke up, ISR ran: YES
...

Conclusion: a pulse of 1024 µs or shorter wakes up the Arduino but
the ISR does not run. If the pulse is 2048 µs or longer, the ISR
does run.

Thank you for your answer! Two questions: 1) I was using serial.available, but pin change interrupt allows me to sleep deeper. Isn't that right? 2) I incorporated the correct way of enabling pin change interrupts, but the same problem persists. Sending one character wakes the uC, but the ISR is not accessed. Why is that?

To be clear, I do not understand how it is possible to wake up from sleep, and at the same time to not run the ISR code. That is what happens when I send one character from the Arduino IDE console.

@NickG: See updated answer.

Your explanation sounds good. I tested the code using the 'SLEEP_MODE_STANDBY' which only leaves the oscillator running, and it worked as expected. I will leave the question opened  for a few days, in case somebody else would like to add or check what we discussed

After more testing, it seems that the problem was that when I sent the character over the console, the interval between the time t1 that the change was noticed and the ISR was fired, and the time t2 that the Serial.read() happened, was very short, almost immediate. As a result, the byte (character) that I had sent over the serial console was not yet ready to be read, and the Serial.read() command returned plain '1's.
Furthermore, to disable/re-enable the pin-change interrupt, the right way seems to be to use the PCMSK register and not the PCICR. The initially posted code, had the extra problem that, when PCICR was re enabled (set to 0x01), the ISR was immediately fired again, reading an extra character (obviously all '1's). That was solved by disabling/ re-enabling the pin change interrupt using PCMSK register. Here is the corrected code, which seems to work fine:
volatile bool MeasReceived=false;
uint8_t inByte;

ISR(PCINT2_vect){   //ISR for pin-change interrupts occuring at PD0-PD7

  PCMSK2 = 0b00000000;    // turn off PD0 interrupt
  MeasReceived=true;      //Set char received Flag

}

void setup() {

  Serial.begin(9600);
  Serial.flush();
  Serial.print("Hello PC");
  delay(1000);

  cli();
  PCICR = 0b00000100;    // turn on port d pin change interrupts
  PCMSK2 = 0b0000001;    // turn on pin PD0 , PCINT16
  sei();
}

void loop() {

  if(MeasReceived==true){  //If ISR fired
    MeasReceived=false;    //Reset the flag
    delay(1000);           //Wait a while for the character to be set. 1000ms may be too much
    inByte = Serial.read();  // Read the character that was sent

    if(inByte=='A'){   //If the character was A, write B to console
       Serial.print('B');
    }
    else{   //else, write the ASCII code of the character received
      Serial.print(inByte);
    }
    PCMSK2 = 0b00000001;   //re-enable PD0 interrupt
  }
}


text:
Implement two processes at the same time
I am a beginner in arduino and due to the lockdown I have been learning it by implementing it on tinkercad. I have made a simulation where I have attached :

Servo Motor

Ultrasonic Sensor

Led Bulb

LCD display

to an arduino uno 3
My AIM :  When something falls under 30cm of the ultrasonic sensor, the servo motor starts from zero position and goes upto 180 degrees in a span of 20seconds and then goes back to its initial position. At the same time and led switches on for 20s and switches off when the motor returns back to its position.
I was able to successfully implement this. But then I added an lcd to show the time i.e time is initialized at 0seconds and then goes to 20 seconds and when the motor resets. Time also resets.
I was able to make a timer on another simulation and I tried to run it in this one by placing the code correctly but I am not able to figure out how?
The present code I have written keeps blinking the led at an interval of one second and the servo moves very very slowly.
Any sort of help will be amazing.
This is my simulation, I have made it public, you may copy and simulate it if you have a tinkercad account. Even without an account you can see how it looks.
Here is the code:
(Please ask if you want me to add comments some areas)
//library code for lcd
#include <LiquidCrystal.h>
//setting up pins
const int rs = 9, en = 8, d4 = 5, d5 = 4, d6 = 3, d7 = 2;

// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

unsigned long readTime=20;

//servo motor
#include <Servo.h>
Servo servo_9;
int pos = 0;
//servo motor end

//ultrasonic sensor pin
const int pingPin = 12;

//lcd
signed short seconds;
char timeline[16];

void setup()
{

  servo_9.attach(13); //servo pin
  Serial.begin(9600);

  pinMode(11,OUTPUT);// led

  //lcd initialize
  lcd.begin(16, 2);
  lcd.print("Time : ");

}

void loop()
{

  long duration, cm;
  //Ultrasonic start
  // The PING))) is triggered by a HIGH pulse of 2 or more microseconds.
  // Give a short LOW pulse beforehand to ensure a clean HIGH pulse:
  pinMode(pingPin, OUTPUT);
  digitalWrite(pingPin, LOW);
  delayMicroseconds(2);
  digitalWrite(pingPin, HIGH);
  delayMicroseconds(5);
  digitalWrite(pingPin, LOW);

  // The same pin is used to read the signal from the PING))): a HIGH
  // pulse whose duration is the time (in microseconds) from the sending
  // of the ping to the reception of its echo off of an object.
  pinMode(pingPin, INPUT);
  duration = pulseIn(pingPin, HIGH);

  // convert the time into a distance
  cm = microsecondsToCentimeters(duration);

  // Print the distance
  Serial.print("Distance: ");
  Serial.print(cm);
  Serial.print("cm");
  Serial.println();
  // ultrasonic end

  // the servo motor should activate when object is
  //less than 30cm close to the sensor

 if(cm < 30) {

  // sweep the servo from 0 to 180 degrees in steps
  // of 1 degrees
  for (pos = 0; pos <= 180; pos += 1) {

    // tell servo to go to position in variable 'pos'
    servo_9.write(pos);

     //LCD TIMER START
    lcd.setCursor(0, 1);
    sprintf(timeline,"%0.2d secs", seconds);
    lcd.print(timeline);
    delay(1000);
    seconds++;

    //led buld switch on
    digitalWrite(11,HIGH);

    // wait 20ms for servo to reach the position
    delay(200);

    //switch of the bulb
    digitalWrite(11,LOW);

  }

  //moving servo back to zero
  for (pos = 180; pos >= 0; pos -= 1) {
      // tell servo to go to position in variable 'pos'
      servo_9.write(pos);
      // wait 20 ms for servo to reach the position
      delay(20); // Wait for 15 millisecond(s)
            }

    } //if end

  delay(100);

}//loop end

//FUNCTIONS

long microsecondsToCentimeters(long microseconds) {
  // The speed of sound is 340 m/s or 29 microseconds per centimeter.
  // The ping travels out and back, so to find the distance of the
  // object we take half of the distance travelled.
  return microseconds / 29 / 2;
}

This program spends most of its time executing delay(), which does no useful work. Study the Blink Without Delay Arduino tutorial and see if it answers your question.

The servo moves with the speed you programmed it. (And there are delays between the moves. ) And don't think in "multiple processes". It's easier than that and you don't have an operating system on an uno.

@EdgarBonet thank you. I will check it out

@DataFiddler ok sure. Thanks for the guidance !!

Think of an Arduino as a circus clown spinning plates. It has to spend very little time on any one plate, and then it can keep a lot of plates spinning, moving quickly from one to the next.
That's how "multi-tasking" works on a realtime device like an Arduino. You write a loop function that buzzes through a bunch of sub-tasks, spending a few microseconds on each one, and then repeats the process. Each plate (sub-task) gets a little bit of time on each pass, but only a little.
The delay() function is the death of that. If you're in a delay(), everything comes to a screeching halt. Your program stops checking for button presses, stops switching output pins to control your motors, etc. It's like the clown taking a coffee break. The plates start crashing to the ground.
You might get away with single-digit delays for things like timing changes in output state (and delayMicroseconds() is rarely a problem since those delays are so short), but a delay(1000) means everything comes to a screeching halt for a full second.
You need to refactor your code to get rid of calls to delay() with delay values of more than a few milliseconds. Do a search on "Arduino blink without delay" to figure out how.
Note that on a single core device with preemptive multi-tasking, the circus clown analogy still holds, but now the OS serves as the clown's manager. The OS schedules the clown's time, and tells it when to switch between plates. If the clown gets distracted by a particularly shiny plate and tries to spend too long on that plate, the OS forces the clown to switch plates. The OS also saves the clown's current state each time it switches away from a task, and restores that state when it returns to that task.
On A multi-core device with preemptive multi-tasking, the manager (OS) has a team of clowns (cores). Each clown (core) gets assigned to different plates (tasks), and all the clowns work at the same time (The cores run concurrently.) The OS has to make sure the clowns (cores) don't bump elbows (have conflicting access to the same memory or other resources.)

Thanks a lot for the answer. It clears a lot of things for me as I am new here and puts the functioning of arduino in a better perspective.

upvote for the best analogy of multitasking i have seen so far ... the spinning plate circus act may actually be something that almost everyone has seen

Best analogy I've heard for Arduino loops so far. I created an account over here to upvote it..

Thank you again. I was able to refactor my code to make it work after implementing the Arduino Work Without Delay Article


text:
3 input (on/off/off with delay) to control 1device using ESP8266 as Web Server
I want to control one device in three ways : turn on / turn off / turn off with delay.
To do that i use an ESP8266 web server + android phone app.
The problem is that turn off with delay wont work.
It works with delay() but i dont want to use delay() as it stops other functions.
I would be grateful if you could help me.
here is my code :
#include <ESP8266WiFi.h>
const int device1 = 14;
unsigned long previousMillis = 0;
const long interval = 5000;
const char* ssid     = "****";
const char* password = "****";
#include <Arduino.h>
WiFiServer server(80);
String data = "";

void setup() {
 pinMode(device1, OUTPUT);
Serial.begin(115200, SERIAL_8N1, SERIAL_TX_ONLY);
WiFi.begin(ssid, password);
IPAddress ip(*,*,*,*);
IPAddress gateway(*,*,*,*);
IPAddress subnet(*,*,*,*);
WiFi.config(ip, gateway, subnet);
 while (WiFi.status() != WL_CONNECTED) {
   delay(500);
   Serial.print(".");
 }
 Serial.println("");
 Serial.println("WiFi connected");

 server.begin();

 Serial.println(WiFi.localIP());
 }

void loop() {
    unsigned long currentMillis = millis();

  WiFiClient client = server.available();
 if (!client) {
   return;
 }

 while(!client.available()){
 }

 String req = client.readStringUntil('\r');
 client.flush();
 if (req.indexOf("/on") != -1)
   { digitalWrite(device1, HIGH);}
 if (req.indexOf("/off") != -1)
   { digitalWrite(device1, LOW);}

 if (req.indexOf("/delay") != -1)
 {
  unsigned long currentMillis = millis();
  unsigned long previousMillis = millis();
if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;

    digitalWrite(device1, LOW);

}
}

separate out the command decoding and the resulting action .... reception of /on should set a flag ... reception of /off and /delay should clear the flag and set turnoff time   ... the device control is done after the if statements have completed

You have various logic problems:
You block until WiFiClient has bytes available. Everything comes to a stop. So if you send a "/delay" command, it will receive and parse that command, turn on the device, then block again, indefinitely, until you send another command. Once you send another command, it will check the interval ONCE, and then lock up again. You need to rewrite your loop to check for bytes, read them if found, and do other work (like checking your time interval) if no bytes are available.
Next, your timing code is a mess. You only ever set currentMillis and previousMillis at the same time, so they will never be different. And you only ever check the times once when you first detect a "/delay" command.
Instead, refactor your logic. Only set previousMillis when you first detect the delay command, and then only compare if previousMillis to currentMillis if  previousMillis is not 0:
if (req.indexOf("/delay") != -1)
{
    previousMillis = millis();
}

if (previousMillis != 0 && millis() - previousMillis >= interval) {
    digitalWrite(device1, LOW);
    previousMillis = 0;
}

(Also note that you were declaring a second, independent variable  previousMillis inside your if statement, which only exists inside the curly braces for that if statement. Don't do that. Use the existing global variable you defined, as I show in my edited code.)

its not working. im confused.could anyone write the whole sketch in correct way  for me please


text:
what is good practice around initializing variables
Should vars be initialed when declared or in setup fuction?
Safe to assume compiler will initialze?
Boolean x;      --- init to true/false here?
Void setup()
.
.            --- or init here?
.
Void loop()
If (x)       --- x is unknown state if not initialized.

Initializing a global is appropriate if you know in advance that it should always have a given value at startup. The compiler will generate a globals image in ROM that will be copied into RAM before any of your code is executed.

Safe to assume compiler will initialze?

The compiler will initialize to 0, a global not specifically initialized by you. Let's take the case of your Boolean. '0' means 'false', right? So 'x' is pre-initialized to 'false'. But I, as the reader (or yourself, six months later) may not know whether you intended this to be initialized to 'false' (the default value) or forgot to initialize it. Specifying it to be 'false' may not have any different effect on the code, but it does inform me or your future self, that you meant it to be set 'false' at startup. Remember that your code communicates to people as well as to the compiler. Write it so you or I will not only be able to understand it, but won't be able to misunderstand it.
If you initialize it in setup(), the compiler generates code in setup() specifically to do that. If the setup() function needs to decide during startup, what the initial value of that variable should be, then this is the place to do it. Otherwise, the extra code just takes up space in Flash. It's not any more harmful than wasting those few extra bytes of code-space, but it doesn't accomplish anything more than letting the globals image do it.
Whatever you did or didn't do with 'x' at load time or in 'setup()', it will persist into 'loop()', so 'x's state isn't unknown when you get there. (If I misunderstood that part of your question, please edit it in your question.)

I wouldn't be surprised if the compiler is smart enough to see that the variable isn't read before being 'initialized' in your setup function, and skip it's own 0-initialization (that is; producing identical code, whether you initialized globally, or inside the setup function)

I just checked, and initializing a variable inside setup creates a slightly bigger sketch.

Presumably because setup() is just like any other function and may be called at any time. Global initialization is expected to have been done by the time any user code is executed.

There is only one rule to follow, really:
Never read a variable before writing a defined value to it.
You don't need to write explicitly into a variable, because the C++ language distinguishes between two kinds of variables:

Static variables are initialized to all zero bits, if no explicit initialization is done.
Automatic variables are never automatically initialized. Their initial value is that of the memory cells they occupy, if no explicit initialization is done.

Static variables are defined outside any function or method, or with the keyword static.
Automatic variables are all others.
Example:
static int s1; // static, initialized to 0
int s2 = 42; // static, initialized to 42

void setup() {
    int a1; // automatic, has an unknown initial value
    static int s3; // static, initialized to 0
}

void your_function() {
    static int s4 = 23; // static, initialized to 23
    int a2 = 7; // automatic, initialized to 7 each time control flow comes here
}

All static variables are initialized exactly one time, before main() is called. Or in the case of Arduino, before setup() or any other method or function is called.

Oh, another quite important rule: Know, what you are doing, don't guess, be sure.
You might need to read the standard, or at least some good book.
If you use some rare feature, make it explicit or comment.

Additional notes:
The Arduino uses C++. This is a really different language than C.
You can think of main() as:
void main() {
    setup();
    for (;;) {
        loop();
    }
}


text:
Wire Library Timer Usage
I would like to know if the Wire Library is using a Hardware Timer from the Arduino Mega 2560. And If so which Timer it is.
As I am using the Timer 1. After implementing the Wire Library I have some strange things happening that are probably due to the Timer.
Thanks a lot.

No, it's not.
It has its own timer called the "Bit Rate Generator Unit" which is controlled using the TWBR register.  It takes its time source direct from the main CPU clock and divides it down.


text:
Is it possible to exit a loop on the change of an input state?
I would like to exit a particular loop if the state of an input changes from LOW to HIGH. This is the current loop:
void brakeFade() {
pixels.clear();
pixels.setBrightness(255);
pixels.fill(16711680, 0, 0);

for(int i=255; i>=10; i-=1) {
  pixels.setBrightness(i);
  pixels.show();
  delay(5);
  }
for(int j=10; j<=255; j+=1) {
  pixels.setBrightness(j);
  pixels.show();
  delay(5);

}
}
I need that loop to exit if
(digitalRead(brakeFeed) == LOW)

Changes to HIGH during the loop.

there is no reason to use two different named index variables, i and j, in the two for loops ... they can both be i .... increment can be done using i++ instead of i+=1 ... same with decrement

figured it out:
void brakeFade2() {
pixels.clear();
pixels.setBrightness(255);
pixels.fill(16711680, 0, 0);

for(int i=255; i>=10; i-=1) {
  if (digitalRead(brakeFeed) == LOW){
  pixels.setBrightness(i);
  pixels.show();
  delay(5);
  }
  else {
    break;
  }
}
for(int j=10; j<=255; j+=1) {
  if (digitalRead(brakeFeed) == LOW){
  pixels.setBrightness(j);
  pixels.show();
  delay(5);
  }
  else {
    break;
  }
  }

}

simpler way would be to add it to the completion test of the for loop ...  for(int i=255; (i>=10) or (digitalRead(brakeFeed) == LOW);  i--) {

Wouldn't that be for(int i=255; (i>=10) && (digitalRead(brakeFeed) == LOW)? The OP wants the loop to continue as long as is >= 10, and the brakeFeed pin still reads as low. It should break if either of those stops being the case.