// =============================================================================================================================
//--------------------------------------------
// ESP32-C3 /S3 Includes defines and initialisations
//--------------------------------------------
#include <NimBLEDevice.h> // For BLE communication https://github.com/h2zero/NimBLE-Arduino
#include <Preferences.h>
Preferences FLASHSTOR;
static uint32_t msTick; // Number of millisecond ticks since we last incremented the second counter
//--------------------------------------------
// BLE //#include <NimBLEDevice.h>
//--------------------------------------------
BLEServer *pServer = NULL;
BLECharacteristic * pTxCharacteristic;
bool deviceConnected = false;
bool oldDeviceConnected = false;
std::string ReceivedMessageBLE;
#define SERVICE_UUID "6E400001-B5A3-F393-E0A9-E50E24DCCA9E" // UART service UUID
#define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
#define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"
//----------------------------------------
// Common
//----------------------------------------
char sptext[120]; // For common print use
struct EEPROMstorage { // Data storage in EEPROM to maintain them after power loss
char Ssid[30];
char Password[40];
char BLEbroadcastName[30]; // Name of the BLE beacon
byte UseBLELongString = 0; // Send strings longer than 20 bytes per message. Possible in IOS app BLEserial Pro
int Checksum = 0;
} Mem;
//--------------------------------------------
// Menu
//0 1 2 3 4
//1234567890123456789012345678901234567890----
char menu[][40] =
{
"A SSID",
"B Password",
"C BLE beacon name",
"I Print this menu",
"R Reset settings"
};
// ------------------------------------- End Definitions ---------------------------------------
// //
//--------------------------------------------
// ARDUINO Setup
//--------------------------------------------
void setup()
{
Serial.begin(115200); Tekstprintln("Serial started"); // Setup the serial port to 115200 baud //
InitStorage(); Tekstprintln("Setting loaded"); // Load settings from storage and check validity
StartBLEService(); Tekstprintln("BLE started"); // Start BLE service // Print the tekst time in the display
SWversion();
}
// //
//--------------------------------------------
// ARDUINO Loop
//--------------------------------------------
void loop()
{
EverySecondCheck();
CheckDevices();
}
//--------------------------------------------
// Common Check connected input devices
//--------------------------------------------
void CheckDevices(void)
{
CheckBLE(); // Something with BLE to do?
SerialCheck(); // Check serial port every second
}
// //
//--------------------------------------------
// CLOCK Update routine to run something every second
//--------------------------------------------
void EverySecondCheck(void)
{
uint32_t msLeap = millis() - msTick;
if (msLeap >999) // Every second enter the loop
{
Serial.println(millis());
msTick = millis();
}
}
//--------------------------------------------
// Common check for serial input
//--------------------------------------------
void SerialCheck(void)
{
String SerialString;
while (Serial.available())
{
char c = Serial.read(); // Serial.write(c);
if (c>31 && c<128) SerialString += c; // Allow input from Space - Del
else c = 0; // Delete a CR
}
if (SerialString.length()>0)
{
ReworkInputString(SerialString+"\n"); // Rework ReworkInputString();
SerialString = "";
}
}
//--------------------------------------------
// Common common print routines
//--------------------------------------------
void Tekstprint(char const *tekst) { if(Serial) Serial.print(tekst); SendMessageBLE(tekst);sptext[0]=0; }
void Tekstprintln(char const *tekst) { sprintf(sptext,"%s\n",tekst); Tekstprint(sptext); }
void TekstSprint(char const *tekst) { printf(tekst); sptext[0]=0;} // printing for Debugging purposes in serial monitor
void TekstSprintln(char const *tekst) { sprintf(sptext,"%s\n",tekst); TekstSprint(sptext); }
//--------------------------------------------
// CLOCK Input from Bluetooth or Serial
//--------------------------------------------
void ReworkInputString(String InputString)
{
char ff[50]; InputString.toCharArray(ff,InputString.length()); // Convert a String to char array
sprintf(sptext,"Inputstring: %s Lengte : %d\n", ff,InputString.length()-1);
// Tekstprint(sptext);
if(InputString.length()> 40){Serial.printf("Input string too long (max40)\n"); return;} // If garbage return
sptext[0] = 0; // Empty the sptext string
if(InputString[0] > 31 && InputString[0] <127) // Does the string start with a letter?
{
switch (InputString[0])
{
case 'A':
case 'a':
if (InputString.length() >5 )
{
InputString.substring(1).toCharArray(Mem.Ssid,InputString.length()-1);
sprintf(sptext,"SSID set: %s", Mem.Ssid);
}
else sprintf(sptext,"**** Length fault. Use between 4 and 30 characters ****");
break;
case 'B':
case 'b':
if (InputString.length() >5 )
{
InputString.substring(1).toCharArray(Mem.Password,InputString.length()-1);
sprintf(sptext,"Password set: %s\n Enter @ to reset ESP32 and connect to WIFI and NTP", Mem.Password);
}
else sprintf(sptext,"%s,**** Length fault. Use between 4 and 40 characters ****",Mem.Password);
break;
case 'C':
case 'c':
if (InputString.length() >5 )
{
InputString.substring(1).toCharArray(Mem.BLEbroadcastName,InputString.length()-1);
sprintf(sptext,"BLE broadcast name set: %s", Mem.BLEbroadcastName);
}
else sprintf(sptext,"**** Length fault. Use between 4 and 30 characters ****");
break;
case 'I':
case 'i':
SWversion();
break;
case 'R':
case 'r':
if (InputString.length() == 2)
{
Reset();
sprintf(sptext,"\nReset to default values: Done");
}
else sprintf(sptext,"**** Length fault. Enter R ****");
break;
default: break;
}
}
Tekstprintln(sptext);
StoreStructInFlashMemory();
InputString = "";
}
//--------------------------------------------
// Print Menu and Version info
//--------------------------------------------
void SWversion(void)
{
#define FILENAAM (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)
PrintLine(35);
for (uint8_t i = 0; i < sizeof(menu) / sizeof(menu[0]); Tekstprintln(menu[i++]));
sprintf(sptext,"SSID: %s", Mem.Ssid); Tekstprintln(sptext);
// sprintf(sptext,"Password: %s", Mem.Password); Tekstprintln(sptext);
sprintf(sptext,"BLE name: %s", Mem.BLEbroadcastName); Tekstprintln(sptext);
sprintf(sptext,"%s",Mem.UseBLELongString? "FastBLE=On":"FastBLE=Off" ); Tekstprintln(sptext);
sprintf(sptext,"Software: %s",FILENAAM); Tekstprintln(sptext); //VERSION);
PrintLine(35);
}
void PrintLine(byte Lengte)
{
for(int n=0; n<Lengte; n++) sptext[n]='_';
sptext[Lengte] = 0;
Tekstprintln(sptext);
}
//-----------------------------
// BLE
// SendMessage by BLE Slow in packets of 20 chars or fast in one long string.
// Fast can be used in IOS app BLESerial Pro
//------------------------------
void SendMessageBLE(std::string Message)
{
if(deviceConnected)
{
if (Mem.UseBLELongString) // If Fast transmission is possible
{
pTxCharacteristic->setValue(Message);
pTxCharacteristic->notify();
delay(10); // Bluetooth stack will go into congestion, if too many packets are sent
}
else // Packets of max 20 bytes
{
int parts = (Message.length()/20) + 1;
for(int n=0;n<parts;n++)
{
pTxCharacteristic->setValue(Message.substr(n*20, 20));
pTxCharacteristic->notify();
delay(40); // Bluetooth stack will go into congestion, if too many packets are sent
}
}
}
}
//-----------------------------
// BLE Start BLE Classes
//------------------------------
class MyServerCallbacks: public BLEServerCallbacks
{
void onConnect(BLEServer* pServer) {deviceConnected = true; };
void onDisconnect(BLEServer* pServer) {deviceConnected = false;}
};
class MyCallbacks: public BLECharacteristicCallbacks
{
void onWrite(BLECharacteristic *pCharacteristic)
{
std::string rxValue = pCharacteristic->getValue();
ReceivedMessageBLE = rxValue + "\n";
// if (rxValue.length() > 0) {for (int i = 0; i < rxValue.length(); i++) printf("%c",rxValue[i]); }
// printf("\n");
}
};
//-----------------------------
// BLE Start BLE Service
//------------------------------
void StartBLEService(void)
{
BLEDevice::init(Mem.BLEbroadcastName); // Create the BLE Device
pServer = BLEDevice::createServer(); // Create the BLE Server
pServer->setCallbacks(new MyServerCallbacks());
BLEService *pService = pServer->createService(SERVICE_UUID); // Create the BLE Service
pTxCharacteristic = // Create a BLE Characteristic
pService->createCharacteristic(CHARACTERISTIC_UUID_TX, NIMBLE_PROPERTY::NOTIFY);
BLECharacteristic * pRxCharacteristic =
pService->createCharacteristic(CHARACTERISTIC_UUID_RX, NIMBLE_PROPERTY::WRITE);
pRxCharacteristic->setCallbacks(new MyCallbacks());
pService->start();
BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
pAdvertising->addServiceUUID(SERVICE_UUID);
pServer->start(); // Start the server
pServer->getAdvertising()->start(); // Start advertising
TekstSprint("BLE Waiting a client connection to notify ...\n");
}
// //
//-----------------------------
// BLE CheckBLE
//------------------------------
void CheckBLE(void)
{
if(!deviceConnected && oldDeviceConnected) // Disconnecting
{
delay(300); // Give the bluetooth stack the chance to get things ready
pServer->startAdvertising(); // Restart advertising
TekstSprint("Start advertising\n");
oldDeviceConnected = deviceConnected;
}
if(deviceConnected && !oldDeviceConnected) // Connecting
{
oldDeviceConnected = deviceConnected;
SWversion();
}
if(ReceivedMessageBLE.length()>0)
{
SendMessageBLE(ReceivedMessageBLE);
String BLEtext = ReceivedMessageBLE.c_str();
ReceivedMessageBLE = "";
ReworkInputString(BLEtext);
}
}
// //
//--------------------------------------------
// Common Init and check contents of EEPROM
//--------------------------------------------
void InitStorage(void)
{
GetStructFromFlashMemory();
if( Mem.Checksum != 25065)
{
sprintf(sptext,"Checksum (25065) invalid: %d\n Resetting to default values",Mem.Checksum);
Tekstprintln(sptext);
Reset(); // If the checksum is NOK the Settings were not set
}
StoreStructInFlashMemory();
}
//--------------------------------------------
// COMMON Store mem.struct in FlashStorage or SD
// Preferences.h
//--------------------------------------------
void StoreStructInFlashMemory(void)
{
FLASHSTOR.begin("Mem",false); // delay(100);
FLASHSTOR.putBytes("Mem", &Mem , sizeof(Mem) );
FLASHSTOR.end();
}
//--------------------------------------------
// COMMON Get data from FlashStorage
// Preferences.h
//--------------------------------------------
void GetStructFromFlashMemory(void)
{
FLASHSTOR.begin("Mem", false);
FLASHSTOR.getBytes("Mem", &Mem, sizeof(Mem) );
FLASHSTOR.end();
sprintf(sptext,"Mem.Checksum = %d",Mem.Checksum);Tekstprintln(sptext);
}
//------------------------------------------------------------------------------
// Common Reset to default settings
//------------------------------------------------------------------------------
void Reset(void)
{
Mem.Checksum = 25065; //
Mem.UseBLELongString = 0;
strcpy(Mem.Ssid,"MySSID"); // Default SSID
strcpy(Mem.Password,"MyPass"); // Default password
strcpy(Mem.BLEbroadcastName,"ESP32Menu");
Tekstprintln("**** Reset of preferences ****");
StoreStructInFlashMemory(); // Update Mem struct
SWversion(); // Display the version number of the software
}