Wednesday, June 30, 2021

UDP communication between Raspberry Pi/Python and Arduino Nano RP2040 Connect.

This exercise run on Raspberry Pi/Python and Arduino Nano RP2040 Connect, communicate in UDP.

WiFiNINA is needed, install it in Arduino IDE's Library Manager. 

Exercise 1: Simple UDP example.

With WiFiNINA installed and board of Arduino Nano RP2040 Connect selected, you can load WiFiNINA example WiFiUdpSendReceiveString. Remember to update ssid and password in arduino_secrets.h to match your WiFi network. Upload it to Nano RP2040, open Serial Monitor, it will connect to the WiFi network. Check the ip show in Serial Monitor.

In Raspberry Pi side, run the Python code with matched UDP_IP; simple send message to nano RP2040 via UDP.

pyUDP_client_20210630.py
# ref:
# https://wiki.python.org/moin/UdpCommunication
import socket

#UDP_IP = "127.0.0.1"
#UDP_PORT = 5005
UDP_IP = "192.168.197.39"
UDP_PORT = 2390
MESSAGE = b"Hello, World!"

print("UDP target IP: %s" % UDP_IP)
print("UDP target port: %s" % UDP_PORT)
print("message: %s" % MESSAGE)

sock = socket.socket(socket.AF_INET, # Internet
                     socket.SOCK_DGRAM) # UDP
sock.sendto(MESSAGE, (UDP_IP, UDP_PORT))

Exercise 2: With GUI using PyQt5

Keep WiFiUdpSendReceiveString run on Nano RP2040.

In Raspberry Pi side, run following code with GUI.

pyQt5_UDP_client_20210630.py
import sys
from pkg_resources import require

from PyQt5.QtWidgets import (QApplication, QWidget, QLabel,
                             QTextEdit, QPushButton,
                             QVBoxLayout, QMessageBox)
from PyQt5.QtGui import QFont

from PyQt5.QtNetwork import QUdpSocket, QHostAddress

UDP_IP = "192.168.197.39"
UDP_PORT = 2390

print("Python version")
print(sys.version)
print()

class AppWindow(QWidget):
    
    def __init__(self):
        super().__init__()
        
        self.sock = QUdpSocket(self)
        self.sock.bind(QHostAddress(UDP_PORT), UDP_PORT)
        self.sock.readyRead.connect(self.sock_readyRead_slot)
        
        lbAppTitle = QLabel('Python UDP Client to send msg')
        lbAppTitle.setFont(QFont('Anton', 15, QFont.Bold))
        lbSysInfo = QLabel('Python:\n' + sys.version)
        vboxInfo = QVBoxLayout()
        vboxInfo.addWidget(lbAppTitle)
        vboxInfo.addWidget(lbSysInfo)
        
        self.edMsg = QTextEdit()
        btnSend = QPushButton("Send")
        btnSend.clicked.connect(self.btnSend_Clicked)
        vboxMsg = QVBoxLayout()
        vboxMsg.addWidget(self.edMsg)
        vboxMsg.addWidget(btnSend)
        
        vboxMain = QVBoxLayout()
        vboxMain.addLayout(vboxInfo)
        vboxMain.addLayout(vboxMsg)
        vboxMain.addStretch()
        self.setLayout(vboxMain)
        
        self.setGeometry(100, 100, 500,400)
        self.show()
        
    def sock_readyRead_slot(self):
        while self.sock.hasPendingDatagrams():
            datagram, host, port = self.sock.readDatagram(
                self.sock.pendingDatagramSize()
            )
            
            print("rx:")
            message = '{}\nHost: {}\nPort: {}\n\n'.format(datagram.decode(),
                                                          host.toString(),
                                                          port)

            print(message)
            print()
        
    def btnSend_Clicked(self):
        msgToSend = self.edMsg.toPlainText()
        print("tx:")
        print(msgToSend)
        print()
        
        datagram = msgToSend.encode()
        self.sock.writeDatagram(datagram, QHostAddress(UDP_IP), UDP_PORT)
        
    def closeEvent(self, event):
        close = QMessageBox.question(
            self,
            "QUIT",
            "Close Application?",
            QMessageBox.Yes | QMessageBox.No)
        if close == QMessageBox.Yes:
            print("Close")
            event.accept()
        else:
            event.ignore()

if __name__ == '__main__':
    print('run __main__')
    app = QApplication(sys.argv)
    window = AppWindow()
    sys.exit(app.exec_())

