rusefi/firmware/console/binary/bluetooth.cpp

328 lines
8.1 KiB
C++

/**
* @file bluetooth.cpp
*
*
* 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.
*
*
* @author andreika, (c) 2017
*/
#include "pch.h"
#include "tunerstudio.h"
#include "tunerstudio_io.h"
#include "bluetooth.h"
#include <stdio.h>
#include <ctype.h>
#if EFI_BLUETOOTH_SETUP
#ifndef EFI_BLUETOOTH_SETUP_DEBUG
#define EFI_BLUETOOTH_SETUP_DEBUG TRUE
#endif
static volatile bool btSetupIsRequested = false;
bluetooth_module_e btModuleType;
static int setBaudIdx = -1;
static char btName[20 + 1];
static char btPinCode[4 + 1];
// JDY-33 has 9: 128000 which we do not
static const struct {
uint32_t rate;
uint8_t code;
} baudRates[] = {
//most popular first
{115200, 8},
{9600, 4},
{38400, 6},
{2400, 2},
{4800, 3},
{19200, 5},
{57600, 7}
};
static const int btModuleTimeout = TIME_MS2I(500);
static void btWrite(TsChannelBase* tsChannel, 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(TsChannelBase* tsChannel, 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(SerialTsChannelBase* tsChannel)
{
int len;
int ret = -1;
char tmp[16];
/* wait for '+OK\r\n' */
len = btReadLine(tsChannel, tmp, sizeof(tmp));
if (len == 5) {
if (strncmp(tmp, "+OK", 3) == 0)
ret = 0;
}
return ret;
}
// Main communication code
// We assume that the user has disconnected the software before starting the code.
static void runCommands(SerialTsChannelBase* tsChannel) {
char tmp[64];
size_t baudIdx = 0;
bool baudFound = false;
// find current baudrate
while (baudFound == false) {
tsChannel->stop();
chThdSleepMilliseconds(10); // safety
if (baudIdx == efi::size(baudRates)) {
efiPrintf("Failed to find current BT module baudrate");
tsChannel->start(engineConfiguration->tunerStudioSerialSpeed);
return;
}
efiPrintf("Restarting at %d", baudRates[baudIdx].rate);
tsChannel->start(baudRates[baudIdx].rate);
chThdSleepMilliseconds(10); // safety
/* Ping BT module */
btWrite(tsChannel, "AT\r\n");
if (btWaitOk(tsChannel) == 0) {
baudFound = true;
} else if (btModuleType == BLUETOOTH_JDY_3x) {
/* try to diconnect in case device already configured and in silence mode */
btWrite(tsChannel, "AT+DISC\r\n");
if (btWaitOk(tsChannel) == 0) {
efiPrintf("JDY33 disconnected");
chThdSleepMilliseconds(10); // safety
baudFound = true;
}
}
/* else try next baudrate */
baudIdx++;
}
if (btModuleType == BLUETOOTH_JDY_3x) {
#if EFI_BLUETOOTH_SETUP_DEBUG
/* Debug, get version, current settings */
btWrite(tsChannel, "AT+VERSION\r\n");
btReadLine(tsChannel, tmp, sizeof(tmp));
btWrite(tsChannel, "AT+BAUD\r\n");
btReadLine(tsChannel, tmp, sizeof(tmp));
btWrite(tsChannel, "AT+TYPE\r\n");
btReadLine(tsChannel, tmp, sizeof(tmp));
btWrite(tsChannel, "AT+PIN\r\n");
btReadLine(tsChannel, tmp, sizeof(tmp));
btWrite(tsChannel, "AT+LADDR\r\n");
btReadLine(tsChannel, tmp, sizeof(tmp));
btWrite(tsChannel, "AT+STAT\r\n");
btReadLine(tsChannel, tmp, sizeof(tmp));
#endif
/* JDY33 specific settings */
/* Reset to defaults */
btWrite(tsChannel, "AT+DEFAULT\r\n");
btWaitOk(tsChannel);
/* No serial port status output */
btWrite(tsChannel, "AT+ENLOG0\r\n");
btWaitOk(tsChannel);
/* SPP connection with no password */
btWrite(tsChannel, "AT+TYPE0\r\n");
btWaitOk(tsChannel);
}
if (btModuleType == BLUETOOTH_HC_05)
chsnprintf(tmp, sizeof(tmp), "AT+UART=%d,0,0\r\n", baudRates[setBaudIdx].rate); // baud rate, 0=(1 stop bit), 0=(no parity bits)
else
chsnprintf(tmp, sizeof(tmp), "AT+BAUD%d\r\n", baudRates[setBaudIdx].code);
btWrite(tsChannel, tmp);
if (btWaitOk(tsChannel) != 0) {
goto cmdFailed;
}
/* restart with new baud */
tsChannel->stop();
chThdSleepMilliseconds(10); // safety
tsChannel->start(baudRates[setBaudIdx].rate);
if (btModuleType == BLUETOOTH_HC_05)
chsnprintf(tmp, sizeof(tmp), "AT+NAME=%s\r\n", btName);
else
chsnprintf(tmp, sizeof(tmp), "AT+NAME%s\r\n", btName);
btWrite(tsChannel, tmp);
if (btWaitOk(tsChannel) != 0) {
goto cmdFailed;
}
if (btModuleType == BLUETOOTH_JDY_3x) {
/* BLE broadcast name */
chsnprintf(tmp, sizeof(tmp), "AT+NAMB%s-BLE\r\n", btName);
btWrite(tsChannel, tmp);
if (btWaitOk(tsChannel) != 0) {
goto cmdFailed;
}
}
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(tsChannel, tmp);
if (btWaitOk(tsChannel) != 0) {
goto cmdFailed;
}
if (btModuleType == BLUETOOTH_JDY_3x) {
/* Now reset module to apply new settings */
btWrite(tsChannel, "AT+RESET\r\n");
if (btWaitOk(tsChannel) != 0) {
efiPrintf("JDY33 fialed to reset");
}
}
efiPrintf("SUCCESS! All commands passed to the Bluetooth module!");
return;
cmdFailed:
efiPrintf("FAIL! Command %s failed", tmp);
}
void bluetoothStart(bluetooth_module_e moduleType, const char *baudRate, const char *name, const char *pinCode) {
static const char *usage = "Usage: bluetooth_<hc05/hc06/bk/jdy> <baud> <name> <pincode>";
if ((baudRate == nullptr) || (name == nullptr) || (pinCode == nullptr)) {
efiPrintf("%s", usage);
return;
}
if (getBluetoothChannel() == nullptr) {
efiPrintf("No Bluetooth channel configured! Check your board config.");
return;
}
if (btSetupIsRequested) {
efiPrintf("The Bluetooth module init procedure is already started!");
return;
}
// now check the arguments and add other commands:
// 1) baud rate
int baud = atoi(baudRate);
// find a known baud rate in our list
setBaudIdx = -1;
for (size_t i = 0; i < efi::size(baudRates); i++) {
if ((int)baudRates[i].rate == baud) {
setBaudIdx = i;
break;
}
}
// check the baud rate index
if (setBaudIdx < 0) {
// unknown baud rate
efiPrintf("Wrong <baud> parameter '%s'! %s", baudRate, usage);
return;
}
// 2) check name
if ((strlen(name) < 1) || (strlen(name) > 20)) {
efiPrintf("Wrong <name> parameter! Up to 20 characters expected! %s", usage);
return;
}
// 3) check pin code
if (strlen(pinCode) != 4) {
efiPrintf("Wrong <pincode> parameter! 4 digits expected! %s", usage);
return;
}
for (int i = 0; i < 4; i++) {
if (!isdigit(pinCode[i])) {
efiPrintf("<pincode> should contain digits only %s", usage);
return;
}
}
/* copy settings */
strncpy(btName, name, 20);
strncpy(btPinCode, pinCode, 4);
btModuleType = moduleType;
btSetupIsRequested = true;
}
// Called after 1S of silence on BT UART...
void bluetoothSoftwareDisconnectNotify(SerialTsChannelBase* tsChannel) {
if (btSetupIsRequested) {
efiPrintf("*** Bluetooth module setup procedure ***");
/* 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!");
}
uint8_t tmp[1];
if (tsChannel->readTimeout(tmp, 1, BLUETOOTH_SILENT_TIMEOUT) != 0) {
efiPrintf("The Bluetooth module init procedure is cancelled (wait for silent timeout)!");
btSetupIsRequested = false;
return;
}
runCommands(tsChannel);
btSetupIsRequested = false;
}
}
#endif /* EFI_BLUETOOTH_SETUP */