Functionality works with ESP32 BLE or classic (not simultaneously)

Use #ifdef ESP32_USE_BLE_RLJ to toggle modes.

Also broken out bluetooth functions into a few files for better separation of code.
This commit is contained in:
rljonesau 2018-10-18 20:49:14 +11:00
parent baed4b3079
commit 399ca22c5a
9 changed files with 465 additions and 206 deletions

View file

@ -3,6 +3,8 @@
{
"name": "Win32",
"includePath": [
"C:\\Program Files (x86)\\Arduino\\tools\\**",
"C:\\Program Files (x86)\\Arduino\\hardware\\arduino\\avr\\**",
"C:\\Users\\ray\\AppData\\Local\\Arduino15\\packages\\esp32\\tools\\**",
"C:\\Users\\ray\\AppData\\Local\\Arduino15\\packages\\esp32\\hardware\\esp32\\1.0.0\\**",
"C:\\Users\\ray\\AppData\\Local\\Arduino15\\packages\\arduino\\tools\\**",

View file

@ -2,5 +2,13 @@
"sketch": "SenderTrial2.ino",
"port": "COM4",
"board": "arduino:sam:arduino_due_x_dbg",
"output": "c:\\Users\\ray\\AppData\\Local\\Arduino\\"
"output": "c:\\Users\\ray\\AppData\\Local\\Arduino\\",
"files.associations": {
"list": "cpp",
"vector": "cpp",
"xhash": "cpp",
"xstring": "cpp",
"xtree": "cpp",
"algorithm": "cpp"
}
}

View file

@ -0,0 +1,183 @@
#include "Bluetooth.h"
#include "TxManage.h"
#include "pins.h"
#if defined (ESP32)
// NOTE: ESP32 uses an entirely different mechanism, please refer to BluetoothESP32.cpp/.h
#else
#if defined(__arm__)
// for Arduino Due
static UARTClass& Bluetooth(Serial2);
#else
// for Mega
static HardwareSerial& Bluetooth(Serial2); // TODO: make proper ESP32 BT client
#endif
bool Bluetooth_Command(const char* cmd);
void Bluetooth_Interpret();
String BluetoothRxData;
const int BTRates[] = {
9600, 38400, 115200, 19200, 57600, 2400, 4800
};
bool bHC05Available = false;
void Bluetooth_Init()
{
#ifndef __ESP32__
// search for BlueTooth adapter, trying the common baud rates, then less common
// as the device cannot be guaranteed to power up with the key pin high
// we are at the mercy of the baud rate stored in the module.
Bluetooth.begin(9600);
digitalWrite(KeyPin, HIGH);
delay(500);
USB.println("\r\n\r\nAttempting to detect HC-05 Bluetooth module...");
int BTidx = 0;
int maxTries = sizeof(BTRates)/sizeof(int);
for(BTidx = 0; BTidx < maxTries; BTidx++) {
USB.print(" @ ");
USB.print(BTRates[BTidx]);
USB.print(" baud... ");
Bluetooth.begin(BTRates[BTidx]); // open serial port at a certain baud rate
Bluetooth.print("\r\n");
Bluetooth.setTimeout(50);
if(Bluetooth_Command("AT\r\n")) {
USB.println(" OK.");
break;
}
// failed, try another baud rate
USB.println("");
Bluetooth.flush();
}
USB.println("");
if(BTidx == maxTries) {
USB.println("FAILED to detect HC-05 Bluetooth module :-(");
}
else {
if(BTRates[BTidx] == 115200) {
USB.println("HC-05 found and already set to 115200 baud, skipping Init.");
bHC05Available = true;
}
else {
do {
USB.println("HC-05 found");
USB.print(" Setting Name to \"DieselHeater\"... ");
if(!Bluetooth_Command("AT+NAME=\"DieselHeater\"\r\n")) {
USB.println("FAILED");
break;
}
USB.println("OK");
USB.print(" Setting baud rate to 115200N81...");
if(!Bluetooth_Command("AT+UART=115200,1,0\r\n")) {
USB.println("FAILED");
break;
};
USB.println("OK");
Bluetooth.begin(115200);
bHC05Available = true;
} while(0);
}
}
digitalWrite(KeyPin, LOW); // leave HC-05 command mode
delay(500);
if(!bHC05Available)
Bluetooth.end(); // close serial port if no module found
USB.println("");
#endif
}
void Bluetooth_Check()
{
// check for data coming back over Bluetooth
if(bHC05Available) {
if(Bluetooth.available()) {
char rxVal = Bluetooth.read();
if(isControl(rxVal)) { // "End of Line"
BluetoothRxData += '\0';
Bluetooth_Interpret(BluetoothRxData);
BluetoothRxData = "";
}
else {
BluetoothRxData += rxVal; // append new char to our Rx buffer
}
}
}
}
void Bluetooth_Report(const char* pHdr, const unsigned char Data[24])
{
if(bHC05Available) {
Bluetooth.print(pHdr);
Bluetooth.write(Data, 24);
}
}
// local function, typically to perform Hayes commands with HC-05
bool Bluetooth_Command(const char* cmd)
{
if(bHC05Available) {
Bluetooth.print(cmd);
char RxBuffer[16];
memset(RxBuffer, 0, 16);
int read = Bluetooth.readBytesUntil('\n', RxBuffer, 16); // \n is not included in returned string!
if((read == 3) && (0 == strcmp(RxBuffer, "OK\r")) ) {
return true;
}
return false;
}
return false;
}
#endif
void Bluetooth_Interpret(String line)
{
if(line.startsWith("[CMD]") ) {
USB.write("BT command Rx'd: ");
// incoming command from BT app!
line.remove(0, 5); // strip away "[CMD]" header
if(line.startsWith("ON") ) {
USB.write("ON\n");
TxManage.RequestOn();
}
else if(line.startsWith("OFF")) {
USB.write("OFF\n");
TxManage.RequestOff();
}
else if(line.startsWith("Pmin")) {
line.remove(0, 4);
USB.write("Pmin\n");
}
else if(line.startsWith("Pmax")) {
line.remove(0, 4);
USB.write("Pmax\n");
}
else if(line.startsWith("Fmin")) {
line.remove(0, 4);
USB.write("Fmin\n");
}
else if(line.startsWith("Fmax")) {
line.remove(0, 4);
USB.write("Fmax\n");
}
}
}

View file

@ -0,0 +1,11 @@
#include <Arduino.h>
void Bluetooth_Init();
void Bluetooth_Report(const char* pHdr, const unsigned char Data[24]);
void Bluetooth_Check();
void Bluetooth_Interpret(String line);

View file

@ -0,0 +1,203 @@
#include "Bluetooth.h"
#include "TxManage.h"
#include "pins.h"
#if defined(ESP32)
// ESP32
void Bluetooth_Interpret();
String BluetoothRxLine;
#ifndef ESP32_USE_BLE_RLJ
/////////////////////////////////////////////////////////////////////////////////////////
// CLASSIC BLUETOOTH
// |
// V
#include "BluetoothSerial.h"
BluetoothSerial SerialBT;
void Bluetooth_Init()
{
if(!SerialBT.begin("ESPHEATER")) {
Serial.println("An error occurred initialising Bluetooth");
}
}
void Bluetooth_Check()
{
if(SerialBT.available()) {
char rxVal = SerialBT.read();
if(isControl(rxVal)) { // "End of Line"
BluetoothRxLine += '\0';
Bluetooth_Interpret(BluetoothRxLine);
BluetoothRxLine = "";
}
else {
BluetoothRxLine += rxVal; // append new char to our Rx buffer
}
}
}
void Bluetooth_Report(const char* pHdr, const unsigned char Data[24])
{
if(SerialBT.hasClient()) {
SerialBT.print(pHdr);
SerialBT.write(Data, 24);
}
}
// ^
// |
// CLASSIC BLUETOOTH
/////////////////////////////////////////////////////////////////////////////////////////
#else // ESP32_USE_BLE_RLJ
/////////////////////////////////////////////////////////////////////////////////////////
// BLE
// |
// V
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>
#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"
void BLE_Send(std::string Data);
BLEServer *pServer = NULL;
BLECharacteristic* pTxCharacteristic = NULL;
volatile bool deviceConnected = false;
bool oldDeviceConnected = false;
class MyServerCallbacks : public BLEServerCallbacks {
void onConnect(BLEServer* pServer) {
deviceConnected = true;
}
void onDisconnect(BLEServer* pServer) {
deviceConnected = false;
}
};
class MyCallbacks : public BLECharacteristicCallbacks {
// this callback is called when the ESP WRITE characteristic has been written to by a client
// We need to *read* the new information!
void onWrite(BLECharacteristic* pCharacteristic) {
std::string rxValue = pCharacteristic->getValue();
while(rxValue.length() > 0) {
char rxVal = rxValue[0];
if(isControl(rxVal)) { // "End of Line"
Bluetooth_Interpret(BluetoothRxLine);
BluetoothRxLine = "";
}
else {
BluetoothRxLine += rxVal; // append new char to our Rx buffer
}
rxValue.erase(0, 1);
}
}
};
void Bluetooth_Init()
{
// create the BLE device
BLEDevice::init("DieselHeater");
// create the BLE server
pServer = BLEDevice::createServer();
pServer->setCallbacks(new MyServerCallbacks);
// create the BLE service
BLEService *pService = pServer->createService(SERVICE_UUID);
// create a BLE characteristic
pTxCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID_TX,
BLECharacteristic::PROPERTY_NOTIFY
);
pTxCharacteristic->addDescriptor(new BLE2902());
BLECharacteristic* pRxCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID_RX,
BLECharacteristic::PROPERTY_WRITE
);
pRxCharacteristic->setCallbacks(new MyCallbacks/*()*/);
// start the service
pService->start();
// start advertising
pServer->getAdvertising()->start();
Serial.println("Awaiting a client to notify...");
}
void Bluetooth_Report(const char* pHdr, const unsigned char Data[24])
{
if(deviceConnected) {
// BLE can only squirt 20 bytes per packet.
// build the entire message then divide and conquer
std::string txData = pHdr;
txData.append((char*)Data, 24);
BLE_Send(txData);
}
}
void Bluetooth_Check()
{
// disconnecting
if (!deviceConnected && oldDeviceConnected) {
delay(500); // give the bluetooth stack the chance to get things ready
pServer->startAdvertising(); // restart advertising
Serial.println("start advertising");
oldDeviceConnected = deviceConnected;
}
// connecting
if (deviceConnected && !oldDeviceConnected) {
// do stuff here on connecting
oldDeviceConnected = deviceConnected;
}
}
// break down supplied string into 20 byte chunks (or less)
// BLE can only handle 20 bytes per packet!
void BLE_Send(std::string Data)
{
while(!Data.empty()) {
std::string substr = Data.substr(0, 20);
int len = substr.length();
pTxCharacteristic->setValue((uint8_t*)Data.data(), len);
pTxCharacteristic->notify();
Data.erase(0, len);
}
}
// ^
// |
// BLE
/////////////////////////////////////////////////////////////////////////////////////////
#endif // ESP32_USE_BLE_RLJ
#endif // __ESP32__

