2020-05-02 19:20:41 -07:00
|
|
|
/**
|
|
|
|
* @file bluetooth.cpp
|
|
|
|
*
|
2020-05-02 23:30:05 -07:00
|
|
|
*
|
|
|
|
* It looks like Bluetooth modules arrive in all kinds of initial configuration.
|
|
|
|
* Sometimes we need to execute a one-time initialization including settings the baud rate. rusEFI setting uartConsoleSerialSpeed or tunerStudioSerialSpeed
|
|
|
|
* has to match BT module configuration.
|
|
|
|
*
|
|
|
|
*
|
2020-05-02 19:20:41 -07:00
|
|
|
* @author andreika, (c) 2017
|
|
|
|
*/
|
|
|
|
|
2021-08-03 19:05:01 -07:00
|
|
|
#include "pch.h"
|
|
|
|
|
2017-06-04 05:52:44 -07:00
|
|
|
#include "tunerstudio.h"
|
|
|
|
|
|
|
|
#include "tunerstudio_io.h"
|
|
|
|
#include "bluetooth.h"
|
|
|
|
|
2022-11-16 15:13:06 -08:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
|
2019-04-12 19:10:57 -07:00
|
|
|
#if EFI_BLUETOOTH_SETUP
|
2017-06-04 05:52:44 -07:00
|
|
|
|
2022-11-16 15:13:06 -08:00
|
|
|
#ifndef EFI_BLUETOOTH_SETUP_DEBUG
|
|
|
|
#define EFI_BLUETOOTH_SETUP_DEBUG FALSE
|
|
|
|
#endif
|
|
|
|
|
2017-06-04 05:52:44 -07:00
|
|
|
static bool btProcessIsStarted = false;
|
|
|
|
|
2022-11-16 15:13:06 -08:00
|
|
|
bluetooth_module_e btModuleType;
|
|
|
|
static int setBaudIdx = -1;
|
|
|
|
static char btName[20 + 1];
|
|
|
|
static char btPinCode[4 + 1];
|
2017-06-04 05:52:44 -07:00
|
|
|
|
2022-03-11 10:06:47 -08:00
|
|
|
// JDY-33 has 9: 128000 which we do not
|
2022-11-16 15:13:06 -08:00
|
|
|
static const unsigned int baudRates[] = { 115200, 9600, 38400, 2400, 4800, 19200, 57600 };
|
|
|
|
static const unsigned int baudRateCodes[] = { 8, 4, 6, 2, 3, 5, 7 };
|
|
|
|
static const int btModuleTimeout = TIME_MS2I(500);
|
2017-06-04 05:52:44 -07:00
|
|
|
|
2021-03-28 06:06:36 -07:00
|
|
|
static SerialTsChannelBase *tsChannel;
|
2017-06-04 05:52:44 -07:00
|
|
|
|
|
|
|
static THD_WORKING_AREA(btThreadStack, UTILITY_THREAD_STACK_SIZE);
|
2019-09-22 05:22:35 -07:00
|
|
|
static thread_t *btThread = nullptr;
|
|
|
|
static thread_reference_t btThreadRef = nullptr; // used by thread suspend/resume as a flag
|
2017-06-04 05:52:44 -07:00
|
|
|
|
2022-11-16 15:13:06 -08:00
|
|
|
static void btWrite(const char *str)
|
|
|
|
{
|
|
|
|
/* Just a wrapper for debug purposes */
|
|
|
|
#if EFI_BLUETOOTH_SETUP_DEBUG
|
|
|
|
efiPrintf("sending %s", str);
|
|
|
|
#endif
|
|
|
|
tsChannel->write((uint8_t *)str, strlen(str));
|
|
|
|
}
|
|
|
|
|
|
|
|
static int btReadLine(char *str, size_t max_len)
|
|
|
|
{
|
|
|
|
size_t len = 0;
|
|
|
|
|
|
|
|
/* read until end of line */
|
|
|
|
do {
|
|
|
|
if (len >= max_len) {
|
|
|
|
efiPrintf("Too long reply from BT");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (tsChannel->readTimeout((uint8_t *)&str[len], 1, btModuleTimeout) != 1) {
|
|
|
|
efiPrintf("Timeout waiting for BT reply");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
} while (str[len++] != '\n');
|
|
|
|
|
|
|
|
/* termination */
|
|
|
|
if (len < max_len)
|
|
|
|
str[len] = 0;
|
|
|
|
else
|
|
|
|
str[max_len - 1] = 0;
|
|
|
|
|
|
|
|
#if EFI_BLUETOOTH_SETUP_DEBUG
|
|
|
|
if (len) {
|
|
|
|
efiPrintf("Received %d %s", len, str);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int btWaitOk(void)
|
|
|
|
{
|
|
|
|
int len;
|
|
|
|
int ret = -1;
|
|
|
|
char tmp[16];
|
|
|
|
|
|
|
|
/* wait for '+OK\r\n' */
|
|
|
|
len = btReadLine(tmp, sizeof(tmp));
|
|
|
|
if (len == 5) {
|
|
|
|
if (strncmp(tmp, "+OK", 3) == 0)
|
|
|
|
ret = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
2017-06-04 05:52:44 -07:00
|
|
|
|
|
|
|
// Main communication code
|
|
|
|
// We assume that the user has disconnected the software before starting the code.
|
|
|
|
static void runCommands() {
|
2022-11-16 15:13:06 -08:00
|
|
|
char tmp[64];
|
|
|
|
size_t baudIdx = 0;
|
|
|
|
bool baudFound = false;
|
2017-06-04 05:52:44 -07:00
|
|
|
|
|
|
|
if (!btProcessIsStarted)
|
|
|
|
return;
|
|
|
|
|
2022-03-10 14:01:25 -08:00
|
|
|
efiPrintf("Sleeping...");
|
2017-11-02 15:10:00 -07:00
|
|
|
chThdSleepMilliseconds(1000); // safety
|
|
|
|
|
2022-11-16 15:13:06 -08:00
|
|
|
// find current baudrate
|
|
|
|
while (baudFound == false) {
|
|
|
|
tsChannel->stop();
|
|
|
|
chThdSleepMilliseconds(10); // safety
|
|
|
|
|
2022-11-16 15:29:50 -08:00
|
|
|
if (chThdShouldTerminateX() || (baudIdx == efi::size(baudRates))) {
|
2022-11-17 08:39:09 -08:00
|
|
|
if (baudIdx == efi::size(baudRates)) {
|
2022-11-16 15:13:06 -08:00
|
|
|
efiPrintf("Failed to find current BT module baudrate");
|
2022-11-17 08:39:09 -08:00
|
|
|
return;
|
|
|
|
}
|
2022-11-16 15:13:06 -08:00
|
|
|
tsChannel->start(engineConfiguration->tunerStudioSerialSpeed);
|
|
|
|
}
|
|
|
|
|
|
|
|
efiPrintf("Restarting at %d", baudRates[baudIdx]);
|
|
|
|
tsChannel->start(baudRates[baudIdx]);
|
|
|
|
chThdSleepMilliseconds(10); // safety
|
|
|
|
|
|
|
|
/* Ping BT module */
|
|
|
|
btWrite("AT\r\n");
|
|
|
|
if (btWaitOk() == 0) {
|
|
|
|
baudFound = true;
|
|
|
|
} else if (btModuleType == BLUETOOTH_JDY_3x) {
|
|
|
|
/* try to diconnect in case device already configured and in silence mode */
|
|
|
|
btWrite("AT+DISC\r\n");
|
|
|
|
if (btWaitOk() == 0) {
|
|
|
|
efiPrintf("JDY33 disconnected");
|
|
|
|
chThdSleepMilliseconds(10); // safety
|
|
|
|
baudFound = true;
|
|
|
|
}
|
2017-06-04 05:52:44 -07:00
|
|
|
}
|
2021-03-28 06:06:36 -07:00
|
|
|
|
2022-11-16 15:13:06 -08:00
|
|
|
/* else try next baudrate */
|
|
|
|
baudIdx++;
|
|
|
|
}
|
2021-03-28 06:06:36 -07:00
|
|
|
|
2022-11-16 15:13:06 -08:00
|
|
|
if (btModuleType == BLUETOOTH_JDY_3x) {
|
|
|
|
#if EFI_BLUETOOTH_SETUP_DEBUG
|
|
|
|
/* Debug, get version, current settings */
|
|
|
|
btWrite("AT+VERSION\r\n");
|
|
|
|
btReadLine(tmp, sizeof(tmp));
|
2020-05-02 23:30:05 -07:00
|
|
|
|
2022-11-16 15:13:06 -08:00
|
|
|
btWrite("AT+BAUD\r\n");
|
|
|
|
btReadLine(tmp, sizeof(tmp));
|
2022-03-10 14:01:25 -08:00
|
|
|
|
2022-11-16 15:13:06 -08:00
|
|
|
btWrite("AT+TYPE\r\n");
|
|
|
|
btReadLine(tmp, sizeof(tmp));
|
2021-03-28 06:06:36 -07:00
|
|
|
|
2022-11-16 15:13:06 -08:00
|
|
|
btWrite("AT+PIN\r\n");
|
|
|
|
btReadLine(tmp, sizeof(tmp));
|
|
|
|
#endif
|
2017-06-04 05:52:44 -07:00
|
|
|
|
2022-11-16 15:13:06 -08:00
|
|
|
/* JDY33 specific settings */
|
|
|
|
/* Reset to defaults */
|
|
|
|
btWrite("AT+DEFAULT\r\n");
|
|
|
|
btWaitOk();
|
2017-06-04 05:52:44 -07:00
|
|
|
|
2022-11-16 15:13:06 -08:00
|
|
|
/* No serial port status output */
|
|
|
|
btWrite("AT+ENLOG0\r\n");
|
|
|
|
btWaitOk();
|
2017-06-04 05:52:44 -07:00
|
|
|
|
2022-11-16 15:13:06 -08:00
|
|
|
/* SPP connection with no password */
|
|
|
|
btWrite("AT+TYPE0\r\n");
|
|
|
|
btWaitOk();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (btModuleType == BLUETOOTH_HC_05)
|
|
|
|
chsnprintf(tmp, sizeof(tmp), "AT+UART=%d,0,0\r\n", baudRates[setBaudIdx]); // baud rate, 0=(1 stop bit), 0=(no parity bits)
|
|
|
|
else
|
|
|
|
chsnprintf(tmp, sizeof(tmp), "AT+BAUD%d\r\n", baudRateCodes[setBaudIdx]);
|
|
|
|
btWrite(tmp);
|
|
|
|
if (btWaitOk() != 0) {
|
|
|
|
goto cmdFailed;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* restart with new baud */
|
|
|
|
tsChannel->stop();
|
|
|
|
chThdSleepMilliseconds(10); // safety
|
|
|
|
tsChannel->start(baudRates[setBaudIdx]);
|
|
|
|
|
|
|
|
chsnprintf(tmp, sizeof(tmp), "AT+NAME=%s\r\n", btName);
|
|
|
|
btWrite(tmp);
|
|
|
|
if (btWaitOk() != 0) {
|
|
|
|
goto cmdFailed;
|
|
|
|
}
|
|
|
|
if (btModuleType == BLUETOOTH_JDY_3x) {
|
|
|
|
/* BLE broadcast name */
|
|
|
|
chsnprintf(tmp, sizeof(tmp), "AT+NAMB=%s\r\n", btName);
|
|
|
|
btWrite(tmp);
|
|
|
|
if (btWaitOk() != 0) {
|
|
|
|
goto cmdFailed;
|
2017-06-04 05:52:44 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-16 15:13:06 -08:00
|
|
|
if (btModuleType == BLUETOOTH_HC_05)
|
|
|
|
chsnprintf(tmp, sizeof(tmp), "AT+PSWD=%s\r\n", btPinCode);
|
|
|
|
else
|
|
|
|
chsnprintf(tmp, sizeof(tmp), "AT+PIN%s\r\n", btPinCode);
|
|
|
|
|
|
|
|
btWrite(tmp);
|
|
|
|
if (btWaitOk() != 0) {
|
|
|
|
goto cmdFailed;
|
2022-03-10 14:01:25 -08:00
|
|
|
}
|
2022-11-16 15:13:06 -08:00
|
|
|
|
|
|
|
if (btModuleType == BLUETOOTH_JDY_3x) {
|
|
|
|
/* Now reset module to apply new settings */
|
|
|
|
btWrite("AT+RESET\r\n");
|
|
|
|
if (btWaitOk() != 0) {
|
|
|
|
efiPrintf("JDY33 fialed to reset");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
efiPrintf("SUCCESS! All commands passed to the Bluetooth module!");
|
|
|
|
return;
|
|
|
|
|
|
|
|
cmdFailed:
|
|
|
|
efiPrintf("FAIL! Command %s failed", tmp);
|
2017-06-04 05:52:44 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static THD_FUNCTION(btThreadEntryPoint, arg) {
|
|
|
|
(void) arg;
|
|
|
|
chRegSetThreadName("bluetooth thread");
|
|
|
|
|
2021-04-19 05:11:59 -07:00
|
|
|
efiPrintf("*** Bluetooth module setup procedure ***");
|
2022-11-16 15:13:06 -08:00
|
|
|
|
|
|
|
/* JDY33 supports disconnect on request */
|
|
|
|
if (btModuleType != BLUETOOTH_JDY_3x) {
|
|
|
|
efiPrintf("!Warning! Please make sure you're not currently using the BT module for communication (not paired)!");
|
|
|
|
efiPrintf("TO START THE PROCEDURE: PLEASE DISCONNECT YOUR PC COM-PORT FROM THE BOARD NOW!");
|
|
|
|
efiPrintf("After that please don't turn off the board power and wait for ~15 seconds to complete. Then reconnect to the board!");
|
|
|
|
}
|
2017-06-04 05:52:44 -07:00
|
|
|
|
|
|
|
// now wait
|
|
|
|
chSysLock();
|
2022-11-16 15:13:06 -08:00
|
|
|
btProcessIsStarted = true;
|
2017-06-04 05:52:44 -07:00
|
|
|
msg_t msg = chThdSuspendTimeoutS(&btThreadRef, BLUETOOTH_COMMAND_TIMEOUT);
|
|
|
|
chSysUnlock();
|
|
|
|
|
|
|
|
if (msg == MSG_TIMEOUT) {
|
2022-10-03 05:51:19 -07:00
|
|
|
// timeout waiting for silence on uart...
|
2021-04-19 05:11:59 -07:00
|
|
|
efiPrintf("The Bluetooth module init procedure is cancelled (timeout)!");
|
2017-06-04 05:52:44 -07:00
|
|
|
} else {
|
|
|
|
// call this when the thread is resumed (after the disconnect)
|
|
|
|
runCommands();
|
|
|
|
}
|
|
|
|
|
|
|
|
// release the command
|
|
|
|
btProcessIsStarted = false;
|
|
|
|
}
|
|
|
|
|
2022-03-10 10:35:24 -08:00
|
|
|
void bluetoothStart(bluetooth_module_e moduleType, const char *baudRate, const char *name, const char *pinCode) {
|
2022-11-16 15:13:06 -08:00
|
|
|
static const char *usage = "Usage: bluetooth_<hc05/hc06/bk/jdy> <baud> <name> <pincode>";
|
2017-06-04 05:52:44 -07:00
|
|
|
|
2022-11-16 15:13:06 -08:00
|
|
|
if ((baudRate == nullptr) || (name == nullptr) || (pinCode == nullptr)) {
|
|
|
|
efiPrintf("%s", usage);
|
|
|
|
return;
|
|
|
|
}
|
2017-06-04 05:52:44 -07:00
|
|
|
|
2022-11-16 15:13:06 -08:00
|
|
|
tsChannel = getBluetoothChannel();
|
2022-09-18 13:15:50 -07:00
|
|
|
if (tsChannel == nullptr) {
|
|
|
|
efiPrintf("No Bluetooth channel configured! Check your board config.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-06-04 05:52:44 -07:00
|
|
|
if (btProcessIsStarted) {
|
2021-04-19 05:11:59 -07:00
|
|
|
efiPrintf("The Bluetooth module init procedure is already started and waiting! To cancel it, run \"bluetooth_cancel\" command!");
|
2017-06-04 05:52:44 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// now check the arguments and add other commands:
|
|
|
|
// 1) baud rate
|
2022-11-16 15:13:06 -08:00
|
|
|
int baud = atoi(baudRate);
|
2017-06-04 05:52:44 -07:00
|
|
|
// find a known baud rate in our list
|
|
|
|
setBaudIdx = -1;
|
2022-11-16 15:29:50 -08:00
|
|
|
for (size_t i = 0; i < efi::size(baudRates); i++) {
|
2017-06-04 05:52:44 -07:00
|
|
|
if (baudRates[i] == baud) {
|
|
|
|
setBaudIdx = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// check the baud rate index
|
2022-11-16 15:13:06 -08:00
|
|
|
if (setBaudIdx < 0) {
|
|
|
|
// unknown baud rate
|
|
|
|
efiPrintf("Wrong <baud> parameter '%s'! %s", baudRate, usage);
|
|
|
|
return;
|
2017-06-04 05:52:44 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// 2) check name
|
2022-11-16 15:13:06 -08:00
|
|
|
if ((strlen(name) < 1) || (strlen(name) > 20)) {
|
2021-04-19 05:11:59 -07:00
|
|
|
efiPrintf("Wrong <name> parameter! Up to 20 characters expected! %s", usage);
|
2017-06-04 05:52:44 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 3) check pin code
|
2022-11-16 15:13:06 -08:00
|
|
|
if (strlen(pinCode) != 4) {
|
2021-04-19 05:11:59 -07:00
|
|
|
efiPrintf("Wrong <pincode> parameter! 4 digits expected! %s", usage);
|
2017-06-04 05:52:44 -07:00
|
|
|
}
|
2022-11-16 15:13:06 -08:00
|
|
|
for (int i = 0; i < 4; i++) {
|
|
|
|
if (!isdigit(pinCode[i])) {
|
|
|
|
efiPrintf("<pincode> should contain digits only %s", usage);
|
|
|
|
}
|
2017-06-04 15:07:02 -07:00
|
|
|
}
|
2022-10-03 05:51:19 -07:00
|
|
|
|
2022-11-16 15:13:06 -08:00
|
|
|
/* copy settings */
|
|
|
|
strncpy(btName, name, 20);
|
|
|
|
strncpy(btPinCode, pinCode, 4);
|
|
|
|
|
|
|
|
btModuleType = moduleType;
|
2022-10-03 05:51:19 -07:00
|
|
|
|
|
|
|
// create a thread to execute these commands after TS disconnected
|
|
|
|
// See bluetoothSoftwareDisconnectNotify
|
|
|
|
btThread = chThdCreateStatic(btThreadStack, sizeof(btThreadStack), PRIO_CONSOLE, (tfunc_t)btThreadEntryPoint, NULL);
|
2017-06-04 05:52:44 -07:00
|
|
|
}
|
2022-10-03 05:51:19 -07:00
|
|
|
|
|
|
|
// Called after 1S of silence on BT UART...
|
2017-06-04 05:52:44 -07:00
|
|
|
void bluetoothSoftwareDisconnectNotify() {
|
|
|
|
if (btProcessIsStarted) {
|
|
|
|
// start communication with the module
|
|
|
|
chThdResume(&btThreadRef, MSG_OK);
|
|
|
|
// wait the thread to finish
|
|
|
|
chThdWait(btThread);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void bluetoothCancel() {
|
|
|
|
if (!btProcessIsStarted) {
|
2021-04-19 05:11:59 -07:00
|
|
|
efiPrintf("The Bluetooth module init procedure was not started! Nothing to cancel!");
|
2017-06-04 05:52:44 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// terminate thread
|
|
|
|
chThdTerminate(btThread);
|
|
|
|
|
|
|
|
btProcessIsStarted = false;
|
2021-04-19 05:11:59 -07:00
|
|
|
efiPrintf("The Bluetooth module init procedure is cancelled!");
|
2017-06-04 05:52:44 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* EFI_BLUETOOTH_SETUP */
|