Merged branch 'master' into ESP32OTA to acquire ClassyBluetooth changes
Resolved Conflict: Arduino/SenderTrial2/SenderTrial2.ino Defined pin 23 for triggering wifiManager
This commit is contained in:
commit
4a841f530a
BIN
Arduino/Libraries/WiFiManager-development.zip
Normal file
BIN
Arduino/Libraries/WiFiManager-development.zip
Normal file
Binary file not shown.
BIN
Arduino/Libraries/telnetspy-master.zip
Normal file
BIN
Arduino/Libraries/telnetspy-master.zip
Normal file
Binary file not shown.
2
Arduino/SenderTrial2/.vscode/arduino.json
vendored
2
Arduino/SenderTrial2/.vscode/arduino.json
vendored
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"board": "esp32:esp32:esp32",
|
||||
"port": "COM9",
|
||||
"port": "192.168.0.101",
|
||||
"sketch": "SenderTrial2.ino",
|
||||
"output": "..\\build",
|
||||
"configuration": "PSRAM=disabled,PartitionScheme=default,FlashMode=qio,FlashFreq=80,FlashSize=4M,UploadSpeed=921600,DebugLevel=none"
|
||||
|
|
10
Arduino/SenderTrial2/.vscode/settings.json
vendored
10
Arduino/SenderTrial2/.vscode/settings.json
vendored
|
@ -11,6 +11,14 @@
|
|||
"xtree": "cpp",
|
||||
"algorithm": "cpp",
|
||||
"initializer_list": "cpp",
|
||||
"xutility": "cpp"
|
||||
"xutility": "cpp",
|
||||
"istream": "cpp",
|
||||
"memory": "cpp",
|
||||
"tuple": "cpp",
|
||||
"type_traits": "cpp",
|
||||
"utility": "cpp",
|
||||
"xlocmon": "cpp",
|
||||
"xlocnum": "cpp",
|
||||
"xloctime": "cpp"
|
||||
}
|
||||
}
|
|
@ -1,2 +1,31 @@
|
|||
// Place Holder Config File - User config vars and defines to be moved here
|
||||
// Jimmy C
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// Configure bluetooth options
|
||||
// ** Recommended to use HC-05 for now **
|
||||
// If none are enabled, we'll use an abstract class that only reports
|
||||
// to the debug port what would have been sent
|
||||
//
|
||||
#define USE_HC05_BLUETOOTH 1
|
||||
#define USE_BLE_BLUETOOTH 0
|
||||
#define USE_CLASSIC_BLUETOOTH 0
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// limit rate of Bluetooth delivery from enthusiastic OEM controllers
|
||||
//
|
||||
#define OEM_TO_BLUETOOTH_MODERATION_TIME 700
|
||||
// show when we did not echo data frames to bluetooth
|
||||
#define REPORT_SUPPRESSED_OEM_DATA_FRAMES 0
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// debug reporting options
|
||||
//
|
||||
// true: each frame of data is reported on a new lines
|
||||
// false: controller, then heater response frmaes are reported on a single line (excel CSV worthy!)
|
||||
//
|
||||
#define TERMINATE_OEM_LINE false /* when an OEM controller exists */
|
||||
#define TERMINATE_BTC_LINE false /* when an OEM controller does not exist */
|
||||
|
||||
|
|
|
@ -16,34 +16,33 @@ bool res;
|
|||
|
||||
void initWifi(int initpin,const char *failedssid, const char *failedpassword)
|
||||
{
|
||||
|
||||
|
||||
TRIG_PIN = initpin;
|
||||
pinMode(TRIG_PIN, INPUT);
|
||||
|
||||
//reset settings - wipe credentials for testing
|
||||
//wm.resetSettings();
|
||||
//reset settings - wipe credentials for testing
|
||||
//wm.resetSettings();
|
||||
|
||||
// Automatically connect using saved credentials,
|
||||
// if connection fails, it starts an access point with the specified name ( "AutoConnectAP"),
|
||||
// if empty will auto generate SSID, if password is blank it will be anonymous AP (wm.autoConnect())
|
||||
// then goes into a blocking loop awaiting configuration and will return success result
|
||||
wm.setConfigPortalTimeout(20);
|
||||
wm.setConfigPortalBlocking(true);
|
||||
// Automatically connect using saved credentials,
|
||||
// if connection fails, it starts an access point with the specified name ( "AutoConnectAP"),
|
||||
// if empty will auto generate SSID, if password is blank it will be anonymous AP (wm.autoConnect())
|
||||
// then goes into a blocking loop awaiting configuration and will return success result
|
||||
wm.setConfigPortalTimeout(20);
|
||||
wm.setConfigPortalBlocking(true);
|
||||
|
||||
res = wm.autoConnect(); // auto generated AP name from chipid
|
||||
res = wm.autoConnect(); // auto generated AP name from chipid
|
||||
|
||||
if(!res) {
|
||||
Serial.println("Failed to connect");
|
||||
Serial.println("Setting up ESP as AP");
|
||||
WiFi.softAP(failedssid, failedpassword);
|
||||
}
|
||||
else {
|
||||
//if you get here you have connected to the WiFi
|
||||
Serial.println("connected...yeey :)");
|
||||
Serial.println("Ready");
|
||||
Serial.print("IP address: ");
|
||||
Serial.println(WiFi.localIP());
|
||||
}
|
||||
if(!res) {
|
||||
Serial.println("Failed to connect");
|
||||
Serial.println("Setting up ESP as AP");
|
||||
WiFi.softAP(failedssid, failedpassword);
|
||||
}
|
||||
else {
|
||||
//if you get here you have connected to the WiFi
|
||||
Serial.println("connected...yeey :)");
|
||||
Serial.println("Ready");
|
||||
Serial.print("IP address: ");
|
||||
Serial.println(WiFi.localIP());
|
||||
}
|
||||
}
|
||||
|
||||
void doWiFiManager(){
|
||||
|
|
|
@ -1,33 +0,0 @@
|
|||
#include <Arduino.h>
|
||||
|
||||
class CProtocol;
|
||||
|
||||
void Bluetooth_Init();
|
||||
void Bluetooth_SendFrame(const char* pHdr, const CProtocol& Frame, bool lineterm=true);
|
||||
void Bluetooth_Check();
|
||||
void Bluetooth_SendACK();
|
||||
|
||||
extern void Command_Interpret(const char* pLine); // decodes received command lines, implemented in main .ino file!
|
||||
|
||||
struct sRxLine {
|
||||
char Line[64];
|
||||
int Len;
|
||||
sRxLine() {
|
||||
clear();
|
||||
}
|
||||
bool append(char val) {
|
||||
if(Len < (sizeof(Line) - 1)) {
|
||||
Line[Len++] = val;
|
||||
Line[Len] = 0;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
void clear() {
|
||||
Line[0] = 0;
|
||||
Len = 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
58
Arduino/SenderTrial2/BluetoothAbstract.h
Normal file
58
Arduino/SenderTrial2/BluetoothAbstract.h
Normal file
|
@ -0,0 +1,58 @@
|
|||
#include <Arduino.h>
|
||||
#include <string.h>
|
||||
|
||||
class CProtocol;
|
||||
|
||||
extern void Command_Interpret(const char* pLine); // decodes received command lines, implemented in main .ino file!
|
||||
|
||||
struct sRxLine {
|
||||
char Line[64];
|
||||
int Len;
|
||||
sRxLine() {
|
||||
clear();
|
||||
}
|
||||
bool append(char val) {
|
||||
if(Len < (sizeof(Line) - 1)) {
|
||||
Line[Len++] = val;
|
||||
Line[Len] = 0;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
void clear() {
|
||||
Line[0] = 0;
|
||||
Len = 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class CBluetoothAbstract {
|
||||
protected:
|
||||
sRxLine _rxLine;
|
||||
unsigned long lastTime;
|
||||
public:
|
||||
virtual void init() {};
|
||||
virtual void sendFrame(const char* pHdr, const CProtocol& Frame, bool lineterm=true) {
|
||||
char msg[32];
|
||||
if(strncmp(pHdr, "[HTR]", 5) == 0) {
|
||||
unsigned delta = millis() - lastTime;
|
||||
sprintf(msg, "%+8dms ", delta);
|
||||
}
|
||||
else {
|
||||
lastTime = millis();
|
||||
sprintf(msg, "%8dms ", lastTime);
|
||||
}
|
||||
DebugPort.print(msg);
|
||||
DebugReportFrame(pHdr, Frame, lineterm ? "\r\n" : " ");
|
||||
};
|
||||
virtual void check() {};
|
||||
virtual void collectRxData(char rxVal) {
|
||||
if(isControl(rxVal)) { // "End of Line"
|
||||
Command_Interpret(_rxLine.Line);
|
||||
_rxLine.clear();
|
||||
}
|
||||
else {
|
||||
_rxLine.append(rxVal); // append new char to our Rx buffer
|
||||
}
|
||||
};
|
||||
};
|
|
@ -1,7 +1,8 @@
|
|||
#include "Bluetooth.h"
|
||||
#include <Arduino.h>
|
||||
#include "pins.h"
|
||||
#include "Protocol.h"
|
||||
#include "debugport.h"
|
||||
#include "BluetoothESP32.h"
|
||||
|
||||
#ifdef TELNET
|
||||
#define DebugPort Debug
|
||||
|
@ -14,242 +15,85 @@
|
|||
|
||||
#ifdef ESP32
|
||||
|
||||
#define ESP32_USE_HC05
|
||||
|
||||
#ifdef BT_LED
|
||||
const int LED = 2;
|
||||
|
||||
// ESP32
|
||||
|
||||
sRxLine RxLine;
|
||||
|
||||
#ifdef ESP32_USE_HC05
|
||||
|
||||
//static HardwareSerial& Bluetooth(Serial2); // TODO: make proper ESP32 BT client
|
||||
|
||||
bool Bluetooth_ATCommand(const char* cmd);
|
||||
|
||||
|
||||
// Search for a HC-05 BlueTooth adapter, trying the more common baud rates first.
|
||||
// As we cannot power up with the key pin high we are at the mercy of the baud rate
|
||||
// stored in the module.
|
||||
// **IMPORTANT**
|
||||
// We must use a HC-05 module that uses a 3 pin 3.3V regulator (NOT 5 pin).
|
||||
// On those modules, the EN input drive pin 34 and can be used to switch to AT
|
||||
// command mode from data mode by raising EN high.
|
||||
// ** BEWARE**
|
||||
// The other style modules (with a 5 pin regulator) will disable the HC-05's power
|
||||
// when the EN pin is low!!!!
|
||||
//
|
||||
// Once in command mode we can start interrogating using a simple "AT" command and
|
||||
// checking for a response.
|
||||
// If no response, try another baud rate till we do find a response.
|
||||
// We can then proceed and configure the device's name, and force 9600 data rate
|
||||
|
||||
void Bluetooth_Init()
|
||||
{
|
||||
const int BTRates[] = {
|
||||
9600, 38400, 115200, 19200, 57600, 2400, 4800, 1200
|
||||
};
|
||||
|
||||
RxLine.clear();
|
||||
|
||||
// attach to the SENSE line from the HC-05 module
|
||||
// this line goes high when a BT client is connected :-)
|
||||
pinMode(HC05_Sense, INPUT);
|
||||
|
||||
digitalWrite(KeyPin, HIGH); // request HC-05 module to enter command mode
|
||||
// Open Serial2, explicitly specify pins for pin multiplexer!);
|
||||
Serial2.begin(9600, SERIAL_8N1, Rx2Pin, Tx2Pin);
|
||||
|
||||
DebugPort.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++) {
|
||||
DebugPort.print(" @ ");
|
||||
DebugPort.print(BTRates[BTidx]);
|
||||
DebugPort.print(" baud... ");
|
||||
Serial2.begin(BTRates[BTidx], SERIAL_8N1, Rx2Pin, Tx2Pin); // open serial port at a std.baud rate
|
||||
delay(10);
|
||||
Serial2.print("\r\n"); // clear the throat!
|
||||
delay(100);
|
||||
Serial2.setTimeout(100);
|
||||
|
||||
if(Bluetooth_ATCommand("AT\r\n")) { // probe with a simple "AT"
|
||||
DebugPort.println(" OK."); // got a response - woo hoo found the module!
|
||||
break;
|
||||
}
|
||||
if(Bluetooth_ATCommand("AT\r\n")) { // sometimes a second try is good...
|
||||
DebugPort.println(" OK.");
|
||||
break;
|
||||
}
|
||||
|
||||
// failed, try another baud rate
|
||||
DebugPort.println("");
|
||||
Serial2.flush();
|
||||
Serial2.end();
|
||||
delay(100);
|
||||
}
|
||||
|
||||
DebugPort.println("");
|
||||
if(BTidx == maxTries) {
|
||||
// we could not get anywhere with teh AT commands, but maybe this is the other module
|
||||
// plough on and assume 9600 baud, but at the mercy of whatever the module name is...
|
||||
DebugPort.println("FAILED to detect a HC-05 Bluetooth module :-(");
|
||||
// leave the EN pin high - if other style module keeps it powered!
|
||||
// assume it is 9600, and just (try to) use it like that...
|
||||
// we will sense the STATE line to prove a client is hanging off the link...
|
||||
DebugPort.println("ASSUMING a HC-05 module @ 9600baud (Unknown name)");
|
||||
Serial2.begin(9600, SERIAL_8N1, Rx2Pin, Tx2Pin);
|
||||
}
|
||||
else {
|
||||
// found a HC-05 module at one of its supported baud rates.
|
||||
// now program it's name and force a 9600 baud data interface.
|
||||
// this is the defacto standard as shipped!
|
||||
|
||||
DebugPort.println("HC-05 found");
|
||||
|
||||
do { // so we can break!
|
||||
DebugPort.print(" Setting Name to \"Diesel Heater\"... ");
|
||||
if(!Bluetooth_ATCommand("AT+NAME=\"Diesel Heater\"\r\n")) {
|
||||
DebugPort.println("FAILED");
|
||||
break;
|
||||
}
|
||||
DebugPort.println("OK");
|
||||
|
||||
DebugPort.print(" Setting baud rate to 9600N81...");
|
||||
if(!Bluetooth_ATCommand("AT+UART=9600,1,0\r\n")) {
|
||||
DebugPort.println("FAILED");
|
||||
break;
|
||||
};
|
||||
DebugPort.println("OK");
|
||||
|
||||
Serial2.begin(9600, SERIAL_8N1, Rx2Pin, Tx2Pin);
|
||||
|
||||
// leave HC-05 command mode, return to data mode
|
||||
digitalWrite(KeyPin, LOW);
|
||||
} while (0); // yeah lame, allows break prior though :-)
|
||||
}
|
||||
|
||||
delay(50);
|
||||
|
||||
DebugPort.println("");
|
||||
}
|
||||
|
||||
void Bluetooth_Check()
|
||||
{
|
||||
// check for data coming back over Bluetooth
|
||||
if(Serial2.available()) {
|
||||
char rxVal = Serial2.read();
|
||||
if(isControl(rxVal)) { // "End of Line"
|
||||
Command_Interpret(RxLine.Line);
|
||||
RxLine.clear();
|
||||
}
|
||||
else {
|
||||
RxLine.append(rxVal); // append new char to our Rx buffer
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Bluetooth_SendFrame(const char* pHdr, const CProtocol& Frame, bool lineterm)
|
||||
{
|
||||
DebugPort.print(millis());
|
||||
DebugPort.print("ms ");
|
||||
// DebugReportFrame(pHdr, Frame, lineterm ? "\r\n" : " ");
|
||||
DebugReportFrame(pHdr, Frame, " ");
|
||||
|
||||
if(digitalRead(HC05_Sense)) {
|
||||
if(Frame.verifyCRC()) {
|
||||
// send data frame to HC-05
|
||||
Serial2.print(pHdr);
|
||||
Serial2.write(Frame.Data, 24);
|
||||
// toggle LED
|
||||
digitalWrite(LED, !digitalRead(LED)); // toggle LED
|
||||
}
|
||||
else {
|
||||
DebugPort.print("Bluetooth data not sent, CRC error ");
|
||||
}
|
||||
}
|
||||
else {
|
||||
DebugPort.print("No Bluetooth client");
|
||||
// force LED off
|
||||
digitalWrite(LED, 0);
|
||||
}
|
||||
if(lineterm)
|
||||
DebugPort.println("");
|
||||
}
|
||||
|
||||
// local function, typically to perform Hayes commands with HC-05
|
||||
bool Bluetooth_ATCommand(const char* cmd)
|
||||
{
|
||||
Serial2.print(cmd);
|
||||
char RxBuffer[16];
|
||||
memset(RxBuffer, 0, 16);
|
||||
int read = Serial2.readBytesUntil('\n', RxBuffer, 16); // \n is not included in returned string!
|
||||
if((read == 3) && (0 == strcmp(RxBuffer, "OK\r")) ) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#else // ESP32_USE_HC05
|
||||
#ifndef ESP32_USE_BLE_RLJ
|
||||
#endif
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
// CLASSIC BLUETOOTH
|
||||
// HC-05 BLUETOOTH with ESP32
|
||||
// |
|
||||
// V
|
||||
//
|
||||
CBluetoothESP32HC05::CBluetoothESP32HC05(int keyPin, int sensePin, int rxPin, int txPin) : CBluetoothHC05(keyPin, sensePin)
|
||||
{
|
||||
_rxPin = rxPin;
|
||||
_txPin = txPin;
|
||||
}
|
||||
|
||||
void
|
||||
CBluetoothESP32HC05::openSerial(int baudrate)
|
||||
{
|
||||
// Open Serial port on the ESP32
|
||||
// best to explicitly specify pins for the pin multiplexer!
|
||||
HC05_SerialPort.begin(baudrate, SERIAL_8N1, _rxPin, _txPin);
|
||||
}
|
||||
// ^
|
||||
// |
|
||||
// HC-05 BLUETOOTH with ESP32
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
// CLASSIC BLUETOOTH on ESP32
|
||||
// |
|
||||
// V
|
||||
|
||||
|
||||
#include "BluetoothSerial.h"
|
||||
|
||||
BluetoothSerial SerialBT;
|
||||
|
||||
void Bluetooth_Init()
|
||||
void
|
||||
CBluetoothESP32Classic::init()
|
||||
{
|
||||
RxLine.clear();
|
||||
_rxLine.clear();
|
||||
#ifdef BT_LED
|
||||
pinMode(LED, OUTPUT);
|
||||
#endif
|
||||
|
||||
if(!SerialBT.begin("ESPHEATER")) {
|
||||
DebugPort.println("An error occurred initialising Bluetooth");
|
||||
}
|
||||
}
|
||||
|
||||
void Bluetooth_Check()
|
||||
void
|
||||
CBluetoothESP32Classic::check()
|
||||
{
|
||||
if(SerialBT.available()) {
|
||||
char rxVal = SerialBT.read();
|
||||
if(isControl(rxVal)) { // "End of Line"
|
||||
Command_Interpret(RxLine.Line);
|
||||
RxLine.clear();
|
||||
}
|
||||
else {
|
||||
RxLine.append(rxVal);
|
||||
}
|
||||
collectRxData(rxVal);
|
||||
}
|
||||
}
|
||||
|
||||
void Bluetooth_SendFrame(const char* pHdr, const CProtocol& Frame, bool lineterm)
|
||||
void
|
||||
CBluetoothESP32Classic::sendFrame(const char* pHdr, const CProtocol& Frame, bool lineterm)
|
||||
{
|
||||
char fullMsg[32];
|
||||
|
||||
DebugPort.print(millis());
|
||||
DebugReportFrame(pHdr, Frame, lineterm ? "\r\n" : " ");
|
||||
// report to debug port
|
||||
CBluetoothAbstract::sendFrame(pHdr, Frame, lineterm);
|
||||
|
||||
delay(40);
|
||||
if(SerialBT.hasClient()) {
|
||||
|
||||
if(Frame.verifyCRC()) {
|
||||
#ifdef BT_LED
|
||||
digitalWrite(LED, !digitalRead(LED)); // toggle LED
|
||||
#endif
|
||||
int len = strlen(pHdr);
|
||||
if(len < 8) {
|
||||
strcpy(fullMsg, pHdr);
|
||||
memcpy(&fullMsg[len], Frame.Data, 24);
|
||||
|
||||
SerialBT.write((uint8_t*)fullMsg, 24+len);
|
||||
}
|
||||
/* SerialBT.print(pHdr);
|
||||
delay(1);
|
||||
SerialBT.write(Frame.Data, 24);*/
|
||||
delay(10);
|
||||
}
|
||||
else {
|
||||
|
@ -258,32 +102,24 @@ void Bluetooth_SendFrame(const char* pHdr, const CProtocol& Frame, bool lineterm
|
|||
}
|
||||
else {
|
||||
DebugPort.println("No Bluetooth client");
|
||||
#ifdef BT_LED
|
||||
digitalWrite(LED, 0);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void Bluetooth_SendACK()
|
||||
{
|
||||
/* if(SerialBT.hasClient()) {
|
||||
SerialBT.print("[ACK]");
|
||||
}*/
|
||||
}
|
||||
|
||||
|
||||
// ^
|
||||
// |
|
||||
// CLASSIC BLUETOOTH
|
||||
// CLASSIC BLUETOOTH on ESP32
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#else // ESP32_USE_BLE_RLJ
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
// BLE
|
||||
// BLE on ESP32
|
||||
// |
|
||||
// V
|
||||
|
||||
|
||||
#include <BLEDevice.h>
|
||||
/*#include <BLEDevice.h>
|
||||
#include <BLEServer.h>
|
||||
#include <BLEUtils.h>
|
||||
#include <BLE2902.h>
|
||||
|
@ -292,28 +128,39 @@ void Bluetooth_SendACK()
|
|||
#define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
|
||||
#define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"
|
||||
|
||||
void BLE_Send(std::string Data);
|
||||
void BLE_Send(std::string Data);*/
|
||||
|
||||
/*
|
||||
BLEServer *pServer = NULL;
|
||||
BLECharacteristic* pTxCharacteristic = NULL;
|
||||
volatile bool deviceConnected = false;
|
||||
bool oldDeviceConnected = false;
|
||||
*/
|
||||
|
||||
class MyServerCallbacks : public BLEServerCallbacks {
|
||||
|
||||
volatile bool& _deviceConnected;
|
||||
public:
|
||||
MyServerCallbacks(volatile bool& devConnected) : _deviceConnected(devConnected), BLEServerCallbacks() {};
|
||||
|
||||
private:
|
||||
void onConnect(BLEServer* pServer) {
|
||||
deviceConnected = true;
|
||||
_deviceConnected = true;
|
||||
}
|
||||
|
||||
void onDisconnect(BLEServer* pServer) {
|
||||
deviceConnected = false;
|
||||
_deviceConnected = false;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
class MyCallbacks : public BLECharacteristicCallbacks {
|
||||
|
||||
CBluetoothESP32BLE* _pHost;
|
||||
public:
|
||||
MyCallbacks(CBluetoothESP32BLE* pHost) : BLECharacteristicCallbacks() {
|
||||
_pHost = pHost;
|
||||
};
|
||||
private:
|
||||
// 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) {
|
||||
|
@ -322,103 +169,133 @@ class MyCallbacks : public BLECharacteristicCallbacks {
|
|||
|
||||
while(rxValue.length() > 0) {
|
||||
char rxVal = rxValue[0];
|
||||
if(isControl(rxVal)) { // "End of Line"
|
||||
Command_Interpret(BluetoothRxLine);
|
||||
BluetoothRxLine = "";
|
||||
}
|
||||
else {
|
||||
BluetoothRxLine += rxVal; // append new char to our Rx buffer
|
||||
}
|
||||
if(_pHost) _pHost->collectRxData(rxVal);
|
||||
rxValue.erase(0, 1);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
void Bluetooth_Init()
|
||||
CBluetoothESP32BLE::CBluetoothESP32BLE()
|
||||
{
|
||||
_pServer = NULL;
|
||||
_pTxCharacteristic = NULL;
|
||||
_deviceConnected = false;
|
||||
_oldDeviceConnected = false;
|
||||
}
|
||||
|
||||
CBluetoothESP32BLE::~CBluetoothESP32BLE()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
CBluetoothESP32BLE::init()
|
||||
{
|
||||
// create the BLE device
|
||||
BLEDevice::init("DieselHeater");
|
||||
|
||||
// create the BLE server
|
||||
pServer = BLEDevice::createServer();
|
||||
pServer->setCallbacks(new MyServerCallbacks);
|
||||
_pServer = BLEDevice::createServer();
|
||||
_pServer->setCallbacks(new MyServerCallbacks(_deviceConnected));
|
||||
|
||||
// create the BLE service
|
||||
BLEService *pService = pServer->createService(SERVICE_UUID);
|
||||
BLEService *pService = _pServer->createService(SERVICE_UUID);
|
||||
|
||||
// create a BLE characteristic
|
||||
pTxCharacteristic = pService->createCharacteristic(
|
||||
_pTxCharacteristic = pService->createCharacteristic(
|
||||
CHARACTERISTIC_UUID_TX,
|
||||
BLECharacteristic::PROPERTY_NOTIFY
|
||||
);
|
||||
pTxCharacteristic->addDescriptor(new BLE2902());
|
||||
_pTxCharacteristic->addDescriptor(new BLE2902());
|
||||
|
||||
|
||||
BLECharacteristic* pRxCharacteristic = pService->createCharacteristic(
|
||||
CHARACTERISTIC_UUID_RX,
|
||||
BLECharacteristic::PROPERTY_WRITE
|
||||
);
|
||||
pRxCharacteristic->setCallbacks(new MyCallbacks/*()*/);
|
||||
pRxCharacteristic->setCallbacks(new MyCallbacks(this));
|
||||
|
||||
// start the service
|
||||
pService->start();
|
||||
// start advertising
|
||||
pServer->getAdvertising()->start();
|
||||
_pServer->getAdvertising()->start();
|
||||
DebugPort.println("Awaiting a client to notify...");
|
||||
}
|
||||
|
||||
void Bluetooth_Report(const char* pHdr, const CProtocol& Frame)
|
||||
void
|
||||
CBluetoothESP32BLE::sendFrame(const char* pHdr, const CProtocol& Frame, bool lineterm)
|
||||
{
|
||||
if(deviceConnected) {
|
||||
char fullMsg[32];
|
||||
|
||||
// report to debug port
|
||||
CBluetoothAbstract::sendFrame(pHdr, Frame, lineterm);
|
||||
|
||||
delay(40);
|
||||
if(_deviceConnected) {
|
||||
|
||||
if(Frame.verifyCRC()) {
|
||||
// BLE can only squirt 20 bytes per packet.
|
||||
// build the entire message then divide and conquer
|
||||
#ifdef BT_LED
|
||||
digitalWrite(LED, !digitalRead(LED)); // toggle LED
|
||||
#endif
|
||||
std::string txData = pHdr;
|
||||
txData.append((char*)Frame.Data, 24);
|
||||
|
||||
|
||||
BLE_Send(txData);
|
||||
delay(10);
|
||||
}
|
||||
else {
|
||||
DebugPort.println("Data not sent to Bluetooth, CRC error!");
|
||||
}
|
||||
}
|
||||
else {
|
||||
DebugPort.println("No Bluetooth client");
|
||||
#ifdef BT_LED
|
||||
digitalWrite(LED, 0);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void Bluetooth_Check()
|
||||
void
|
||||
CBluetoothESP32BLE::check()
|
||||
{
|
||||
// disconnecting
|
||||
if (!deviceConnected && oldDeviceConnected) {
|
||||
if (!_deviceConnected && _oldDeviceConnected) {
|
||||
delay(500); // give the bluetooth stack the chance to get things ready
|
||||
pServer->startAdvertising(); // restart advertising
|
||||
_pServer->startAdvertising(); // restart advertising
|
||||
DebugPort.println("start advertising");
|
||||
oldDeviceConnected = deviceConnected;
|
||||
DebugPort.println("CLIENT DISCONNECTED");
|
||||
_oldDeviceConnected = _deviceConnected;
|
||||
}
|
||||
// connecting
|
||||
if (deviceConnected && !oldDeviceConnected) {
|
||||
if (_deviceConnected && !_oldDeviceConnected) {
|
||||
// do stuff here on connecting
|
||||
oldDeviceConnected = deviceConnected;
|
||||
DebugPort.println("CLIENT CONNECTED");
|
||||
_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)
|
||||
void
|
||||
CBluetoothESP32BLE::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();
|
||||
_pTxCharacteristic->setValue((uint8_t*)Data.data(), len);
|
||||
_pTxCharacteristic->notify();
|
||||
Data.erase(0, len);
|
||||
}
|
||||
}
|
||||
|
||||
// ^
|
||||
// |
|
||||
// BLE
|
||||
// BLE on ESP32
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#endif // ESP32_USE_BLE_RLJ
|
||||
|
||||
#endif // ESP32_USE_HC05
|
||||
|
||||
#endif // __ESP32__
|
||||
|
||||
|
|
41
Arduino/SenderTrial2/BluetoothESP32.h
Normal file
41
Arduino/SenderTrial2/BluetoothESP32.h
Normal file
|
@ -0,0 +1,41 @@
|
|||
|
||||
#include "BluetoothHC05.h"
|
||||
#include "BluetoothSerial.h"
|
||||
|
||||
class CBluetoothESP32HC05 : public CBluetoothHC05 {
|
||||
int _rxPin, _txPin;
|
||||
public:
|
||||
CBluetoothESP32HC05(int keyPin, int sensePin, int rxPin, int txPin);
|
||||
protected:
|
||||
void openSerial(int baudrate);
|
||||
};
|
||||
|
||||
class CBluetoothESP32Classic : public CBluetoothAbstract {
|
||||
BluetoothSerial SerialBT;
|
||||
public:
|
||||
virtual void init();
|
||||
virtual void sendFrame(const char* pHdr, const CProtocol& Frame, bool lineterm=true);
|
||||
virtual void check();
|
||||
};
|
||||
|
||||
#include <BLEDevice.h>
|
||||
#include <BLEServer.h>
|
||||
#include <BLEUtils.h>
|
||||
#include <BLE2902.h>
|
||||
|
||||
class CBluetoothESP32BLE : public CBluetoothAbstract {
|
||||
const char* SERVICE_UUID = "6E400001-B5A3-F393-E0A9-E50E24DCCA9E"; // UART service UUID
|
||||
const char* CHARACTERISTIC_UUID_RX = "6E400002-B5A3-F393-E0A9-E50E24DCCA9E";
|
||||
const char* CHARACTERISTIC_UUID_TX = "6E400003-B5A3-F393-E0A9-E50E24DCCA9E";
|
||||
BLEServer *_pServer;
|
||||
BLECharacteristic* _pTxCharacteristic;
|
||||
volatile bool _deviceConnected;
|
||||
bool _oldDeviceConnected;
|
||||
void BLE_Send(std::string Data);
|
||||
public:
|
||||
CBluetoothESP32BLE();
|
||||
virtual ~CBluetoothESP32BLE();
|
||||
virtual void init();
|
||||
virtual void sendFrame(const char* pHdr, const CProtocol& Frame, bool lineterm=true);
|
||||
virtual void check();
|
||||
};
|
|
@ -1,41 +1,35 @@
|
|||
#include "Bluetooth.h"
|
||||
#include "pins.h"
|
||||
#include "Protocol.h"
|
||||
#include "debugport.h"
|
||||
#include "BluetoothHC05.h"
|
||||
|
||||
// Bluetooth access via HC-05 Module, using a UART
|
||||
|
||||
#ifndef ESP32
|
||||
// NOTE: ESP32 uses an entirely different mechanism, please refer to BluetoothESP32.cpp/.h
|
||||
|
||||
#ifdef __arm__
|
||||
// for Arduino Due
|
||||
static UARTClass& Bluetooth(Serial2);
|
||||
#else
|
||||
// for Mega
|
||||
static HardwareSerial& Bluetooth(Serial2); // TODO: make proper ESP32 BT client
|
||||
#endif
|
||||
|
||||
bool Bluetooth_ATCommand(const char* cmd);
|
||||
|
||||
sRxLine RxLine;
|
||||
|
||||
const int BTRates[] = {
|
||||
9600, 38400, 115200, 19200, 57600, 2400, 4800
|
||||
};
|
||||
|
||||
bool bHC05Available = false;
|
||||
|
||||
void Bluetooth_Init()
|
||||
CBluetoothHC05::CBluetoothHC05(int keyPin, int sensePin)
|
||||
{
|
||||
RxLine.clear();
|
||||
// extra control pins required to fully drive a HC05 module
|
||||
_keyPin = keyPin; // used to enable AT command mode (ONLY ON SUPPORTED MODULES!!!!)
|
||||
_sensePin = sensePin; // feedback signal used to sense if a client is connected
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CBluetoothHC05::init()
|
||||
{
|
||||
const int BTRates[] = {
|
||||
9600, 38400, 115200, 19200, 57600, 2400, 4800, 1200
|
||||
};
|
||||
|
||||
_rxLine.clear();
|
||||
|
||||
// attach to the SENSE line from the HC-05 module
|
||||
// this line goes high when a BT client is connected :-)
|
||||
pinMode(_sensePin, INPUT);
|
||||
|
||||
// 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);
|
||||
digitalWrite(_keyPin, HIGH); // request HC-05 module to enter command mode
|
||||
|
||||
openSerial(9600); // virtual function, may call derived class method here
|
||||
|
||||
DebugPort.println("\r\n\r\nAttempting to detect HC-05 Bluetooth module...");
|
||||
|
||||
|
@ -45,113 +39,136 @@ void Bluetooth_Init()
|
|||
DebugPort.print(" @ ");
|
||||
DebugPort.print(BTRates[BTidx]);
|
||||
DebugPort.print(" baud... ");
|
||||
Bluetooth.end();
|
||||
Bluetooth.begin(BTRates[BTidx]); // open serial port at a certain baud rate
|
||||
Bluetooth.print("\r\n");
|
||||
Bluetooth.setTimeout(50);
|
||||
openSerial(BTRates[BTidx]); // open serial port at a std.baud rate
|
||||
delay(10);
|
||||
HC05_SerialPort.print("\r\n"); // clear the throat!
|
||||
delay(100);
|
||||
HC05_SerialPort.setTimeout(100);
|
||||
|
||||
if(Bluetooth_ATCommand("AT\r\n")) {
|
||||
if(ATCommand("AT\r\n")) { // probe with a simple "AT"
|
||||
DebugPort.println(" OK."); // got a response - woo hoo found the module!
|
||||
break;
|
||||
}
|
||||
if(ATCommand("AT\r\n")) { // sometimes a second try is good...
|
||||
DebugPort.println(" OK.");
|
||||
break;
|
||||
}
|
||||
|
||||
// failed, try another baud rate
|
||||
DebugPort.println("");
|
||||
Bluetooth.flush();
|
||||
HC05_SerialPort.flush();
|
||||
HC05_SerialPort.end();
|
||||
delay(100);
|
||||
}
|
||||
|
||||
DebugPort.println("");
|
||||
if(BTidx == maxTries) {
|
||||
DebugPort.println("FAILED to detect HC-05 Bluetooth module :-(");
|
||||
// we could not get anywhere with the AT commands, but maybe this is the other module
|
||||
// plough on and assume 9600 baud, but at the mercy of whatever the module name is...
|
||||
DebugPort.println("FAILED to detect a HC-05 Bluetooth module :-(");
|
||||
// leave the EN pin high - if other style module keeps it powered!
|
||||
// assume it is 9600, and just (try to) use it like that...
|
||||
// we will sense the STATE line to prove a client is hanging off the link...
|
||||
DebugPort.println("ASSUMING a HC-05 module @ 9600baud (Unknown name)");
|
||||
openSerial(9600);
|
||||
}
|
||||
else {
|
||||
if(BTRates[BTidx] == 115200) {
|
||||
DebugPort.println("HC-05 found and already set to 115200 baud, skipping Init.");
|
||||
bHC05Available = true;
|
||||
// found a HC-05 module at one of its supported baud rates.
|
||||
// now program it's name and force a 9600 baud data interface.
|
||||
// this is the defacto standard as shipped!
|
||||
|
||||
DebugPort.println("HC-05 found");
|
||||
|
||||
DebugPort.print(" Setting Name to \"Diesel Heater\"... ");
|
||||
if(!ATCommand("AT+NAME=\"Diesel Heater\"\r\n")) {
|
||||
DebugPort.println("FAILED");
|
||||
}
|
||||
else {
|
||||
do {
|
||||
DebugPort.println("HC-05 found");
|
||||
|
||||
DebugPort.print(" Setting Name to \"DieselHeater\"... ");
|
||||
if(!Bluetooth_ATCommand("AT+NAME=\"DieselHeater\"\r\n")) {
|
||||
DebugPort.println("FAILED");
|
||||
break;
|
||||
}
|
||||
DebugPort.println("OK");
|
||||
|
||||
DebugPort.print(" Setting baud rate to 115200N81...");
|
||||
if(!Bluetooth_ATCommand("AT+UART=115200,1,0\r\n")) {
|
||||
DebugPort.println("FAILED");
|
||||
break;
|
||||
};
|
||||
DebugPort.println("OK");
|
||||
|
||||
Bluetooth.end();
|
||||
Bluetooth.begin(115200);
|
||||
bHC05Available = true;
|
||||
|
||||
} while(0);
|
||||
|
||||
DebugPort.println("OK");
|
||||
}
|
||||
|
||||
DebugPort.print(" Setting baud rate to 9600N81...");
|
||||
if(!ATCommand("AT+UART=9600,1,0\r\n")) {
|
||||
DebugPort.println("FAILED");
|
||||
}
|
||||
else {
|
||||
DebugPort.println("OK");
|
||||
}
|
||||
|
||||
openSerial(9600);
|
||||
|
||||
// leave HC-05 command mode, return to data mode
|
||||
digitalWrite(_keyPin, LOW);
|
||||
}
|
||||
digitalWrite(KeyPin, LOW); // leave HC-05 command mode
|
||||
|
||||
delay(500);
|
||||
|
||||
if(!bHC05Available)
|
||||
Bluetooth.end(); // close serial port if no module found
|
||||
delay(50);
|
||||
|
||||
DebugPort.println("");
|
||||
}
|
||||
|
||||
void Bluetooth_Check()
|
||||
{
|
||||
|
||||
void
|
||||
CBluetoothHC05::check()
|
||||
{
|
||||
// check for data coming back over Bluetooth
|
||||
if(bHC05Available) {
|
||||
if(Bluetooth.available()) {
|
||||
char rxVal = Bluetooth.read();
|
||||
if(isControl(rxVal)) { // "End of Line"
|
||||
Command_Interpret(RxLine.Line);
|
||||
RxLine.clear();
|
||||
}
|
||||
else {
|
||||
RxLine.append(rxVal); // append new char to our Rx buffer
|
||||
}
|
||||
}
|
||||
if(HC05_SerialPort.available()) { // serial rx data is available
|
||||
char rxVal = HC05_SerialPort.read();
|
||||
collectRxData(rxVal);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Bluetooth_SendFrame(const char* pHdr, const CProtocol& Frame)
|
||||
void
|
||||
CBluetoothHC05::sendFrame(const char* pHdr, const CProtocol& Frame, bool lineterm)
|
||||
{
|
||||
if(bHC05Available) {
|
||||
// report to debug port
|
||||
CBluetoothAbstract::sendFrame(pHdr, Frame, false);
|
||||
|
||||
if(digitalRead(_sensePin)) {
|
||||
if(Frame.verifyCRC()) {
|
||||
Bluetooth.print(pHdr);
|
||||
Bluetooth.write(Frame.Data, 24);
|
||||
// send data frame to HC-05
|
||||
HC05_SerialPort.print(pHdr);
|
||||
HC05_SerialPort.write(Frame.Data, 24);
|
||||
// toggle LED
|
||||
#ifdef BT_LED
|
||||
digitalWrite(LED, !digitalRead(LED)); // toggle LED
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
DebugPort.print("Bluetooth data not sent, CRC error ");
|
||||
DebugPort.println(pHdr);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(lineterm) { // only report no client if this will be at end of line (long line support)
|
||||
DebugPort.print("No Bluetooth client");
|
||||
}
|
||||
// force LED off
|
||||
#ifdef BT_LED
|
||||
digitalWrite(LED, 0);
|
||||
#endif
|
||||
}
|
||||
if(lineterm)
|
||||
DebugPort.println("");
|
||||
}
|
||||
|
||||
// local function, typically to perform Hayes commands with HC-05
|
||||
bool Bluetooth_ATCommand(const char* cmd)
|
||||
void
|
||||
CBluetoothHC05::openSerial(int baudrate)
|
||||
{
|
||||
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;
|
||||
// standard serial port for Due, Mega (ESP32 uses virtual, derived from this class)
|
||||
HC05_SerialPort.begin(baudrate);
|
||||
}
|
||||
|
||||
// protected function, to perform Hayes commands with HC-05
|
||||
bool
|
||||
CBluetoothHC05::ATCommand(const char* cmd)
|
||||
{
|
||||
HC05_SerialPort.print(cmd);
|
||||
char RxBuffer[16];
|
||||
memset(RxBuffer, 0, 16);
|
||||
int read = HC05_SerialPort.readBytesUntil('\n', RxBuffer, 16); // \n is not included in returned string!
|
||||
if((read == 3) && (0 == strcmp(RxBuffer, "OK\r")) ) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
|
27
Arduino/SenderTrial2/BluetoothHC05.h
Normal file
27
Arduino/SenderTrial2/BluetoothHC05.h
Normal file
|
@ -0,0 +1,27 @@
|
|||
|
||||
#include "BluetoothAbstract.h"
|
||||
|
||||
// Define the serial port for access to a HC-05 module.
|
||||
// This is generally Serial2, but different platforms use
|
||||
// a different class for the implementation.
|
||||
#ifdef __arm__
|
||||
// for Arduino Due
|
||||
static UARTClass& HC05_SerialPort(Serial2);
|
||||
#else
|
||||
// for Mega, ESP32
|
||||
static HardwareSerial& HC05_SerialPort(Serial2);
|
||||
#endif
|
||||
|
||||
// define a derived class that offers bluetooth messaging over the HC-05
|
||||
|
||||
class CBluetoothHC05 : public CBluetoothAbstract {
|
||||
bool ATCommand(const char* str);
|
||||
int _sensePin, _keyPin;
|
||||
public:
|
||||
CBluetoothHC05(int keyPin, int sensePin);
|
||||
void init();
|
||||
void sendFrame(const char* pHdr, const CProtocol& Frame, bool lineterm=true);
|
||||
void check();
|
||||
protected:
|
||||
virtual void openSerial(int baudrate);
|
||||
};
|
|
@ -269,3 +269,15 @@ CProtocol::Init(int FrameMode)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
CProtocol::DebugReport(const char* hdr, const char* ftr)
|
||||
{
|
||||
DebugPort.print(hdr); // header
|
||||
for(int i=0; i<24; i++) {
|
||||
char str[16];
|
||||
sprintf(str, " %02X", Data[i]); // build 2 dig hex values
|
||||
DebugPort.print(str); // and print
|
||||
}
|
||||
DebugPort.print(ftr); // footer
|
||||
}
|
||||
|
||||
|
|
|
@ -164,6 +164,8 @@ public:
|
|||
short getTemperature_HeatExchg(); // temperature of heat exchanger
|
||||
void setTemperature_HeatExchg(short degC); // temperature of heat exchanger
|
||||
|
||||
void DebugReport(const char* hdr, const char* ftr);
|
||||
|
||||
CProtocol& operator=(const CProtocol& rhs);
|
||||
};
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
If Pin 21 is grounded on the Due, this simple stream will be reported over Serial and
|
||||
no control from the Arduino will be allowed.
|
||||
This allows sniffing of the blue wire in a normal system.
|
||||
This allows passive sniffing of the blue wire in a normal system.
|
||||
|
||||
The binary data is received from the line.
|
||||
If it has been > 100ms since the last blue wire activity this indicates a new frame
|
||||
|
@ -27,12 +27,12 @@
|
|||
Capture those bytes and store them in the Heater1 data array.
|
||||
Once again these bytes are then reported over Serial to the PC in ASCII.
|
||||
|
||||
If no activity is sensed in a second, it is assumed no controller is attached and we
|
||||
If no activity is sensed in a second, it is assumed no OEM controller is attached and we
|
||||
have full control over the heater.
|
||||
|
||||
Either way we can now inject a message onto the blue wire allowing our custom
|
||||
on/off control.
|
||||
We must remain synchronous with the OEM controller if it exists otherwise E-07
|
||||
We must remain synchronous with an OEM controller if it exists otherwise E-07
|
||||
faults will be caused.
|
||||
|
||||
Typical data frame timing on the blue wire is then:
|
||||
|
@ -43,19 +43,20 @@
|
|||
But this does rise if new max/min or voltage settings are sent.
|
||||
**The heater only ever sends Rx data in response to a data frame from a controller**
|
||||
|
||||
A HC-05 Bluetooth module is attached to Serial2:
|
||||
For Bluetooth connectivity, a HC-05 Bluetooth module is attached to Serial2:
|
||||
TXD -> Rx2 (pin 17)
|
||||
RXD -> Tx2 (pin 16)
|
||||
EN(key) -> pin 15
|
||||
STATE -> pin 4
|
||||
|
||||
|
||||
This code only works with boards that have more than one hardware serial port like Arduino
|
||||
Mega, Due, Zero etc.
|
||||
Mega, Due, Zero, ESP32 etc.
|
||||
|
||||
|
||||
The circuit:
|
||||
- a Tx Rx multiplexer is required to combine the Arduino's Tx1 And Rx1 pins onto the blue wire.
|
||||
- a Tx Enable signal from pin 20 controls the multiplexer
|
||||
- a Tx Enable signal from pin 22 controls the multiplexer, high for Tx, low for Rx
|
||||
- Serial logging software on Serial0 via USB link
|
||||
|
||||
created 23 Sep 2018 by Ray Jones
|
||||
|
@ -70,18 +71,35 @@
|
|||
#include "debugport.h"
|
||||
#include "SmartError.h"
|
||||
#include "BTCWifi.h"
|
||||
#include "BTCConfig.h"
|
||||
|
||||
#define HOST_NAME "remotedebug-sample"
|
||||
#include "BTCota.h"
|
||||
|
||||
|
||||
|
||||
#define HOST_NAME "BTCHeater"
|
||||
#define TRIGGER_PIN 0
|
||||
|
||||
#define FAILEDSSID "BTCESP32"
|
||||
#define FAILEDPASSWORD "thereisnospoon"
|
||||
|
||||
#define ESP32_USE_BLE_RLJ
|
||||
#include "Bluetooth.h"
|
||||
//comment this out to remove TELNET
|
||||
|
||||
//#define TELNET
|
||||
|
||||
#ifdef TELNET
|
||||
#define DebugPort Debug
|
||||
#endif
|
||||
|
||||
#ifndef TELNET
|
||||
#define DebugPort DebugPort
|
||||
#endif
|
||||
|
||||
#ifdef ESP32
|
||||
#include "BluetoothESP32.h"
|
||||
#else
|
||||
#include "BluetoothHC05.h"
|
||||
#endif
|
||||
|
||||
// Setup Serial Port Definitions
|
||||
#if defined(__arm__)
|
||||
|
@ -106,6 +124,9 @@ class CommStates {
|
|||
m_State = eState;
|
||||
m_Count = 0;
|
||||
}
|
||||
eCS get() {
|
||||
return m_State;
|
||||
}
|
||||
bool is(eCS eState) {
|
||||
return m_State == eState;
|
||||
}
|
||||
|
@ -114,7 +135,7 @@ class CommStates {
|
|||
return m_Count == limit;
|
||||
}
|
||||
private:
|
||||
int m_State;
|
||||
eCS m_State;
|
||||
int m_Count;
|
||||
};
|
||||
|
||||
|
@ -151,13 +172,42 @@ public:
|
|||
|
||||
CommStates CommState;
|
||||
CTxManage TxManage(TxEnbPin, BlueWireSerial);
|
||||
//CProtocol OEMCtrlFrame; // data packet received from heater in response to OEM controller packet
|
||||
//CProtocol HeaterFrame1; // data packet received from heater in response to OEM controller packet
|
||||
CModeratedFrame OEMCtrlFrame; // data packet received from heater in response to OEM controller packet
|
||||
CModeratedFrame HeaterFrame1; // data packet received from heater in response to OEM controller packet
|
||||
CProtocol HeaterFrame2; // data packet received from heater in response to our packet
|
||||
CProtocol DefaultBTCParams(CProtocol::CtrlMode); // defines the default parameters, used in case of no OEM controller
|
||||
CSmartError SmartError;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Bluetooth instantiation
|
||||
//
|
||||
#ifdef ESP32
|
||||
|
||||
// Bluetooth options for ESP32
|
||||
#if USE_HC05_BLUETOOTH == 1
|
||||
CBluetoothESP32HC05 Bluetooth(HC05_KeyPin, HC05_SensePin, Rx2Pin, Tx2Pin); // Instantiate ESP32 using a HC-05
|
||||
#elif USE_BLE_BLUETOOTH == 1
|
||||
CBluetoothESP32BLE Bluetooth; // Instantiate ESP32 BLE server
|
||||
#elif USE_CLASSIC_BLUETOOTH == 1
|
||||
CBluetoothESP32Classic Bluetooth; // Instantiate ESP32 Classic Bluetooth server
|
||||
#else // none selected
|
||||
CBluetoothAbstract Bluetooth; // default no bluetooth support - empty shell
|
||||
#endif
|
||||
|
||||
#else // !ESP32
|
||||
|
||||
// Bluetooth for others
|
||||
#if USE_HC05_BLUETOOTH == 1
|
||||
CBluetoothHC05 Bluetooth(HC05_KeyPin, HC05_SensePin); // Instantiate a HC-05
|
||||
#else // none selected
|
||||
CBluetoothAbstract Bluetooth; // default no bluetooth support - empty shell
|
||||
#endif // closing USE_HC05_BLUETOOTH
|
||||
|
||||
#endif // closing ESP32
|
||||
//
|
||||
// END Bluetooth instantiation
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
long lastRxTime; // used to observe inter character delays
|
||||
bool hasOEMController = false;
|
||||
|
||||
|
@ -170,18 +220,17 @@ CHeaterStorage NVStorage; // dummy, for now
|
|||
#endif
|
||||
CHeaterStorage* pNVStorage = NULL;
|
||||
|
||||
void PrepareTxFrame(const CProtocol& basisFrame, CProtocol& TxFrame, bool isBTCmaster);
|
||||
|
||||
void setup()
|
||||
{
|
||||
initWifi(TRIGGER_PIN, FAILEDSSID, FAILEDPASSWORD);
|
||||
void setup() {
|
||||
// initWifi(TRIGGER_PIN, FAILEDSSID, FAILEDPASSWORD);
|
||||
initWifi(WiFi_TriggerPin, FAILEDSSID, FAILEDPASSWORD);
|
||||
initOTA();
|
||||
pinMode(Tx2Pin, OUTPUT);
|
||||
digitalWrite(Tx2Pin, HIGH);
|
||||
pinMode(Rx2Pin, INPUT_PULLUP);
|
||||
pinMode(ListenOnlyPin, INPUT_PULLUP);
|
||||
pinMode(KeyPin, OUTPUT);
|
||||
digitalWrite(KeyPin, LOW);
|
||||
pinMode(HC05_KeyPin, OUTPUT);
|
||||
digitalWrite(HC05_KeyPin, LOW);
|
||||
|
||||
// initialize serial port to interact with the "blue wire"
|
||||
// 25000 baud, Tx and Rx channels of Chinese heater comms interface:
|
||||
|
@ -214,7 +263,7 @@ void setup()
|
|||
DefaultBTCParams.setFan_Min(1680);
|
||||
DefaultBTCParams.setFan_Max(4500);
|
||||
|
||||
Bluetooth_Init();
|
||||
Bluetooth.init();
|
||||
|
||||
// create pointer to CHeaterStorage
|
||||
// via the magic of polymorphism we can use this to access whatever
|
||||
|
@ -224,11 +273,12 @@ void setup()
|
|||
pNVStorage->load();
|
||||
}
|
||||
|
||||
// main functional loop is based about a state machine approach, waiting for data
|
||||
// to appear upon the blue wire, and marshalling into an appropriate receive buffer
|
||||
// according to the state.
|
||||
|
||||
|
||||
// main functional loop is based about a state machine approach, waiting for data
|
||||
// to appear upon the blue wire, and marshalling into an appropriate receive buffers
|
||||
// according to the state.
|
||||
|
||||
void loop()
|
||||
{
|
||||
unsigned long timenow = millis();
|
||||
|
@ -246,7 +296,7 @@ void loop()
|
|||
}
|
||||
}
|
||||
|
||||
Bluetooth_Check(); // check for Bluetooth activity
|
||||
Bluetooth.check(); // check for Bluetooth activity
|
||||
|
||||
// calc elapsed time since last rxd byte
|
||||
// used to detect no OEM controller, or the start of an OEM frame sequence
|
||||
|
@ -277,6 +327,7 @@ void loop()
|
|||
// Blue wire data reception
|
||||
// Reads data from the "blue wire" Serial port, (to/from heater)
|
||||
// If an OEM controller exists we will also see it's data frames
|
||||
// Note that the data is read now, then held for later use in the state machine
|
||||
//
|
||||
sRxData BlueWireData;
|
||||
|
||||
|
@ -292,128 +343,156 @@ void loop()
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// do our state machine to track the reception and delivery of blue wire data
|
||||
|
||||
// we may need to transit to a OEMCtrlRx if we captured a new byte, so stand alone if here!
|
||||
if( CommState.is(CommStates::Idle)) {
|
||||
switch(CommState.get()) {
|
||||
|
||||
// Detect the possible start of a new frame sequence from an OEM controller
|
||||
// This will be the first activity for considerable period on the blue wire
|
||||
// The heater always responds to a controller frame, but otherwise never by itself
|
||||
if(BlueWireData.available() && (RxTimeElapsed > 100)) {
|
||||
DebugPort.print("Re-sync'd with OEM Controller. ");
|
||||
DebugPort.print(RxTimeElapsed);
|
||||
DebugPort.println("ms Idle time.");
|
||||
hasOEMController = true;
|
||||
CommState.set(CommStates::OEMCtrlRx); // we must add this new byte!
|
||||
}
|
||||
case CommStates::Idle:
|
||||
// Detect the possible start of a new frame sequence from an OEM controller
|
||||
// This will be the first activity for considerable period on the blue wire
|
||||
// The heater always responds to a controller frame, but otherwise never by itself
|
||||
if(RxTimeElapsed >= 970) {
|
||||
// have not seen any receive data for a second.
|
||||
// OEM controller is probably not connected. 6
|
||||
// Skip state machine immediately to BTC_Tx, sending our own settings.
|
||||
hasOEMController = false;
|
||||
bool isBTCmaster = true;
|
||||
TxManage.PrepareFrame(DefaultBTCParams, isBTCmaster); // use our parameters, and mix in NV storage values
|
||||
TxManage.Start(timenow);
|
||||
CommState.set(CommStates::BTC_Tx);
|
||||
break;
|
||||
}
|
||||
|
||||
if(RxTimeElapsed >= 970) {
|
||||
// have not seen any receive data for a second.
|
||||
// OEM controller is probably not connected. 6
|
||||
// Skip state machine immediately to BTC_Tx, sending our own settings.
|
||||
hasOEMController = false;
|
||||
CommState.set(CommStates::BTC_Tx);
|
||||
bool isBTCmaster = true;
|
||||
TxManage.PrepareFrame(DefaultBTCParams, isBTCmaster); // use our parameters, and mix in NV storage values
|
||||
TxManage.Start(timenow);
|
||||
}
|
||||
|
||||
} // CommState::Idle
|
||||
|
||||
if( CommState.is(CommStates::OEMCtrlRx) ) {
|
||||
// collect OEM controller frame
|
||||
if(BlueWireData.available()) {
|
||||
if(CommState.collectData(OEMCtrlFrame, BlueWireData.getValue()) ) {
|
||||
CommState.set(CommStates::OEMCtrlReport); // collected 24 bytes, move on!
|
||||
if(BlueWireData.available() && (RxTimeElapsed > 100)) {
|
||||
#ifdef REPORT_OEM_RESYNC
|
||||
DebugPort.print("Re-sync'd with OEM Controller. ");
|
||||
DebugPort.print(RxTimeElapsed);
|
||||
DebugPort.println("ms Idle time.");
|
||||
#endif
|
||||
hasOEMController = true;
|
||||
CommState.set(CommStates::OEMCtrlRx); // we must add this new byte!
|
||||
//
|
||||
// ** IMPORTANT - we must drop through to OEMCtrlRx *NOW* (skip break) **
|
||||
//
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if( CommState.is(CommStates::OEMCtrlReport) ) {
|
||||
// filled OEM controller frame, report
|
||||
// echo received OEM controller frame over Bluetooth, using [OEM] header
|
||||
if(OEMCtrlFrame.elapsedTime() > 700) {
|
||||
Bluetooth_SendFrame("[OEM]", OEMCtrlFrame, true);
|
||||
OEMCtrlFrame.setTime();
|
||||
}
|
||||
else {
|
||||
DebugPort.println("Suppressed delivery of OEM frame");
|
||||
}
|
||||
CommState.set(CommStates::HeaterRx1);
|
||||
}
|
||||
|
||||
else if( CommState.is(CommStates::HeaterRx1) ) {
|
||||
// collect heater frame, always in response to an OEM controller frame
|
||||
if(BlueWireData.available()) {
|
||||
if( CommState.collectData(HeaterFrame1, BlueWireData.getValue()) ) {
|
||||
CommState.set(CommStates::HeaterReport1);
|
||||
else {
|
||||
break; // only break if we failed all the Idle tests
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if(CommState.is(CommStates::HeaterReport1) ) {
|
||||
// received heater frame (after controller message), report
|
||||
|
||||
case CommStates::OEMCtrlRx:
|
||||
// collect OEM controller frame
|
||||
if(BlueWireData.available()) {
|
||||
if(CommState.collectData(OEMCtrlFrame, BlueWireData.getValue()) ) {
|
||||
CommState.set(CommStates::OEMCtrlReport); // collected 24 bytes, move on!
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case CommStates::OEMCtrlReport:
|
||||
// filled OEM controller frame, report
|
||||
// echo received OEM controller frame over Bluetooth, using [OEM] header
|
||||
// note that Rotary Knob and LED OEM controllers can flood the Bluetooth
|
||||
// handling at the client side, moderate OEM Bluetooth delivery
|
||||
if(OEMCtrlFrame.elapsedTime() > OEM_TO_BLUETOOTH_MODERATION_TIME) {
|
||||
Bluetooth.sendFrame("[OEM]", OEMCtrlFrame, TERMINATE_OEM_LINE);
|
||||
OEMCtrlFrame.setTime();
|
||||
}
|
||||
else {
|
||||
#if REPORT_SUPPRESSED_OEM_DATA_FRAMES != 0
|
||||
DebugPort.println("Suppressed delivery of OEM frame");
|
||||
#endif
|
||||
}
|
||||
CommState.set(CommStates::HeaterRx1);
|
||||
break;
|
||||
|
||||
|
||||
case CommStates::HeaterRx1:
|
||||
// collect heater frame, always in response to an OEM controller frame
|
||||
if(BlueWireData.available()) {
|
||||
if( CommState.collectData(HeaterFrame1, BlueWireData.getValue()) ) {
|
||||
CommState.set(CommStates::HeaterReport1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case CommStates::HeaterReport1:
|
||||
// received heater frame (after controller message), report
|
||||
|
||||
// do some monitoring of the heater state variable
|
||||
// if suspicious transitions, introduce a smart error!
|
||||
SmartError.monitor(HeaterFrame1);
|
||||
// do some monitoring of the heater state variable
|
||||
// if abnormal transitions, introduce a smart error!
|
||||
SmartError.monitor(HeaterFrame1);
|
||||
|
||||
// echo heater reponse data to Bluetooth client
|
||||
if(HeaterFrame1.elapsedTime() > 700) {
|
||||
Bluetooth_SendFrame("[HTR]", HeaterFrame1);
|
||||
HeaterFrame1.setTime();
|
||||
}
|
||||
else {
|
||||
DebugPort.println("Suppressed delivery of OEM heater response frame");
|
||||
}
|
||||
|
||||
if(digitalRead(ListenOnlyPin)) {
|
||||
bool isBTCmaster = false;
|
||||
TxManage.PrepareFrame(OEMCtrlFrame, isBTCmaster); // parrot OEM parameters, but block NV modes
|
||||
TxManage.Start(timenow);
|
||||
CommState.set(CommStates::BTC_Tx);
|
||||
}
|
||||
else {
|
||||
CommState.set(CommStates::Idle); // "Listen Only" input is held low, don't send out Tx
|
||||
}
|
||||
}
|
||||
|
||||
// Handle time interval where we send data to the blue wire
|
||||
else if(CommState.is(CommStates::BTC_Tx)) {
|
||||
lastRxTime = timenow; // *we* are pumping onto blue wire, track this activity!
|
||||
if(TxManage.CheckTx(timenow) ) { // monitor progress of our data delivery
|
||||
CommState.set(CommStates::HeaterRx2); // then await heater repsonse
|
||||
}
|
||||
}
|
||||
|
||||
else if( CommState.is(CommStates::HeaterRx2) ) {
|
||||
// collect heater frame, in response to our control frame
|
||||
if(BlueWireData.available()) {
|
||||
if( CommState.collectData(HeaterFrame2, BlueWireData.getValue()) ) {
|
||||
CommState.set(CommStates::HeaterReport2);
|
||||
// echo heater reponse data to Bluetooth client
|
||||
// note that Rotary Knob and LED OEM controllers can flood the Bluetooth
|
||||
// handling at the client side, moderate OEM Bluetooth delivery
|
||||
if(HeaterFrame1.elapsedTime() > OEM_TO_BLUETOOTH_MODERATION_TIME) {
|
||||
Bluetooth.sendFrame("[HTR]", HeaterFrame1, true);
|
||||
HeaterFrame1.setTime();
|
||||
}
|
||||
else {
|
||||
#if REPORT_SUPPRESSED_OEM_DATA_FRAMES != 0
|
||||
DebugPort.println("Suppressed delivery of OEM heater response frame");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if( CommState.is(CommStates::HeaterReport2) ) {
|
||||
// received heater frame (after our control message), report
|
||||
if(digitalRead(ListenOnlyPin)) {
|
||||
bool isBTCmaster = false;
|
||||
TxManage.PrepareFrame(OEMCtrlFrame, isBTCmaster); // parrot OEM parameters, but block NV modes
|
||||
TxManage.Start(timenow);
|
||||
CommState.set(CommStates::BTC_Tx);
|
||||
}
|
||||
else {
|
||||
CommState.set(CommStates::Idle); // "Listen Only" input is held low, don't send out Tx
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
// do some monitoring of the heater state variable
|
||||
// if suspicious transitions, introduce a smart error!
|
||||
SmartError.monitor(HeaterFrame2);
|
||||
case CommStates::BTC_Tx:
|
||||
// Handle time interval where we send data to the blue wire
|
||||
lastRxTime = timenow; // *we* are pumping onto blue wire, track this activity!
|
||||
if(TxManage.CheckTx(timenow) ) { // monitor progress of our data delivery
|
||||
if(!hasOEMController) {
|
||||
// only convey this frames to Bluetooth when NOT using an OEM controller!
|
||||
Bluetooth.sendFrame("[BTC]", TxManage.getFrame(), TERMINATE_BTC_LINE); // BTC => Bluetooth Controller :-)
|
||||
}
|
||||
CommState.set(CommStates::HeaterRx2); // then await heater repsonse
|
||||
}
|
||||
break;
|
||||
|
||||
delay(5);
|
||||
if(!hasOEMController) {
|
||||
// only convey these frames to Bluetooth when NOT using an OEM controller!
|
||||
Bluetooth_SendFrame("[BTC]", TxManage.getFrame(), true); // BTC => Bluetooth Controller :-)
|
||||
Bluetooth_SendFrame("[HTR]", HeaterFrame2); // pin not grounded, suppress duplicate to BT
|
||||
}
|
||||
CommState.set(CommStates::Idle);
|
||||
|
||||
case CommStates::HeaterRx2:
|
||||
// collect heater frame, in response to our control frame
|
||||
if(BlueWireData.available()) {
|
||||
if( CommState.collectData(HeaterFrame2, BlueWireData.getValue()) ) {
|
||||
CommState.set(CommStates::HeaterReport2);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case CommStates::HeaterReport2:
|
||||
// received heater frame (after our control message), report
|
||||
|
||||
// do some monitoring of the heater state variables
|
||||
// if abnormal transitions, introduce a smart error!
|
||||
SmartError.monitor(HeaterFrame2);
|
||||
|
||||
delay(5);
|
||||
if(!hasOEMController) {
|
||||
// only convey these frames to Bluetooth when NOT using an OEM controller!
|
||||
// Bluetooth.sendFrame("[BTC]", TxManage.getFrame(), TERMINATE_BTC_LINE); // BTC => Bluetooth Controller :-)
|
||||
Bluetooth.sendFrame("[HTR]", HeaterFrame2, true); // pin not grounded, suppress duplicate to BT
|
||||
}
|
||||
CommState.set(CommStates::Idle);
|
||||
|
||||
#ifdef SHOW_HEAP
|
||||
Serial.print("Free heap ");
|
||||
Serial.println(ESP.getFreeHeap());
|
||||
Serial.print("Free heap ");
|
||||
Serial.println(ESP.getFreeHeap());
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
||||
} // switch(CommState)
|
||||
|
||||
} // loop
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#include <Arduino.h>
|
||||
|
||||
class CProtocol;
|
||||
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
const int TxEnbPin = 22;
|
||||
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 HC05_Sense = 4;
|
||||
const int HC05_KeyPin = 15;
|
||||
const int HC05_SensePin = 4;
|
||||
const int WiFi_TriggerPin = 23;
|
||||
|
|
Loading…
Reference in a new issue