1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
/*
* This file is part of the "bluetoothheater" distribution
* (https://gitlab.com/mrjones.id.au/bluetoothheater)
*
* Copyright (C) 2018 Ray Jones <ray@mrjones.id.au>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#include "BluetoothHC05.h"
#include "../cfg/pins.h"
#include "../cfg/BTCConfig.h"
#include "../Protocol/Protocol.h"
#include "../Protocol/helpers.h"
#include "../Utility/DebugPort.h"
// Bluetooth access via HC-05 Module, using a UART
CBluetoothHC05::CBluetoothHC05(int keyPin, int sensePin)
{
// 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
pinMode(_keyPin, OUTPUT);
digitalWrite(_keyPin, LOW); // request HC-05 module to enter data mode
// attach to the SENSE line from the HC-05 module
// this line goes high when a BT client is connected :-)
pinMode(_sensePin, INPUT);
}
void
CBluetoothHC05::begin()
{
const int BTRates[] = {
9600, 38400, 115200, 19200, 57600, 2400, 4800, 1200
};
_rxLine.clear();
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...");
int BTidx = 0;
int maxTries = sizeof(BTRates)/sizeof(int);
for(BTidx = 0; BTidx < maxTries; BTidx++) {
DebugPort.print(" @ ");
DebugPort.print(BTRates[BTidx]);
DebugPort.print(" baud... ");
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(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("");
HC05_SerialPort.flush();
HC05_SerialPort.end();
delay(100);
}
DebugPort.println("");
if(BTidx == maxTries) {
// 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 {
// 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 {
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);
}
delay(50);
DebugPort.println("");
}
void
CBluetoothHC05::check()
{
// check for data coming back over Bluetooth
if(HC05_SerialPort.available()) { // serial rx data is available
char rxVal = HC05_SerialPort.read();
collectRxData(rxVal);
}
}
bool
CBluetoothHC05::isConnected()
{
return digitalRead(_sensePin);
}
void
CBluetoothHC05::send(const char* Str)
{
HC05_SerialPort.print(Str);
}
void
CBluetoothHC05::sendFrame(const char* pHdr, const CProtocol& Frame, bool lineterm)
{
// report to debug port
CBluetoothAbstract::sendFrame(pHdr, Frame, false);
if(isConnected()) {
if(Frame.verifyCRC()) {
// send data frame to HC-05
HC05_SerialPort.print(pHdr);
HC05_SerialPort.write(Frame.Data, 24);
// toggle LED
#if BT_LED == 1
digitalWrite(LED_Pin, !digitalRead(LED_Pin)); // toggle LED
#endif
}
else {
DebugPort.print("Bluetooth data not sent, CRC error ");
}
}
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
#if BT_LED == 1
digitalWrite(LED_Pin, LOW);
#endif
}
if(lineterm)
DebugPort.println("");
}
void
CBluetoothHC05::openSerial(int baudrate)
{
// 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;
}
void
CBluetoothHC05::foldbackDesiredTemp()
{
StaticJsonBuffer<32> jsonBuffer; // create a JSON buffer on the stack
JsonObject& root = jsonBuffer.createObject(); // create object to add JSON commands to
if(foldbackModerator.addJson("TempDesired", getSetTemp(), root)) {
char opStr[32];
root.printTo(opStr);
send(opStr);
}
}