# Question
Title: A LED should be lit when 'high'. Why does mine only burn with 'low'?
This is my followup question based on a serie of one project. Go my to profile to read 'm all.

So I'm building something which includes a function that has a count (1000) that decreases over time, but by pressing a soft pot meter the count increases. By every increment of 200 one LED is lit. So if the count is 837 4 LEDs are burning.

In my previous question I had issues lighting the LEDs, because they didn't burn even when the code was, as far as I could see correct. Instead it did the opposite of what I coded. Now I changed my code the opposite direction,

writing:

> digitalWrite(LED1, LOW); // turn the LED on (LOW is the voltage level)

Which actually set the LED to bright. While is I'd write it 'HIGH' it would dim.

So my actual question is: How could my LED be lit if it's set to 'low', while you have to set it to 'high' to be actually popping off light?

---

***My complete code:***

```
int cleanCount = 1000;
int IsItWorkingLED = 13;
int softpotPin = A0; //analog pin 0
int LED1 = 1;
int LED2 = 2;
int LED3 = 4;
int LED4 = 5;
int LED5 = 7;

void setup () {
    Serial.begin(9600);
    digitalWrite(softpotPin, HIGH); //enable pullup resistor
    pinMode(LED1, OUTPUT);
    pinMode(LED2, OUTPUT);
    pinMode(LED3, OUTPUT);
    pinMode(LED4, OUTPUT);
    pinMode(LED5, OUTPUT);

    digitalWrite(LED1, HIGH);   // turn the LED on (HIGH is the voltage level)
    digitalWrite(LED2, HIGH);   // turn the LED on (HIGH is the voltage level)
    digitalWrite(LED3, HIGH);   // turn the LED on (HIGH is the voltage level)
    digitalWrite(LED4, HIGH);   // turn the LED on (HIGH is the voltage level)
    digitalWrite(LED5, HIGH);   // turn the LED on (HIGH is the voltage level)
}

void loop() {
    int softpotReading = analogRead(softpotPin);
    if (softpotReading < 980) { // IF TOUCHED
        digitalWrite(IsItWorkingLED, HIGH);
        ++cleanCount;
        Serial.println(cleanCount);
        delay(8); // Increase 5 times as fast
    }
    else if (softpotReading > 980) { // IF NOT TOUCHED
        digitalWrite(IsItWorkingLED, LOW);
        --cleanCount;
        Serial.println(cleanCount);
        delay(32); // Decrease slowly
    }
    else {      // If there is something wrong..
        Serial.println("Something wrong!");
        digitalWrite(IsItWorkingLED, HIGH);
        delay(250);
        digitalWrite(IsItWorkingLED, LOW);
        delay(250);
    }

        if (cleanCount <= 200) {
            Serial.println("Knal 1 LED aan");
            digitalWrite(LED1, LOW);   // turn the LED on (LOW is the voltage level)
            digitalWrite(LED2, HIGH);   // turn the LED on (LOW is the voltage level)
            digitalWrite(LED3, HIGH);   // turn the LED on (LOW is the voltage level)
            digitalWrite(LED4, HIGH);   // turn the LED on (LOW is the voltage level)
            digitalWrite(LED5, HIGH);   // turn the LED on (LOW is the voltage level)
        }
        else if (cleanCount >= 201 && cleanCount <= 400) {
            Serial.println("Knal 2 LEDs aan");
            digitalWrite(LED1, LOW);   // turn the LED on (LOW is the voltage level)
            digitalWrite(LED2, LOW);   // turn the LED on (LOW is the voltage level)
            digitalWrite(LED3, HIGH);   // turn the LED on (LOW is the voltage level)
            digitalWrite(LED4, HIGH);   // turn the LED on (LOW is the voltage level)
            digitalWrite(LED5, HIGH);   // turn the LED on (LOW is the voltage level)
        }
        else if (cleanCount >= 401 && cleanCount <= 600) {
            Serial.println("Knal 3 LEDs aan");
            digitalWrite(LED1, LOW);   // turn the LED on (LOW is the voltage level)
            digitalWrite(LED2, LOW);   // turn the LED on (LOW is the voltage level)
            digitalWrite(LED3, LOW);   // turn the LED on (LOW is the voltage level)
            digitalWrite(LED4, HIGH);   // turn the LED on (LOW is the voltage level)
            digitalWrite(LED5, HIGH);   // turn the LED on (LOW is the voltage level)
        }
        else if (cleanCount >= 601 && cleanCount <= 800) {
            Serial.println("Knal 4 LEDs aan");
            digitalWrite(LED1, LOW);   // turn the LED on (LOW is the voltage level)
            digitalWrite(LED2, LOW);   // turn the LED on (LOW is the voltage level)
            digitalWrite(LED3, LOW);   // turn the LED on (LOW is the voltage level)
            digitalWrite(LED4, LOW);   // turn the LED on (LOW is the voltage level)
            digitalWrite(LED5, HIGH);   // turn the LED on (LOW is the voltage level)
        }
        else if (cleanCount >= 801 && cleanCount <= 1000) {
            Serial.println("Knal 5 LEDs aan");
            digitalWrite(1, LOW);   // turn the LED on (LOW is the voltage level)
            digitalWrite(2, LOW);   // turn the LED on (LOW is the voltage level)
            digitalWrite(4, LOW);   // turn the LED on (LOW is the voltage level)
            digitalWrite(5, LOW);   // turn the LED on (LOW is the voltage level)
            digitalWrite(7, LOW);   // turn the LED on (LOW is the voltage level)
        }
        else {
            Serial.println("Just..do nothing");
        }

}

```

# Answer
Your assumption that a high is required to light a LED is false. All you need is to meet certain minimum voltage and current thresholds. Since the anode of the LED is tied high, the way to meet these is to bring the cathode low.
> 2 votes

# Answer
When you command digitalWrite LOW you are basically connecting that pin to GND. If you command digitalWrite HIGH then you are connecting that pin to +5v. So depending on how you have the LED wired up you can use either to turn on the LED. Since LOW turns your LED on then you must have the long lead of the LED attached to +5v supply and the short lead to the pin on the arduino. I don't know why the LED doesn't turn all the way off when you command digitalWrite HIGH, but it should.

If you wanted to dim the leds then you should try using the analogWrite command which will send a PWM signal and will allow you to make the LEDs any intensity you want to.
> 0 votes

# Answer
An LED wants positive voltage to flow from the anode to the cathode (the + terminal to the - terminal)

