rusEFI
The most advanced open source ECU
Loading...
Searching...
No Matches
bluetooth.cpp
Go to the documentation of this file.
1/**
2 * @file bluetooth.cpp
3 *
4 *
5 * It looks like Bluetooth modules arrive in all kinds of initial configuration.
6 * Sometimes we need to execute a one-time initialization including settings the baud rate. rusEFI setting uartConsoleSerialSpeed or tunerStudioSerialSpeed
7 * has to match BT module configuration.
8 *
9 *
10 * @author andreika, (c) 2017
11 */
12
13#include "pch.h"
14
15#include "tunerstudio.h"
16
17#include "tunerstudio_io.h"
18#include "bluetooth.h"
19
20#include <stdio.h>
21#include <ctype.h>
22
23#if EFI_BLUETOOTH_SETUP
24
25#ifndef EFI_BLUETOOTH_SETUP_DEBUG
26#define EFI_BLUETOOTH_SETUP_DEBUG TRUE
27#endif
28
29static volatile bool btSetupIsRequested = false;
30
32static int setBaudIdx = -1;
33static char btName[20 + 1];
34static char btPinCode[4 + 1];
35static uint8_t workingBaudIndex;
36
37// JDY-33 has 9: 128000 which we do not
38static const struct {
39 uint32_t rate;
40 uint8_t code;
41} baudRates[] = {
42 //most popular first
43 {115200, 8},
44 {9600, 4},
45 {38400, 6},
46 {2400, 2},
47 {4800, 3},
48 {19200, 5},
49 {57600, 7}
50};
51
52static const int btModuleTimeout = TIME_MS2I(2500);
53
54static void btWrite(TsChannelBase* tsChannel, const char *str)
55{
56 /* Just a wrapper for debug purposes */
57#if EFI_BLUETOOTH_SETUP_DEBUG
58 efiPrintf("sending %s", str);
59#endif
60 tsChannel->write((uint8_t *)str, strlen(str));
61}
62
63static int btReadLine(TsChannelBase* tsChannel, char *str, size_t max_len) {
64 size_t len = 0;
65
66 /* read until end of line */
67 do {
68 if (len >= max_len) {
69 efiPrintf("BT reply is unexpectedly long");
70 return -1;
71 }
72 if (tsChannel->readTimeout((uint8_t *)&str[len], 1, btModuleTimeout) != 1) {
73 efiPrintf("Timeout waiting for BT reply after %d byte(s)", len);
74 return -1;
75 }
76 } while (str[len++] != '\n');
77
78 /* termination */
79 if (len < max_len)
80 str[len] = 0;
81 else
82 str[max_len - 1] = 0;
83
84#if EFI_BLUETOOTH_SETUP_DEBUG
85 if (len) {
86 efiPrintf("Received %d %s", len, str);
87 }
88#endif
89
90 return len;
91}
92
93static int btWaitOk(SerialTsChannelBase* tsChannel) {
94 int len;
95 int ret = -1;
96 char tmp[16];
97
98 /* wait for '+OK\r\n' */
99 len = btReadLine(tsChannel, tmp, sizeof(tmp));
100 if (len == 5) {
101 if (strncmp(tmp, "+OK", 3) == 0)
102 ret = 0;
103 }
104
105 return ret;
106}
107
108static int btBaudOk(SerialTsChannelBase* tsChannel)
109{
110 int len;
111 int ret = -1;
112 char tmp[16];
113
114 /* wait for resposne */
115 len = btReadLine(tsChannel, tmp, sizeof(tmp));
116 if (len == 9) {
117 ret = 0;
118 }
119
120 return ret;
121}
122
123// Main communication code
124// We assume that the user has disconnected the software before starting the code.
125static void runCommands(SerialTsChannelBase* tsChannel) {
126 char tmp[64];
127
128 workingBaudIndex = findBaudIndex(tsChannel);//find it
129 if(workingBaudIndex == 255)//failed
130 return;//problem connecting
131
134#if EFI_BLUETOOTH_SETUP_DEBUG
135 /* Debug, get version, current settings */
136 btWrite(tsChannel, "AT+VERSION\r\n");
137 btReadLine(tsChannel, tmp, sizeof(tmp));
138
139 btWrite(tsChannel, "AT+BAUD\r\n");
140 btReadLine(tsChannel, tmp, sizeof(tmp));
141
143 btWrite(tsChannel, "AT+TYPE\r\n");
144 btReadLine(tsChannel, tmp, sizeof(tmp));
145 }
146
147 btWrite(tsChannel, "AT+PIN\r\n");
148 btReadLine(tsChannel, tmp, sizeof(tmp));
149
150 btWrite(tsChannel, "AT+LADDR\r\n");
151 btReadLine(tsChannel, tmp, sizeof(tmp));
152
154 btWrite(tsChannel, "AT+STAT\r\n");
155 btReadLine(tsChannel, tmp, sizeof(tmp));
156 }
157#endif
158
159 /* JDY33/JDY31 specific settings */
160 /* Reset to defaults */
161 btWrite(tsChannel, "AT+DEFAULT\r\n");
162 btWaitOk(tsChannel);
163
164 /* No serial port status output */
165 btWrite(tsChannel, "AT+ENLOG0\r\n");
166 btWaitOk(tsChannel);
167
169 /* SPP connection with no password */
170 btWrite(tsChannel, "AT+TYPE0\r\n");
171 btWaitOk(tsChannel);
172 }
173 }
174
175 /* restart with a working baud, then change settings */
176 tsChannel->stop();
177 chThdSleepMilliseconds(10); // safety
178
180
182 chsnprintf(tmp, sizeof(tmp), "AT+NAME=%s\r\n", btName);
183 else
184 chsnprintf(tmp, sizeof(tmp), "AT+NAME%s\r\n", btName);
185 btWrite(tsChannel, tmp);
186 if (btWaitOk(tsChannel) != 0) {
187 goto cmdFailed;
188 }
190 /* BLE broadcast name */
191 chsnprintf(tmp, sizeof(tmp), "AT+NAMB%s-BLE\r\n", btName);
192 btWrite(tsChannel, tmp);
193 if (btWaitOk(tsChannel) != 0) {
194 goto cmdFailed;
195 }
196 }
197
199 chsnprintf(tmp, sizeof(tmp), "AT+PSWD=%s\r\n", btPinCode);
200 else
201 chsnprintf(tmp, sizeof(tmp), "AT+PIN%s\r\n", btPinCode);
202
203 btWrite(tsChannel, tmp);
204 if (btWaitOk(tsChannel) != 0) {
205 goto cmdFailed;
206 }
207
209 chsnprintf(tmp, sizeof(tmp), "AT+UART=%d,0,0\r\n", baudRates[setBaudIdx].rate); // baud rate, 0=(1 stop bit), 0=(no parity bits)
210 else
211 chsnprintf(tmp, sizeof(tmp), "AT+BAUD%d\r\n", baudRates[setBaudIdx].code);
212 btWrite(tsChannel, tmp);
213 if (btWaitOk(tsChannel) != 0) {
214 goto cmdFailed;
215 }
216
219 /* Now reset module to apply new settings */
220 btWrite(tsChannel, "AT+RESET\r\n");
221 if (btWaitOk(tsChannel) != 0) {
222 efiPrintf("JDY3x failed to reset");
223 }
224 }
225
226 efiPrintf("SUCCESS! All commands passed to the Bluetooth module!");
227 return;
228
229cmdFailed:
230 efiPrintf("FAIL! Command %s failed", tmp);
231}
232
234 // find current baudrate
235 for(uint8_t baudIdx=0; baudIdx < efi::size(baudRates); baudIdx++) {
236 tsChannel->stop();
237 chThdSleepMilliseconds(10); // safety
238
239 if (baudIdx == efi::size(baudRates)) {
240 efiPrintf("Failed to find current BT module baudrate");
242 return 255;//failed
243 }
244
245 efiPrintf("Restarting at %lu", baudRates[baudIdx].rate);
246 tsChannel->start(baudRates[baudIdx].rate);
247 chThdSleepMilliseconds(10); // safety
248
249 /* Ping BT module */
250 btWrite(tsChannel, "AT\r\n");
251 if (btWaitOk(tsChannel) == 0) {
252 return baudIdx;
253 } else if (btModuleType == BLUETOOTH_JDY_3x) {
254 /* try to disconnect in case device already configured and in silence mode */
255 btWrite(tsChannel, "AT+DISC\r\n");
256 if (btWaitOk(tsChannel) == 0) {
257 efiPrintf("JDY33 disconnected");
258 chThdSleepMilliseconds(10); // safety
259 return baudIdx;
260 }
261 } else if (btModuleType == BLUETOOTH_JDY_31) {
262 /* try to disconnect in case device already configured and in silence mode */
263 btWrite(tsChannel, "AT+BAUD\r\n");
264 if (btBaudOk(tsChannel) == 0) {
265 efiPrintf("JDY31 disconnected");
266 chThdSleepMilliseconds(10); // safety
267 return baudIdx;
268 }
269 }
270 /* try next baudrate */
271 }
272 return 255;//failed
273}
274
275void bluetoothStart(bluetooth_module_e moduleType, const char *baudRate, const char *name, const char *pinCode) {
276 static const char *usage = "Usage: bluetooth_<hc05/hc06/bk/jdy> <baud> <name> <pincode>";
277
278 if ((baudRate == nullptr) || (name == nullptr) || (pinCode == nullptr)) {
279 efiPrintf("%s", usage);
280 return;
281 }
282
283 if (getBluetoothChannel() == nullptr) {
284 efiPrintf("This firmware does not support bluetooth [%s]", getTsSignature());
285 return;
286 }
287
288 if (btSetupIsRequested) {
289 efiPrintf("The Bluetooth module init procedure is already started!");
290 return;
291 }
292
293 // now check the arguments and add other commands:
294 // 1) baud rate
295 int baud = atoi(baudRate);
296 // find a known baud rate in our list
297 setBaudIdx = -1;
298 for (size_t i = 0; i < efi::size(baudRates); i++) {
299 if ((int)baudRates[i].rate == baud) {
300 setBaudIdx = i;
301 break;
302 }
303 }
304 // check the baud rate index
305 if (setBaudIdx < 0) {
306 // unknown baud rate
307 efiPrintf("Wrong <baud> parameter '%s'! %s", baudRate, usage);
308 return;
309 }
310
311 // 2) check name
312 if ((strlen(name) < 1) || (strlen(name) > 20)) {
313 efiPrintf("Wrong <name> parameter! Up to 20 characters expected! %s", usage);
314 return;
315 }
316
317 // 3) check pin code
318 if (strlen(pinCode) != 4) {
319 efiPrintf("Wrong <pincode> parameter! 4 digits expected! %s", usage);
320 return;
321 }
322 for (int i = 0; i < 4; i++) {
323 if (!isdigit(pinCode[i])) {
324 efiPrintf("<pincode> should contain digits only %s", usage);
325 return;
326 }
327 }
328
329 /* copy settings */
330 strncpy(btName, name, 20);
331 strncpy(btPinCode, pinCode, 4);
332
333 btModuleType = moduleType;
334 btSetupIsRequested = true;
335}
336
337// Called after 1S of silence on BT UART...
339 if (btSetupIsRequested) {
340 efiPrintf("*** Bluetooth module setup procedure ***");
341
342 /* JDY33 & JDY31 supports disconnect on request */
345 efiPrintf("!Warning! Please make sure you're not currently using the BT module for communication (not paired)!");
346 efiPrintf("TO START THE PROCEDURE: PLEASE DISCONNECT YOUR PC COM-PORT FROM THE BOARD NOW!");
347 efiPrintf("After that please don't turn off the board power and wait for ~15 seconds to complete. Then reconnect to the board!");
348 }
349
350 uint8_t tmp[1];
351 if (tsChannel->readTimeout(tmp, 1, BLUETOOTH_SILENT_TIMEOUT) != 0) {
352 efiPrintf("The Bluetooth module init procedure is cancelled (wait for silent timeout)!");
353 btSetupIsRequested = false;
354 return;
355 }
356
357 runCommands(tsChannel);
358 btSetupIsRequested = false;
359 }
360}
361
362#endif /* EFI_BLUETOOTH_SETUP */
static volatile bool btSetupIsRequested
Definition bluetooth.cpp:29
static int btWaitOk(SerialTsChannelBase *tsChannel)
Definition bluetooth.cpp:93
static const int btModuleTimeout
Definition bluetooth.cpp:52
void bluetoothSoftwareDisconnectNotify(SerialTsChannelBase *tsChannel)
uint8_t findBaudIndex(SerialTsChannelBase *tsChannel)
static void btWrite(TsChannelBase *tsChannel, const char *str)
Definition bluetooth.cpp:54
static const struct @5 baudRates[]
uint32_t rate
Definition bluetooth.cpp:39
static int setBaudIdx
Definition bluetooth.cpp:32
static int btBaudOk(SerialTsChannelBase *tsChannel)
static uint8_t workingBaudIndex
Definition bluetooth.cpp:35
uint8_t code
Definition bluetooth.cpp:40
void bluetoothStart(bluetooth_module_e moduleType, const char *baudRate, const char *name, const char *pinCode)
static int btReadLine(TsChannelBase *tsChannel, char *str, size_t max_len)
Definition bluetooth.cpp:63
static void runCommands(SerialTsChannelBase *tsChannel)
static char btName[20+1]
Definition bluetooth.cpp:33
static char btPinCode[4+1]
Definition bluetooth.cpp:34
bluetooth_module_e btModuleType
Definition bluetooth.cpp:31
bluetooth_module_e
Definition bluetooth.h:21
@ BLUETOOTH_HC_05
Definition bluetooth.h:22
@ BLUETOOTH_JDY_3x
Definition bluetooth.h:29
@ BLUETOOTH_JDY_31
Definition bluetooth.h:30
virtual void start(uint32_t baud)=0
virtual void stop()
virtual void write(const uint8_t *buffer, size_t size, bool isEndOfPacket=false)=0
virtual size_t readTimeout(uint8_t *buffer, size_t size, int timeout)=0
static constexpr engine_configuration_s * engineConfiguration
const char * getTsSignature()
Definition signature.cpp:31
SerialTsChannelBase * getBluetoothChannel()