print("- bye -")

Exercise 3: Raspberry Pi/Python remote control Nano RP2040 onboard RGB LED via UDP.

In Nano RP2040, modify to control onboard RGB LED base on incoming command: start with "#RGB", follow with three bytes for R, G and B.
WiFiUdp_RGB__20210630.ino
/*
  WiFi UDP to control Nano RP2040 Connect onboard RGB
 */
#include <SPI.h>
#include <WiFiNINA.h>
#include <WiFiUdp.h>

int status = WL_IDLE_STATUS;
#include "arduino_secrets.h" 
///////please enter your sensitive data in the Secret tab/arduino_secrets.h
char ssid[] = SECRET_SSID;  // your network SSID (name)
char pass[] = SECRET_PASS;  // your network password (use for WPA, or use as key for WEP)
int keyIndex = 0;           // your network key index number (needed only for WEP)

unsigned int localPort = 2390;      // local port to listen on

char packetBuffer[256]; //buffer to hold incoming packet
char  ReplyBuffer[] = "acknowledged";       // a string to send back

WiFiUDP Udp;

void setup() {
  //Initialize serial and wait for port to open:
  Serial.begin(9600);

  pinMode(LEDR, OUTPUT);
  pinMode(LEDG, OUTPUT);
  pinMode(LEDB, OUTPUT);

  analogWrite(LEDR, 0);
  analogWrite(LEDG, 0);
  analogWrite(LEDB, 0);
  
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }
  analogWrite(LEDR, 255);
  analogWrite(LEDG, 255);
  analogWrite(LEDB, 255);

  // check for the WiFi module:
  if (WiFi.status() == WL_NO_MODULE) {
    Serial.println("Communication with WiFi module failed!");
    // don't continue
    while (true);
  }

  String fv = WiFi.firmwareVersion();
  if (fv < WIFI_FIRMWARE_LATEST_VERSION) {
    Serial.println("Please upgrade the firmware");
  }

  // attempt to connect to WiFi network:
  while (status != WL_CONNECTED) {
    Serial.print("Attempting to connect to SSID: ");
    Serial.println(ssid);
    // Connect to WPA/WPA2 network. Change this line if using open or WEP network:
    status = WiFi.begin(ssid, pass);

    // wait 10 seconds for connection:
    delay(10000);
  }
  Serial.println("Connected to WiFi");
  printWifiStatus();

  Serial.println("\nStarting connection to server...");
  // if you get a connection, report back via serial:
  Udp.begin(localPort);

  analogWrite(LEDR, 0);
  analogWrite(LEDG, 0);
  analogWrite(LEDB, 0);
}

void loop() {

  // if there's data available, read a packet
  int packetSize = Udp.parsePacket();
  if (packetSize) {
    Serial.print("Received packet of size ");
    Serial.println(packetSize);
    Serial.print("From ");
    IPAddress remoteIp = Udp.remoteIP();
    Serial.print(remoteIp);
    Serial.print(", port ");
    Serial.println(Udp.remotePort());

    // read the packet into packetBufffer
    int len = Udp.read(packetBuffer, 255);
    if (len > 0) {
      packetBuffer[len] = 0;
    }
    Serial.println("Contents:");
    Serial.println(packetBuffer);

    // send a reply, to the IP address and port that sent us the packet we received
    Udp.beginPacket(Udp.remoteIP(), Udp.remotePort());
    Udp.write(ReplyBuffer);
    Udp.endPacket();

    String cmd = String(packetBuffer);
    if(cmd.startsWith("#RGB")){
      Serial.println("CMD: #RGB");
      int valR = (int)(packetBuffer[4]);
      int valG = (int)(packetBuffer[5]);
      int valB = (int)(packetBuffer[6]);
      Serial.println("R: " + String(valR));
      Serial.println("G: " + String(valG));
      Serial.println("B: " + String(valB));

      analogWrite(LEDR, 255-valR);
      analogWrite(LEDG, 255-valG);
      analogWrite(LEDB, 255-valB);
    }else{
      Serial.println("NOT MATCH");
    }

  }
}


void printWifiStatus() {
  // print the SSID of the network you're attached to:
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

  // print your board's IP address:
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);

  // print the received signal strength:
  long rssi = WiFi.RSSI();
  Serial.print("signal strength (RSSI):");
  Serial.print(rssi);
  Serial.println(" dBm");
}

In Raspberry Pi side:

pyQt5_UDP_client_RGB_20210630.py
import sys
from pkg_resources import require