You can wire it to a digital pin 2 different ways. (In both cases you'll also need a current limiting resistor to avoid burning out your LED and/or your digital pin, but ignore that for this discussion.)

You can wire the positive terminal of the LED to +5V, and the negative terminal to a digital pin. It sounds like this is what you've done. When you do that, if you set the digital output to HIGH, then both terminals of the LED are connected to +5V, so the LED will be off. Set the output to LOW, and it gets connected to ground. Now current flows out of the +5V rail, through the LED, into the grounded digital pin, and the LED lights up.

You can reverse that wiring instead. Connect the positive terminal of the LED to a digital pin and the negative side to ground. Now, when you set the pin to HIGH, +5V flows out of the pin, through the LED, and into the ground connection, so the LED lights. Set the pin to LOW and both sides of the LED are connected to ground, so it turns off.

# Edit:

Note that you talk about voltage levels and dimming LEDs. If you're using digital outputs and HIGH or LOW, you can only turn the LED on or off. There's no way to vary its brightness.

You can, however, hook an LED to a PWM (Pulse Width Modulation) pin and set up that pin for analog output. In PWM, the Arduino switches the LED on and off rapidly. Set it to the highest output value, 255, and the LED stops flashing and is on 100% o the time. Set the output to 128, and the LED is on half the time and off half the time. Set the output to 64, and the LED is on 1/4 of the time and off 3/4 of the time, and so on.

When you flash a light fast enough, our eyes average out the brightness, and a light that's on 1/4 of the time looks 1/4 as bright as a light that's on 100% of the time.

Most Arduinos have a limited number of analog outputs. The Arduino model you're using might not have 7 analog outputs.
> 0 votes

---
Tags: led
---


# Question
Title: Can I get around extremely long time to setup WIFI connection WPA2 Personal?
I'm using the Arduino Wifi Nina Library to connect an Arduino Uno Wifi Rev2 to wifi and then using the Arduino HTTP Client library to make HTTP post calls to the internet.

To connect the Arduino to my home Wifi Network (WPA2 Personal), I use the `WiFi.begin()` method. This method takes an excruciatingly long 4 seconds to connect to the Wifi. This seems to be a known issue. Since this methods is synchronous/blocking, my sketch is completely unresponsive during this time to any user input such as button-presses etc. I'm trying to create a proof-of-concept for a commercial-grade product. So having it go unresponsive to user-input for several seconds is unacceptable.

Is there any workaround to this? Is there a asynchronous library to achieve the same goal? Is there some other workaround? How do other people deal with this situation?

# Answer
> 2 votes
4 even 5 seconds is normal for connecting to WiFi. How long takes your phone or other devices to connect?

You can connect a little faster with static IP address.

EDIT: With WiFiNINA library for Uno WiFi Rev.2, you can change the connection timeout with `WiFi.setTimeout()`. The default is 5 seconds. WiFi.begin() can end with WL\_CONNECT\_FAILED but if you later check the status of the connection it will eventually be connected.

---

With esp8266 or esp32 you can make the connection persistent and it is build up immediately after boot and asynchronously. WiFiNINA library doesn't make this possible yet. Some future version will offer WiFi provisioning.

# Answer
> 1 votes
For a proof-of-concept, use two Arduinos, one for WiFi and one for everything else. The everything-else Arduino can keep your system responsive (minus the WiFi, of course, during connection time) and poll the WiFi Arduino periodically (without blocking) to find out when WiFi becomes available.

# Answer
> 0 votes
I think better solution is to use ESP8266 WiFi module and Connect if needed another Arduino through GPIO pins of ESP8266.

This video will be helpful, https://www.youtube.com/watch?v=dWM4p\_KaTHY

---
Tags: wifi, arduino-uno-wifi
---


# Question
Title: Ardiuno DUE board. Sketch uploading Error
I am working on Arduino UDE board in Ubuntu 18.04. I've followed following link tutorial.

https://www.arduino.cc/en/Guide/ArduinoDue#:~:text=Use%20your%20Arduino%20Due%20on%20the%20Arduino%20Desktop%20IDE,the%20Arduino%20Boards%20Manager%20page.

In Ardiuno IDE I am getting as /dev/ttyS4. Also, I've gone with follwing procedure :

```
sudo usermod -a -G dialout username
sudo chmod a+rw /dev/ttyS4
ls -l /dev/ttyS4

```

This gave the following outpit

```
crw-rw-rw- 1 root dialout 4, 68 Jun 17 17:26 /dev/ttyS4

```

And I am getting following error while uploading sketch though Ardiuno IDE :

```
Sketch uses 11092 bytes (2%) of program storage space. Maximum is 524288 bytes.
Forcing reset using 1200bps open/close on port /dev/ttyS4
/home/user/.arduino15/packages/arduino/tools/bossac/1.6.1-arduino/bossac -i -d --port=ttyS4 -U false -e -w -v -b /tmp/arduino_build_718911/ardiuno_to_python.ino.bin -R
Send auto-baud
No device found on ttyS4
An error occurred while uploading the sketch
Set binary mode

```

I've tried following solution of decreasing baudrate to 1200 by following command line mulitple times till I get output as 1200 :

```
stty -F /dev/ttyS4 speed 1200 cs8 -cstopb -parenb

```

Still I am facing the error while uploading sketch. I've tried pressing reset and erase buttons few seconds but still not getting anything. Can anyone please help

# Answer
The problem is solved. The cable came with my Arduino was charge only , I tried data transfer cable and it worked. This is so dumb. sorry for wasting your time.
> 2 votes

---
Tags: arduino-due, sketch, uploading
---


# Question
Title: 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*

# Answer
esp8266 ArduinoOTA library has

```
  WiFiUDP::stopAll();
  WiFiClient::stopAll();

```

to ensure undisturbed OTA upload
> 0 votes

---
Tags: esp8266, ota, esp
---


# Question
Title: 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.

# Answer
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`.
> 3 votes

# Answer
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.
> 2 votes

---
Tags: c++, atmega2560, assembly
---


title: My code seems to be a train wreck

text:
# Question
Title: My code seems to be a train wreck
I am new to programming and I thought a simple project to do would be to create an ammo counter. I have been troubleshooting this code for several hours now, and can not figure out why my code is riddled with errors. Below is my program. Please give it a glance and let me know what mistake I have made. I will post the error report beneath my program. I apologize for my bad programming in advance and hope that there is still hope for me with the proper tutelage. The program worked just fine when I ran a test using only one saved function, "twentyBullets()". After I added a 30 additional functions and created a chain of if-else-if conditions, the program began to report all sorts of errors.

```
 /*
    7-SEGMENT DISPLAY HANDLING CODE!
    The below code handles the 7-segment display for the digital ammo counter.

     A
    ___
  F|   |B
   G---G
  E|___|C
     D

 Above is the alphabet letter assignment for the different segments of
 the B07BMPPNQY display. Digital ammo counter project will use common pins, L3 and L4.
 */
  // Display pin declaration.
  // P_: Where P indicates the pin output for the segment of the display to be illuminated followed by a lower case letter
  // which indicates which specific led in the segment to illuminate.
  // ten: Where ten indicates the ten's place on the 7 segment display.
  // one: Where one indicates the one's place on the 7 segement display.

int Pa = 0;
int Pb = 1;
int Pc = 2;
int Pd = 3;
int Pe = 4;
int Pf = 5;
int Pg = 6;
int ten = 7;
int one = 8;
int ammo = 10;

void setup() {
  // put your setup code here, to run once:

pinMode(Pa, OUTPUT);
pinMode(Pb, OUTPUT);
pinMode(Pc, OUTPUT);
pinMode(Pd, OUTPUT);
pinMode(Pe, OUTPUT);
pinMode(Pf, OUTPUT);
pinMode(Pg, OUTPUT);
pinMode(ten, OUTPUT);
pinMode(one, OUTPUT);

}

void loop(){
  // put your main code here, to run repeatedly:
  if (ammo == 1) {
  oneBullet();
  }
  else if (ammo == 2) {
  twoBullets();
  }
  else if (ammo == 3) {
   threeBullets();
  }
  else if (ammo == 4) {
    fourBullets();
  }
  else if (ammo == 5) {
    fiveBullets();
  }
  else if (ammo == 6) {
    sixBullets();
  }
  else if (ammo == 7) {
    sevenBullets();
  }
  else if (ammo == 8) {
    eightBullets();
  }
  else if (ammo == 9) {
    nineBullets();
  }
  else if (ammo == 10) {
    tenBullets();
  }
  else if (ammo == 11) {
    elevenBullets();
  }
  else if (ammo == 12) {
    twelveBullets();
  }
  else if (ammo == 13) {
    thirteenBullets();
  }
  else if (ammo == 14) {
    fourteenBullets();
  }
  else if (ammo == 15) {
    fifteenBullets();
  }
  else if (ammo == 16) {
    sixteenBullets();
  }
  else if (ammo == 17) {
    seventeenBullets();
  }
  else if (ammo == 18) {
    eighteenBullets();
  }
  else if (ammo == 19) {
    nineteenBullets();
  }
  else if (ammo == 20) {
   twentyBullets();
  }
  else if (ammo == 21) {
   twentyoneBullets();
  }
  else if (ammo == 22) {
    twentytwoBullets();
  }
  else if (ammo == 23) {
    twentythreeBullets();
  }
  else if (ammo == 24) {
    twentyfourBullets();
  }
  else if (ammo == 25) {
    twentyfiveBullets();
  }
  else if (ammo == 26) {
    twentysixBullets();
  }
  else if (ammo == 27) {
   twentysevenBullets();
  }
  else if (ammo == 28) {
   twentyeightBullets();
  }
  else if (ammo == 29) {
   twentynineBullets();
  }
  else if (ammo == 30){
   thirtyBullets();
  }
  else {
    zeroBullets();
  }
}
void zeroBullets()
           //0
{ digitalWrite(one, LOW);
  digitalWrite(ten, HIGH);
  digitalWrite(Pa, LOW);
  digitalWrite(Pb, LOW);
  digitalWrite(Pc, LOW);
  digitalWrite(Pd, LOW);
  digitalWrite(Pe, LOW);
  digitalWrite(Pf, LOW);
  digitalWrite(Pg, HIGH);
  delay(10);

        //0
  digitalWrite(one, HIGH);
  digitalWrite(ten, LOW);
  digitalWrite(Pa, LOW);
  digitalWrite(Pb, LOW);
  digitalWrite(Pc, LOW);
  digitalWrite(Pd, LOW);
  digitalWrite(Pe, LOW);
  digitalWrite(Pf, LOW);
  digitalWrite(Pg, HIGH);
  delay(10);
}
void oneBullet()
          //1
{  digitalWrite(one, LOW);
  digitalWrite(ten, HIGH);
  digitalWrite(Pa, HIGH);
  digitalWrite(Pb, LOW);
  digitalWrite(Pc, LOW);
  digitalWrite(Pd, HIGH);
  digitalWrite(Pe, HIGH);
  digitalWrite(Pf, HIGH);
  digitalWrite(Pg, HIGH);
  delay(10);

          //0
  digitalWrite(one, HIGH);
  digitalWrite(ten, LOW);
  digitalWrite(Pa, LOW);
  digitalWrite(Pb, LOW);
  digitalWrite(Pc, LOW);
  digitalWrite(Pd, LOW);
  digitalWrite(Pe, LOW);
  digitalWrite(Pf, LOW);
  digitalWrite(Pg, HIGH);
  delay(10);
}

void twoBullets()
          //2
{  digitalWrite(one, LOW);
  digitalWrite(ten, HIGH);
  digitalWrite(Pa, LOW);
  digitalWrite(Pb, LOW);
  digitalWrite(Pc, HIGH);
  digitalWrite(Pd, LOW);
  digitalWrite(Pe, LOW);
  digitalWrite(Pf, HIGH);
  digitalWrite(Pg, LOW);
  delay(10);

          //0
  digitalWrite(one, HIGH);
  digitalWrite(ten, LOW);
  digitalWrite(Pa, LOW);
  digitalWrite(Pb, LOW);
  digitalWrite(Pc, LOW);
  digitalWrite(Pd, LOW);
  digitalWrite(Pe, LOW);
  digitalWrite(Pf, LOW);
  digitalWrite(Pg, HIGH);
  delay(10);
}
void threeBullets()
          //6
{  digitalWrite(one, LOW);
  digitalWrite(ten, HIGH);
  digitalWrite(Pa, LOW);
  digitalWrite(Pb, LOW);
  digitalWrite(Pc, LOW);
  digitalWrite(Pd, LOW);
  digitalWrite(Pe, HIGH);
  digitalWrite(Pf, HIGH);
  digitalWrite(Pg, LOW);
  delay(10);

          //0
  digitalWrite(one, HIGH);
  digitalWrite(ten, LOW);
  digitalWrite(Pa, LOW);
  digitalWrite(Pb, LOW);
  digitalWrite(Pc, LOW);
  digitalWrite(Pd, LOW);
  digitalWrite(Pe, LOW);
  digitalWrite(Pf, LOW);
  digitalWrite(Pg, HIGH);
  delay(10);
}
void fourBullets()
          //4
{  digitalWrite(one, LOW);
  digitalWrite(ten, HIGH);
  digitalWrite(Pa, HIGH);
  digitalWrite(Pb, LOW);
  digitalWrite(Pc, LOW);
  digitalWrite(Pd, HIGH);
  digitalWrite(Pe, HIGH);
  digitalWrite(Pf, LOW);
  digitalWrite(Pg, LOW);
  delay(10);

          //0
  digitalWrite(one, HIGH);
  digitalWrite(ten, LOW);
  digitalWrite(Pa, LOW);
  digitalWrite(Pb, LOW);
  digitalWrite(Pc, LOW);
  digitalWrite(Pd, LOW);
  digitalWrite(Pe, LOW);
  digitalWrite(Pf, LOW);
  digitalWrite(Pg, HIGH);
  delay(10);
}
void fiveBullets()
          //5
{  digitalWrite(one, LOW);
  digitalWrite(ten, HIGH);
  digitalWrite(Pa, LOW);
  digitalWrite(Pb, HIGH);
  digitalWrite(Pc, LOW);
  digitalWrite(Pd, LOW);
  digitalWrite(Pe, HIGH);
  digitalWrite(Pf, LOW);
  digitalWrite(Pg, LOW);
  delay(10);

          //0
  digitalWrite(one, HIGH);
  digitalWrite(ten, LOW);
  digitalWrite(Pa, LOW);
  digitalWrite(Pb, LOW);
  digitalWrite(Pc, LOW);
  digitalWrite(Pd, LOW);
  digitalWrite(Pe, LOW);
  digitalWrite(Pf, LOW);
  digitalWrite(Pg, HIGH);
  delay(10);
}
void sixBullets()
          //6
{  digitalWrite(one, LOW);
  digitalWrite(ten, HIGH);
  digitalWrite(Pa, HIGH);
  digitalWrite(Pb, HIGH);
  digitalWrite(Pc, LOW);
  digitalWrite(Pd, LOW);
  digitalWrite(Pe, LOW);
  digitalWrite(Pf, LOW);
  digitalWrite(Pg, LOW);
  delay(10);

          //0
  digitalWrite(one, HIGH);
  digitalWrite(ten, LOW);
  digitalWrite(Pa, LOW);
  digitalWrite(Pb, LOW);
  digitalWrite(Pc, LOW);
  digitalWrite(Pd, LOW);
  digitalWrite(Pe, LOW);
  digitalWrite(Pf, LOW);
  digitalWrite(Pg, HIGH);
  delay(10);
}
void sevenBullets()
          //7
{  digitalWrite(one, LOW);
  digitalWrite(ten, HIGH);
  digitalWrite(Pa, LOW);
  digitalWrite(Pb, LOW);
  digitalWrite(Pc, LOW);
  digitalWrite(Pd, HIGH);
  digitalWrite(Pe, HIGH);
  digitalWrite(Pf, HIGH);
  digitalWrite(Pg, HIGH);
  delay(10);

          //0
  digitalWrite(one, HIGH);
  digitalWrite(ten, LOW);
  digitalWrite(Pa, LOW);
  digitalWrite(Pb, LOW);
  digitalWrite(Pc, LOW);
  digitalWrite(Pd, LOW);
  digitalWrite(Pe, LOW);
  digitalWrite(Pf, LOW);
  digitalWrite(Pg, HIGH);
  delay(10);
}
void eightBullets()
          //8
{  digitalWrite(one, LOW);
  digitalWrite(ten, HIGH);
  digitalWrite(Pa, LOW);
  digitalWrite(Pb, LOW);
  digitalWrite(Pc, LOW);
  digitalWrite(Pd, LOW);
  digitalWrite(Pe, LOW);
  digitalWrite(Pf, LOW);
  digitalWrite(Pg, LOW);
  delay(10);

          //0
  digitalWrite(one, HIGH);
  digitalWrite(ten, LOW);
  digitalWrite(Pa, LOW);
  digitalWrite(Pb, LOW);
  digitalWrite(Pc, LOW);
  digitalWrite(Pd, LOW);
  digitalWrite(Pe, LOW);
  digitalWrite(Pf, LOW);
  digitalWrite(Pg, HIGH);
  delay(10);
}
void nineBullets()
              //9
{  digitalWrite(one, LOW);
  digitalWrite(ten, HIGH);
  digitalWrite(Pa, LOW);
  digitalWrite(Pb, LOW);
  digitalWrite(Pc, LOW);
  digitalWrite(Pd, HIGH);
  digitalWrite(Pe, HIGH);
  digitalWrite(Pf, LOW);
  digitalWrite(Pg, HIGH);
  delay(10);

          //0
  digitalWrite(one, HIGH);
  digitalWrite(ten, LOW);
  digitalWrite(Pa, LOW);
  digitalWrite(Pb, LOW);
  digitalWrite(Pc, LOW);
  digitalWrite(Pd, LOW);
  digitalWrite(Pe, LOW);
  digitalWrite(Pf, LOW);
  digitalWrite(Pg, HIGH);
  delay(10);
}
void tenBullets()
              //0
{  digitalWrite(one, LOW);
  digitalWrite(ten, HIGH);
  digitalWrite(Pa, LOW);
  digitalWrite(Pb, LOW);
  digitalWrite(Pc, LOW);
  digitalWrite(Pd, LOW);
  digitalWrite(Pe, LOW);
  digitalWrite(Pf, LOW);
  digitalWrite(Pg, HIGH);
  delay(10);

          //1
  digitalWrite(one, HIGH);
  digitalWrite(ten, LOW);
  digitalWrite(Pa, HIGH);
  digitalWrite(Pb, LOW);
  digitalWrite(Pc, LOW);
  digitalWrite(Pd, HIGH);
  digitalWrite(Pe, HIGH);
  digitalWrite(Pf, HIGH);
  digitalWrite(Pg, HIGH);
  delay(10);
}
void elevenBullets()
              //1
{  digitalWrite(one, LOW);
  digitalWrite(ten, HIGH);
  digitalWrite(Pa, HIGH);
  digitalWrite(Pb, LOW);
  digitalWrite(Pc, LOW);
  digitalWrite(Pd, HIGH);
  digitalWrite(Pe, HIGH);
  digitalWrite(Pf, HIGH);
  digitalWrite(Pg, HIGH);
  delay(10);

          //1
  digitalWrite(one, HIGH);
  digitalWrite(ten, LOW);
  digitalWrite(Pa, HIGH);
  digitalWrite(Pb, LOW);
  digitalWrite(Pc, LOW);
  digitalWrite(Pd, HIGH);
  digitalWrite(Pe, HIGH);
  digitalWrite(Pf, HIGH);
  digitalWrite(Pg, HIGH);
  delay(10);
}
void twelveBullets()
             //2
{  digitalWrite(one, LOW);
  digitalWrite(ten, HIGH);
  digitalWrite(Pa, LOW);
  digitalWrite(Pb, LOW);
  digitalWrite(Pc, HIGH);
  digitalWrite(Pd, LOW);
  digitalWrite(Pe, LOW);
  digitalWrite(Pf, HIGH);
  digitalWrite(Pg, LOW);
  delay(10);

          //1
  digitalWrite(one, HIGH);
  digitalWrite(ten, LOW);
  digitalWrite(Pa, HIGH);
  digitalWrite(Pb, LOW);
  digitalWrite(Pc, LOW);
  digitalWrite(Pd, HIGH);
  digitalWrite(Pe, HIGH);
  digitalWrite(Pf, HIGH);
  digitalWrite(Pg, HIGH);
  delay(10);
}
void thirteenBullets()
          //3
{  digitalWrite(one, HIGH);
  digitalWrite(ten, LOW);
  digitalWrite(Pa, LOW);
  digitalWrite(Pb, LOW);
  digitalWrite(Pc, LOW);
  digitalWrite(Pd, LOW);
  digitalWrite(Pe, HIGH);
  digitalWrite(Pf, HIGH);
  digitalWrite(Pg, LOW);
  delay(10);

          //1
  digitalWrite(one, HIGH);
  digitalWrite(ten, LOW);
  digitalWrite(Pa, HIGH);
  digitalWrite(Pb, LOW);
  digitalWrite(Pc, LOW);
  digitalWrite(Pd, HIGH);
  digitalWrite(Pe, HIGH);
  digitalWrite(Pf, HIGH);
  digitalWrite(Pg, HIGH);
  delay(10);
}
void fourteenBullets()
          //4
{  digitalWrite(one, HIGH);
  digitalWrite(ten, LOW);
  digitalWrite(Pa, HIGH);
  digitalWrite(Pb, LOW);
  digitalWrite(Pc, LOW);
  digitalWrite(Pd, HIGH);
  digitalWrite(Pe, HIGH);
  digitalWrite(Pf, LOW);
  digitalWrite(Pg, LOW);
  delay(10);

          //1
  digitalWrite(one, HIGH);
  digitalWrite(ten, LOW);
  digitalWrite(Pa, HIGH);
  digitalWrite(Pb, LOW);
  digitalWrite(Pc, LOW);
  digitalWrite(Pd, HIGH);
  digitalWrite(Pe, HIGH);
  digitalWrite(Pf, HIGH);
  digitalWrite(Pg, HIGH);
  delay(10);
}
void fifteenBullets()
          //5
{  digitalWrite(one, HIGH);
  digitalWrite(ten, LOW);
  digitalWrite(Pa, LOW);
  digitalWrite(Pb, HIGH);
  digitalWrite(Pc, LOW);
  digitalWrite(Pd, LOW);
  digitalWrite(Pe, HIGH);
  digitalWrite(Pf, LOW);
  digitalWrite(Pg, LOW);
  delay(10);

          //1
  digitalWrite(one, HIGH);
  digitalWrite(ten, LOW);
  digitalWrite(Pa, HIGH);
  digitalWrite(Pb, LOW);
  digitalWrite(Pc, LOW);
  digitalWrite(Pd, HIGH);
  digitalWrite(Pe, HIGH);
  digitalWrite(Pf, HIGH);
  digitalWrite(Pg, HIGH);
  delay(10);
}
void sixteenBullets()
          //6
{  digitalWrite(one, HIGH);
  digitalWrite(ten, LOW);
  digitalWrite(Pa, HIGH);
  digitalWrite(Pb, HIGH);
  digitalWrite(Pc, LOW);
  digitalWrite(Pd, LOW);
  digitalWrite(Pe, LOW);
  digitalWrite(Pf, LOW);
  digitalWrite(Pg, LOW);
  delay(10);

          //1
  digitalWrite(one, HIGH);
  digitalWrite(ten, LOW);
  digitalWrite(Pa, HIGH);
  digitalWrite(Pb, LOW);
  digitalWrite(Pc, LOW);
  digitalWrite(Pd, HIGH);
  digitalWrite(Pe, HIGH);
  digitalWrite(Pf, HIGH);
  digitalWrite(Pg, HIGH);
  delay(10);
}
void seventeenBullets()
          //7
{  digitalWrite(one, HIGH);
  digitalWrite(ten, LOW);
  digitalWrite(Pa, LOW);
  digitalWrite(Pb, LOW);
  digitalWrite(Pc, LOW);
  digitalWrite(Pd, HIGH);
  digitalWrite(Pe, HIGH);
  digitalWrite(Pf, HIGH);
  digitalWrite(Pg, HIGH);
  delay(10);

          //1
  digitalWrite(one, HIGH);
  digitalWrite(ten, LOW);
  digitalWrite(Pa, HIGH);
  digitalWrite(Pb, LOW);
  digitalWrite(Pc, LOW);
  digitalWrite(Pd, HIGH);
  digitalWrite(Pe, HIGH);
  digitalWrite(Pf, HIGH);
  digitalWrite(Pg, HIGH);
  delay(10);
}
void eighteenBullets()
          //8
{  digitalWrite(one, HIGH);
  digitalWrite(ten, LOW);
  digitalWrite(Pa, LOW);
  digitalWrite(Pb, LOW);
  digitalWrite(Pc, LOW);
  digitalWrite(Pd, LOW);
  digitalWrite(Pe, LOW);
  digitalWrite(Pf, LOW);
  digitalWrite(Pg, LOW);
  delay(10);

          //1
  digitalWrite(one, HIGH);
  digitalWrite(ten, LOW);
  digitalWrite(Pa, HIGH);
  digitalWrite(Pb, LOW);
  digitalWrite(Pc, LOW);
  digitalWrite(Pd, HIGH);
  digitalWrite(Pe, HIGH);
  digitalWrite(Pf, HIGH);
  digitalWrite(Pg, HIGH);
  delay(10);
}
void nineteenBullets()
          //9
{  digitalWrite(one, HIGH);
  digitalWrite(ten, LOW);
  digitalWrite(Pa, LOW);
  digitalWrite(Pb, LOW);
  digitalWrite(Pc, LOW);
  digitalWrite(Pd, HIGH);
  digitalWrite(Pe, HIGH);
  digitalWrite(Pf, LOW);
  digitalWrite(Pg, LOW);
  delay(10);

          //1
  digitalWrite(one, HIGH);
  digitalWrite(ten, LOW);
  digitalWrite(Pa, HIGH);
  digitalWrite(Pb, LOW);
  digitalWrite(Pc, LOW);
  digitalWrite(Pd, HIGH);
  digitalWrite(Pe, HIGH);
  digitalWrite(Pf, HIGH);
  digitalWrite(Pg, HIGH);
  delay(10);
}
void twentyBullets()
        //0
{  digitalWrite(one, LOW);
  digitalWrite(ten, HIGH);
  digitalWrite(Pa, LOW);
  digitalWrite(Pb, LOW);
  digitalWrite(Pc, LOW);
  digitalWrite(Pd, LOW);
  digitalWrite(Pe, LOW);
  digitalWrite(Pf, LOW);
  digitalWrite(Pg, HIGH);
  delay(10);

          //2
  digitalWrite(one, HIGH);
  digitalWrite(ten, LOW);
  digitalWrite(Pa, LOW);
  digitalWrite(Pb, LOW);
  digitalWrite(Pc, HIGH);
  digitalWrite(Pd, LOW);
  digitalWrite(Pe, LOW);
  digitalWrite(Pf, HIGH);
  digitalWrite(Pg, LOW);
  delay(10);
}
void twentyoneBullets()
        //1
{  digitalWrite(one, LOW);
  digitalWrite(ten, HIGH);
  digitalWrite(Pa, HIGH);
  digitalWrite(Pb, LOW);
  digitalWrite(Pc, LOW);
  digitalWrite(Pd, HIGH);
  digitalWrite(Pe, HIGH);
  digitalWrite(Pf, HIGH);
  digitalWrite(Pg, HIGH);
  delay(10);

          //2
  digitalWrite(one, HIGH);
  digitalWrite(ten, LOW);
  digitalWrite(Pa, LOW);
  digitalWrite(Pb, LOW);
  digitalWrite(Pc, HIGH);
  digitalWrite(Pd, LOW);
  digitalWrite(Pe, LOW);
  digitalWrite(Pf, HIGH);
  digitalWrite(Pg, LOW);
  delay(10);
}
void twentytwoBullets()
        //2
{  digitalWrite(one, LOW);
  digitalWrite(ten, HIGH);
  digitalWrite(Pa, LOW);
  digitalWrite(Pb, LOW);
  digitalWrite(Pc, HIGH);
  digitalWrite(Pd, LOW);
  digitalWrite(Pe, LOW);
  digitalWrite(Pf, HIGH);
  digitalWrite(Pg, LOW);
  delay(10);

          //2
  digitalWrite(one, HIGH);
  digitalWrite(ten, LOW);
  digitalWrite(Pa, LOW);
  digitalWrite(Pb, LOW);
  digitalWrite(Pc, HIGH);
  digitalWrite(Pd, LOW);
  digitalWrite(Pe, LOW);
  digitalWrite(Pf, HIGH);
  digitalWrite(Pg, LOW);
  delay(10);
}
void twentythreeBullets()
        //3
{  digitalWrite(one, LOW);
  digitalWrite(ten, HIGH);
  digitalWrite(Pa, LOW);
  digitalWrite(Pb, LOW);
  digitalWrite(Pc, LOW);
  digitalWrite(Pd, LOW);
  digitalWrite(Pe, HIGH);
  digitalWrite(Pf, HIGH);
  digitalWrite(Pg, LOW);
  delay(10);

          //2
  digitalWrite(one, HIGH);
  digitalWrite(ten, LOW);
  digitalWrite(Pa, LOW);
  digitalWrite(Pb, LOW);
  digitalWrite(Pc, HIGH);
  digitalWrite(Pd, LOW);
  digitalWrite(Pe, LOW);
  digitalWrite(Pf, HIGH);
  digitalWrite(Pg, LOW);
  delay(10);
}
void twentyfourBullets()
        //4
{  digitalWrite(one, LOW);
  digitalWrite(ten, HIGH);
  digitalWrite(Pa, HIGH);
  digitalWrite(Pb, LOW);
  digitalWrite(Pc, LOW);
  digitalWrite(Pd, HIGH);
  digitalWrite(Pe, HIGH);
  digitalWrite(Pf, LOW);
  digitalWrite(Pg, LOW);
  delay(10);

          //2
  digitalWrite(one, HIGH);
  digitalWrite(ten, LOW);
  digitalWrite(Pa, LOW);
  digitalWrite(Pb, LOW);
  digitalWrite(Pc, HIGH);
  digitalWrite(Pd, LOW);
  digitalWrite(Pe, LOW);
  digitalWrite(Pf, HIGH);
  digitalWrite(Pg, LOW);
  delay(10);
}
void twentyfiveBullets()
        //5
{  digitalWrite(one, LOW);
  digitalWrite(ten, HIGH);
  digitalWrite(Pa, LOW);
  digitalWrite(Pb, HIGH);
  digitalWrite(Pc, LOW);
  digitalWrite(Pd, LOW);
  digitalWrite(Pe, HIGH);
  digitalWrite(Pf, LOW);
  digitalWrite(Pg, LOW);
  delay(10);

          //2
  digitalWrite(one, HIGH);
  digitalWrite(ten, LOW);
  digitalWrite(Pa, LOW);
  digitalWrite(Pb, LOW);
  digitalWrite(Pc, HIGH);
  digitalWrite(Pd, LOW);
  digitalWrite(Pe, LOW);
  digitalWrite(Pf, HIGH);
  digitalWrite(Pg, LOW);
  delay(10);
}
void twentysixBullets()
        //6
{  digitalWrite(one, LOW);
  digitalWrite(ten, HIGH);
  digitalWrite(Pa, LOW);
  digitalWrite(Pb, HIGH);
  digitalWrite(Pc, LOW);
  digitalWrite(Pd, LOW);
  digitalWrite(Pe, LOW);
  digitalWrite(Pf, LOW);
  digitalWrite(Pg, LOW);
  delay(10);

          //2
  digitalWrite(one, HIGH);
  digitalWrite(ten, LOW);
  digitalWrite(Pa, LOW);
  digitalWrite(Pb, LOW);
  digitalWrite(Pc, HIGH);
  digitalWrite(Pd, LOW);
  digitalWrite(Pe, LOW);
  digitalWrite(Pf, HIGH);
  digitalWrite(Pg, LOW);
  delay(10);
}
void twentysevenBullets()
        //7
{  digitalWrite(one, LOW);
  digitalWrite(ten, HIGH);
  digitalWrite(Pa, LOW);
  digitalWrite(Pb, LOW);
  digitalWrite(Pc, LOW);
  digitalWrite(Pd, HIGH);
  digitalWrite(Pe, HIGH);
  digitalWrite(Pf, HIGH);
  digitalWrite(Pg, HIGH);
  delay(10);

          //2
  digitalWrite(one, HIGH);
  digitalWrite(ten, LOW);
  digitalWrite(Pa, LOW);
  digitalWrite(Pb, LOW);
  digitalWrite(Pc, HIGH);
  digitalWrite(Pd, LOW);
  digitalWrite(Pe, LOW);
  digitalWrite(Pf, HIGH);
  digitalWrite(Pg, LOW);
  delay(10);
}
void twentyeightBullets()
        //8
{  digitalWrite(one, LOW);
  digitalWrite(ten, HIGH);
  digitalWrite(Pa, LOW);
  digitalWrite(Pb, LOW);
  digitalWrite(Pc, LOW);
  digitalWrite(Pd, LOW);
  digitalWrite(Pe, LOW);
  digitalWrite(Pf, LOW);
  digitalWrite(Pg, LOW);
  delay(10);

          //2
  digitalWrite(one, HIGH);
  digitalWrite(ten, LOW);
  digitalWrite(Pa, LOW);
  digitalWrite(Pb, LOW);
  digitalWrite(Pc, HIGH);
  digitalWrite(Pd, LOW);
  digitalWrite(Pe, LOW);
  digitalWrite(Pf, HIGH);
  digitalWrite(Pg, LOW);
  delay(10);
}
void twentynineBullets()
      //9
{  digitalWrite(one, LOW);
  digitalWrite(ten, HIGH);
  digitalWrite(Pa, LOW);
  digitalWrite(Pb, LOW);
  digitalWrite(Pc, LOW);
  digitalWrite(Pd, HIGH);
  digitalWrite(Pe, HIGH);
  digitalWrite(Pf, LOW);
  digitalWrite(Pg, LOW);
  delay(10);

          //2
  digitalWrite(one, HIGH);
  digitalWrite(ten, LOW);
  digitalWrite(Pa, LOW);
  digitalWrite(Pb, LOW);
  digitalWrite(Pc, HIGH);
  digitalWrite(Pd, LOW);
  digitalWrite(Pe, LOW);
  digitalWrite(Pf, HIGH);
  digitalWrite(Pg, LOW);
  delay(10);
}

void thirtyBullets()
        //0
  digitalWrite(one, LOW);
  digitalWrite(ten, HIGH);
  digitalWrite(Pa, LOW);
  digitalWrite(Pb, LOW);
  digitalWrite(Pc, LOW);
  digitalWrite(Pd, LOW);
  digitalWrite(Pe, LOW);
  digitalWrite(Pf, LOW);
  digitalWrite(Pg, HIGH);
  delay(10);

          //3
  digitalWrite(one, HIGH);
  digitalWrite(ten, LOW);
  digitalWrite(Pa, LOW);
  digitalWrite(Pb, LOW);
  digitalWrite(Pc, LOW);
  digitalWrite(Pd, LOW);
  digitalWrite(Pe, HIGH);
  digitalWrite(Pf, HIGH);
  digitalWrite(Pg, LOW);
  delay(10);
}

