# Question
Title: Serial communication between multiple devices (or Arduinos)
What I know from my search on the internet, for both **SPI** and **I2C** protocols, communication between multiple devices needs a master, which initiates the communication, and slaves, which respond to the master's request. Basically slaves can't initiate a transfer.

Is there any way to make different devices communicate on their will? I'm not sure about **UART**, but I think the story is the same here. But I know that it is possible to use a USB hub to connect multiple USB devices to one port on the computer. How can that be done? Can I use the same principle with Arduino?

To clarify what I want to do, consider that I have different modules (might be Arduinos) with different characteristics. I want to connect them on a bus line to a master Arduino. The module connections should be indifferent so that the user doesn't have to worry about which port should be used to connect the module. For this reason, using an Arduino Mega with more serial interfaces doesn't solve the problem, because we don't know which device is connected to which port.

# Answer
Almost any serial communication system can be "bent" to make a multi-master system - some easier than others. The biggest problem you have is that of detecting and handling collisions.

However, if you can get away with a master-\>slave(s) system whereby one node on your bus makes requests to the slave nodes to get them to do something and respond with information then the whole system is far far simpler.

That is the normal way that I2C and SPI work, although I2C does have multi-master in its specification (though the Arduino API doesn't handle it AFAIK).

The industry standard way of making a UART able to communicate with multiple devices is through converting it to a standard bus system, such as EIA-422 or EIA-485 (AKA RS-422/RS-485). A half-duplex multi-drop EIA-485 is probably the simplest to arrange, and there are breakout boards for the Arduino that will convert UART to EIA-485.

It is possible (if you are clever) to make UARTs directly work as a multi-drop bus, but it requires a deeper understanding of UART control registers and electrical characteristics to emulate either an open-collector or tri-state TX pin on the slaves.

Of course, for all devices to operate on the same bus they must all conform to the specified operation of the bus. For instance, for EIA-485 all the slaves must have the ability to switch the transceiver into TX mode when needed, and react only to requests from the master and never send anything unsolicited. Just hooking random devices up to a bus with a transceiver is never going to work.

As far as USB goes - that is a single master (the PC) and multiple slaves (your keyboard, mouse, printer, scanner, webcam, Arduino, etc). Hubs are just a way of wiring them all together and routing the signals to the different peripherals at the right speeds.
> 1 votes

# Answer
I2C protocol has Multi-master Arbitration Support, i.e. any I2C device can be master and slave. I2C is a multimaster bus Master start communication, but master device can change. If one device wants to communicate, acts as a master. The problem is that before sending data you must be sure the bus is not busy with other master.

More information: https://www.i2c-bus.org/multimaster/

With UART is not possible to build a bus, only point to point communication.
> 0 votes

# Answer
Another option thats possible if you can control the firmware on each node, as in your case with multiple arduino's, is to create a ring bus using UART ports with multiple peers on it where each node would be responsible for forwarding packets to the next node.

The UART rx tz lines for nodes would have to be connected in a ring like this:

* NodeA Tx =\> NodeB Rx
* NodeB Tx =\> NodeC Rx
* NodeC Tx =\> NodeA Rx

This would require design of a somewhat complicated protocol and controlling firmware on each node, and you would need to think through issues like:

1. how many devices can be supported on the ring
2. message size
3. how much memory is available to buffer messages on each node
4. how many message is each node allowed to send etc.
> 0 votes

---
Tags: arduino-uno, serial, i2c, spi, uart
---


# Question
Title: How to produce 6 PWM signals with 60 degrees phase shift?
How to produce 6 PWM signals with 60 degrees phase shift using Arduino Uno 6 PWM pins like in the image below?

# Answer
> 2 votes
Using hardware it's not possible. Simply because you effectively only have three PWM timer units, each with two compare outputs.

That means you have three timebases, which are each compared with two values for two PWM signals each.

You would need a single master timebase with six independent offsettable counters with comparison for your needs.

It would be possible to (roughly) do it in software, though, depending on your needs. You get jitter from software generated PWM, due to interrupts getting in the way of your smooth execution. However you have complete control over how the waveform is generated. Instead of a 0-X duty cycle you could program it to have an X-Y duty cycle. And with all of them taken from the same counter value it's then all synchronised 100%.

# Answer
> 3 votes
I found the correct method for 6-phase PWM as the OP requested. And it can have any duty-cycle you want. My erroneous findings for 50% only duty we're because I used Fast-PWM mode. When I switched to Phase-PWM (mode-10-PWM in a 2560 ARduino), I got the correct waveforms, the same as the OP wanted.

Below is a link to a logic-analyzer snapshot showing the 6-phases from a 2560. The frequency is 500 Hz but that's easy to change. 4 Timers in all used to realize this outcome. 3 Timers used mode-10-PWM, 1 mode-14-PWM at the same frequency.

The full project is documented at Runtime Micro.

**EDIT:** I can now do this using an Uno. But there are limitations to duty-cycle and some other concerns. Provides usable N-channel (2, 3, 4, 5, and 6) phase-shift PWM from a single Uno board.

**EDIT:** A full 6-channel PSPWM solution using only an Uno is now published at Runtime Micro under Projects Menu. You'll find details, images, code and diagram. There are limitations such as no channel-to-channel overlap in pulse-width.

FWIW

# Answer
> 0 votes
Use a timer to trigger an interrupt. Set the timer to 1/6 of the overall pwm cycle to get to 60degree phase. Each time the interrupt is triggered it turns on the next channel.

You could have a second timer and interrupt to turn them off working in the same manner.

---
Tags: arduino-uno, pwm
---


# Question
Title: Read both battery voltage and analog sensor value with NodeMCU ESP8266
I have a soil sensor that reports value once every 5 minutes, deepsleep in between. Is there a way to also report battery voltage (with ESP.getVcc())?

To get the battery voltage reading to work I need to set ADC\_MODE(ADC\_VCC); but that disables the reading of the sensor.

# Answer
> to read VCC voltage, ADC pin must be kept unconnected. Additionally, the following line has to be added to the sketch: ADC\_MODE(ADC\_VCC);

The setting of a purpose of the analog pin of esp8266 is at low level and must be projected into the compiled binary. It can't be changed at runtime.

On esp8266 if you want to use the power sensing or to have more ADC you must use an external I2C ADC.

reference
> 3 votes

# Answer
I found a solution that I believe works great.

Although the ADC\_MODE macro cannot be modified after the board is started, we can actually set its integer input as the output of a function and then use RTC memory to trigger different modes, depending for example on how many times the board has been started.

```
#include "ESP8266WiFi.h"
#define QUERY_VCC_INTERVAL  10

int adc_selection;
ADC_MODE(get_adc());

int get_adc(){

  typedef struct {
  uint32_t adc_mode;
  uint32_t count;
  } rtcStore;

  rtcStore rtcMem;

  system_rtc_mem_read(100, &rtcMem, sizeof(rtcMem));

  if ((rtcMem.adc_mode != ADC_VCC) && (rtcMem.adc_mode != ADC_TOUT)) return ADC_TOUT;

  return rtcMem.adc_mode;
}

int get_adc_and_write_change(){

  typedef struct {
  uint32_t adc_mode;
  uint32_t count;
  } rtcStore;

  int a;
  rtcStore rtcMem;

  system_rtc_mem_read(100, &rtcMem, sizeof(rtcMem));
  a = rtcMem.adc_mode;

  Serial.print("CYCLE NUMBER: ");
  Serial.println(rtcMem.count);

  if (rtcMem.count > QUERY_VCC_INTERVAL){
        rtcMem.adc_mode = ADC_VCC;
        rtcMem.count = 0;
  } else {
        rtcMem.adc_mode = ADC_TOUT;
        rtcMem.count++;
  }

  system_rtc_mem_write(100, &rtcMem, sizeof(rtcMem));

  return a;

}

void setup() {

  int vcc;

  Serial.begin(9600);
  Serial.println(" ---------- ");
  delay(1000);

  adc_selection = get_adc_and_write_change();
  Serial.print("VALUE FOR ADC MODE WAS: ");
  Serial.println(adc_selection);

  vcc = ESP.getVcc();
  Serial.print("VALUE WHEN READING VCC: ");
  Serial.println(vcc);

  if (adc_selection == ADC_TOUT){
    Serial.println("VCC SHOULD BE 65535");
   } else {
    Serial.println("VCC SHOULD NOT BE 65535");
   }

  Serial.println("RESET BOARD TO CONTINUE");
  delay(1000);

}

void loop() {
}

```

Note that the function gets executed very early on the board startup, so we cannot even count on using or writing to global variable definitions of the script's code. This is why all structures are defined within the get\_adc function.

The above code triggers ADC\_MODE(ADC\_VCC) for every 10 times that ADC\_MODE(ADC\_TOUT) is triggered. This allows me to read analogue sensors for 10 times after the board is woken up from deep sleep and then read the VCC level to gauge the battery voltage once every 10 times.

Note also that to have VCC readings work correctly I need to connect analogue sensor power to a digital pin and use that to power the sensors ON/OFF as needed.

I have tested the above code with a NodeMCU v3, on the Arduino IDE.
> 0 votes

---
Tags: esp8266, analogread, nodemcu, battery
---


# Question
Title: Arduino IDE + ESP32 Webserver - how to redirect to root after click on button
I'm trying to use ESP32 + Arduino IDE to control a relay.

I've started by using the library and the code below.

The problem I'm having:

after clicking on the button and activating the pin, if the browser is left like this, and then the page gets refreshed by mistake, the action will be repeated.

What I thought might help, is if for any click on the button, the pin activates, and then I get a redirect back to the root of the page. so refreshing will not pose any issue.

I've searched allover the internet and could not find anything conclusive, except for this piece of code, which doesnt seem to make any difference nomatter where I place it in the main code

```
client.println("HTTP/1.1 307 Temporary Redirect");
client.println("Location: /");
client.println("Connection: Close");
client.println();
client.stop();

```

and this is the main code:

```
// Load Wi-Fi library
#include <WiFi.h>

// Replace with your network credentials
const char* ssid     = "WalrusnTiny";
const char* password = "994483329I";

// Set web server port number to 80
WiFiServer server(80);

// Variable to store the HTTP request
String header;

// Auxiliar variables to store the current output state
String output26State = "off";
String output27State = "off";

// Assign output variables to GPIO pins
const int output26 = 26;
const int output27 = 27;

void setup() {

  Serial.begin(115200);
  // Initialize the output variables as outputs
  pinMode(output26, OUTPUT);
  pinMode(output27, OUTPUT);
  // Set outputs to LOW
  digitalWrite(output26, LOW);
  digitalWrite(output27, LOW);

  // Connect to Wi-Fi network with SSID and password
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  // Print local IP address and start web server
  Serial.println("");
  Serial.println("WiFi connected.");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
  server.begin();
}

void loop(){
  WiFiClient client = server.available();   // Listen for incoming clients

  if (client) {                             // If a new client connects,
    Serial.println("New Client.");          // print a message out in the serial port
    String currentLine = "";                // make a String to hold incoming data from the client
    while (client.connected()) {            // loop while the client's connected
      if (client.available()) {             // if there's bytes to read from the client,
        char c = client.read();             // read a byte, then
        Serial.write(c);                    // print it out the serial monitor
        header += c;
        if (c == '\n') {                    // if the byte is a newline character
          // if the current line is blank, you got two newline characters in a row.
          // that's the end of the client HTTP request, so send a response:
          if (currentLine.length() == 0) {
            // HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
            // and a content-type so the client knows what's coming, then a blank line:
            client.println("HTTP/1.1 200 OK");
            client.println("Content-type:text/html");
            client.println("Connection: close");
            client.println();

            // turns the GPIOs on and off
            if (header.indexOf("GET /26/on") >= 0) {
              client.println();
              output26State = "on";
              digitalWrite(output26, HIGH);

            } else if (header.indexOf("GET /26/off") >= 0) {
              Serial.println("GPIO 26 off");
              output26State = "off";
              digitalWrite(output26, LOW);

            } else if (header.indexOf("GET /27/on") >= 0) {
              Serial.println("GPIO 27 on");
              output27State = "on";
              digitalWrite(output27, HIGH);

            } else if (header.indexOf("GET /27/off") >= 0) {
              Serial.println("GPIO 27 off");
              output27State = "off";
              digitalWrite(output27, LOW);
            }

            // Display the HTML web page
            client.println("<!DOCTYPE html><html>");
            client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
            client.println("<link rel=\"icon\" href=\"data:,\">");
            // CSS to style the on/off buttons
            // Feel free to change the background-color and font-size attributes to fit your preferences
            client.println("<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}");
            client.println(".button { background-color: #4CAF50; border: none; color: white; padding: 16px 40px;");
            client.println("text-decoration: none; font-size: 30px; margin: 2px; cursor: pointer;}");
            client.println(".button2 {background-color: #555555;}</style></head>");

            // Web Page Heading
            client.println("<body><h1>ESP32 Web Server</h1>");
            // Display current state, and ON/OFF buttons for GPIO 26
            client.println("<p>GPIO 26 - State " + output26State + "</p>");
            // If the output26State is off, it displays the ON button
            if (output26State=="off") {
              client.println("<p><a href=\"/26/on\"><button class=\"button\">ON</button></a></p>");
            } else {
              client.println("<p><a href=\"/26/off\"><button class=\"button button2\">OFF</button></a></p>");
            }

            // Display current state, and ON/OFF buttons for GPIO 27
            client.println("<p>GPIO 27 - State " + output27State + "</p>");
            // If the output27State is off, it displays the ON button
            if (output27State=="off") {
              client.println("<p><a href=\"/27/on\"><button class=\"button\">ON</button></a></p>");
            } else {
              client.println("<p><a href=\"/27/off\"><button class=\"button button2\">OFF</button></a></p>");
            }
            client.println("</body></html>");

            // The HTTP response ends with another blank line
            client.println();
            // Break out of the while loop
            break;
          } else { // if you got a newline, then clear currentLine
            currentLine = "";
          }
        } else if (c != '\r') {  // if you got anything else but a carriage return character,
          currentLine += c;      // add it to the end of the currentLine
        }
      }
    }
    // Clear the header variable

    header = "";
    // Close the connection

    Serial.println("Client disconnected.");
    Serial.println("");
  }
}

```

Any help would be greatly appreciated. Thank you in advance.

# Answer
Solved:

Just needed to add this code to every button press,

```
 client.print("<HEAD>");
 client.print("<meta http-equiv=\"refresh\" content=\"0;url=/\">");
 client.print("</head>");

```
> 2 votes

# Answer
First probably mention this is too much overhead for a webserver

adding

```
include <WebServer.h>

```

you can handle those endpoints easily

See https://lastminuteengineers.com/creating-esp32-web-server-arduino-ide/

Basically:

```
setup() {
  ...
  server.on("/", handle_OnConnect);
  server.on("/led1on", handle_led1on);
  server.on("/led1off", handle_led1off);
  server.on("/led2on", handle_led2on);
  server.on("/led2off", handle_led2off);
  server.onNotFound(handle_NotFound);

  server.begin();
  Serial.println("HTTP server started");
}

void loop() {
  server.handleClient();
  ...
}

void handle_led1on() {
  LED1status = HIGH;
  Serial.println("GPIO4 Status: ON");
  server.send(200, "text/html", SendHTML(true,LED2status));
}

```

Anyway this is still wrong, as you end with same problem, `/led1on` renders as your main page

A better solution would be to use this endpoint handlers to set the variable and just redirect:

Here a complete solution

```
#include <WiFi.h>
include <WebServer.h>

// Replace with your network credentials
const char* ssid = "SSID";
const char* password = "password";

// Set web server port number to 80
WebServer server(80);

uint8_t led1Pin = 12;
uint8_t led2Pin = 13;

bool led1State = LOW;
bool led2State = LOW;

void setup() {
  Serial.begin(115200);
  // Initialize the output variables as outputs
  pinMode(led1Pin, OUTPUT);
  pinMode(led2Pin, OUTPUT);
  // Set outputs to LOW
  led1State = LOW;
  led2State = LOW;
  digitalWrite(led1Pin, led1State);
  digitalWrite(led2Pin, led2State);

  // Connect to Wi-Fi network with SSID and password
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  // Print local IP address and start web server
  Serial.println("");
  Serial.println("WiFi connected.");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());

  server.on("/", handle_root);
  server.on("/led/1/on", handle_led1on);
  server.on("/led/1/off", handle_led1off);
  server.on("/led/2/on", handle_led2on);
  server.on("/led/2/off", handle_led2off);
  server.onNotFound(handle_NotFound);

  server.begin();
  Serial.println("HTTP Server started");
}

void handle_root() {
  server.send(200, "text/html", sendHTML());
}

void handle_led1on() {
  led1State = HIGH;
  Serial.println("led1 state: ON");
  server.sendHeader("Location", "/",true);
  server.send(302, "text/plain", "");
}

void handle_led1off() {
  led1State = LOW;
  Serial.println("led1 state: OFF");
  server.sendHeader("Location", "/",true);
  server.send(302, "text/plain", "");
}

void handle_led2on() {
  led2State = HIGH;
  Serial.println("led2 state: ON");
  server.sendHeader("Location", "/",true);
  server.send(302, "text/plain", "");
}

void handle_led2off() {
  led2State = LOW;
  Serial.println("led2 state: OFF");
  server.sendHeader("Location", "/",true);
  server.send(302, "text/plain", "");
}

void handle_NotFound() {
  server.send(404, "text/html", sendPageUnknown());
}

String sendPageUnknown() {
    String ptr = "<!DOCTYPE html> <html>\n";

  ptr += "<head>";

  ptr += "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=no\">\n";
  //ptr += "<meta http-equiv=\"refresh\" content=\"0;url=/\">";

  ptr += "<title>Page unknown</title>\n";

  ptr += "</head>\n";

  ptr += "<body>\n";
  ptr += "<h1>Page unknown</h1>\n";

  ptr += "<a href=\"/\">Return to main page</a>\n";

  ptr += "</body>\n";
  ptr += "</html>\n";
  return ptr;
}

String sendHTML() {
  digitalWrite(led1Pin, led1State);
  digitalWrite(led2Pin, led2State);

  String ptr = "<!DOCTYPE html> <html>\n";

  ptr += "<head>";

  ptr += "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=no\">\n";

  ptr += "<title>LED Dashboard</title>\n";

  ptr += "<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}\n";
  ptr += "body{margin-top: 50px;} h1 {color: #444444;margin: 50px auto 30px;} h3 {color: #444444;margin-bottom: 50px;}\n";
  ptr += ".button {display: block;width: 80px;background-color: #3498db;border: none;color: white;padding: 13px 30px;text-decoration: none;font-size: 25px;margin: 0px auto 35px;cursor: pointer;border-radius: 4px;}\n";
  ptr += ".button-on {background-color: #3498db;}\n";
  ptr += ".button-on:active {background-color: #2980b9;}\n";
  ptr += ".button-off {background-color: #34495e;}\n";
  ptr += ".button-off:active {background-color: #2c3e50;}\n";
  ptr += "p {font-size: 14px;color: #888;margin-bottom: 10px;}\n";
  ptr += "</style>\n";
  ptr += "</head>\n";

  ptr += "<body>\n";
  ptr += "<h1>ESP32 Web Server</h1>\n";

  if (led1State)
  {
    ptr += "<p>LED1: ON</p><a class=\"button button-off\" href=\"/led/1/off\">OFF</a>\n";
  }
  else
  {
    ptr += "<p>LED1: OFF</p><a class=\"button button-on\" href=\"/led/1/on\">ON</a>\n";
  }

  if (led2State)
  {
    ptr += "<p>LED2: ON</p><a class=\"button button-off\" href=\"/led/2/off\">OFF</a>\n";
  }
  else
  {
    ptr += "<p>LED2: OFF</p><a class=\"button button-on\" href=\"/led/2/on\">ON</a>\n";
  }

  ptr += "</body>\n";
  ptr += "</html>\n";
  return ptr;
}

void loop() {
  server.handleClient();
}

```

Even that is suboptimal, as led endpoints shouldn't be GET endpoints but POST (really PUT as it only updates info, but let's stick to POST for simplicity)

