-
Notifications
You must be signed in to change notification settings - Fork 11
/
Copy pathBluetooth.ino
381 lines (294 loc) · 11.7 KB
/
Bluetooth.ino
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
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
/*
NANODE SMA PV MONITOR
Latest version found at https://github.com/stuartpittaway/nanodesmapvmonitor
Attribution-NonCommercial-ShareAlike 3.0 Unported (CC BY-NC-SA 3.0)
http://creativecommons.org/licenses/by-nc-sa/3.0/
You are free:
to Share — to copy, distribute and transmit the work
to Remix — to adapt the work
Under the following conditions:
Attribution — You must attribute the work in the manner specified by the author or licensor (but not in any way that suggests that they endorse you or your use of the work).
Noncommercial — You may not use this work for commercial purposes.
Share Alike — If you alter, transform, or build upon this work, you may distribute the resulting work only under the same or similar license to this one.
All code is copyright Stuart Pittaway, (c)2012.
*/
#include <SoftwareSerial.h>
#include <EEPROM.h>
SoftwareSerial blueToothSerial(RxD,TxD);
void BTStart() {
if (!readArrayFromEEPROM(myBTAddress,6,ADDRESS_MY_BTADDRESS) || !readArrayFromEEPROM(smaBTInverterAddressArray,6,ADDRESS_SMAINVERTER_BTADDRESS))
{
debugMsgln("Fail pair");
BTInitStartup(true);
}
else BTInitStartup(false);
//Start normal connection to BT chip, it will auto-connect as master to the SMA inverter (slave)
blueToothSerial.begin(9600);
debugMsgln("BT Rdy"); //Bluetooth ready
}
void sendPacket(unsigned char *btbuffer) {
quickblink();
for(int i=0;i<packetposition;i++) {
blueToothSerial.write(btbuffer[i]);
}
}
void quickblink() {
digitalWrite( RED_LED, LOW);
delay(30);
digitalWrite( RED_LED, HIGH);
}
void BTInitStartup(bool ForcePair) {
BTSwitchOff();
pinMode(INVERTERSCAN_PIN, INPUT);
delay(250);
//Check if pin/button is pressed during power on - if so begin SMA Inverter bluetooth pairing/scanning
if (digitalRead(INVERTERSCAN_PIN)==1 || ForcePair) {
BTScanForSMAInverterToPairWith();
}
BTSwitchOn();
}
void BTSwitchOn() {
analogWrite(BLUETOOTH_POWER_PIN, 255); //Ensure BT chip is on
delay(1800); //Give chip time to warm up and enter command mode
}
void BTSwitchOff() {
analogWrite(BLUETOOTH_POWER_PIN, 0); //Ensure Bluetooth chip is powered off
pinMode(BT_KEY, OUTPUT);
digitalWrite(BT_KEY, LOW); // Turn off command mode
}
void BTScanForSMAInverterToPairWith()
{
//Bluetooth configuration and scanning/pairing for HC05 chip
//These sequence of instructions have taken a VERY long time to work out!
//This code switches on the BT HC05 chip, forces it into command mode by holding
//pin BT_KEY high during power up (serial=38400,8,n,1)
//More information on AT command set for HC05 from
//http://elecfreaks.com/store/download/datasheet/Bluetooth/HC-0305%20serail%20module%20AT%20commamd%20set%20201104%20revised.pdf
char retstring[50];
char comparebuff[15];
char smabtinverteraddress[14];
unsigned char tempaddress[6]; //BT address
debugMsgln("Config BT");
digitalWrite(BT_KEY, HIGH); // Turn BT chip into command mode (HC05)
delay(200);
BTSwitchOn();
blueToothSerial.begin(38400);
//Before tidy 8416 bytes, 8282, 8390
//Send AT wake up
BTSendStringAndWait(retstring,F("AT"));
//Firmware Version = +VERSION=2.0-20100601
BTSendStringAndWait(retstring,F("AT+VERSION?"));
//Factory reset to defaults
BTSendStringAndWait(retstring,F("AT+ORGL"));
//Name of chip
BTSendStringAndWait(retstring,F("AT+NAME=SMA_SOLAR"));
//Set password to zeros
BTSendStringAndWait(retstring,F("AT+PSWD=0000"));
//MASTER mode
BTSendStringAndWait(retstring,F("AT+ROLE=1"));
//Forget existing pairing
BTSendStringAndWait(retstring,F("AT+RMAAD"));
//Sets speed to 9600 bits for normal operation (effective after reset of chip)
BTSendStringAndWait(retstring,F("AT+UART=9600,0,0"));
//Allow connection to any slave
BTSendStringAndWait(retstring,F("AT+CMODE=1"));
//Initialize the SPP profile lib
BTSendStringAndWait(retstring,F("AT+INIT"));
//Make sure were are in INITIALIZED mode
strcpy_P(comparebuff, (const prog_char *)F("INITIALIZED"));
do {
BTSendStringAndWait(retstring,F("AT+STATE?"));
}
while (strncmp(retstring+7,comparebuff,11)!=0);
//The following automatically scans for the SMA inverter and then pairs with it.
//Limit results to SMA inverter bluetooth class/filters
BTSendStringAndWait(retstring,F("AT+IAC=9e8b33"));
//1F04 = Class of device (SMA Inverter)
BTSendStringAndWait(retstring,F("AT+CLASS=1F04"));
//Just find first device which answers our call within 20 seconds
BTSendStringAndWait(retstring,F("AT+INQM=1,1,20"));
//Start the INQUIRE process
BTSendStringAndWait(retstring,F("AT+INQ"));
//Process the BT address returned an replace characters...
char *comma=strchr(retstring,',');
strncpy(smabtinverteraddress,retstring+5,(comma-retstring)-5);
smabtinverteraddress[(comma-retstring)-5]='\0'; //Add null string terminator
//Change : for , characters
for(int i=0; i<strlen(smabtinverteraddress); i++) {
if (smabtinverteraddress[i]==':') smabtinverteraddress[i]=',';
}
//Serial.print(F("SMA BT="));Serial.println(smabtinverteraddress);
//RNAME = get remote bluetooth name, usually looks like "+RNAME:SMA001d SN: 1234567890 SN123456"
BTSendStringAndWait(retstring,smabtinverteraddress,F("AT+RNAME?"));
//PAIR device
blueToothSerial.print(F("AT+PAIR="));
blueToothSerial.print(smabtinverteraddress);
blueToothSerial.println(F(",20"));
waitBlueToothReply(retstring);
//FSAD = Seek the authenticated device in the Bluetooth pair list
BTSendStringAndWait(retstring,smabtinverteraddress,F("AT+FSAD="));
//Ask BT chip for its address
BTSendStringAndWait(retstring,F("AT+ADDR?"));
//Convert BT Address into a more useful byte array, the BT address is in a really awful format to parse!
convertBTADDRStringToArray(retstring+6,tempaddress,':');
writeArrayIntoEEPROM(tempaddress,6,ADDRESS_MY_BTADDRESS); //EEPROM address 0 contains our bluetooth chip address
//Ask BT chip what its set to pair with
BTSendStringAndWait(retstring,F("AT+MRAD?"));
//Convert BT Address into a more useful byte array, the BT address is in a really awful format to parse!
convertBTADDRStringToArray(retstring+6,tempaddress,':');
writeArrayIntoEEPROM(tempaddress,6,ADDRESS_SMAINVERTER_BTADDRESS); //EEPROM address 10 contains SMA inverter address
//BIND = Set/Inquire - bind Bluetooth address
BTSendStringAndWait(retstring,smabtinverteraddress,F("AT+BIND="));
//Connect the module to the specified Bluetooth address. (Bluetooth address can be specified by the binding command)
BTSendStringAndWait(retstring,F("AT+CMODE=0"));
//Make sure were PAIRED and then connect...
strcpy_P(comparebuff, (const prog_char *)F("PAIRED"));
do {
BTSendStringAndWait(retstring,F("AT+STATE?"));
}
while (strncmp(retstring+7,comparebuff,6)!=0);
BTSendStringAndWait(retstring,F("AT+RESET"));
blueToothSerial.end();
delay(100);
digitalWrite(BT_KEY, LOW); // Turn off command mode
delay(500);
//debugMsgln("Bluetooth configure. Finished.");
}
void writeArrayIntoEEPROM(unsigned char readbuffer[],int length,int EEPROMoffset) {
//Writes an array into EEPROM and calculates a simple XOR checksum
byte checksum=0;
for(int i=0;i<length; i++) {
EEPROM.write(EEPROMoffset+i,readbuffer[i]);
//Serial.print(EEPROMoffset+i); Serial.print("="); Serial.println(readbuffer[i],HEX);
checksum^= readbuffer[i];
}
//Serial.print(EEPROMoffset+length); Serial.print("="); Serial.println(checksum,HEX);
EEPROM.write(EEPROMoffset+length,checksum);
}
bool readArrayFromEEPROM(unsigned char readbuffer[],int length,int EEPROMoffset) {
//Writes an array into EEPROM and calculates a simple XOR checksum
byte checksum=0;
for(int i=0;i<length; i++) {
readbuffer[i]=EEPROM.read(EEPROMoffset+i);
//Serial.print(EEPROMoffset+i); Serial.print("="); Serial.println(readbuffer[i],HEX);
checksum^= readbuffer[i];
}
//Serial.print(EEPROMoffset+length); Serial.print("="); Serial.println(checksum,HEX);
return (checksum==EEPROM.read(EEPROMoffset+length));
}
void BTSendStringAndWait(char retstring[], const __FlashStringHelper* str) {
Serial.println(str);
blueToothSerial.println(str);
waitBlueToothReply(retstring);
}
void BTSendStringAndWait(char retstring[], char smabtinverteraddress[14], const __FlashStringHelper* str) {
Serial.print(str);
Serial.println(smabtinverteraddress);
blueToothSerial.print(str);
blueToothSerial.println(smabtinverteraddress);
waitBlueToothReply(retstring);
}
void waitBlueToothReply(char outbuf[]) {
//Wait max 10 lines of input before error
unsigned int errorloop=10;
char btb[50];
outbuf[0]=0;
delay(15);
do {
int bp=0;
do {
btb[bp]=getByte();
Serial.print(btb[bp]);
bp++;
if (btb[bp-1]=='\n') break; //New line
}
while ((btb[bp-1]!='\n') && (bp<50));
btb[bp]=0; //Force end of string
if (btb[0]=='+') {
strncpy (outbuf,btb,bp-2);
outbuf[bp-2]='\0';
}
if ((strncmp(btb,"ERROR",5)==0) || (strncmp(btb,"FAIL",4)==0) ) {
Serial.print(btb);
error();
}
errorloop--;
if (errorloop==0) error();
}
while (strncmp(btb,"OK\r\n",4)!=0);
}
unsigned char getByte() {
//Return a single byte from the bluetooth stream (with error timeout/reset)
unsigned long time;
//This will eventually loop back to zero (about 70 days I think) but we
//would have to be very unlucky to hit that exact event!
//Max wait 60 seconds, before throwing an fatal error
time = 60000+millis();
if (blueToothSerial.overflow()) {
debugMsgln("Overflw");
}
while (blueToothSerial.available()==false) {
delay(5); //Wait for BT byte to arrive
if (millis() > time) {
debugMsgln("Timeout");
error();
}
}
return (unsigned char)blueToothSerial.read();
}
void convertBTADDRStringToArray(char *tempbuf,unsigned char *outarray, char match) {
//Convert BT Address into a more useful byte array, the BT address is in a really awful format to parse!
//Must be a better way of doing this function!
//Unit test cases...
//Test BT address strcpy(tempbuf,"1234:56:0\x0");
//Test BT address strcpy(tempbuf,"1010:7:310068\x0");
//Test BT address strcpy(tempbuf,"80:25:1dac53\x0");
//Test BT address strcpy(tempbuf,"2:72:D2224\x0");
//Test BT address strcpy(tempbuf,"1234:56:0\x0");
//Test BT address strcpy(tempbuf,"1:72:D2224\x0");
//Test BT address strcpy(tempbuf,"1234:56:0\x0");
//Test BT address strcpy(tempbuf,"1234,56,abcdef\x0");
//Test BT address strcpy(tempbuf,"0002,72,0d2224\x0");
int l=strlen(tempbuf);
char *firstcolon=strchr(tempbuf,match)+1;
char *lastcolon=strrchr(tempbuf,match)+1;
//Could use a shared buffer here to save RAM
char output[13]={
'0','0','0','0','0','0','0','0','0','0','0','0',0 };
//Deliberately avoided sprintf as it adds over 1600bytes to the program size at compile time.
int partlen=(firstcolon-tempbuf)-1;
strncpy(output+(4-partlen),tempbuf,partlen);
partlen=(lastcolon-firstcolon)-1;
strncpy(output+4+(2-partlen),firstcolon,partlen);
partlen=l-(lastcolon-tempbuf);
strncpy(output+6+(6-partlen),lastcolon,partlen);
//Finally convert the string (11AABB44FF66) into a real byte array
//written backwards in the same format that the SMA packets expect it in
int i2=5;
for(int i=0; i<12; i+=2){
outarray[i2--]=hex2bin(&output[i]);
}
/*
Serial.print("BT StringToArray=");
for(int i=0; i<6; i+=1) debugPrintHexByte(outarray[i]);
Serial.println("");
*/
}
int hex2bin( const char *s )
{
int ret=0;
int i;
for( i=0; i<2; i++ )
{
char c = *s++;
int n=0;
if( '0'<=c && c<='9' )
n = c-'0';
else if( 'a'<=c && c<='f' )
n = 10 + c-'a';
else if( 'A'<=c && c<='F' )
n = 10 + c-'A';
ret = n + ret*16;
}
return ret;
}