```

THE ERROR REPORT:

```
Arduino: 1.8.10 (Windows 10), Board: "Arduino/Genuino Uno"

Digital_Ammo_Counter.ino: In function 'void loop()':

sketch_Digital_Ammo_Counter:138:4: error: 'thirtyBullets' was not declared in this scope

    thirtyBullets();

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

sketch_Digital_Ammo_Counter.ino:138:4: note: suggested alternative: 'twentyBullets'

    thirtyBullets();

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

    twentyBullets

sketch_Digital_Ammo_Counter.ino: At global scope:

sketch_Digital_Ammo_Counter:898:3: error: expected initializer before 'digitalWrite'

   digitalWrite(one, LOW);

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

sketch_Digital_Ammo_Counter:899:15: error: expected constructor, destructor, or type conversion before '(' token

   digitalWrite(ten, HIGH);

               ^

sketch_Digital_Ammo_Counter:900:15: error: expected constructor, destructor, or type conversion before '(' token

   digitalWrite(Pa, LOW);

               ^

sketch_Digital_Ammo_Counter:901:15: error: expected constructor, destructor, or type conversion before '(' token

   digitalWrite(Pb, LOW);

               ^

sketch_Digital_Ammo_Counter:902:15: error: expected constructor, destructor, or type conversion before '(' token

   digitalWrite(Pc, LOW);

               ^