Here a version using POST and unique endpoint /led to handle any number of less to manage:

```
#include <WebServer.h>

// Replace with your network credentials
const char* ssid = "SSID";
const char* password = "password";

// Set web server port number to 80
WebServer server(80);

uint8_t led1Pin = 12;
uint8_t led2Pin = 13;

bool led1State = LOW;
bool led2State = LOW;

void setup() {
  Serial.begin(115200);
  // Initialize the output variables as outputs
  pinMode(led1Pin, OUTPUT);
  pinMode(led2Pin, OUTPUT);
  // Set outputs to LOW
  led1State = LOW;
  led2State = LOW;
  digitalWrite(led1Pin, led1State);
  digitalWrite(led2Pin, led2State);

  // Connect to Wi-Fi network with SSID and password
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  // Print local IP address and start web server
  Serial.println("");
  Serial.println("WiFi connected.");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());

  server.on("/", handle_root);
  server.on("/led", HTTP_POST, handle_led);
  server.onNotFound(handle_NotFound);

  server.begin();
  Serial.println("HTTP Server started");
}

void handle_root() {
  server.send(200, "text/html", sendHTML());
}

uint8_t evaluate_led_state(String ledState) {
  uint8_t state;
  if (ledState == "on") {
    Serial.println("led state: ON");
    state = HIGH;
  } else if (ledState == "off") {
    Serial.println("led state: OFF");
    state = LOW;
  } else {
    Serial.println("unknow led state: "+ledState);
  }
  return state;
}

void handle_led() {
  String ledPin = server.arg("ledPin");
  String ledState = server.arg("ledState");

  if (ledPin == "1") {
    Serial.println("setting led1");
    led1State = evaluate_led_state(ledState);
  } else if (ledPin == "2") {
    Serial.println("setting led2");
    led2State = evaluate_led_state(ledState);
  } else {
    Serial.println("led unknow: "+ledPin);
  }
  server.sendHeader("Location", "/",true);
  server.send(302, "text/plain", "");
}

void handle_NotFound() {
  server.send(404, "text/html", sendPageUnknown());
}

String sendPageUnknown() {
    String ptr = "<!DOCTYPE html> <html>\n";

  ptr += "<head>";

  ptr += "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=no\">\n";

  ptr += "<title>Page unknown</title>\n";

  ptr += "</head>\n";

  ptr += "<body>\n";
  ptr += "<h1>Page unknown</h1>\n";

  ptr += "<a href=\"/\">Return to main page</a>\n";

  ptr += "</body>\n";
  ptr += "</html>\n";
  return ptr;
}

String build_led_form(String ledPin, uint8_t ledState) {
  String ptr = "<form action=\"led\" method=\"post\">\n";
  ptr += "  <input type=\"hidden\" name=\"ledPin\" value=\""+ledPin+"\">\n";

  String ledStateStr;

  if (ledState)
  {
    ledStateStr = "off";
  }
  else
  {
    ledStateStr = "on";
  }

  ptr += "  <input type=\"hidden\" name=\"ledState\" value=\""+ledStateStr+"\">\n";
  ptr += "  <label>Led"+ledPin+"</label>\n";
  ptr += "  <input type=\"submit\" class=\"button button-"+ledStateStr+"\" value=\"";
  ledStateStr.toUpperCase();
  ptr += ledStateStr+"\">\n";

  ptr += "</form>\n";
  return ptr;
}

String sendHTML() {
  digitalWrite(led1Pin, led1State);
  digitalWrite(led2Pin, led2State);

  String ptr = "<!DOCTYPE html> <html>\n";

  ptr += "<head>";

  ptr += "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=no\">\n";

  ptr += "<title>LED Dashboard</title>\n";

  ptr += "<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}\n";
  ptr += "body{margin-top: 50px;} h1 {color: #444444;margin: 50px auto 30px;} h3 {color: #444444;margin-bottom: 50px;} form {margin-bottom: 30px;}\n";
  ptr += ".button {display: block;width: 80px;background-color: #3498db;border: none;color: white;text-decoration: none;font-size: 25px;margin: auto;cursor: pointer;border-radius: 4px;}\n";
  ptr += ".button-on {background-color: #3498db;}\n";
  ptr += ".button-on:active {background-color: #2980b9;}\n";
  ptr += ".button-off {background-color: #34495e;}\n";
  ptr += ".button-off:active {background-color: #2c3e50;}\n";
  ptr += "p {font-size: 14px;color: #888;margin-bottom: 10px;}\n";
  ptr += "</style>\n";
  ptr += "</head>\n";

  ptr += "<body>\n";
  ptr += "<h1>ESP32 Web Server</h1>\n";

  ptr += build_led_form("1", led1State);
  ptr += build_led_form("2", led2State);

  ptr += "</body>\n";
  ptr += "</html>\n";
  return ptr;
}

void loop() {
  server.handleClient();
}

```