from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import (QApplication, QWidget, QLabel,
                             QSlider, QPushButton,
                             QVBoxLayout, QHBoxLayout, QMessageBox)
from PyQt5.QtGui import QFont

from PyQt5.QtNetwork import QUdpSocket, QHostAddress

UDP_IP = "192.168.197.39"
UDP_PORT = 2390

print("Python version")
print(sys.version)
print()

class AppWindow(QWidget):
    
    def __init__(self):
        super().__init__()
        
        self.sock = QUdpSocket(self)
        self.sock.bind(QHostAddress(UDP_PORT), UDP_PORT)
        self.sock.readyRead.connect(self.sock_readyRead_slot)
        
        lbAppTitle = QLabel('Python UDP Client to control RGB')
        lbAppTitle.setFont(QFont('Anton', 15, QFont.Bold))
        lbSysInfo = QLabel('Python:\n' + sys.version)
        vboxInfo = QVBoxLayout()
        vboxInfo.addWidget(lbAppTitle)
        vboxInfo.addWidget(lbSysInfo)

        
        lbR = QLabel(' R: ')
        self.sliderR = QSlider(Qt.Horizontal, self)
        self.sliderR.setRange(0, 255)
        self.sliderR.valueChanged.connect(self.sliderRGB_valueChanged_slot)
        boxR = QHBoxLayout()
        boxR.addWidget(lbR)
        boxR.addWidget(self.sliderR)
        
        lbG = QLabel(' G: ')
        self.sliderG = QSlider(Qt.Horizontal, self)
        self.sliderG.setRange(0, 255)
        self.sliderG.valueChanged.connect(self.sliderRGB_valueChanged_slot)
        boxG = QHBoxLayout()
        boxG.addWidget(lbG)
        boxG.addWidget(self.sliderG)
        
        lbB = QLabel(' B: ')
        self.sliderB = QSlider(Qt.Horizontal, self)
        self.sliderB.setRange(0, 255)
        self.sliderB.valueChanged.connect(self.sliderRGB_valueChanged_slot)
        boxB = QHBoxLayout()
        boxB.addWidget(lbB)
        boxB.addWidget(self.sliderB)
        
        boxRGB = QVBoxLayout()
        boxRGB.addLayout(boxR)
        boxRGB.addLayout(boxG)
        boxRGB.addLayout(boxB)
        
        btnSend = QPushButton("Update")
        btnSend.clicked.connect(self.btnSend_Clicked)
        vboxMsg = QVBoxLayout()
        vboxMsg.addLayout(boxRGB)
        vboxMsg.addWidget(btnSend)
        
        vboxMain = QVBoxLayout()
        vboxMain.addLayout(vboxInfo)
        vboxMain.addLayout(vboxMsg)
        vboxMain.addStretch()
        self.setLayout(vboxMain)
        
        self.setGeometry(100, 100, 500,400)
        self.show()
        
    def sock_readyRead_slot(self):
        while self.sock.hasPendingDatagrams():
            datagram, host, port = self.sock.readDatagram(
                self.sock.pendingDatagramSize()
            )
            
            print("rx:")
            message = '{}\nHost: {}\nPort: {}\n\n'.format(datagram.decode(),
                                                          host.toString(),
                                                          port)

            print(message)
            print()
        
    def btnSend_Clicked(self):
        print("tx:")
        
        valueR = self.sliderR.value()
        valueG = self.sliderG.value()
        valueB = self.sliderB.value()
        
        CMD_RGB = "#RGB"
        bCMD_RGB = str.encode(CMD_RGB) + bytes([valueR, valueG, valueB])
        print(type(bCMD_RGB))
        print("CMD: ", bCMD_RGB)
        
        self.sock.writeDatagram(bCMD_RGB, QHostAddress(UDP_IP), UDP_PORT)
        
        """
        msgToSend = self.edMsg.toPlainText()
        print("tx:")
        print(msgToSend)
        print()
        
        datagram = msgToSend.encode()
        self.sock.writeDatagram(datagram, QHostAddress(UDP_IP), UDP_PORT)
        """
        
    def sliderRGB_valueChanged_slot(self):
        print("sliderRGB_valueChanged_slot")
        valueR = self.sliderR.value()
        valueG = self.sliderG.value()
        valueB = self.sliderB.value()
        print(" R: ", valueR, " G: ", valueG, " B: ", valueB)
        
        CMD_RGB = "#RGB"
        bCMD_RGB = str.encode(CMD_RGB) + bytes([valueR, valueG, valueB])
        print(type(bCMD_RGB))
        print(bCMD_RGB)
        
    def closeEvent(self, event):
        close = QMessageBox.question(
            self,
            "QUIT",
            "Close Application?",
            QMessageBox.Yes | QMessageBox.No)
        if close == QMessageBox.Yes:
            print("Close")
            event.accept()
        else:
            event.ignore()