sketch_Digital_Ammo_Counter:903:15: error: expected constructor, destructor, or type conversion before '(' token

   digitalWrite(Pd, LOW);

               ^

sketch_Digital_Ammo_Counter:904:15: error: expected constructor, destructor, or type conversion before '(' token

   digitalWrite(Pe, LOW);

               ^

sketch_Digital_Ammo_Counter:905:15: error: expected constructor, destructor, or type conversion before '(' token

   digitalWrite(Pf, LOW);

               ^

sketch_Digital_Ammo_Counter:906:15: error: expected constructor, destructor, or type conversion before '(' token

   digitalWrite(Pg, HIGH);

               ^

sketch_Digital_Ammo_Counter:907:8: error: expected constructor, destructor, or type conversion before '(' token

   delay(10);

        ^

sketch_Digital_Ammo_Counter:910:15: error: expected constructor, destructor, or type conversion before '(' token

   digitalWrite(one, HIGH);

               ^

sketch_Digital_Ammo_Counter:911:15: error: expected constructor, destructor, or type conversion before '(' token

   digitalWrite(ten, LOW);

               ^

sketch_Digital_Ammo_Counter:912:15: error: expected constructor, destructor, or type conversion before '(' token

   digitalWrite(Pa, LOW);

               ^

sketch_Digital_Ammo_Counter:913:15: error: expected constructor, destructor, or type conversion before '(' token

   digitalWrite(Pb, LOW);

               ^

