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.

Monday, June 21, 2021

ArduinoBLE exercise on Nano RP2040 Connect: BLE Peripheral

ArduinoBLE exercise run on Nano RP2040 Connect, act as BLE Peripheral. Tested with nRF Connect app on Android.


nanoRP2040_BLE_Peripheral_20210622a.ino
/*
 * 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, 10);  //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);
  
}



~ More exercises for Arduino Nano RP2040 Connect

Sunday, June 13, 2021

Raspberry Pi/Python BLE Central + Arduino Nano RP2040 Connect BLE Peripheral

This exercise implement Python 3 code run on Raspberry Pi act as BLE Central, connect to Arduino Nano RP2040 Connect act as BLE Peripheral. And send data (0x01/0x00) to turn the Nano RP2040 Connect's onboard LED ON/OFF.


Arduino Nano RP2040 Connect act as BLE Peripheral side:

- Make sure ArduinoBLE library is installed.

- The Arduino code is modified from ArduinoBLE Examples > Peripheral > CallbackLED. With MAC, Service UUID, Characteristic UUID, and BLE written data displayed. Such that we can program Central side accordingly.

nanoRP2040_BLE_CallbackLED.ino
/*
  Callback LED

  This example creates a BLE peripheral with service that contains a
  characteristic to control an LED. The callback features of the
  library are used.

  The circuit:
  - Arduino MKR WiFi 1010, Arduino Uno WiFi Rev2 board, Arduino Nano 33 IoT,
    Arduino Nano 33 BLE, or Arduino Nano 33 BLE Sense board.

  You can use a generic BLE central app, like LightBlue (iOS and Android) or
  nRF Connect (Android), to interact with the services and characteristics
  created in this sketch.

  This example code is in the public domain.
*/

#include <ArduinoBLE.h>

BLEService ledService("19B10000-E8F2-537E-4F6C-D104768A1214"); // create service

// create switch characteristic and allow remote device to read and write
BLEByteCharacteristic switchCharacteristic("19B10001-E8F2-537E-4F6C-D104768A1214", BLERead | BLEWrite);

const int ledPin = LED_BUILTIN; // pin to use for the LED

void setup() {
  Serial.begin(9600);
  while (!Serial);
  delay(1000);
  Serial.println("\n--- Start---");
  
  pinMode(ledPin, OUTPUT); // use the LED pin as an output

  // begin initialization
  if (!BLE.begin()) {
    Serial.println("starting BLE failed!");

    while (1);
  }

  Serial.print("My BLE MAC:\t\t ");
  Serial.println(BLE.address());
  Serial.print("Service UUID:\t\t ");
  Serial.println(ledService.uuid());
  Serial.print("Characteristic UUID:\t ");
  Serial.println(switchCharacteristic.uuid());
  Serial.println();

  // set the local name peripheral advertises
  BLE.setLocalName("LEDCallback");
  // set the UUID for the service this peripheral advertises
  BLE.setAdvertisedService(ledService);

  // add the characteristic to the service
  ledService.addCharacteristic(switchCharacteristic);

  // add service
  BLE.addService(ledService);

  // assign event handlers for connected, disconnected to peripheral
  BLE.setEventHandler(BLEConnected, blePeripheralConnectHandler);
  BLE.setEventHandler(BLEDisconnected, blePeripheralDisconnectHandler);

  // assign event handlers for characteristic
  switchCharacteristic.setEventHandler(BLEWritten, switchCharacteristicWritten);
  // set an initial value for the characteristic
  switchCharacteristic.setValue(0);

  // start advertising
  BLE.advertise();

  Serial.println(("Bluetooth device active, waiting for connections..."));
}

void loop() {
  // poll for BLE events
  BLE.poll();
}

void blePeripheralConnectHandler(BLEDevice central) {
  // central connected event handler
  Serial.print("Connected event, central: ");
  Serial.println(central.address());
}

void blePeripheralDisconnectHandler(BLEDevice central) {
  // central disconnected event handler
  Serial.print("Disconnected event, central: ");
  Serial.println(central.address());
}

void switchCharacteristicWritten(BLEDevice central, BLECharacteristic characteristic) {
  // central wrote new value to characteristic, update LED
  Serial.println("Characteristic event, written: ");

  byte charValue = switchCharacteristic.value();
  Serial.println(charValue);

  if (charValue) {
    Serial.println("LED on");
    digitalWrite(ledPin, HIGH);
  } else {
    Serial.println("LED off");
    digitalWrite(ledPin, LOW);
  }
}

Raspberry Pi/Python BLE Central Side:
- bluepy library is used to control Bluetooth BLE.

To install bluepy for Python3, enter the command:
$ sudo pip3 install bluepy

- tkinter is used for GUI.

py_BLE_Central_LedControl.py connect to Peripheral with matched MAC, and search for service/characteristic with match UUID. Then send 0x01/0x00 to turn ON/OFF the Nano RP2040 Connect's onboard LED.