For non trivial management you probably want to use spiffs

https://randomnerdtutorials.com/esp32-web-server-spiffs-spi-flash-file-system/
> 0 votes

---
Tags: arduino-ide, web-server, esp32
---


title: Rename cu.usbserial-1410 on macOS

text:
# Question
Title: Rename cu.usbserial-1410 on macOS
Is it possible to rename, e.g., cu.usbserial-1410 to something else?

I have to connect multiple Arduino's and right now the order is rather important. Being able to set a fixed name would help a lot.

# Answer
> 1 votes
### Proposal:

Instead of trying to convince the PC's OS (be it macOS, Windows, or Linux) to use a fixed name for interfaces that connect specific Arduinos, add a identifying feature to your Arduino application. Then from the PC application ask each connected Arduino for its name to identify it.

---
Tags: usb
---


# Question
Title: Can't convert string to UTF-16LE for MD5 calculation on an Arduino
## TLDR

I need to convert text from a website into UTF-16LE format so that I can get the proper MD5 checksum but can't figure out how to go about doing that. This is all happening on an Arduino to log in to a router.

## Background

I want to read values from a smart home device connected to a Fritz!Box router using an Arduino with an ethernet connection. The router has an open API and I'm using HTTP (EN|DE) to get the values. C++ programming is not my strong point.

I have been basing my attempts on BASH and javascript examples. For MD5 calculation I'm using tzikis' ArduinoMD5 library.

## Steps

Based on the manual, you need to do the following:

1. Contact the router to get a challenge string (router sends XML)
2. Generate a response by calculating an MD5 checksum using the challenge string and password: `<challenge>-<password>`
3. Send the response, `<challenge>-<response>`, via POST
4. Receive the XLM answer from the router containing the SID
5. Use SID to request data or control a smart home device

I'm stuck on step 2. I have the challenge but cannot calculate the correct checksum.

The manual states:

> The MD5 hash is generated from the byte sequence of the UTF-16LE coding of this string (without BOM and without terminating 0 bytes).

## Attempts

So far I can request the challenge: 70067288 for example. The reponse appears to always be alphanumeric. My password is also alphanumeric.

```
unsigned char* hash2 = MD5::make_hash("1234567z-äbc");
char *md5str2 = MD5::make_digest(hash2, 16);
free(hash2);
Serial.print("MD5: ");
Serial.println(md5str2);

```

This was my attempt at confirmation. The manual gave `1234567z` as a challenge example with `äbc` (the a in the example does indeed have umlauts) as a password. The response shown for this example was `1234567z-9e224a41eeefa284df7bb0f26c2913e2` but my checksum from the above code was `935fe44e659beb5a3bb7a4564fba0513`.

I tried "manually" generating UTF-16LE and calculating the MD5 but that didn't work either.

```
byte rawTest[] = {0x3100, 0x3200, 0x3300, 0x3400, 0x3500, 0x3600, 0x3700, 0x7a00, 0x2d00, 0xe400, 0x6200, 0x6300};
char buffer[12] = {};
unsigned char* hash2 = MD5::make_hash(&buffer[0]);
char *md5str2 = MD5::make_digest(hash2, 16);
free(hash2);
Serial.print("MD5: ");
Serial.println(md5str2);

```

It gave me `d41d8cd98f00b204e9800998ecf8427e`.

I am not entirely sure the example given was correctly calculated. Using their example in the API documentation with BASH code from the site mentioned above, I get a different answer: `1234567z-bb6e5b7c7d4d485590f4e084ad3da989`.

```
#!/bin/bash
# -----------
# definitions
# -----------
FBF="http://192.168.178.1/"
USER="root"
PASS="äbc"
AIN="AINOFYOURFRITZDECTDEVICE"
# ---------------
# fetch challenge
# ---------------
CHALLENGE="1234567z"
# -----
# login
# -----
MD5=$(echo -n ${CHALLENGE}"-"${PASS} | iconv -f ISO8859-1 -t UTF-16LE | md5sum -b | awk '{print substr($0,1,32)}')
RESPONSE="${CHALLENGE}-${MD5}"
echo $RESPONSE

```

Any help getting it working is greatly appreciatet.

---

## Working Example (with caveats)

Requirements:

* Password using only characters found in ASCII
* Password at least 17 characters long

The password must use *only* ASCII characters due to the simple way it's being converted to UTF-16LE.

I can't explain why the password must be at least 17 characters long though. My code checks the length of the actual password programmatically.

With a password at least 17 characters long I get something like this:

> Challenge: 6c607ee5
>
> Challenge Pass (26): 6c607ee5-01234567890123456
>
> Challenge Pass Preallocation Length: 26
>
> MD5 (UTF-16LE): 3b26241ae4aab8eaf71d5c1599932178

Any password short and I get something like this:

> Challenge: 621611e1
>
> Challenge Pass (26): 621611e1-0123456789012345�
>
> Challenge Pass Preallocation Length: 25
>
> MD5 (UTF-16LE): 30a163ab8a267adfbb524b2b7412e81b

Please excuse any poor coding, C++ is not my strongpoint.

```
void fritzboxSID() {
  EthernetClient fritzBox;
  const char* pass = "01234567890123456";  // 17 ASCII character minimum
  const char* user = "fritz3456";  // Account on router, randomly generated or user created
  const size_t passLength = strlen(pass);  // Password length
  char c;
  uint8_t xml = 0;
  char challenge[9] = {0};  // Challenge
  char challengePass[8 + 1 + passLength];  // challenge-password
  uint8_t challengeCount = 0;

  if (fritzBox.connect("192.168.200.1", 80)) {
    // Send login request
    fritzBox.println("GET /login_sid.lua HTTP/1.1");
    fritzBox.println("Host: 192.168.200.1");
    fritzBox.println("Connection: close");
    fritzBox.println();

    while (fritzBox.connected()) {
      while (fritzBox.available()) {
        c = fritzBox.read();  // Read a single character from the router response
        if (c == '>') {
          xml++;
        }
        if (xml == 5) {
            // Challenge starts after the fifth >
            if (challengeCount > 0 & challengeCount < 9) {
                // Save the challenge, character by character
                challenge[challengeCount-1] = c;
                challengePass[challengeCount-1] = c;
            }
            challengeCount++;
        }
        Serial.print(c);  // Print HTTP response
      }
    }
    challengePass[8] = '-';
    for (size_t i = 0;i < passLength; i++){
      // Copy password into the combined challenge-password string
      challengePass[i+9] = pass[i];
    }

    // Show challenge and pass, checking lengths
    //      If the strlen(challengePass) doesn't equal the preallocation length then the MD5 will be incorrect
    Serial.println("");
    Serial.print("Challenge: ");
    Serial.println(challenge);
    Serial.print("Challenge Pass (");
    Serial.print(strlen(challengePass));
    Serial.print("): ");
    Serial.println(challengePass);
    Serial.print("Challenge Pass Preallocation Length: ");
    Serial.println(8 + 1 + passLength);

    // Convert to UTF-16LE (only works for standard ASCII characters)
    const size_t length = strlen(challengePass);
    char buffer[2*length];
    for (size_t i = 0; i < length; i++) {
      buffer[2*i] = challengePass[i];
      buffer[2*i+1] = 0;
    }

    // Generate MD5
    unsigned char* hash = MD5::make_hash(buffer, 2*length);
    char *md5str = MD5::make_digest(hash, 16);
    free(hash);
    Serial.print("MD5 (UTF-16LE): ");
    Serial.println(md5str);
  } else {
    Serial.println("Cannot connect to 192.168.200.1");
  }
}

```

If it helps, the response from the router for the initial login request is this:

```
HTTP/1.1 200 OK
Cache-Control: no-cache
Connection: close
Content-Type: text/xml
Date: Fri, 16 Sep 2022 08:21:27 GMT
Expires: -1
Pragma: no-cache
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
Content-Security-Policy: default-src 'none'; connect-src 'self'; font-src 'self'; frame-src https://service.avm.de https://help.avm.de https://www.avm.de https://avm.de https://assets.avm.de https://clickonce.avm.de http://clickonce.avm.de http://download.avm.de https://download.avm.de 'self'; img-src 'self' https://tv.avm.de https://help.avm.de/images/ http://help.avm.de/images/ data:; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; frame-ancestors 'self'; media-src 'self'

<?xml version="1.0" encoding="utf-8"?><SessionInfo><SID>0000000000000000</SID><Challenge>621611e1</Challenge><BlockTime>0</BlockTime><Rights></Rights><Users><User last="1">fritz3456</User><User>UserName</User></Users></SessionInfo>

```

# Answer
You have to convert the string "\<challenge\>-\<password\>" to UTF-16LE. If the whole string is plain ASCII, the conversion is trivial: you just have to add a zero byte after each ASCII byte.

```
// ASCII string to be hashed.
const char* text = "1234567z-abc";  // umlaut removed

// Convert to UTF-16LE.
const size_t length = strlen(text);
char buffer[2*length];
for (size_t i = 0; i < length; i++) {
    buffer[2*i] = text[i];
    buffer[2*i+1] = 0;
}

// Compute and print the hash.
unsigned char* hash2 = MD5::make_hash(buffer, 2*length);
char *md5str2 = MD5::make_digest(hash2, 16);
free(hash2);
Serial.print("MD5: ");
Serial.println(md5str2);

```

Note that I use the two-parameter version of `MD5::make_hash()` in order to pass the length of the buffer. The one parameter version of this method would stop at the first zero byte.

---

**Edit**: Regarding your extended question (the new section “Working Example”), this is a problem completely unrelated to the previous one. It is about string termination.

In C and C++, strings are arrays of characters terminated with a NUL ASCII character (numeric value zero). The terminating NUL is not part of the string per se, but it should be stored in the array holding the string. String literals are interpreted by the compiler as NUL-terminated arrays of characters. Every function that expects a string as an input expects it to be NUL-terminated.

In this particular instance, you failed to NUL-terminate `challengePass`. When this array is given to `strelen()`, this function scans the memory until it finds a zero byte. If that zero byte happens to be right after the end of the array, your code will work as expected. Otherwise, any non-zero byte coming after `challengePass` in memory will be interpreted as being part of the string. The program behavior is unpredictable, because you do not know what will be stored in memory right after `challengePass`.

The solution is to NUL-terminate the string. Start by allocating one more byte:

```
char challengePass[8 + 1 + passLength + 1];  // challenge-password

```

Then, right after copying the password, add a zero byte to terminate the string:

```
challengePass[8 + 1 + passLength] = '\0';  // terminate the string

```

Note that `'\0'` means “the character with numeric value zero”.

Alternatively, you can terminate the string right after adding the dash, then use `strcat()` to concatenate the password. `strcat()` will take care of terminating the string:

```
challengePass[8] = '-';
challengePass[9] = '\0';  // temporarily terminate the string
strcat(challengePass, pass);  // append password

```
> 2 votes

---
Tags: c++
---


# Question
Title: IF statement to run even if the requirement isn't met anymore
I have built a flasher for the headlamps on my race car. Whilst it works when I hold the switch down, if I release the switch and the circuit is closed my IF statements requirements are no longer met and it stops flashing.

Is there a way to have it continue to run the IF statement (but only once) even after I've let go of the switch and the requirement is no longer met?