sketch_Digital_Ammo_Counter:914:15: error: expected constructor, destructor, or type conversion before '(' token

   digitalWrite(Pc, LOW);

               ^

sketch_Digital_Ammo_Counter:915:15: error: expected constructor, destructor, or type conversion before '(' token

   digitalWrite(Pd, LOW);

               ^

sketch_Digital_Ammo_Counter:916:15: error: expected constructor, destructor, or type conversion before '(' token

   digitalWrite(Pe, HIGH);

               ^

sketch_Digital_Ammo_Counter:917:15: error: expected constructor, destructor, or type conversion before '(' token

   digitalWrite(Pf, HIGH);

               ^

sketch_Digital_Ammo_Counter:918:15: error: expected constructor, destructor, or type conversion before '(' token

   digitalWrite(Pg, LOW);

               ^

sketch_Digital_Ammo_Counter:919:8: error: expected constructor, destructor, or type conversion before '(' token

   delay(10);

        ^

sketch_Digital_Ammo_Counter:920:1: error: expected declaration before '}' token

 }

 ^

exit status 1
'thirtyBullets' was not declared in this scope

This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.

```

# Answer
> 40 votes
The error cascade is caused by the missing opening curly bracket `{` at the start of the `thirtyBullets()` function. This causes the function name to be not declared and also the following function calls to `digitalWrite()` to fail. Putting in this missing opening curly bracket should fix all the errors (though I cannot test it since I don't have a compiler at hand currently).

Besides that, your code can be made way shorter with a trick. Currently you use one function for every number, where you write the corresponding digital pins. So the situation is, that you always need to write to the same pins, just different values depending on a simple unsigned integer number. So I suggest, that you define the pin patterns for the digits in a 2 dimensional array. Then you can use only 1 function to output any of them. I will give you an example:

```
uint8_t led_pattern[10][7]= {
    {0, 0, 0, 0, 0, 0, 1}, // pattern for the digit 0
    {1, 0, 0, 1, 1, 1, 1}, // pattern for the digit 1
    {0, 0, 1, 0, 0, 1, 0}, // pattern for the digit 2
    ...
    {0, 0, 0, 0, 1, 0, 0}}; // pattern for the digit 9

void display_digit(uint8_t position, uint8_t digit){
    digitalWrite(one, position); // Writes low (aka zero) to pin one, when position is zero, else high
    digitalWrite(ten, !position); // Writes low to pin ten, when position is greater than zero, else high

    for(uint8_t i=0; i<7; i++){
        digitalWrite(i, led_pattern[digit][i]);
    }
    delay(10);
}

void display_number(uint8_t number){
    display_digit(0, number % 10);
    display_digit(1, number / 10);
}

void loop(){
    display_number(ammo);
}

```

**So, what is happening here?**

First we define the LED patterns in a 2 dimensional array. It's first index is the digit, that we want to display; it's second index is the number of the LED to light. The value then is the state of the corresponding LED. I wrote `1` and `0`, because it is short. You could also write `HIGH` and `LOW` (since these are also only defines for `1` and `0`). So the pattern `{1, 0, 0, 1, 1, 1, 1}` means, that only the segments b and c output low, thus are turned on.

Then we define a function to display one digit. It takes the position of the digit and the actual digit (0 to 9) as parameters. We write the two outputs for our position directly with the variable. This is a very short way to do it and it doesn't work, when you have more than 2 digits. If you want to extend your counter one day, you can replace these 2 lines by a different construct (for example a switch case statement). Then we do a for loop from 0 to 6, so that we go through all the digits. In your case you use the pin numbers 0 to 6, so we can directly use `i` as pin number. (If you want to use other pins, you could save those pins in an array and reference the values in the array with `i`). In every iteration of the for loop, we write the value for the corresponding digit and LED to the corresponding output pin. After that, we only delay a short time and leave the function.

To make it easier, I also defined the function `display_number()`, which will display the complete number, by displaying the it's digits successively on the corresponding positions. If you are a beginnner, you might not recognize, what calculations I made there. The modulo operator `%` returns the rest of an integer division. So if I take `23 % 10` this would return `3` (integer division `23 / 10` is 2 and the rest is 3). This gives us the first (least significant) digit. We can then get the second digit by simply doing an integer division with 10, as it will cut the part after the decimal point. If you want to display numbers greater than 99 one day, you have to change both functions to accomodate for that.

Note, that I used `uint8_t` as type everywhere. This is just the smallest unsigned number type (8 bit wide). I used the smallest, since you don't need greater numbers here and it saves a bit of memory. When you want to extend your display to show values greater than 255, you need to change the type of the `number` parameter in the `display_number()` function to a greater type, for example `unsigned int` (which is 16 bits wide).

Also note, that I have not tested this code, since I don't have a compiler or Arduino at hand currently.

---

So now, you can display a number on your digit with just one function call and you don't need nearly 1000 lines of code for it.

When extending your code to do more things, than displaying numbers, you can easily get to the point, where using `delay()` is a bad thing, since the Arduino cannot do anything else during that time. Then you need to rewrite your code to avoid `delay()` and use the `millis()` function instead to make it unblocking. There are tons of tutorials out there for this and I just wanted to mention it.

# Answer
> 8 votes
You've found the bug, but how could you have found it easier?

The most important step mentally is to accept that *you* did something wrong. We don't know yet what, but it is exceedingly unlikely that the compiler complains about correct code. So the question is: What did you do wrong?

The compiler complained about a function "thirtyBullets". It didn't complain about "twentynineBullets". It doesn't realise that there is a function "thirtyBullets". The first thing is to check the spelling. If you named the function "thirrtyBullets" by mistake, that would explain things. But the name is right.

Then you see that the compiler complains about the line immediately after the start of the function. Hard to figure out what the compiler is complaining about, so something you did just before confused it. So now you check the line "void thirtyBullets()", that's Ok, the next line "digitalWrite(one, LOW);" looks Ok but something MUST be wrong here, and that's where you hopefully figure out the missing "{".

# Answer
> 1 votes
Just to add to the idea of using an array—since C does not care about whitespace you can quite easily format your data like this:

```
uint8_t led_pattern[10][7]= {
      {0,  // pattern for the digit 0
     0,  0,
       0,
     0,  0,
       0},

      {0, // pattern for the digit 1
     0,  1,
       0,
     0,  1,
       0},

      {1, // pattern for the digit 2
     0,  1,
       1,
     1,  0,
       1},
      ...
};

```

This is an example of the "good habit" of making your code about your *intent* rather than about *instructing* the machine. You can spend 50% more time making your code clear, or spend 500% more time debugging it. As the saying goes,

> There are two ways to develop software: Make it so simple that there are obviously no bugs, or so complex that there are no obvious bugs.

**Note:** The above code will give you your digitalOut values in a different order to your pins (so chrisl's `for` loop won't work.) You can just manually do 7 digitalWrites to the correct pins when displaying the `digit`.

```
digitalWrite( <pin number> , led_pattern[digit][ <led position> ]);

```

# Answer
> 0 votes
Your code actually isn't bad. There aren't very many good ways of doing this sort of pin mapping, and the few that are have their own downsides as well. The main issue was the missing bracket, which I found by checking the drawThirty function since it was mentioned specifically and had cascading errors implying a missed semicolon or bracket.

One further tweak is that your code will only work on Arduino (so you're fine, but a different IDE may get mad at you). C does not search the whole file for function names, so if you declare/define the function after you use it, it will error out. Arduino uses a special pre-parser to fix this for you.

The proper way is to forward-declare the function as follows:

```
int returnAPieceOfData(byte x, char c, int i);//Now C knows it exists somewhere and won't error.

void foo(){

//somewhere in here you need returnAPieceOfData
}

int returnAPieceOfData(byte x, char c, int i){
//You now define the function after it's used, but have no errors!

}

```

This usually results in a C file where all the functions are declared at the top, and then the function definitions below can use them in any order without problems. It also makes it easier to tell if the file has a function, and if you add them in the same order, where it is.

---

I will mention a potentially-useful method of alternately implementing the array lookup table for writing the pins. The above are very good suggestions, especially the shaped whitespace, but that approach will use a lot of extra memory because it uses full bytes per pixel.

If you are willing to accept a format that is somewhat harder to visualize, you could encode the entire space into a single byte, which I'll show below. You can also put the **pin numbers** into an array so that you *can* use a FOR loop.

Essentially, you have two options when writing this sort of system. You can go for code complexity, which is what your example did, or you can go for memory/data complexity, which I'm showing here. The downsides to THIS technique are that the data is somewhat arcane and hard to modify (since it's encoded and there's kinda a lot of it), and that it uses extra memory to hold that data.

```
void drawAllSegments(byte ammo_ct){
  byte hi=ammo_ct/10;
  byte lo=ammo_ct%10;
  drawLowSegments(lo);
  drawHighSegments(hi);
}

byte lpinNums[]={apin,bpin,cpin,dpin,epin,fpin,gpin};//pins for 0s display
byte hpinNums[]={apin,bpin,cpin,dpin,epin,fpin,gpin};//pins for 10s display
byte numbers[]={0b00111111,0b01111001,...};
//Format the "numbers" as 0bXGFEDCBA, where X is a don't-care
//(its value is never used and can be either 0 or 1)
//My example may be wrong. I think it's negative logic, but could also have made an error on top of that.

void drawLowSegments(byte ammo_ct){
  digitalWrite(one, HIGH);//set up the display select
  digitalWrite(ten, LOW);
  for (byte i=0;i<7;i++){//then draw!
    byte state=(numbers[ammo_ct]>>i)&0x01;//decompress the state of that segment
    digitalWrite(lpinNums[i],state);
  }
}

void drawHighSegments(byte ammo_ct){
  digitalWrite(one, HIGH);//set up the display select
  digitalWrite(ten, LOW);
  for (byte i=0;i<7;i++){//then draw!
    byte state=(numbers[ammo_ct]>>i)&0x01;//decompress the state of that segment
    digitalWrite(hpinNums[i],state);
  }
}

```

The advantages of this approach is that the code is just as compact as the array system, but that it uses 1/8 the RAM for that array. I don't imagine you are doing something that uses a whole lot of RAM, but it's still a good idea to minimize it where possible. In this case it also is much further expandable, since you can fit more numbers in before you run out of RAM.

You can also switch to PROGMEM, but reading that is a bit weird in some ways and it's easy to forget to read it in the first place (which results in reads of random RAM). In this case it should be small enough that further such optimization isn't required.

One last note is that, if you ever do something for which a byte is too small, you can use larger numbers up to the uint32\_t, which is 32 bits of useful pixels, or potentially the uint64\_t, which is 64 bits but may not be supported on the Arduino (I've never tried the latter).

---
Tags: debugging
---


# Question
Title: How to keep track of millis during sleep mode
In my application, I need to keep track of the time the application has been running as well as use sleep modes. However, when using the sleep modes, Timer0 is disabled, and therefore millis stop counting.

**Is there a way to measure/count how long the Arduino was in sleep mode for?**

To give you some more background info, this is what I'm trying to achieve: I am using a pressure sensor which sends an interrupt to the Arduino every 80ms and wakes it up. The program does various routines to process the data which can take anywhere from 2ms to 60ms. It then goes into sleep mode until another external interrupt occurs, approx 20-78ms later. The application has many processes based on time, such as a stopwatch, timer and alarm, so I need to be able to keep track of this, preferably using millis(). The device is running on a single cell 250mah LiPo battery which at present only lasts about 4 hours. I'm using an ATMega1284.

In most of the sleep modes Timer0 is disabled. Which means that millis() stops counting. Is there a way, without using an RTC (Both Space and weight are at a premium), to keep millis counting whilst in sleep mode?

I notice that SLEEP\_MODE\_IDLE keeps Timer0 running, but that means that for every millisecond an interrupt wakes up the device. Please correct me if I'm wrong, but given that my loop can take about 60ms to execute, I don't see much advantage to sleeping for 1ms.

**Possible solutions:**

* Use Timer2 for the millis function?
* Use the Watchdog Timer to count how much time has passed whilst in sleep mode and add this to millis() when waking up?
* If there was a VERY small SMD RTC which didn't need any external components such as oscilators etc then this might be feasible.

# Answer
> 3 votes
The only way to keep `millis()` running is sleep mode is to sleep in SLEEP\_MODE\_IDLE. Switching to Timer 2 would make no difference, as all timers but the watchdog are stopped in other sleep modes. The watchdog is horribly inaccurate, so you do not want to rely on it for any kind of timekeeping.

> I don't see much advantage to sleeping for 1 ms.

Sleeping for 1 ms saves a little bit of power. But if you do that 60 times every 80 ms you will save a lot of power. I suggest you do just that: sleep when you are done with your calculations. When you wake up, if you see that the waking up came from the external interrupt, the you process it. Otherwise you just go back to sleep.

Note that if the 80 ms period of the external interrupt is consistent enough, you could use *that* as time source.

# Answer
> 2 votes
I found a RealTimeClock that I could use: RV-8803. It's only 3.2mm x 1.5mm x 0.8mm, has an internal XTAL, and can provide time in 100th of a second. Sparkfun do a breakout board (BOB-16281), and accompanying library.

Given that I've already got a bunch of decoupling capacitors in my circuit and can use the internal pullups of the ATMega1284, I think I can probably integrate the RV-8803 without the need for any additional components.

On the breadboard, interrupts are working well and I can now use EXTENDED\_STANDBY sleep mode instead. The only downside is that the RTC records time in 100ths of a second, whereas my program was using milliseconds previously. I'll need to see if 100ths is accurate enough for my needs.

Failing that, I'll have a look at @Gerben's suggestion above.

---
Tags: power, timers, time, millis, sleep
---


# Question
Title: 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]);

```

# Answer
> 2 votes
Create them as char arrays like this:

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

```

and use them like this:

```
Serial.println(menu[0]);

```

---
Tags: arduino-uno, string
---


# Question
Title: delay() problem for 74HC595 and 7-segment
I'm trying to run a 3-digit 7-segment using single 74HC595 based on Arduino. But I have a serious problem with `delay()` function. When I want to count from 000 to 999 with `delay(1000)`, this delay function causes all digits to be off! My code is as below and I uploaded a video **Click Here** to understand my purpose. This problem can affect some applications like reading the temperature of DS12b20 which requires a delay itself.

```
//                 2        1         0
//               ----      ----      ----
//              |    |    |    |    |    |
//               ----      ----      ----
//              |    |    |    |    |    |
//               ----      ----      ----

int latch = 8; //74HC595  pin STCP
int clock = 9; //74HC595  pin SHCP
int data = 10; //74HC595  pin DS

// Each annode pin (for those that don't know think of it as an on switch when it's assigned HIGH)
int dig1 = 2; // digit0
int dig2 = 3; // digit1
int dig3 = 4; // digit2
int digit[4]={dig1, dig2, dig3};

int timer=3;
// these are bits to make the 8 bit byte accepted by the segment display the 9th is the demical point
// 0-9 then invald numbers
byte table[] = {
  B00111111, B00000110, B01011011, B01001111, B01100110,
  B01101101, B01111101, B00000111, B01111111, B01101111, B01111111
};

void setup(){
  pinMode(latch, OUTPUT);
  pinMode(clock, OUTPUT);
  pinMode(data, OUTPUT);
  pinMode(dig1, OUTPUT);
  pinMode(dig2, OUTPUT);
  pinMode(dig3, OUTPUT);
}

//this sends the data to the digit
void RunNum(int num, int SelectDigit){
  digitalWrite(latch, LOW);
  shiftOut(data, clock, MSBFIRST, table[num]);
  digitalWrite(latch, HIGH);
  digitalWrite(digit[SelectDigit], LOW);
  delay(timer);
  digitalWrite(digit[SelectDigit], HIGH);

}

//main program
void loop() {
  for (int i=0; i<10; i++){
    for (int j=0; j<10; j++){
      for (int k=0; k<10; k++){
        RunNum(k, 0);
        RunNum(j, 1);
        RunNum(i, 2);
        delay(1000);  //  <====    This line affects the project
      }
    }
  }
}

```

I updated my code (only `void loop()`) as below using `millis()`. You can watch the results (**Click Here**). But, the delay problem has not been solved so far!

```
const long interval = 1000;   //  1000 ms = 1 s
long previousMillis = 0;
unsigned long currentMillis=0;

//main program
void loop() {
  for (int i=0; i<10; i++){
    for (int j=0; j<10; j++){
      for (int k=0; k<10; k++){
        while (currentMillis - previousMillis < interval){
          currentMillis=millis();
          RunNum(k, 0);
          RunNum(j, 1);
          RunNum(i, 2);
        }
        previousMillis = currentMillis;
      }
    }
  }
}

```

# Answer
With the displays which use shift register to light multiple seven segment digit blocks, the register lights up only one digit at a time. The illusion of multiple digits lit is created by fast switching the digits in round. Small delays in this cause the number to look dim, larger delays create flickering and long delays show only one digit lit. So a sketch handling this type of display must run without delays.

In this type of sketch, everything must be handled without delays, so if some sensor requires a delay, start the reading and a millis timer and after the elapsed time read the result.

There are displays using specialized chips, for example TM1637D, which handle the seven segments even if your sketch stops in delay.

---

adoption of the BlinkWithoutDelay basic example for your algorithm:

```
unsigned long previousMillis = 0;
const long interval = 1000;
int i, j, k;

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

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

  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;
    k++;
    if ( k == 10) {
      k = 0;
      j++;
      if (j == 10) {
        j = 0;
        i++;
        if (i == 10) {
          i = 0;
        }
      }
    }
    Serial.print(i);
    Serial.print(j);
    Serial.println(k);
  }
}