if __name__ == '__main__':
    print('run __main__')
    app = QApplication(sys.argv)
    window = AppWindow()
    sys.exit(app.exec_())

print("- bye -")


~ More exercise of Arduino Nano RP2040 Connect.

Thursday, June 24, 2021

Arduino Nano RP2040 Connect + ILI9341 SPI TFT, using adafruit_ILI9341 library.

To drive ILI9341 SPI TFT on Arduino Nano RP2040 Connect (Arduino framework), Adafruit_ILI9341 library can be used.

Install Library:

In Arduino IDE, open Library Manager, search and install Adafruit ILI9341, Adafruit GFX library is needed also.


You will be asked to install extra libraries needed, click Install All.

Connection:

Connection:
ILI9341 TFT	Nano RP2040 Connect
-------------------------------
VCC		3V3
GND		GND
CS		D10
RESET		RESET
DC		D9
SDI(MOSI)	D11 (SPI0 TX)
SCK		D13 (SPI0 SCK)
LED		3V3
SDA(MISO)	D12 (SPI0 RX)
After then, you can try Adafruit_ILI9341 example graphicstest.

~ More exercise of Arduino Nano RP2040 Connect.

Wednesday, June 23, 2021

BLE Communication between Nano RP2040 Connect (Peripheral) and ESP32 (Central), in Arduino framework.

Exercise of BLE Communication between Nano RP2040 Connect (Peripheral) and ESP32 (Central), in Arduino framework.

nanoRP2040_BLE_Peripheral_20210623a.ino run on Arduino Nano RP2040 Connect, act as BLE Peripheral (server), wait to be connected.

/*
 * Arduino nano RP2040 Connect exercise:
 * as BLE Peripheral 
 * 
 * reference:
 * ArduinoBLE library-
 * https://www.arduino.cc/en/Reference/ArduinoBLE
 * 
 * In my implementation:
 * BLEByteCharacteristic written event checked by polling.
 * BLEStringCharacteristic/BLEIntCharacteristic using event haandler.
 * 
 */
 #include <ArduinoBLE.h>

/*  Visit Online GUID / UUID Generator
 *  (https://www.guidgenerator.com/)
 *  to generate your uuid
 */
const char* serviceUUID =    "20a07a95-8c12-484c-94fa-b828c4465a3c";
const char* byteCharUUID =   "d34dda3b-7b4a-4ce3-9666-a8338db4e604";
const char* stringCharUUID = "41281b9c-8dc4-4649-8cbe-c39fa01513e2";
const char* intCharUUID =    "c7d27dc6-f4d8-4523-b060-3e2e4c187808";

const char* myLocalName = "MyBLE";
 
BLEService myBLEService(serviceUUID);
BLEByteCharacteristic myBLEByteCharacteristic(byteCharUUID, 
                              BLERead|BLEWrite);
BLEStringCharacteristic myBLEStringCharacteristic(stringCharUUID, 
                              BLERead|BLEWrite|BLENotify, 24);  //max length = 10
BLEIntCharacteristic myBLEIntCharacteristic(intCharUUID,
                              BLERead|BLEWrite);


void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);
  Serial.begin(115200);
  delay(100);
  digitalWrite(LED_BUILTIN, HIGH);

  //Started, connect Serial to begin
  while(!Serial);
  Serial.println("\n---Start ---");
  digitalWrite(LED_BUILTIN, LOW);

  Serial.println("Initialize BLE...");
  if(!BLE.begin()){
    Serial.println("Starting BLE failed!");
    while(1);
  }
  Serial.println("BLE initialized.");
  Serial.print("MAC: ");
  Serial.println(BLE.address());
  Serial.println("Service UUIID: \t\t\t" + String(serviceUUID));
  Serial.println("Byte Characteristic UUIID: \t" + String(byteCharUUID));
  Serial.println("String Characteristic UUIID: \t" + String(stringCharUUID));
  Serial.println("Int Characteristic UUIID: \t" + String(intCharUUID));
  
  Serial.println();

  BLE.setLocalName(myLocalName);
  BLE.setAdvertisedService(myBLEService);
  myBLEService.addCharacteristic(myBLEByteCharacteristic);
  myBLEService.addCharacteristic(myBLEStringCharacteristic);
  myBLEService.addCharacteristic(myBLEIntCharacteristic);
  BLE.addService(myBLEService);

  myBLEStringCharacteristic.setEventHandler(BLEWritten, myBLEString_Written_Hndl);
  myBLEIntCharacteristic.setEventHandler(BLEWritten, myBLEInt_Written_Hndl);

  BLE.advertise();

}