"""
Python/Raspberry Pi BluetoothLE exercise:
using bluepy library

Work with Arduino Nano RP2040 Connect example:
ArduinoBLE > Peripheral > CallbackLED

Connect to Peripheral with matched MAC.
Check for service uuid and characteristic uuid,
if matched found: send bytes 0x01 and 0x00 for three time
to turn Nano RP2040 Connect onboard LED ON/OFF.
"""

from bluepy import btle
import time

#Have to match with Peripheral
MAC = "84:cc:a8:2e:8d:76"
SERVICE_UUID = "19b10000-e8f2-537e-4f6c-d104768a1214"
CHARACTERISTIC_UUID = "19b10001-e8f2-537e-4f6c-d104768a1214"

nanoRP2040_Char = None

print("Hello")

print("Connect to:" + MAC)
dev = btle.Peripheral(MAC)
print("\n--- dev ----------------------------")
print(type(dev))
print(dev)

print("\n--- dev.services -------------------")
for svc in dev.services:
    print(str(svc))
    
print("\n------------------------------------")
print("Get Serice By UUID: " + SERVICE_UUID)
service_uuid = btle.UUID(SERVICE_UUID)
service = dev.getServiceByUUID(service_uuid)

print(service)
print("\n--- service.getCharacteristics() ---")
print(type(service.getCharacteristics()))
print(service.getCharacteristics())

#----------------------------------------------
characteristics = dev.getCharacteristics()
print("\n--- dev.getCharacteristics() -------")
print(type(characteristics))
print(characteristics)
    
for char in characteristics:
    print("----------")
    print(type(char))
    print(char)
    print(char.uuid)
    if(char.uuid == CHARACTERISTIC_UUID ):
        print("=== !CHARACTERISTIC_UUID matched! ==")
        nanoRP2040_Char = char
        print(char)
        print(dir(char))
        #print(char.getDescriptors)
        #print(char.propNames)
        #print(char.properties)
        #print(type(char.read()))
        print(char.read())
        
bytes_ON = b'\x01'
bytes_OFF = b'\x00'

if nanoRP2040_Char != None:
    print("\nnanoRP2040_Char found")
    print(nanoRP2040_Char)
    for i in range(3):
        nanoRP2040_Char.write(bytes_ON, True)
        print(nanoRP2040_Char.read())
        time.sleep(1.0)
        nanoRP2040_Char.write(bytes_OFF, True)
        print(nanoRP2040_Char.read())
        time.sleep(1.0)
else:
    print("\nnanoRP2040_Char NOT found!")
#=============================================
dev.disconnect()
print("\n--- bye ---\n")
pyTk_BLE_Central_LedControl.py implement GUI with tkinter, user click on button to turn ON/OFF LED.
"""
Python/Raspberry Pi BluetoothLE exercise:
using bluepy library

Work with Arduino Nano RP2040 Connect example:
ArduinoBLE > Peripheral > CallbackLED

Connect to Peripheral with matched MAC.
Check for service uuid and characteristic uuid,
if matched found:
    Start GUI to control Nano RP2040 Connect onboard LED
"""

from bluepy import btle
import time
import tkinter as tk

#Have to match with Peripheral
MAC = "84:cc:a8:2e:8d:76"
SERVICE_UUID = "19b10000-e8f2-537e-4f6c-d104768a1214"
CHARACTERISTIC_UUID = "19b10001-e8f2-537e-4f6c-d104768a1214"

nanoRP2040_Char = None

def toggle():
    if toggle_btn.config('relief')[-1] == 'sunken':
        toggle_btn.config(relief="raised")
        nanoRP2040_Char.write(bytes_OFF, True)
        toggle_btn['text'] = 'Turn LED ON'
    else:
        toggle_btn.config(relief="sunken")
        nanoRP2040_Char.write(bytes_ON, True)
        toggle_btn['text'] = 'Turn LED OFF'

print("Hello")

print("Connect to:" + MAC)
dev = btle.Peripheral(MAC)
print("\n--- dev ----------------------------")
print(type(dev))
print(dev)

print("\n--- dev.services -------------------")
for svc in dev.services:
    print(str(svc))
    
print("\n------------------------------------")
print("Get Serice By UUID: " + SERVICE_UUID)
service_uuid = btle.UUID(SERVICE_UUID)
service = dev.getServiceByUUID(service_uuid)

print(service)
print("\n--- service.getCharacteristics() ---")
print(type(service.getCharacteristics()))
print(service.getCharacteristics())

#----------------------------------------------
characteristics = dev.getCharacteristics()
print("\n--- dev.getCharacteristics() -------")
print(type(characteristics))
print(characteristics)
    
for char in characteristics:
    print("----------")
    print(type(char))
    print(char)
    print(char.uuid)
    if(char.uuid == CHARACTERISTIC_UUID ):
        print("=== !CHARACTERISTIC_UUID matched! ==")
        nanoRP2040_Char = char
        print(char)
        print(dir(char))
        #print(char.getDescriptors)
        #print(char.propNames)
        #print(char.properties)
        #print(type(char.read()))
        print(char.read())
        