Thanks in advance.

CODE:

```
#define trig A3

const int flash = 3; //D3
const float mVc = 4.67; //reference voltage
float counts = 0;
float mV = 0;

void setup() {
  Serial.begin(115200);
  pinMode(flash, OUTPUT);
}

void loop() {
  counts = analogRead(trig);
  //counts = 255;
  Serial.println(String(counts));

  mV = (counts*mVc) / 1000;
  Serial.println("Input Voltage: " + String(mV) + "v");

  //delay(1000);

// voltage will need to be changed to matched output voltage when on car
  if (counts > 10) {
    analogWrite(flash, 100);
    delay(300);
    analogWrite(flash, 0);
    delay(80);
    analogWrite(flash, 100);
    delay(300);
    analogWrite(flash, 0);
    delay(80);
    analogWrite(flash, 100);
    delay(300);
    analogWrite(flash, 0);
    delay(80);
    analogWrite(flash, 100);
    delay(300);
    analogWrite(flash, 0);
    delay(80);
    analogWrite(flash, 100);
    delay(300);
    analogWrite(flash, 0);
    delay(1000);
  }
}

```

---

EDIT:

TL;DR Don't use voltage dividers to power the Nano.

When using a voltage divider to power the Nano (I know, I know) the below solution didn't fix the issue. I thought it may be due to the voltage dropping when the Nano supplies the 5vo to the mosfet but I'm not sure why holding the switch would stop that from happening. Regardless I swapped to a linear voltage regulator and then it started to flash, *"Hurrah!"* -- almost.

With the regulator in it was running the code constantly. I decided to print the runcount and I got a number over 35,000, meaning it would run the flash 5 times for \>35,000 times. Although curious as to what would happen when it reached zero, I decided to go back to my original code and...now it works.

So I guess the lesson is: Even if you can calculate the drop off, don't run your Nano on a voltage divider.

---

**I have checked the answer below as the solution, although it didn't fix my issue there is no reason it shouldn't have worked and it may be useful to someone else.**

# Answer
You could define an `int runcount = 0` variable at the top. Then change your loop logic to something like

```
if (counts > 10) {
  runcount = 2;
}

if (runcount-- > 0) {
  //flashy flashy
}

```

The effect is, that while button is pressed and `counts > 10`, runcount is set to two. Every time we check the runcount, it is decreased by 1. While the button is pressed, runcount is resat to 2. If you let go of the button, runcount will be 1 at the start of the if condition check. It will be compared to 0, condition will be true, and it will then be decreased to 0 and the if section will be executed one last time. Using another number than 2 will change the number of extra runs.
> 0 votes

---
Tags: arduino-nano, analogread, analogwrite
---


# Question
Title: On ATtiny84, why does delay() stop working properly when RadioHead ASK is used?
When I call the `delay()` function on the ATtiny84 micro, it delays for the expected time, until I call the `init()` function on an `RH_ASK` object. After this, the micro seems to freeze.

```
#include <RH_ASK.h>
RH_ASK driver();

void setup() {
    delay(100); // works ok
    driver.init();
    delay(100); // freezes a long time (or maybe forever?)
}

```

# Answer
After reading the source code, `RH_ASK.cpp`, I found a commented out macro.

```
// RH_ASK on ATtiny8x uses Timer 0 to generate interrupts 8 times per
// bit interval. Timer 0 is used by Arduino platform for millis()/micros()
// which is used by delay()
// Uncomment the define RH_ASK_ATTINY_USE_TIMER1 bellow, if you want to use
// Timer 1 instead of Timer 0 on ATtiny
// Timer 1 is also used by some other libraries, e.g. Servo. Alway check
// usage of Timer 1 before enabling this.
// Should be moved to header file
//#define RH_ASK_ATTINY_USE_TIMER1

```

In other words, the default behaviour of RadioHead ASK `init()` is to use **Timer 0**, which causes `delay()` (which uses `millis()`/`micro()`) to behave incorrectly.

**To fix:** Tell RadioHead ASK to use **Timer 1**. Because the `RH_ASK_ATTINY_USE_TIMER1` macro is in the source and not the header (for now), you have to modify the actual RadioHead ASK source file, `RH_ASK.cpp`\*. Un-comment the line `#define RH_ASK_ATTINY_USE_TIMER1` which will use **Timer 1** instead of **Timer 0**. Re-compile your code, and `delay()` should start working properly again.

* `RH_ASK.cpp` can be found in `%USERPROFILE%\Documents\Arduino\libraries\RadioHead` on Windows, if you installed RadioHead via the Arduino IDE library manager.
> 2 votes

---
Tags: attiny
---


title: Upload to board with no USB connection

text:
# Question
Title: Upload to board with no USB connection
I have a Spark Fun Pro Micro (ATmega32U4) without a USB connection (it was broken off at an earlier point) that I want to use to duplicate a prototype running on another Pro Micro.

How can I upload a sketch to an Arduino without a USB connection?

# Answer
> 0 votes
The best solution is to solder back the connector or to buy a new board.

Ways to use a board with ATmega32u4 without USB for development are:

* ICSP programming
* upload over a serial bootloader.

Both require additional hardware.

For ICSP upload you need a programmer device. After configuring it, select the programmer in Tools menu and you can use "Upload using programmer" from the sketch menu. It is even possible to create a custom board definition which will use "Upload using programmer" with the "Upload" button from the toolbar.

To make serial upload possible you will need and USB-to-TTL-Serial adapter and Optiboot compiled for the 32u4. To burn the bootloader you will need an ICSP programmer or a second Arduino to use with the Arduino as ISP sketch.

# Answer
> -1 votes
Use a programmer, such as one based on CH341A that has pins broken out for CLK, CS, MOSI, MIOS \[sic\], GND, 3.3V, and connected those to pins on the Pro Micro as follows:

```
Programmer    Pro Micro
CLK-----------15 (SCK)
CS------------RST
MOSI----------16 (MOSI)
MIOS----------14 (MISO)
GND-----------GND
3.3V----------RAW

```

It doesn't appear that the programmer is supported in the Arduino IDE, so I grabbed chavrprog.

And ran the command `$ sudo ./chavrprog -d mega32u4 -a s ~/Arduino/test/test.ino.leonardo.hex`

---
Tags: avr, atmega32u4, programmer
---


# Question
Title: Recovering from lost USB connection (Leonardo to Raspberry Pi)
I have several Arduino Leonardos connected to a Raspberry Pi (running Ubuntu) via USB. They appear as `/dev/ttyACM0`, `/dev/ttyACM1`, etc.

Occasionally, one will disappear and even pressing the Arduino's reset button won't bring it back. Is there any way to "refresh" or "reinitialize" the ttyACM\* devices to make them reappear without having to reboot the Raspberry Pi?

# Answer
The USB devices are created dynamically. You might find this question and answer from the SE Raspberry Pi helpful: How to force rescan of USB serial devices?.

You can use the **dmesg(8)** command on the Pi to see the messages generated by the USB sub-system. Watch the output to see if there are errors associated with the Arduino dropping off the bus. This is what the output will look like (roughly, this is from an Uno connected to a Raspbian system), note the last line which is a disconnect from unplugging the Uno from the Pi. Resetting the Uno did not do anything that the Pi saw. I would guess that that is because the reset button on the Uno doesn't reset the 16U2 (the processor handling the USB port).

```
[  459.936719] usb 1-1.3: new full-speed USB device number 5 using dwc_otg
[  460.051182] usb 1-1.3: New USB device found, idVendor=2a03, idProduct=0043
[  460.051212] usb 1-1.3: New USB device strings: Mfr=1, Product=2, SerialNumber=220
[  460.051229] usb 1-1.3: Product: Arduino Uno
[  460.051245] usb 1-1.3: Manufacturer: Arduino Srl
[  460.051262] usb 1-1.3: SerialNumber: 75431343334351F061E2
[  460.088018] cdc_acm 1-1.3:1.0: ttyACM0: USB ACM device
[  460.089250] usbcore: registered new interface driver cdc_acm
[  460.089270] cdc_acm: USB Abstract Control Model driver for USB modems and ISDN adapters
[  534.212365] usb 1-1.3: USB disconnect, device number 5

```

From reading that question and its answers it appears that some versions of the Leonardo may have problems that can cause this behavior.

Another thing that might be worth looking into is the power supply for the Leonardos. If they are being powered by the Pi through the USB interface that might be pushing the capability of the Pi to provide power.
> 3 votes

# Answer
Every device is also found on a symlink, named by its hardware wireing. So this names stay the same after re-appering!

```
root@raspberrypi:/etc/udev/rules.d# ls -l /dev/serial/by-path/
total 0
lrwxrwxrwx 1 root root 13 May  2 18:11 platform-20980000.usb-usb-0:1.2:1.0 -> ../../ttyACM0
lrwxrwxrwx 1 root root 13 May  2 18:11 platform-20980000.usb-usb-0:1.3.1:1.0-port0 -> ../../ttyUSB0
lrwxrwxrwx 1 root root 13 May  2 18:11 platform-20980000.usb-usb-0:1.3.1:1.0-port1 -> ../../ttyUSB1

```
> 0 votes

---
Tags: usb, arduino-leonardo, linux
---


# Question
Title: Unable to upload code to my digispark ATtiny 85 after upgrading bootloader
I've just received my digispark ATtiny85 (model B, I believe). I'm using Pop\_OS for my PC, had a bit of a headache getting the arduino IDE recognising the device but after some trial and error I got there.

When uploading a sketch I would then get *erase errors* and if I recall correctly it was error -71.

I couldn't work it out but found out that my boards came with v1.6 of the micronucleus firmware. So I upgraded to the latest which is v2.6. Now when I upload a sketch however the output looks like the following

```
Sketch uses 718 bytes (11%) of program storage space. Maximum is 6012 bytes.
Global variables use 9 bytes of dynamic memory.
Running Digispark Uploader...
Plug in device now... (will timeout in 60 seconds)
Warning: device with unknown new version of Micronucleus detected.
This tool doesn't know how to upload to this new device. Updates may be available.
Device reports version as: 2.6
Warning: device with unknown new version of Micronucleus detected.
This tool doesn't know how to upload to this new device. Updates may be available.
Device reports version as: 2.6

```

I don't have a clue what to try next as everything feels like it should be at a working point. Not sure how to decipher "Updates may be available". I'm using the latest arduino IDE, with the digistump board manager url and using the latest micronucleus firmware for the board.

I tried to re-flash the firmware to v2.4 just on the off chance that the firmware was too new to be supported in arduino IDE but I received the same error as above but with just a different version number reported.

# Answer
> 2 votes
It seems the latest version (1.6.7) of the Digispark board support package is quite old, older than I'd have guessed. And so it does come with an old Micronucleus programming tool. The tool appears to compare the major version number of the firmware as found in the USB device version. And since the Micronucleus tool in the 1.6.7 package is expecting nothing newer than major version 1, major version 2 of the firmware is not going to work with it.

You have a couple of options.

### Reprogram old firmware (1.11)

You already seem familiar with burning .hex files. So, if you want to use the latest official Digispark board support you need to burn the hex file for Micronucleus version 1.11. I replicated your error, but using an OLIMEXINO-85-ASM which is highly similar to the Digispark but may not be identical. After programming micronucleus-1.11.hex the board worked with the official Digispark board support package.

### Use ATTinyCore

However, you could also just abandon that old official package and use ATTinyCore which does come with a Micronucleus bootloader new enough to program the Digispark board with Micronucleus 2.6. I tested that as well.

### Patch a new Micronucleus tool into your old official support package

You can replace the Micronucleus tool with a newer one in your *arduino15*`/packages/digistump/tools/micronucleus/2.0a4` directory. Incidentally, I have no idea where the `2.0a4` comes from, but it is not indicative of a Micronucleus 2.0 in any way that I can tell.

For testing I put the 2.6 firmware on the board, specifically the t85\_default.hex file, and stole the Micronucleus tool out of the latest ATTinyCore board packages tools directory, by renaming the existing file an symbolically linking in the other one:

```
$ pwd
/home/user/.arduino15/packages/digistump/tools/micronucleus/2.0a4
$ ls
launcher  micronucleus
$ mv -iv micronucleus micronucleus.backup
renamed 'micronucleus' -> 'micronucleus.backup'
$ ln -s ~/.arduino15/packages/ATTinyCore/tools/micronucleus/2.5-azd1b/micronucleus
$ readlink micronucleus
/home/user/.arduino15/packages/ATTinyCore/tools/micronucleus/2.5-azd1b/micronucleus
$

```

And that works as well.

---
Tags: arduino-ide, attiny85, firmware
---


# Question
Title: Simulate pin behaviour based on PulseView recording
I have a bunch of PulseView recordings from an existing device. Currently to verify if my Arduino handles the input properly I always use the real device. However it would be great if I could somehow test my code with existing recordings. I am using platform.io. Perhaps there is some test framework that can mock a pin based on a recording? For example when I start the test, pin 8 should be high for 10μs then low for 7 and so on. Is there some framework to mock such things?

# Answer
> 1 votes
I've never heard of such a test framework and I doubt there is one, at least for hobbyists. Such a framework would need to include a lot of hardware to accommodate all the possible electrical test cases and also a rather complex software to control the hardware according to user input. So it is not really practical to have a general testing framework.

But you can build your own for your specific case. Using another Arduino and outputting the requested pulses should not be too difficult. In the simplest version just some `digitalWrite()`s and some `delayMicroseconds()` calls.

---
Tags: testing, platformio
---