void loop() {
  BLEDevice central = BLE.central();

  if(central){
    digitalWrite(LED_BUILTIN, HIGH);
    Serial.print("Connected: ");
    Serial.println(central.address());

    while(central.connected()){

      if(myBLEByteCharacteristic.written()){
        byte valByte = myBLEByteCharacteristic.value();
        Serial.print("myBLEByteCharacteristic received: ");
        Serial.println(valByte, HEX);
      }
    }

    digitalWrite(LED_BUILTIN, LOW);
    Serial.println("Disconnected.");
  }
}

// Event Handler for myBLEStringCharacteristic Written
// Print received Sring, and write back in upper case.
void myBLEString_Written_Hndl(BLEDevice central, BLECharacteristic characteristic) {
  Serial.print("BLEStringCharacteristic event, written: ");

  Serial.println("myBLEStringCharacteristic received: len=" + 
                  String(myBLEStringCharacteristic.valueLength()));
  String valString = myBLEStringCharacteristic.value();
  Serial.println(valString);
  valString.toUpperCase();
  Serial.println(valString);
  myBLEStringCharacteristic.setValue(valString);
}

// Event Handler for myBLEIntCharacteristic Written
void myBLEInt_Written_Hndl(BLEDevice central, BLECharacteristic characteristic) {
  Serial.print("BLEIntCharacteristic event, written: ");
  
  int valInt = myBLEIntCharacteristic.value();
  Serial.println(valInt);
  
}


ESP32_BLE_Central_20210623a.ino run on ESP32 Dev. Board, act as Central (client), scan and connect to Peripheral, and send something.
/*
 * ESP32 BLE exercise, as Central (Client)
 * connect to nanoRP2040 BLE Peripheral
 * 
 */

 #include "BLEDevice.h"

const String targetName = "MyBLE";

// The remote service/characteristic we wish to connect to.
// UUID(s) have to match with Peripheral side.
const char* serviceUUID =    "20a07a95-8c12-484c-94fa-b828c4465a3c";
const char* byteCharUUID =   "d34dda3b-7b4a-4ce3-9666-a8338db4e604";
const char* stringCharUUID = "41281b9c-8dc4-4649-8cbe-c39fa01513e2";
const char* intCharUUID =    "c7d27dc6-f4d8-4523-b060-3e2e4c187808";

static BLEUUID BLEUUID_service(serviceUUID);
static BLEUUID BLEUUID_byteChar(byteCharUUID);
static BLEUUID BLEUUID_stringChar(stringCharUUID);
static BLEUUID BLEUUID_intChar(intCharUUID);

static BLERemoteCharacteristic* pRemoteChar_byte;
static BLERemoteCharacteristic* pRemoteChar_string;
static BLERemoteCharacteristic* pRemoteChar_int;

static boolean doConnect = false;
static boolean connected = false;
static boolean doScan = false;

static BLEAdvertisedDevice* myDevice;

int notifyDur;

static void notifyCallback(
  BLERemoteCharacteristic* pBLERemoteCharacteristic,
  uint8_t* pData,
  size_t length,
  bool isNotify) {
    Serial.println("pRemoteChar_string notify callback -");
    Serial.println(pBLERemoteCharacteristic->getUUID().toString().c_str());
    Serial.print(" of data length ");
    Serial.println(length);
    Serial.print("data: ");
    Serial.println((char*)pData);
}

class MyClientCallback : public BLEClientCallbacks {
  void onConnect(BLEClient* pclient) {
  }

  void onDisconnect(BLEClient* pclient) {
    connected = false;
    Serial.println("onDisconnect");
  }
};