bytes_ON = b'\x01'
bytes_OFF = b'\x00'

if nanoRP2040_Char != None:
    print("\nnanoRP2040_Char found")
    print(nanoRP2040_Char)
    
    root = tk.Tk()
    label = tk.Label( root, text="Toggle button to Turn ON/OFF the nano RP040 Connect LED")
    label.pack(pady=10)
    toggle_btn = tk.Button(text="Turn LED ON", width=12, relief="raised", command=toggle)

    toggle_btn.pack(pady=10)
    root.geometry("500x200")

    #Place tkinter window center
    root.eval('tk::PlaceWindow %s center' % root.winfo_pathname(root.winfo_id()))
    root.title("arduino-er.blogspot.com")
    root.mainloop()
else:
    print("\nnanoRP2040_Char NOT found!")
#=============================================
dev.disconnect()
print("\n--- bye ---\n")


~ More exercises of Arduino Nano RP2040 Connect.

Friday, June 11, 2021

Arduino Nano RP2040 Connect exercise: control onboard RGB LED

The Nano RP2040 Connect onboard RGB LED is connected through the W-102 module, so the WiFiNINA library needs to be installed and included in sketch.

Exercise to control onboard RGB LED.

#include <WiFiNINA.h>

void setup() {

  delay(2000);

  Serial.begin(9600);
  Serial.println(LEDR);
  Serial.println(LEDG);
  Serial.println(LEDB);
  
  pinMode(LEDR, OUTPUT);
  pinMode(LEDG, OUTPUT);
  pinMode(LEDB, OUTPUT);

  digitalWrite(LEDR, HIGH); //RED
  digitalWrite(LEDG, HIGH); //GREEN
  digitalWrite(LEDB, HIGH); //BLUE

}

void loop() {
  delay(1000);
  digitalWrite(LEDR, LOW); //RED
  digitalWrite(LEDG, LOW); //GREEN
  digitalWrite(LEDB, LOW); //BLUE

  delay(1000);
  digitalWrite(LEDR, HIGH); //RED
  digitalWrite(LEDG, LOW); //GREEN
  digitalWrite(LEDB, LOW); //BLUE


  delay(1000);
  digitalWrite(LEDR, LOW); //RED
  digitalWrite(LEDG, HIGH); //GREEN
  digitalWrite(LEDB, LOW); //BLUE

  delay(1000);
  digitalWrite(LEDR, LOW); //RED
  digitalWrite(LEDG, LOW); //GREEN
  digitalWrite(LEDB, HIGH); //BLUE
}


update@20211-06-28:

After WiFiNINA library updated, the code Serial.println(LEDR) (also LEDG and LEDB) throw error of :

error: call to 'NinaPin::operator int' declared with attribute error: Change me to a #define Serial.println(LEDR);

Just comment the codes to make it work.

Thursday, June 10, 2021

Arduino Nano RP2040 Connect example: read onboard LSM6DSOX IMU module (accelerometer and gyroscope)

Examples to read Nano RP2040 Connect onboard LSM6DSOX IMU module (accelerometer and gyroscope), in Arduino framework.

Install LSM6DSOX library:

- Open Library Manager in Arduino IDE:
Click on Menu Sketch > Include Library > Manager Libraries...

- Search and install Arduino_LSM6DSOX library.


LSM6DSOX examples:

Now you can try LSM6DSOX examples to read accelerometer and gyroscope data from Nano RP2040 Connect onboard LSM6DSOX IMU module.


with graphical view using Menu > Tools > Serial Plotter.

SimpleAccelerometer

SimpleGyroscope




Wednesday, June 9, 2021

Arduino Nano RP2040 Connect

Just receive Arduino Nano RP2040 Connect:





Install Nano RP2040 Connect to Arduino IDE and fix "An error occurred while uploading the sketch":
 

Install Arduino Nano RP2040 Connect board to Arduino IDE.

- Open Board Manager in Arduino IDE.
- Search and install Arduino Mbed OS Nano Boards by Arduino. It's version 2.1.0 currently.


- Once installed, Arduino Mbed OS Nano Boards > Arduino Nano RP2040 Connect will available in board selection list.

If you have XIAO BLE Sense also, check Remark on "Arduino Nano RP2040 Connect" of "Arduino Mbed OS Boards" vs "Arduino Mbed OS Nano Boards".


Fix "An error occurred while uploading the sketch".

In my case on Raspberry Pi, sketch cannot be uploaded; with "An error occurred while uploading the sketch".

To fix it:
- Switch to mbed_rp2040 installed folder:
/home/pi/.arduino15/packages/arduino/hardware/mbed_rp2040/2.1.0
- Run post_install.sh:
$ sudo ./post_install.sh

- Then, you can upload the sketch again.


More exercise:
read onboard LSM6DSOX IMU module (accelerometer and gyroscope)