```
> 3 votes

# Answer
In `loop()` as you've shown it in your code, you can move `RunNum(i,2);` down to outside of the 'j' and 'k' loops. Likewise you can move `RunNum(j,1);` down to outside of the 'k' loop. This won't fix your problem but it will speed up each update of the display.

Then, know that you can tell one (or all) of your DS18B20 sensors to start a temperature conversion *without waiting for the conversion to finish*. Then you use millis() to tell you when the conversion is done, and you can get the result very quickly. Some libraries provide the amount of time you need to wait for the conversion; some provide some kind of an "is it done yet?" boolean function. Either one of those will let you remove the 'wait til done' delay.

Update:

> This strategy doesn't work properly!...

Sorry if I missed something - it looked like there were opportunities to optimize there.

> About temperature sensor, I should say that reading the temperature takes about 750 ms itself. In other words, it acts as a delay and causes turning off the display for 750 ms.

It is temperature measurement and conversion to a 12-bit result - which takes place *entirely within the DS18B20* sensor itself - that takes 750ms. *The Arduino is not involved in that process* and could be doing other tasks such as maintaining your display during that time.

*Reading* the temperatures, once the conversion is done, is much quicker. If your library doesn't provide the ability to start a conversion and return, without waiting for the results, and separate entry to read the results, look for a library that does.

Update: Miles Burton's Arduino-Temperature-Control-Library provides a 'wait for conversion' flag that you can set false so ::requestsTemperatures() will return immediately, and an ::isConversionComplete() call to check whether the data is ready. (Of course, knowing that the device takes 750ms for a 12-bit conversion, you could just as well use millis() to decide that.)
> 1 votes

---
Tags: 7-segment
---


title: Use an LDR to run a sketch

text:
# Question
Title: 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

# Answer
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();

```
> 2 votes

# Answer
@ 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);
  }
  {

  }
}

```
> -1 votes

---
Tags: led, sketch
---


# Question
Title: 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&)'

```

# Answer
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];
    }

}

```
> 3 votes

---
Tags: arduino-uno, usb, joystick
---


# Question
Title: 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`... )

# Answer
> 0 votes
replacing `gmtime(&timeinfo)` with `localtime(&timeinfo)` in `myIOT32::convEpoch` passes definition of time-zone as needed.

for more information in this cpluspls site

---
Tags: esp32, time
---