bool connectToServer() {
    Serial.print("Forming a connection to ");
    Serial.println(myDevice->getAddress().toString().c_str());
    
    BLEClient*  pClient  = BLEDevice::createClient();
    Serial.println(" - Created client");

    pClient->setClientCallbacks(new MyClientCallback());

    // Connect to the remove BLE Server.
    pClient->connect(myDevice);
    Serial.println(" - Connected to server");

    // Obtain a reference to the service we are after in the remote BLE server.
    BLERemoteService* pRemoteService = pClient->getService(BLEUUID_service);
    if (pRemoteService == nullptr) {
      Serial.print("Failed to find our service UUID: ");
      Serial.println(BLEUUID_service.toString().c_str());
      pClient->disconnect();
      return false;
    }
    Serial.println(" - Found our service");


    // Obtain a reference to the characteristic in the service of the remote BLE server.
    pRemoteChar_byte = pRemoteService->getCharacteristic(BLEUUID_byteChar);
    pRemoteChar_string = pRemoteService->getCharacteristic(BLEUUID_stringChar);
    pRemoteChar_int = pRemoteService->getCharacteristic(BLEUUID_intChar);

    //assume all characteristics found, skip checking
    /*
    if (pRemoteChar_string == nullptr) {
      Serial.print("Failed to find our characteristic UUID: ");
      Serial.println(BLEUUID_stringChar.toString().c_str());
      pClient->disconnect();
      return false;
    }
    */
    Serial.println(" - Found our characteristic");

    // Read the value of the characteristic.
    if(pRemoteChar_string->canRead()) {
      std::string value = pRemoteChar_string->readValue();
      Serial.print("The characteristic value was: ");
      Serial.println(value.c_str());
    }

    if(pRemoteChar_string->canNotify()){
      Serial.println("pRemoteChar_string CAN Notify");
      pRemoteChar_string->registerForNotify(notifyCallback);
    }else{
      Serial.println("pRemoteChar_string CANNOT Notify");
    }

    connected = true;
    return true;
}

/**
 * Scan for BLE servers and find the first one matched advertises service
 */
class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {
 /**
   * Called for each advertising BLE server.
   */
  void onResult(BLEAdvertisedDevice advertisedDevice) {
    //Serial.print("BLE Advertised Device found: ");
    //Serial.println(advertisedDevice.toString().c_str());
    String devName = advertisedDevice.getName().c_str();
    //Serial.println(devName);

    if(devName == targetName){
      Serial.println("Target found-");
      // We have found a device,
      // let us now see if it contains the service we are looking for.
      Serial.println(advertisedDevice.getServiceUUID().toString().c_str());
      
      if (advertisedDevice.haveServiceUUID() && 
            advertisedDevice.isAdvertisingService(BLEUUID_service)) {
        Serial.println("BLEUUID_service match -");
        BLEDevice::getScan()->stop();
        myDevice = new BLEAdvertisedDevice(advertisedDevice);
        doConnect = true;
        doScan = true;
      } // Found our server
    }
  } // onResult
}; // MyAdvertisedDeviceCallbacks



void setup() {
  Serial.begin(115200);
  delay(1000);
  Serial.println("\n--- ESP32 Start ---");

  BLEDevice::init("");

  // Retrieve a Scanner and set the callback we want to use to be informed when we
  // have detected a new device.  Specify that we want active scanning and start the
  // scan to run for 5 seconds.
  BLEScan* pBLEScan = BLEDevice::getScan();
  pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
  pBLEScan->setInterval(1349);
  pBLEScan->setWindow(449);
  pBLEScan->setActiveScan(true);
  pBLEScan->start(5, false);
}

// This is the Arduino main loop function.
void loop() {

  // If the flag "doConnect" is true then we have scanned for and found the desired
  // BLE Server with which we wish to connect.  Now we connect to it.  Once we are 
  // connected we set the connected flag to be true.
  if (doConnect == true) {
    if (connectToServer()) {
      Serial.println("We are now connected to the BLE Server.");
    } else {
      Serial.println("We have failed to connect to the server; there is nothin more we will do.");
    }
    doConnect = false;
  }

  // If we are connected to a peer BLE Server, update the characteristic each time we are reached
  // with the current time since boot.
  if (connected) {
    notifyDur = millis();
    String newValue = "time since boot: " + String(notifyDur/1000);
    
    // Set the characteristic's value to be the array of bytes that is actually a string.
    pRemoteChar_string->writeValue(newValue.c_str(), newValue.length());
    pRemoteChar_int->writeValue(notifyDur, true);
  }else if(doScan){
    BLEDevice::getScan()->start(0);
  }
  
  delay(1000); // Delay a second between loops.
} // End of loop




~ More exercise of Arduino Nano RP2040 Connect.