View file

@ -64,18 +64,24 @@
#include "Protocol.h"
#include "TxManage.h"
#include "Bluetooth.h"
#include "pins.h"
#if defined(__arm__)
// for Arduino Due
static UARTClass& BlueWire(Serial1);
#else
// for ESP32, Mega
static HardwareSerial& BlueWire(Serial1);
#endif
void SerialReport(const char* hdr, const unsigned char* pData, const char* ftr);
void BluetoothDetect();
bool BlueToothCommand(const char* cmd);
void BlueToothReport(const char* pHdr, const unsigned char Data[24]);
void BluetoothInterpret();
class CommStates {
public:
// comms states
enum eCS {
Idle, ControllerRx, ControllerReport, HeaterRx1, HeaterReport1, SelfTx, HeaterRx2, HeaterReport2
Idle, ControllerRx, ControllerReport, HeaterRx1, HeaterReport1, BTC_Tx, HeaterRx2, HeaterReport2
};
CommStates() {
set(Idle);
@ -96,50 +102,14 @@ private:
int m_Count;
};
#if defined(__arm__)
// for Arduino Due
UARTClass& USB(Serial);
UARTClass& BlueWire(Serial1);
UARTClass& BlueTooth(Serial2);
#else
// for ESP32, Mega
HardwareSerial& USB(Serial);
HardwareSerial& BlueWire(Serial1);
#if defined(__ESP32__)
// ESP32
HardwareSerial& BlueTooth(Serial2); // TODO: make proper ESP32 BT client
#else
// Mega
HardwareSerial& BlueTooth(Serial2);
#endif
#endif
#if defined(__ESP32__)
const int TxEnbPin = 22;
#else
const int TxEnbPin = 20;
#endif
const int ListenOnlyPin = 21;
const int KeyPin = 15;
const int Tx1Pin = 18;
const int Rx1Pin = 19;
const int Tx2Pin = 16;
const int Rx2Pin = 17;
const int BTRates[] = {
9600, 38400, 115200, 19200, 57600, 2400, 4800
};
CommStates CommState;
CTxManage TxManage(TxEnbPin, Serial1);
CProtocol Controller; // most recent data packet received from OEM controller found on blue wire
CProtocol OEMController; // most recent data packet received from OEM controller found on blue wire
CProtocol Heater1; // data packet received from heater in response to OEM controller packet
CProtocol Heater2; // data packet received from heater in response to our packet
CProtocol SelfParams(CProtocol::CtrlMode); // holds our local parameters, used in case of no OEM controller
CProtocol BTCParams(CProtocol::CtrlMode); // holds our local parameters, used in case of no OEM controller
long lastRxTime; // used to observe inter character delays
bool bBlueToothAvailable = false;
String BluetoothRxData;
void setup()
@ -172,15 +142,15 @@ void setup()
TxManage.begin(); // ensure Tx enable pin setup
// define defaults should heater controller be missing
SelfParams.setTemperature_Desired(23);
SelfParams.setTemperature_Actual(22);
SelfParams.Controller.OperatingVoltage = 120;
SelfParams.setPump_Min(16);
SelfParams.setPump_Max(55);
SelfParams.setFan_Min(1680);
SelfParams.setFan_Max(4500);
BTCParams.setTemperature_Desired(23);
BTCParams.setTemperature_Actual(22);
BTCParams.Controller.OperatingVoltage = 120;
BTCParams.setPump_Min(16);
BTCParams.setPump_Max(55);
BTCParams.setFan_Min(1680);
BTCParams.setFan_Max(4500);
BluetoothDetect();
Bluetooth_Init();
}
void loop()
@ -198,21 +168,11 @@ void loop()
}
}
// check for data coming back over Bluetooth
if(BlueTooth.available()) {
char rxVal = BlueTooth.read();
if(isControl(rxVal)) { // "End of Line"
BluetoothRxData += '\0';
BluetoothInterpret();
}
else {
BluetoothRxData += rxVal; // append new char to our Rx buffer
}
}
// check for Bluetooth activity
Bluetooth_Check();
// Handle time interval where we send data to the blue wire
if(CommState.is(CommStates::SelfTx)) {
if(CommState.is(CommStates::BTC_Tx)) {
lastRxTime = timenow; // we are pumping onto blue wire, track this activity!
if(TxManage.CheckTx(timenow) ) { // monitor our data delivery
CommState.set(CommStates::HeaterRx2); // then await heater repsonse
@ -227,11 +187,11 @@ void loop()
if(CommState.is(CommStates::Idle) && (RxTimeElapsed >= 970)) {
// have not seen any receive data for a second.
// OEM controller probably not connected.
// Skip to SelfTx, sending our own settings.
CommState.set(CommStates::SelfTx);
// Skip to BTC_Tx, sending our own settings.
CommState.set(CommStates::BTC_Tx);
bool bOurParams = true;
TxManage.Start(SelfParams, timenow, bOurParams);
BlueToothReport("[BTC]", SelfParams.Data); // BTC => Bluetooth Controller :-)
TxManage.Start(BTCParams, timenow, bOurParams);
Bluetooth_Report("[BTC]", BTCParams.Data); // BTC => Bluetooth Controller :-)
}
// precautionary action if all 24 bytes were not received whilst expecting them
@ -257,7 +217,7 @@ void loop()
int inByte = BlueWire.read(); // read hex byte
if( CommState.is(CommStates::ControllerRx) ) {
if(CommState.saveData(Controller.Data, inByte) ) {
if(CommState.saveData(OEMController.Data, inByte) ) {
CommState.set(CommStates::ControllerReport);
}
}
@ -279,20 +239,20 @@ void loop()
if( CommState.is(CommStates::ControllerReport) ) {
// filled controller frame, report
BlueToothReport("[OEM]", Controller.Data);
SerialReport("Ctrl ", Controller.Data, " ");
Bluetooth_Report("[OEM]", OEMController.Data);
SerialReport("Ctrl ", OEMController.Data, " ");
CommState.set(CommStates::HeaterRx1);
}
else if(CommState.is(CommStates::HeaterReport1) ) {
// received heater frame (after controller message), report
SerialReport("Htr1 ", Heater1.Data, "\r\n");
BlueToothReport("[HTR]", Heater1.Data);
Bluetooth_Report("[HTR]", Heater1.Data);
if(digitalRead(ListenOnlyPin)) {
bool bOurParams = false;
TxManage.Start(Controller, timenow, bOurParams);
CommState.set(CommStates::SelfTx);
TxManage.Start(OEMController, timenow, bOurParams);
CommState.set(CommStates::BTC_Tx);
}
else {
CommState.set(CommStates::Idle); // "Listen Only" input held low, don't send out Tx
@ -303,7 +263,7 @@ void loop()
// received heater frame (after our control message), report
SerialReport("Htr2 ", Heater2.Data, "\r\n");
// if(!digitalRead(ListenOnlyPin)) {
BlueToothReport("[HTR]", Heater2.Data); // pin not grounded, suppress duplicate to BT
Bluetooth_Report("[HTR]", Heater2.Data); // pin not grounded, suppress duplicate to BT
// }
CommState.set(CommStates::Idle);
}
@ -321,132 +281,3 @@ void SerialReport(const char* hdr, const unsigned char* pData, const char* ftr)
USB.print(ftr); // footer
}
void BluetoothDetect()
{
#if defined(__ESP32__)
#else
// search for BlueTooth adapter, trying the common baud rates, then less common
// as the device cannot be guaranteed to power up with the key pin high
// we are at the mercy of the baud rate stored in the module.
BlueTooth.begin(9600);
digitalWrite(KeyPin, HIGH);
delay(500);
USB.println("\r\n\r\nAttempting to detect HC-05 Bluetooth module...");
int BTidx = 0;
int maxTries = sizeof(BTRates)/sizeof(int);
for(BTidx = 0; BTidx < maxTries; BTidx++) {
USB.print(" @ ");
USB.print(BTRates[BTidx]);
USB.print(" baud... ");
BlueTooth.begin(BTRates[BTidx]); // open serial port at a certain baud rate
BlueTooth.print("\r\n");
BlueTooth.setTimeout(50);
if(BlueToothCommand("AT\r\n")) {
USB.println(" OK.");
break;
}
// failed, try another baud rate
USB.println("");
BlueTooth.flush();
}
USB.println("");
if(BTidx == maxTries) {
USB.println("FAILED to detect HC-05 Bluetooth module :-(");
}
else {
if(BTRates[BTidx] == 115200) {
USB.println("HC-05 found and already set to 115200 baud, skipping Init.");
bBlueToothAvailable = true;
}
else {
do {
USB.println("HC-05 found");
USB.print(" Setting Name to \"DieselHeater\"... ");
if(!BlueToothCommand("AT+NAME=\"DieselHeater\"\r\n")) {
USB.println("FAILED");
break;
}
USB.println("OK");
USB.print(" Setting baud rate to 115200N81...");
if(!BlueToothCommand("AT+UART=115200,1,0\r\n")) {
USB.println("FAILED");
break;
};
USB.println("OK");
BlueTooth.begin(115200);
bBlueToothAvailable = true;
} while(0);
}
}
digitalWrite(KeyPin, LOW); // leave HC-05 command mode
delay(500);
if(!bBlueToothAvailable)
BlueTooth.end(); // close serial port if no module found
USB.println("");
#endif
}
bool BlueToothCommand(const char* cmd)
{
if(bBlueToothAvailable) {
BlueTooth.print(cmd);
char RxBuffer[16];
memset(RxBuffer, 0, 16);
int read = BlueTooth.readBytesUntil('\n', RxBuffer, 16); // \n is not included in returned string!
if((read == 3) && (0 == strcmp(RxBuffer, "OK\r")) ) {
return true;
}
return false;
}
return false;
}
void BlueToothReport(const char* pHdr, const unsigned char Data[24])
{
if(bBlueToothAvailable) {
BlueTooth.print(pHdr);
BlueTooth.write(Data, 24);
}
}
void BluetoothInterpret()
{
if(BluetoothRxData.startsWith("[CMD]") ) {
USB.write("BT command Rx'd: ");
// incoming command from BT app!
BluetoothRxData.remove(0, 5); // strip away "[CMD]" header
if(BluetoothRxData.startsWith("ON")) {
USB.write("ON\n");
TxManage.RequestOn();
}
else if(BluetoothRxData.startsWith("OFF")) {
USB.write("OFF\n");
TxManage.RequestOff();
}
else if(BluetoothRxData.startsWith("Pmin")) {
USB.write("Pmin\n");
}
else if(BluetoothRxData.startsWith("Pmax")) {
USB.write("Pmax\n");
}
else if(BluetoothRxData.startsWith("Fmin")) {
USB.write("Fmin\n");
}
else if(BluetoothRxData.startsWith("Fmax")) {
USB.write("Fmax\n");
}
}
BluetoothRxData = ""; //flush string, ready for new data
}

View file

@ -1,4 +1,4 @@
#include <Arduino.h>
//#include <Arduino.h>
#include "TxManage.h"
extern void SerialReport(const char* hdr, const unsigned char* pData, const char* ftr);

View file

@ -28,3 +28,5 @@ private:
void _send();
};
extern CTxManage TxManage;

View file

@ -0,0 +1,19 @@
#if defined(__ESP32__)
const int TxEnbPin = 22;
#else
const int TxEnbPin = 20;
#endif
const int ListenOnlyPin = 21;
const int KeyPin = 15;
const int Tx1Pin = 18;
const int Rx1Pin = 19;
const int Tx2Pin = 16;
const int Rx2Pin = 17;
#if defined(__arm__)
// for Arduino Due
static UARTClass& USB(Serial); // TODO: make proper ESP32 BT client
#else
// for ESP32, Mega
static HardwareSerial& USB(Serial); // TODO: make proper ESP32 BT client
#endif