# Question
Title: Arduino Uno R3 (with Atmega 16u2) and MAC OSX 10.11 (El capitan) not working
I have Chinese copy of arduino which uses ATmega16u2 (at least that's what is written on the chip itself). When connected, it is visible in system information under USB section:

> Communication Device:
>
> Product ID: 0x0043
> Vendor ID: 0x2341
> Version: 0.01
> Serial Number: 75237333636351600270
> Speed: Up to 12 Mb/sec
> Manufacturer: Arduino (www.arduino.cc)
> Location ID: 0x1a140000 / 6
> Current Available (mA): 1000
> Current Required (mA): 100
> Extra Operating Current (mA): 0
> Built-In: Yes

But it doesn't show up in arduino program ports.

I've searched a lot, and it seems that people mostly had problems with arduinos on CH340 chips. I also have one such arduino, but it works properly after installing signed drivers as described here.

Are there any solutions for atmega 16u2 chips?

My system:

* OS X El Capitan 10.11.2 (15C50) (hackintosh if it changes anything).
* Arduino Uno R3 (chinese copy)
* Arduino soft version 1.6.7

Additional info: I've tried connecting Arduino Mega 2560 with Atmega16u2 chip and it also doesn't work

Info I've got using Nick's awesome program:

```
Atmega chip detector.
Written by Nick Gammon.
Version 1.17
Compiled on Jan  8 2016 at 21:35:08 with Arduino IDE 10607.
Attempting to enter ICSP programming mode ...
Entered programming mode OK.
Signature = 0x1E 0x94 0x89
Processor = ATmega16U2
Flash memory size = 16384 bytes.
LFuse = 0xFF
HFuse = 0xD9
EFuse = 0xF4
Lock byte = 0xFF
Clock calibration = 0x56
Bootloader in use: No
EEPROM preserved through erase: No
Watchdog timer always on: No
Bootloader is 4096 bytes starting at 3000

Bootloader:

3000: 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
3010: 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
3020: 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
...

MD5 sum of bootloader = 0x6A 0xE5 0x9E 0x64 0x85 0x03 0x77 0xEE 0x54 0x70 0xC8 0x54 0x76 0x15 0x51 0xEA
No bootloader (all 0xFF)

First 256 bytes of program memory:

0: 0x90 0xC0 0x00 0x00 0xA9 0xC0 0x00 0x00 0xA7 0xC0 0x00 0x00 0xA5 0xC0 0x00 0x00
10: 0xA3 0xC0 0x00 0x00 0xA1 0xC0 0x00 0x00 0x9F 0xC0 0x00 0x00 0x9D 0xC0 0x00 0x00
20: 0x9B 0xC0 0x00 0x00 0x99 0xC0 0x00 0x00 0x97 0xC0 0x00 0x00 0x48 0xC4 0x00 0x00
30: 0x0C 0xC4 0x00 0x00 0x91 0xC0 0x00 0x00 0x8F 0xC0 0x00 0x00 0x8D 0xC0 0x00 0x00
40: 0x8B 0xC0 0x00 0x00 0x89 0xC0 0x00 0x00 0x87 0xC0 0x00 0x00 0x85 0xC0 0x00 0x00
50: 0x83 0xC0 0x00 0x00 0x81 0xC0 0x00 0x00 0x7F 0xC0 0x00 0x00 0x02 0xC1 0x00 0x00
60: 0x7B 0xC0 0x00 0x00 0x79 0xC0 0x00 0x00 0x77 0xC0 0x00 0x00 0x75 0xC0 0x00 0x00
70: 0x73 0xC0 0x00 0x00 0x71 0xC0 0x00 0x00 0x6F 0xC0 0x00 0x00 0x6D 0xC0 0x00 0x00
80: 0x6B 0xC0 0x00 0x00 0x69 0xC0 0x00 0x00 0x67 0xC0 0x00 0x00 0x65 0xC0 0x00 0x00
90: 0x63 0xC0 0x00 0x00 0x61 0xC0 0x00 0x00 0x12 0x01 0x10 0x01 0x02 0x00 0x00 0x08
A0: 0x41 0x23 0x43 0x00 0x01 0x00 0x01 0x02 0xDC 0x01 0x09 0x02 0x3E 0x00 0x02 0x01
B0: 0x00 0xC0 0x32 0x09 0x04 0x00 0x00 0x01 0x02 0x02 0x01 0x00 0x05 0x24 0x00 0x01
C0: 0x10 0x04 0x24 0x02 0x06 0x05 0x24 0x06 0x00 0x01 0x07 0x05 0x82 0x03 0x08 0x00
D0: 0xFF 0x09 0x04 0x01 0x00 0x02 0x0A 0x00 0x00 0x00 0x07 0x05 0x04 0x02 0x40 0x00
E0: 0x01 0x07 0x05 0x83 0x02 0x40 0x00 0x01 0x04 0x03 0x09 0x04 0x32 0x03 0x41 0x00
F0: 0x72 0x00 0x64 0x00 0x75 0x00 0x69 0x00 0x6E 0x00 0x6F 0x00 0x20 0x00 0x28 0x00

Programming mode off.

```

Fuses info:

```
Atmega fuse calculator.
Written by Nick Gammon.
Version 1.10
Compiled on Jan  8 2016 at 22:19:34 with Arduino IDE 10607.
Attempting to enter programming mode ...
Entered programming mode OK.
Signature = 0x1E 0x94 0x89
Processor = ATmega16U2
Flash memory size = 16384
LFuse = 0xFF
HFuse = 0xD9
EFuse = 0xF4
Lock byte = 0xFF
Clock calibration = 0x56
Hardare Boot Enable..................... [X]
Debug Wire Enable....................... [ ]
External Reset Disable.................. [ ]
Enable Serial (ICSP) Programming........ [X]
Watchdog Timer Always On................ [ ]
Preserve EEPROM through chip erase...... [ ]
Boot into bootloader.................... [ ]
Divide clock by 8....................... [ ]
Clock output............................ [ ]
Bootloader size: 4096 bytes.
Start-up time: SUT0: [ ]  SUT1: [ ] (see datasheet)
Clock source: low-power crystal.
Brownout detection at: 3.0V.

```

# Answer
> 0 votes
After two months I finally found a solution. The problem was with USB drivers for my hackintosh. Few days ago new Multibeast 8.1 was released with new USB drivers. After installing El Capitan 10.11.4 update and then installing USB drivers from Multibeast my Arduinos magically starter working again!

# Answer
> 3 votes
You can use my Chip detector sketch to confirm (using another Arduino to run the sketch) if the target chip is a Atmega16u2 or not, and if so, what fuses etc. are set.

Wiring would be like this:

Close-up:

ICSP header (from above):

You should see something like this:

```
Atmega chip detector.
Written by Nick Gammon.
Version 1.17
Compiled on Jan  3 2016 at 07:34:08 with Arduino IDE 10605.
Attempting to enter ICSP programming mode ...
Entered programming mode OK.
Signature = 0x1E 0x94 0x89
Processor = ATmega16U2
Flash memory size = 16384 bytes.
LFuse = 0xEF
HFuse = 0xD9
EFuse = 0xF4
Lock byte = 0xCF
Clock calibration = 0x96
Bootloader in use: No
EEPROM preserved through erase: No
Watchdog timer always on: No
Bootloader is 4096 bytes starting at 3000

Bootloader:

3000: 0x4B 0xC0 0x00 0x00 0x64 0xC0 0x00 0x00 0x62 0xC0 0x00 0x00 0x60 0xC0 0x00 0x00
3010: 0x5E 0xC0 0x00 0x00 0x5C 0xC0 0x00 0x00 0x5A 0xC0 0x00 0x00 0x58 0xC0 0x00 0x00
3020: 0x56 0xC0 0x00 0x00 0x54 0xC0 0x00 0x00 0x52 0xC0 0x00 0x00 0xEE 0xC4 0x00 0x00

...

MD5 sum of bootloader = 0xD8 0x8C 0x70 0x6D 0xFE 0x1F 0xDC 0x38 0x82 0x1E 0xCE 0xAE 0x23 0xB2 0xE6 0xE7
Bootloader name: Arduino-dfu-usbserial-atmega16u2-Uno-Rev3

First 256 bytes of program memory:

0: 0x90 0xC0 0x00 0x00 0xA9 0xC0 0x00 0x00 0xA7 0xC0 0x00 0x00 0xA5 0xC0 0x00 0x00
10: 0xA3 0xC0 0x00 0x00 0xA1 0xC0 0x00 0x00 0x9F 0xC0 0x00 0x00 0x9D 0xC0 0x00 0x00
20: 0x9B 0xC0 0x00 0x00 0x99 0xC0 0x00 0x00 0x97 0xC0 0x00 0x00 0x48 0xC4 0x00 0x00
30: 0x0C 0xC4 0x00 0x00 0x91 0xC0 0x00 0x00 0x8F 0xC0 0x00 0x00 0x8D 0xC0 0x00 0x00
40: 0x8B 0xC0 0x00 0x00 0x89 0xC0 0x00 0x00 0x87 0xC0 0x00 0x00 0x85 0xC0 0x00 0x00
50: 0x83 0xC0 0x00 0x00 0x81 0xC0 0x00 0x00 0x7F 0xC0 0x00 0x00 0x02 0xC1 0x00 0x00
60: 0x7B 0xC0 0x00 0x00 0x79 0xC0 0x00 0x00 0x77 0xC0 0x00 0x00 0x75 0xC0 0x00 0x00
70: 0x73 0xC0 0x00 0x00 0x71 0xC0 0x00 0x00 0x6F 0xC0 0x00 0x00 0x6D 0xC0 0x00 0x00
80: 0x6B 0xC0 0x00 0x00 0x69 0xC0 0x00 0x00 0x67 0xC0 0x00 0x00 0x65 0xC0 0x00 0x00
90: 0x63 0xC0 0x00 0x00 0x61 0xC0 0x00 0x00 0x12 0x01 0x10 0x01 0x02 0x00 0x00 0x08
A0: 0x41 0x23 0x43 0x00 0x01 0x00 0x01 0x02 0xDC 0x01 0x09 0x02 0x3E 0x00 0x02 0x01
B0: 0x00 0xC0 0x32 0x09 0x04 0x00 0x00 0x01 0x02 0x02 0x01 0x00 0x05 0x24 0x00 0x01
C0: 0x10 0x04 0x24 0x02 0x06 0x05 0x24 0x06 0x00 0x01 0x07 0x05 0x82 0x03 0x08 0x00
D0: 0xFF 0x09 0x04 0x01 0x00 0x02 0x0A 0x00 0x00 0x00 0x07 0x05 0x04 0x02 0x40 0x00
E0: 0x01 0x07 0x05 0x83 0x02 0x40 0x00 0x01 0x04 0x03 0x09 0x04 0x32 0x03 0x41 0x00
F0: 0x72 0x00 0x64 0x00 0x75 0x00 0x69 0x00 0x6E 0x00 0x6F 0x00 0x20 0x00 0x28 0x00

Programming mode off.

```

---

On my genuine Uno I get these settings from OS/X:

```
  Product ID:   0x0043
  Vendor ID:    0x2341
  Version:   0.01
  Serial Number:    74134373733351300000
  Speed:    Up to 12 Mb/sec
  Manufacturer: Arduino (www.arduino.cc)
  Location ID:  0xfd130000 / 8
  Current Available (mA):   500
  Current Required (mA):    100

```

I haven't had any problems using the Uno with OS/X however I don't remember whether or not I had to install a device driver for it.

---

> Info I've got using Nick's awesome program:

```
...
Signature = 0x1E 0x94 0x89
Processor = ATmega16U2
Flash memory size = 16384 bytes.
LFuse = 0xFF
HFuse = 0xD9
EFuse = 0xF4
...
Bootloader:

3000: 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
....

MD5 sum of bootloader = 0x6A 0xE5 0x9E 0x64 0x85 0x03 0x77 0xEE 0x54 0x70 0xC8 0x54 0x76 0x15 0x51 0xEA
No bootloader (all 0xFF)

```

It is interesting that they are shipping without a bootloader on the ATmega16U2. Whilst that chip doesn't need one (and it is disabled by the fuses in mine) clearly there are *some* differences. I checked the "first 256 bytes" of the code between your board and mine and they are the same, so possibly the main code is identical.

I would try to plug your Arduino into another Mac, if possible. It may be that your "hackintosh" has enough differences in its loaded software that it doesn't recognize that USB interface.

# Answer
> 1 votes
There is complete documentation on Arduino website, I followed the steps and I was able to install driver

https://support.arduino.cc/hc/en-us/articles/4408887452434-Flash-USB-to-serial-firmware-in-DFU-mode

---
Tags: arduino-uno, arduino-mega, usb, mac-os
---


# Question
Title: Strange problems driving an Optocoupler (PC123) with a Nano
I'm having some strange issues getting a Nano to drive a PC123 optocoupler properly.

What I'm trying to do: In the real world, I need to press a button ONCE, and have the device that I'm connecting this too, see FIVE quick button presses... (Input 1 press, and Output 5 presses, at the timing I set in the code). I am using a mix of LED "Blinking / Flashing" code to do what I need.

My connection of the Opto seems fine. It works perfectly if I run this "BLINK" code: (With the PC123 optocoupler connected to Pin13):

```
// the setup function runs once when you press reset or power the board
void setup() {
  // initialize digital pin LED_BUILTIN as an output.
  pinMode(LED_BUILTIN, OUTPUT);
}

// the loop function runs over and over again forever
void loop() {
  digitalWrite(LED_BUILTIN, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(200);                       // wait for a while
  digitalWrite(LED_BUILTIN, LOW);    // turn the LED off by making the voltage LOW
  delay(200);                       // wait for a while
}

```

When I run this, the Optocoupler turns ON and OFF as I need, and the device I am controlling is happy, but it obviously runs forever as I have no counters or anything.. (This proves my hardware is good at this point!)

But, when I try this following code, with the exact same hardware circuit, the output goes HIGH as soon as I ground Pin2, and it stays HIGH! It holds the optocoupler ON and there is no ON/OFF or "blinking or flashing". BUT, it only does this when the OPTO is connected (there is load) on the Nano output. If I disconnect the Opto, the Pin13 LED will flash as expected. And my code seems to work fine (on the on-board Pin 13 LED).

VERY interestingly and very strangley though, when the "power-up" Pin 13 LED flashes (i.e- when you power cycle the Nano, or press the reset button) this will trigger the Opto ON/OFF perfectly! But when the code starts to run, via my Pin 2 input switch, with the Opto connected to the Nano, the output locks HIGH again! What the!?

```
int ledPin = 13;   // LED is connected to digital pin 13
int switchPin = 2;   // switch connected to digital pin 2
int switchValue;   // a variable to keep track of when switch is pressed
int counter = 0;

void setup()
{
      pinMode(ledPin, OUTPUT);   // sets the ledPin to be an output
      pinMode(switchPin, INPUT);   // sets the switchPin to be an input
      digitalWrite(switchPin, HIGH);   // sets the default (unpressed) state of switchPin to HIGH
}

void loop()   // run over and over again
{

    switchValue = digitalRead(switchPin);   // check to see if the switch is pressed
      if ((switchValue == LOW) && (counter <= 1)) {   // if the switch is pressed then,
          for(int ii = 0; ii <= 5; ii++)   // 7 = 4 flashes, 5 = 3 flashes, etc
      {
          digitalWrite(ledPin, !digitalRead(ledPin));
          delay(100); // Length of the flashes in ms
          counter++;
      }
    }
      if (switchValue == HIGH)
      //if ((switchValue == HIGH) && (counter > 2))
      {
           counter = 0;
           delay(100); // Debounce

      }
}

```

I have tried filtering capacitors, diodes, resistance, pull-ups, pull-downs, everything I can think of and I am at a loss. Can anyone help me out? I'm thinking its a code issue (because I am an Arduino noob - please be gentle!), or a maybe a deficiency in the hardware of the Nano? FYI, I have done all of this on different Input and Output pins with the same results.

Any help would be greatly appreciated!

# Answer
**Thank you @DrG** for your excellent reply! I really appreciate the time you have taken on this. I will answer your questions here:

* What am I trying to do? I am adding the Nano to a Ham Radio Transceiver, that can change frequency (via button presses on the microphone) in only 1kHz, or 10kHz frequency steps. What I am doing here, is by adding this Nano to the microphone button circuit, and selecting the "1kKz" step option, I will get a "5kHz" step! This is great for searching for SSB signals quicky (1kHz is slow, 10kHz is too big and you miss some!). So, I press 1 time, the radio will step 5 times. This is the purpose of my project. :)
* How have I wired it up? **Exactly** the same as you have shown, and I have also used both D13 (not recommended as you said, and D10 (as you have used in your proposed answer).
* Your code is great, and I really like that it will use D13 to show what it's doing on the LED, and use D10 to drive the Opto. GREAT!

Now - here is the crazy part... Even with your code, and the exact circuit (other than my PC123 vs your 4N25 (I have 4N35's here too), I get exactly the same problem I had before! As soon as the Nano drives the Opto, regardless of the GPIO I configure, it locks HIGH! The D13 LED flashes as expected, but D10 goes high and never goes low again, until a reboot or power cycle...

I now believe that even my original code is fine (not the best way to do it, but still functional) but my NANO is faulty! It's an "ELEGOO NANO" clone. And I think it's the issue!!!

Your input is not wasted as I will use your code, it is much better than mine! :) I am going to get a new NANO and try this again, and now I am pretty confident that with a new Arduino, this will work! I will report back and let you know how it goes.

Best regards,

Pez
> 0 votes

# Answer
I confess that I am not sure what you are trying to do, but I have an idea and I hope this helps. First, there are several Nanos and not all of them are AVR-based. I used an OLD Nano clone and even had to select the ATMega 328P (old bootloader) - it's been a while. I also used a 4N25 opto \[this could make a difference, look at the data sheet for your device)..

You have not shown exactly how you have things wired up. Let's assume that it is like this - and I DO NOT think it is a good way of doing things (bear with me), and

Using this code, it works exactly as it should.

```
int ledPin = 13;
int switchPin = 2;
int nflashes=10;
void setup()
{
  pinMode(ledPin, OUTPUT);
  pinMode(switchPin, INPUT);
}

void loop() {
  if ( digitalRead(switchPin)==HIGH) {
  for (int i = 0; i < nflashes; i++) {
      digitalWrite(ledPin, !digitalRead(ledPin));
      delay(100);
    }
    while (digitalRead(switchPin) == HIGH); // wait until switch is released
  }
}

```

The opto turns on with D13 lighting the added LED and the onboard LED also turns on. Note that the onboard LED is dimmer because you are driving TWO LEDs ; the onboard one attached to D13 and the LED inside the opto and you have no current limiting resistor on the opto LED. I'm not sure if you have it wired this way but if so, in my view, it is not a good way of doing things.

Apart from that, think about what happens when you hit reset...my guess is that the ATMega sets all GPIO to input AND the boot loader initializes the onboard LED to an output and apparently flashes that LED - I am guessing and have not gone through the code. I notice that with the above scheme, I see both the new LED and the onboard LED flash once briefly on reset, as I would expect.

Hooking up the switch as I have shown (pulled to ground) will eliminate any problems from floating states during a reset. It will only be read HIGH when you press the switch after you initialize the GPIO.

---

I would put the opto on a separate GPIO like this:

...and using this slightly modified code

```
int ledPin = 13;
int switchPin = 2;
int optoPin=10;
int nflashes=10;
void setup()
{
  pinMode(ledPin, OUTPUT);
  pinMode(switchPin, INPUT);
  pinMode(optoPin, OUTPUT);
}

void loop() {
  if ( digitalRead(switchPin)==HIGH) {
  for (int i = 0; i < nflashes; i++) {
      digitalWrite(ledPin, !digitalRead(ledPin));
      digitalWrite(optoPin, !digitalRead(optoPin));
      delay(100);
    }
    while (digitalRead(switchPin) == HIGH); // wait here until switch is released
  }
}

```

Everything works fine and the new LED does not flash during a reset and nothing gets stuck.

I wish you had show exactly what connections you made and I apologize if I missed some point.

Again, hope it helps.
> 0 votes

---
Tags: arduino-nano, led
---


# Question
Title: nRF52832 BLE "conn_handle" to disconnect the current connected devices
I'm working on nRF52832 Bluefruit Adafruit Module. I want the BLE connection to disconnect using a function and can call whenever required. But the issue is the disconnect function needs "conn\_handle" to disconnect from the current connected Client.

Can anyone help me find where I can get the "conn\_handle" of the connected client?

```
/**
 * Callback invoked when a connection is dropped
 * @param conn_handle
 * @param reason is a BLE_HCI_STATUS_CODE which can be found in ble_hci.h
 */
void disconnect_callback(uint16_t conn_handle, uint8_t reason)
{
  (void) conn_handle;
  (void) reason;

  connection_num--;

  // Mark the ID as invalid
  int id  = findConnHandle(conn_handle);

  // Non-existant connection, something went wrong, DBG !!!
  if ( id < 0 ) return;

  // Mark conn handle as invalid
  prphs[id].conn_handle = BLE_CONN_HANDLE_INVALID;

  Serial.print(prphs[id].name);
  Serial.println(" disconnected!");
}

```

The below complete code is for "Central Bleuart Multi"-

```
/*********************************************************************

 This is an example for our nRF52 based Bluefruit LE modules

 Pick one up today in the adafruit shop!

 Adafruit invests time and resources providing this open source code,
 please support Adafruit and open-source hardware by purchasing
 products from Adafruit!

 MIT license, check LICENSE for more information
 All text above, and the splash screen below must be included in
 any redistribution
*********************************************************************/

/* This sketch demonstrates the central API() that allows you to connect
 * to multiple peripherals boards (Bluefruit nRF52 in peripheral mode, or
 * any Bluefruit nRF51 boards).
 *
 * One or more Bluefruit boards, configured as a peripheral with the
 * bleuart service running are required for this demo.
 *
 * This sketch will:
 *  - Read data from the HW serial port (normally USB serial, accessible
 *    via the Serial Monitor for example), and send any incoming data to
 *    all other peripherals connected to the central device.
 *  - Forward any incoming bleuart messages from a peripheral to all of
 *    the other connected devices.
 *
 * It is recommended to give each peripheral board a distinct name in order
 * to more easily distinguish the individual devices.
 *
 * Connection Handle Explanation
 * -----------------------------
 * The total number of connections is BLE_MAX_CONNECTION (20)
 *
 * The 'connection handle' is an integer number assigned by the SoftDevice
 * (Nordic's proprietary BLE stack). Each connection will receive it's own
 * numeric 'handle' starting from 0 to BLE_MAX_CONNECTION-1, depending on the order
 * of connection(s).
 *
 * - E.g If our Central board connects to a mobile phone first (running as a peripheral),
 * then afterwards connects to another Bluefruit board running in peripheral mode, then
 * the connection handle of mobile phone is 0, and the handle for the Bluefruit
 * board is 1, and so on.
 */

/* LED PATTERNS
 * ------------
 * LED_RED   - Blinks pattern changes based on the number of connections.
 * LED_BLUE  - Blinks constantly when scanning
 */

#include <bluefruit.h>

// Struct containing peripheral info
typedef struct
{
  char name[16+1];

  uint16_t conn_handle;

  // Each prph need its own bleuart client service
  BLEClientUart bleuart;
} prph_info_t;

/* Peripheral info array (one per peripheral device)
 *
 * There are 'BLE_MAX_CONNECTION' central connections, but the
 * the connection handle can be numerically larger (for example if
 * the peripheral role is also used, such as connecting to a mobile
 * device). As such, we need to convert connection handles <-> the array
 * index where appropriate to prevent out of array accesses.
 *
 * Note: One can simply declares the array with BLE_MAX_CONNECTION and use connection
 * handle as index directly with the expense of SRAM.
 */
prph_info_t prphs[BLE_MAX_CONNECTION];

// Software Timer for blinking the RED LED
SoftwareTimer blinkTimer;
uint8_t connection_num = 0; // for blink pattern

void setup()
{
  Serial.begin(115200);
  while ( !Serial ) delay(10);   // for nrf52840 with native usb

  // Initialize blinkTimer for 100 ms and start it
  blinkTimer.begin(100, blink_timer_callback);
  blinkTimer.start();

  Serial.println("Bluefruit52 Central Multi BLEUART Example");
  Serial.println("-----------------------------------------\n");

  // Initialize Bluefruit with max concurrent connections as Peripheral = 0, Central = 4
  // SRAM usage required by SoftDevice will increase with number of connections
  Bluefruit.begin(0, 4);

  // Set Name
  Bluefruit.setName("Bluefruit52 Central");

  // Init peripheral pool
  for (uint8_t idx=0; idx<BLE_MAX_CONNECTION; idx++)
  {
    // Invalid all connection handle
    prphs[idx].conn_handle = BLE_CONN_HANDLE_INVALID;

    // All of BLE Central Uart Serivce
    prphs[idx].bleuart.begin();
    prphs[idx].bleuart.setRxCallback(bleuart_rx_callback);
  }

  // Callbacks for Central
  Bluefruit.Central.setConnectCallback(connect_callback);
  Bluefruit.Central.setDisconnectCallback(disconnect_callback);

  /* Start Central Scanning
   * - Enable auto scan if disconnected
   * - Interval = 100 ms, window = 80 ms
   * - Filter only accept bleuart service in advertising
   * - Don't use active scan (used to retrieve the optional scan response adv packet)
   * - Start(0) = will scan forever since no timeout is given
   */
  Bluefruit.Scanner.setRxCallback(scan_callback);
  Bluefruit.Scanner.restartOnDisconnect(true);
  Bluefruit.Scanner.setInterval(160, 80);       // in units of 0.625 ms
  Bluefruit.Scanner.filterUuid(BLEUART_UUID_SERVICE);
  Bluefruit.Scanner.useActiveScan(false);       // Don't request scan response data
  Bluefruit.Scanner.start(0);                   // 0 = Don't stop scanning after n seconds
}

/**
 * Callback invoked when scanner picks up an advertising packet
 * @param report Structural advertising data
 */
void scan_callback(ble_gap_evt_adv_report_t* report)
{
  // Since we configure the scanner with filterUuid()
  // Scan callback only invoked for device with bleuart service advertised
  // Connect to the device with bleuart service in advertising packet
  Bluefruit.Central.connect(report);
}

/**
 * Callback invoked when an connection is established
 * @param conn_handle
 */
void connect_callback(uint16_t conn_handle)
{
  // Find an available ID to use
  int id  = findConnHandle(BLE_CONN_HANDLE_INVALID);

  // Eeek: Exceeded the number of connections !!!
  if ( id < 0 ) return;

  prph_info_t* peer = &prphs[id];
  peer->conn_handle = conn_handle;

  Bluefruit.Connection(conn_handle)->getPeerName(peer->name, sizeof(peer->name)-1);

  Serial.print("Connected to ");
  Serial.println(peer->name);

  Serial.print("Discovering BLE UART service ... ");

  if ( peer->bleuart.discover(conn_handle) )
  {
    Serial.println("Found it");
    Serial.println("Enabling TXD characteristic's CCCD notify bit");
    peer->bleuart.enableTXD();

    Serial.println("Continue scanning for more peripherals");
    Bluefruit.Scanner.start(0);

    Serial.println("Enter some text in the Serial Monitor to send it to all connected peripherals:");
  } else
  {
    Serial.println("Found ... NOTHING!");

    // disconnect since we couldn't find bleuart service
    Bluefruit.disconnect(conn_handle);
  }

  connection_num++;
}

/**
 * Callback invoked when a connection is dropped
 * @param conn_handle
 * @param reason is a BLE_HCI_STATUS_CODE which can be found in ble_hci.h
 */
void disconnect_callback(uint16_t conn_handle, uint8_t reason)
{
  (void) conn_handle;
  (void) reason;

  connection_num--;

  // Mark the ID as invalid
  int id  = findConnHandle(conn_handle);

  // Non-existant connection, something went wrong, DBG !!!
  if ( id < 0 ) return;

  // Mark conn handle as invalid
  prphs[id].conn_handle = BLE_CONN_HANDLE_INVALID;

  Serial.print(prphs[id].name);
  Serial.println(" disconnected!");
}

/**
 * Callback invoked when BLE UART data is received
 * @param uart_svc Reference object to the service where the data
 * arrived.
 */
void bleuart_rx_callback(BLEClientUart& uart_svc)
{
  // uart_svc is prphs[conn_handle].bleuart
  uint16_t conn_handle = uart_svc.connHandle();

  int id = findConnHandle(conn_handle);
  prph_info_t* peer = &prphs[id];

  // Print sender's name
  Serial.printf("[From %s]: ", peer->name);

  // Read then forward to all peripherals
  while ( uart_svc.available() )
  {
    // default MTU with an extra byte for string terminator
    char buf[20+1] = { 0 };

    if ( uart_svc.read(buf,sizeof(buf)-1) )
    {
      Serial.println(buf);
      sendAll(buf);
    }
  }
}

/**
 * Helper function to send a string to all connected peripherals
 */
void sendAll(const char* str)
{
  Serial.print("[Send to All]: ");
  Serial.println(str);

  for(uint8_t id=0; id < BLE_MAX_CONNECTION; id++)
  {
    prph_info_t* peer = &prphs[id];

    if ( peer->bleuart.discovered() )
    {
      peer->bleuart.print(str);
    }
  }
}

void loop()
{
  // First check if we are connected to any peripherals
  if ( Bluefruit.Central.connected() )
  {
    // default MTU with an extra byte for string terminator
    char buf[20+1] = { 0 };

    // Read from HW Serial (normally USB Serial) and send to all peripherals
    if ( Serial.readBytes(buf, sizeof(buf)-1) )
    {
      sendAll(buf);
    }
  }
}

/**
 * Find the connection handle in the peripheral array
 * @param conn_handle Connection handle
 * @return array index if found, otherwise -1
 */
int findConnHandle(uint16_t conn_handle)
{
  for(int id=0; id<BLE_MAX_CONNECTION; id++)
  {
    if (conn_handle == prphs[id].conn_handle)
    {
      return id;
    }
  }

  return -1;
}

/**
 * Software Timer callback is invoked via a built-in FreeRTOS thread with
 * minimal stack size. Therefore it should be as simple as possible. If
 * a periodically heavy task is needed, please use Scheduler.startLoop() to
 * create a dedicated task for it.
 *
 * More information http://www.freertos.org/RTOS-software-timer.html
 */
void blink_timer_callback(TimerHandle_t xTimerID)
{
  (void) xTimerID;

  // Period of sequence is 10 times (1 second).
  // RED LED will toggle first 2*n times (on/off) and remain off for the rest of period
  // Where n = number of connection
  static uint8_t count = 0;

  if ( count < 2*connection_num ) digitalToggle(LED_RED);
  if ( count % 2 && digitalRead(LED_RED)) digitalWrite(LED_RED, LOW); // issue #98

  count++;
  if (count >= 10) count = 0;
}

```

GitHub Source code

I want to invoke this disconnect function, but I don't know where to get conn\_handle. If anyone has any idea please help me.

I have already tried going into libraries; the best it shows is just the definition of the callback function:

```
1: Bluefruit.Central.setDisconnectCallback(disconnect_callback);

2: void BLECentral::setDisconnectCallback( ble_disconnect_callback_t fp )
   {
     _disconnect_cb = fp;
   }

3: class BLECentral
   {
     ...
     private:
       ble_disconnect_callback_t _disconnect_cb;
   }

4: typedef void (*ble_disconnect_callback_t ) (uint16_t conn_hdl, uint8_t reason);

```

This is all I got regarding this disconnect function in different libraries following the definition but nothing related to conn\_handle.

# Answer
> 0 votes
Idk if its a right or not but it works.

When there's is a new connection established, "connect" gets revoked, with "conn\_handle" as its argument. If someone knows please tell how is this function revoke itself.

But what I did is make a global variable `uint16_t conn_handle`

```
uint16_t g_conn_handle;
void connect_callback(uint16_t conn_handle)
    {
      g_conn_handle=conn_handle;
      // Find an available ID to use
      int id  = findConnHandle(BLE_CONN_HANDLE_INVALID);

      // Eeek: Exc
      ...

```

Now I can call the Disconnect function with this `g_conn_handle` global variable.

---
Tags: arduino-ide, ble, nrf52
---


# Question
Title: How does a callback function get revoke itself eg. Connect function get revoked when there is new connection
Further to my previous question here

Can anyone help me understand how the callback function gets revoked itself? The connect function, disconnect function.

BLE custom UUID code source here

Another example is BLEUART which have callback functions:

```
/*********************************************************************
 This is an example for our nRF52 based Bluefruit LE modules

 Pick one up today in the adafruit shop!

 Adafruit invests time and resources providing this open source code,
 please support Adafruit and open-source hardware by purchasing
 products from Adafruit!

 MIT license, check LICENSE for more information
 All text above, and the splash screen below must be included in
 any redistribution
*********************************************************************/

/*
 * This sketch demonstrate the central API(). A additional bluefruit
 * that has bleuart as peripheral is required for the demo.
 */
#include <bluefruit.h>

BLEClientBas  clientBas;  // battery client
BLEClientDis  clientDis;  // device information client
BLEClientUart clientUart; // bleuart client

void setup()
{
  Serial.begin(115200);
//  while ( !Serial ) delay(10);   // for nrf52840 with native usb

  Serial.println("Bluefruit52 Central BLEUART Example");
  Serial.println("-----------------------------------\n");

  // Initialize Bluefruit with maximum connections as Peripheral = 0, Central = 1
  // SRAM usage required by SoftDevice will increase dramatically with number of connections
  Bluefruit.begin(0, 1);

  Bluefruit.setName("Bluefruit52 Central");

  // Configure Battery client
  clientBas.begin();

  // Configure DIS client
  clientDis.begin();

  // Init BLE Central Uart Serivce
  clientUart.begin();
  clientUart.setRxCallback(bleuart_rx_callback);

  // Increase Blink rate to different from PrPh advertising mode
  Bluefruit.setConnLedInterval(250);

  // Callbacks for Central
  Bluefruit.Central.setConnectCallback(connect_callback);
  Bluefruit.Central.setDisconnectCallback(disconnect_callback);

  /* Start Central Scanning
   * - Enable auto scan if disconnected
   * - Interval = 100 ms, window = 80 ms
   * - Don't use active scan
   * - Start(timeout) with timeout = 0 will scan forever (until connected)
   */
  Bluefruit.Scanner.setRxCallback(scan_callback);
  Bluefruit.Scanner.restartOnDisconnect(true);
  Bluefruit.Scanner.setInterval(160, 80); // in unit of 0.625 ms
  Bluefruit.Scanner.useActiveScan(false);
  Bluefruit.Scanner.start(0);                   // // 0 = Don't stop scanning after n seconds
}

/**
 * Callback invoked when scanner pick up an advertising data
 * @param report Structural advertising data
 */
void scan_callback(ble_gap_evt_adv_report_t* report)
{
  // Check if advertising contain BleUart service
  if ( Bluefruit.Scanner.checkReportForService(report, clientUart) )
  {
    Serial.print("BLE UART service detected. Connecting ... ");

    // Connect to device with bleuart service in advertising
    Bluefruit.Central.connect(report);
  }else
  {
    // For Softdevice v6: after received a report, scanner will be paused
    // We need to call Scanner resume() to continue scanning
    Bluefruit.Scanner.resume();
  }
}

/**
 * Callback invoked when an connection is established
 * @param conn_handle
 */
void connect_callback(uint16_t conn_handle)
{
  Serial.println("Connected");

  Serial.print("Dicovering Device Information ... ");
  if ( clientDis.discover(conn_handle) )
  {
    Serial.println("Found it");
    char buffer[32+1];

    // read and print out Manufacturer
    memset(buffer, 0, sizeof(buffer));
    if ( clientDis.getManufacturer(buffer, sizeof(buffer)) )
    {
      Serial.print("Manufacturer: ");
      Serial.println(buffer);
    }

    // read and print out Model Number
    memset(buffer, 0, sizeof(buffer));
    if ( clientDis.getModel(buffer, sizeof(buffer)) )
    {
      Serial.print("Model: ");
      Serial.println(buffer);
    }

    Serial.println();
  }else
  {
    Serial.println("Found NONE");
  }

  Serial.print("Dicovering Battery ... ");
  if ( clientBas.discover(conn_handle) )
  {
    Serial.println("Found it");
    Serial.print("Battery level: ");
    Serial.print(clientBas.read());
    Serial.println("%");
  }else
  {
    Serial.println("Found NONE");
  }

  Serial.print("Discovering BLE Uart Service ... ");
  if ( clientUart.discover(conn_handle) )
  {
    Serial.println("Found it");

    Serial.println("Enable TXD's notify");
    clientUart.enableTXD();

    Serial.println("Ready to receive from peripheral");
  }else
  {
    Serial.println("Found NONE");

    // disconnect since we couldn't find bleuart service
    Bluefruit.disconnect(conn_handle);
  }
}

/**
 * Callback invoked when a connection is dropped
 * @param conn_handle
 * @param reason is a BLE_HCI_STATUS_CODE which can be found in ble_hci.h
 */
void disconnect_callback(uint16_t conn_handle, uint8_t reason)
{
  (void) conn_handle;
  (void) reason;

  Serial.print("Disconnected, reason = 0x"); Serial.println(reason, HEX);
}

/**
 * Callback invoked when uart received data
 * @param uart_svc Reference object to the service where the data
 * arrived. In this example it is clientUart
 */
void bleuart_rx_callback(BLEClientUart& uart_svc)
{
  Serial.print("[RX]: ");

  while ( uart_svc.available() )
  {
    Serial.print( (char) uart_svc.read() );
  }

  Serial.println();
}

void loop()
{
  if ( Bluefruit.Central.connected() )
  {
    // Not discovered yet
    if ( clientUart.discovered() )
    {
      // Discovered means in working state
      // Get Serial input and send to Peripheral
      if ( Serial.available() )
      {
        delay(2); // delay a bit for all characters to arrive

        char str[20+1] = { 0 };
        Serial.readBytes(str, 20);

        clientUart.print( str );
      }
    }
  }
}

```

The following helps set the callback functions:

```
clientUart.setRxCallback(bleuart_rx_callback);
...
Bluefruit.Central.setConnectCallback(connect_callback);
...
Bluefruit.Central.setDisconnectCallback(disconnect_callback);

```

Tracing back the libraries I found :

```
void BLEPeriph::setConnectCallback( ble_connect_callback_t fp )
{
  _connect_cb = fp;
}

void BLEPeriph::setDisconnectCallback( ble_disconnect_callback_t fp )
{
  _disconnect_cb = fp;
}

```

But I can't understand how this initializes the calling of the connect or disconnect function while getting a new connection or break in connection respectively.

# Answer
All a callback function assignment does is link an internal pointer to the function that you provide.

Any time the callback is needed to be called the code just uses the pointer that your function has been assigned to.

Thus `_connect_cb` and `connect_callback()` are one and the same thing. Any time `connect_callback()` would be expected to be used `_connect_cb()` is used instead.

It is, in effect, just creating an internal alias to your code then using that alias to call your code when it needs to.
> 0 votes

---
Tags: arduino-ide, uart, class, ble, nrf52
---


# Question
Title: Neo 6M + ESP32 unable to take a fix on battery but works fine with laptop USB
I am using Neo 6M GPS module with ESP32 and 2 X 3.5V(7 v in series) 18650 lithium ion battery stepped down to 5V using LM2596 buck converter.

Problem which I am facing is when I power ESP32 using 5V output of LM2596 by connecting Vin pin and powering Neo6M using 5V output of buck converter or 3.3 V of ESP32 then my Neo 6M is unable to fix on satellite, however when removing battery and LM2596 and powering ESP32 using laptop usb cable and Neo 6M using 3V pin of ESP32 then its able to take a fix in 1 minute.

Any idea what mistake I could be doing. Note - When using battery ESP32 is working as normal and able to connect to wifi and submit Tiny GPS++ output everysecond.

Please let me know in case more information required.

# Answer
> 0 votes
With full battery charge to 3.7V this issue was resolved also using 10uf capacitor between vcc and ground help to improve

# Answer
> 0 votes
You have several problems. You are telling me it is power related as the ESP runs fine but the Neo 6M failed. Reason the Neo 6M does not tolerate as wide a voltage range as the ESP32. Using a Buck converter is a mistook, you should use a SEPIC (bicl/boost in one), this will maintain the voltage to your project as the battery voltage changes with its charge etc. With the correct SEPIC converter you can parallel the batteries giving you more instantaneous current. The buck converter needs head room, that is so much voltage above the output to work properly. I doubt it is less than 2v. Using small wires will esterbate your problems. The 10uF was a good idea but you also want to add something for high frequency. This should get you going.

---
Tags: esp32, gps
---


title: Arduino keyboard Input language problem

text:
# Question
Title: Arduino keyboard Input language problem
I need my Arduino (Leonardo) to open cmd, but if keyboard input language isn’t English it prints another language letters.

——— code ———

```
Keyboard.begin();
Keyboard.press(KEY_LEFT_GUI);
Keyboard.press('r');
delay(1000);
Keyboard.releaseAll();
Keyboard.write("cmd");
Keyboard.press(KEY_RETURN);
Keyboard.releaseAll();
delay(1000);

```

——— ——— ———

So my question is: can I somehow detect language, and if it’s not there add it?

My idea was to set languagelist via powershell, and it would be perfect for my program, but I don’t know how I can write English text from Arduino on pc with another language :(

Also my Arduino has sd card, maybe it helps.

——— code ———

```
powershell $OldList = Get-WinUserLanguageList

powershell Set-WinUserLanguageList -LanguageList en-US -Force

-something

powershell Set-WinUserLanguageList -LanguageList $OldList -Force

```

——— ——— ———

Sorry if it is 0iq question, I’m very new to Arduino, it will be great to hear your ideas!

# Answer
> 2 votes
Your Arduino will be virtually typing on a keyboard like this:

© Aon fi – CC-BY 3.0

See the labels on the keys? There are none. Your Windows OS has its own idea of what each key means, but the Arduino has no way of knowing that. Instead, you have to tell it explicitly what keyboard layout to use, e.g.:

```
Keyboard.begin(KeyboardLayout_fr_FR);

```

If you don't, the Keyboard library will assume `KeyboardLayout_en_US`.

There is no way the computer can tell the keyboard what layout it expects.

# Answer
> 1 votes
i finaly found a solution for my problem. I wrote an algorithm, that automaticly change system input language if there are only two languages and one of them is English. This code is writen on Duckduino shortcuts, but it is not a problem to convert it back.

```
DELAY 1000

GUI r
DELAY 1000
STRING powershell
ENTER
DELAY 1000
STRING "ok"
ENTER
DELAY 1000
STRING Set-WinUserLanguageList -LanguageList en-US, ru -Force
ENTER
DELAY 1000
STRING exit
ENTER
DELAY 1000

ALT SHIFT
DELAY 1000
GUI r
DELAY 1000
STRING powershell
ENTER
DELAY 1000
STRING "ok"
ENTER
DELAY 1000
STRING Set-WinUserLanguageList -LanguageList ru, en-US -Force
ENTER
DELAY 1000
ALT SHIFT
DELAY 1000
STRING exit
ENTER
DELAY 1000

GUI r
DELAY 1000
STRING powershell
ENTER
DELAY 1000
STRING "ENGLISH"
ENTER
DELAY 1000

```

You can use for ru another language, for **"ok"** i want to add `Get-WinUserLanguageList | ConvertTo-Json | Out-File C:\WinUserLanguageList.json` to save user's list.

> Than language is different than english this code makes errors, and than language is right it changes language list, thats how it works!

Update:

```
DELAY 1000

GUI r
DELAY 1000
STRING powershell
ENTER
DELAY 1000
STRING Get-WinUserLanguageList | ConvertTo-Json | Out-File C:\WinUserLanguageList.json
ENTER
DELAY 1000
STRING Set-WinUserLanguageList -LanguageList en-US, ru -Force
ENTER
DELAY 1000
STRING exit
ENTER
DELAY 1000

ALT SHIFT
DELAY 1000
GUI r
DELAY 1000
STRING powershell
ENTER
DELAY 1000
STRING Get-WinUserLanguageList | ConvertTo-Json | Out-File C:\WinUserLanguageList.json
ENTER
DELAY 1000
STRING Set-WinUserLanguageList -LanguageList ru, en-US -Force
ENTER
DELAY 1000
ALT SHIFT
DELAY 1000
STRING exit
ENTER
DELAY 1000

GUI r
DELAY 1000
STRING powershell
ENTER
DELAY 1000
STRING "CODE IN ENGLISH"
ENTER
DELAY 1000
STRING exit
ENTER
DELAY 1000

GUI r
DELAY 1000
STRING powershell
ENTER
DELAY 1000
STRING Get-WinUserLanguageList
ENTER
DELAY 1000
STRING $importedFile = Get-Content C:\WinUserLanguageList.json | ConvertFrom-Json
ENTER
DELAY 1000
STRING $langCollection = New-Object System.Collections.Generic.List[Microsoft.InternationalSettings.Commands.WinUserLanguage]
ENTER
DELAY 1000
STRING foreach ($item in $importedFile) {
ENTER
DELAY 1000
STRING $lang = [Microsoft.InternationalSettings.Commands.WinUserLanguage]::new($item.LanguageTag)
ENTER
DELAY 1000
STRING $lang.InputMethodTips.Clear()
ENTER
DELAY 1000
STRING foreach ($inputMethod in $item.InputMethodTips) {
ENTER
DELAY 1000
STRING $lang.InputMethodTips.Add($inputMethod) }
ENTER
DELAY 1000
STRING $lang.Handwriting = $item.Handwriting
ENTER
DELAY 1000
STRING $lang.Spellchecking = $item.Spellchecking
ENTER
DELAY 1000
STRING $langCollection += $lang }
ENTER
DELAY 1000
STRING Set-WinUserLanguageList $langCollection -Force
ENTER
DELAY 1000
STRING Remove-Item C:\WinUserLanguageList.json
ENTER
DELAY 1000
STRING exit
ENTER
DELAY 1000

GUI r
DELAY 1000
STRING https://ma.kak.si
ENTER

```

---
Tags: keyboard, windows
---