Merge pull request #436 from andreika-git/bluetooth_init

Bluetooth module setup procedure
This commit is contained in:
rusefi 2017-06-04 11:01:52 -04:00 committed by GitHub
commit 400bc02890
8 changed files with 403 additions and 1 deletions

View File

@ -56,6 +56,11 @@
*/
#define EFI_TUNER_STUDIO TRUE
/**
* Bluetooth UART setup support.
*/
#define EFI_BLUETOOTH_SETUP FALSE
/**
* TunerStudio debug output
*/

View File

@ -0,0 +1,263 @@
#include "main.h"
#include "engine_state.h"
#include "tunerstudio.h"
#include "tunerstudio_io.h"
#include "bluetooth.h"
#include "engine_configuration.h"
#if EFI_BLUETOOTH_SETUP || defined(__DOXYGEN__)
static bool btProcessIsStarted = false;
static bool btProcessIsRunning = false;
static const char *commands[5];
static int numCommands = 0;
static int setBaudIdx = -1;
static char cmdBaud[10];
static char cmdName[30];
static char cmdPin[16];
static const int baudRates[] = { 0, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200, -1 };
static const int baudRateIndexList[] = { 4 /*9600*/, 6 /*38400*/, 8 /*115200*/, 7, 5, 3, 2, 1, -1 };
static const int btModuleTimeout = MS2ST(1000);
static ts_channel_s *tsChannel;
static THD_WORKING_AREA(btThreadStack, UTILITY_THREAD_STACK_SIZE);
static thread_t *btThread = NULL;
static thread_reference_t btThreadRef = NULL; // used by thread suspend/resume as a flag
static LoggingWithStorage btLogger("bluetooth");
EXTERN_ENGINE
;
// Main communication code
// We assume that the user has disconnected the software before starting the code.
static void runCommands() {
uint8_t buffer[2];
if (!btProcessIsStarted)
return;
// Store current serial port speed - we're going to change it
int savedSerialSpeed = boardConfiguration->tunerStudioSerialSpeed;
int prevBaudIdx = -1, baudIdx = -1, baudListIdx = 0;
int cmdIdx = 0;
// run all commands
while (true) {
if (baudIdx < 0) {
// try all available baud rates, in order of preference
baudIdx = baudRateIndexList[baudListIdx++];
// we've tried all baud rates?
if (baudIdx < 0)
break;
}
bool restoreAndExit = (cmdIdx >= numCommands || baudIdx < 0);
// if the baud rate is changed, reinit the UART
if (baudIdx != prevBaudIdx || restoreAndExit) {
// deinit UART
if (!stopTsPort(tsChannel)) {
scheduleMsg(&btLogger, "Failed! Cannot restart serial port connection!");
return;
}
chThdSleepMilliseconds(10); // safety
// change the port speed
boardConfiguration->tunerStudioSerialSpeed = restoreAndExit ? savedSerialSpeed : baudRates[baudIdx];
// init UART
startTsPort(tsChannel);
chThdSleepMilliseconds(10); // safety
prevBaudIdx = baudIdx;
}
// exit if all commands were sent
if (restoreAndExit)
break;
// send current command
sr5WriteData(tsChannel, (uint8_t *)commands[cmdIdx], strlen(commands[cmdIdx]));
// waiting for an answer
bool wasAnswer = false;
if (sr5ReadDataTimeout(tsChannel, buffer, 2, btModuleTimeout) == 2) {
wasAnswer = (buffer[0] == 'O' && buffer[1] == 'K');
}
// wait 1 second and skip all remaining response bytes from the bluetooth module
while (true) {
if (sr5ReadDataTimeout(tsChannel, buffer, 1, btModuleTimeout) < 1)
break;
}
if (wasAnswer) {
// if we changed the baud rate
if (commands[cmdIdx] == cmdBaud) {
// this is what we've set
baudIdx = setBaudIdx;
// if we fail somehow, try all other baud rates
baudListIdx = 0;
}
// move to the next command
cmdIdx++;
} else {
// try other baud rate
baudIdx = -1;
}
}
// the connection is already restored to the current baud rate, so print the result
if (cmdIdx == numCommands)
scheduleMsg(&btLogger, "SUCCESS! All commands (%d of %d) passed to the Bluetooth module!", cmdIdx, numCommands);
else
scheduleMsg(&btLogger, "FAIL! Only %d commands (of %d total) were passed to the Bluetooth module!", cmdIdx, numCommands);
}
static THD_FUNCTION(btThreadEntryPoint, arg) {
(void) arg;
chRegSetThreadName("bluetooth thread");
scheduleMsg(&btLogger, "*** Bluetooth module setup procedure ***");
scheduleMsg(&btLogger, "!Warning! Please make sure you're not currently using the BT module for communication (not paired)!");
scheduleMsg(&btLogger, "TO START THE PROCEDURE: PLEASE DISCONNECT YOUR PC COM-PORT FROM THE BOARD NOW!");
scheduleMsg(&btLogger, "After that please don't turn off the board power and wait for ~15 seconds to complete. Then reconnect to the board!");
// now wait
chSysLock();
msg_t msg = chThdSuspendTimeoutS(&btThreadRef, BLUETOOTH_COMMAND_TIMEOUT);
chSysUnlock();
if (msg == MSG_TIMEOUT) {
scheduleMsg(&btLogger, "The Bluetooth module init procedure is cancelled (timeout)!");
return;
} else {
// call this when the thread is resumed (after the disconnect)
btProcessIsRunning = true;
runCommands();
btProcessIsRunning = false;
}
// release the command
btProcessIsStarted = false;
chThdExit(MSG_OK);
}
void bluetoothStart(ts_channel_s *tsChan, bluetooth_module_e moduleType, const char *baudRate, const char *name, const char *pinCode) {
static const char *usage = "Usage: bluetooth_hc06 <baud> <name> <pincode>";
tsChannel = tsChan;
// if a binary protocol uses USB, we cannot init the bluetooth module!
if (!boardConfiguration->useSerialPort) {
scheduleMsg(&btLogger, "Failed! Serial Port connection is disabled!");
return;
}
if (btProcessIsStarted) {
scheduleMsg(&btLogger, "The Bluetooth module init procedure is already started and waiting! To cancel it, run \"bluetooth_cancel\" command!");
return;
}
// todo: add support for other BT module types
if (moduleType != BLUETOOTH_HC_06) {
scheduleMsg(&btLogger, "This Bluetooth module is currently not supported!");
return;
}
numCommands = 0;
// now check the arguments and add other commands:
// 1) baud rate
int baud = (baudRate != NULL) ? atoi(baudRate) : 0;
int i;
// find a known baud rate in our list
setBaudIdx = -1;
for (i = 1; baudRates[i] > 0; i++) {
if (baudRates[i] == baud) {
setBaudIdx = i;
break;
}
}
// check the baud rate index
if (setBaudIdx < 1) {
if (baud == 0)
scheduleMsg(&btLogger, "The <baud> parameter is set to zero! The baud rate won't be set!");
else {
// unknown baud rate
scheduleMsg(&btLogger, "Wrong <baud> parameter '%s'! %s", baudRate, usage);
return;
}
} else {
// ok, add command!
}
// 2) check name
if (name == NULL || strlen(name) < 1 || strlen(name) > 20) {
scheduleMsg(&btLogger, "Wrong <name> parameter! Up to 20 characters expected! %s", usage);
return;
}
// 3) check pin code
int numDigits = 0;
// check the pincode
if (pinCode != NULL && strlen(pinCode) == 4) {
for (i = 0; i < 4; i++) {
if (pinCode[i] >= '0' && pinCode[i] <= '9') // digit
numDigits++;
}
}
if (numDigits != 4) {
scheduleMsg(&btLogger, "Wrong <pincode> parameter! 4 digits expected! %s", usage);
return;
}
// ok, add commands!
commands[numCommands++] = "AT"; // this command is added to test a connection
chsnprintf(cmdBaud, sizeof(cmdBaud), "AT+BAUD%c", '0' + setBaudIdx);
commands[numCommands++] = cmdBaud;
chsnprintf(cmdName, sizeof(cmdName), "AT+NAME%s", name);
commands[numCommands++] = cmdName;
chsnprintf(cmdPin, sizeof(cmdPin), "AT+PIN%s", pinCode);
commands[numCommands++] = cmdPin;
// create a thread to execute these commands later
btThread = chThdCreateStatic(btThreadStack, sizeof(btThreadStack), NORMALPRIO, (tfunc_t)btThreadEntryPoint, NULL);
btProcessIsStarted = true;
}
void bluetoothSoftwareDisconnectNotify() {
if (btProcessIsStarted) {
// start communication with the module
chThdResume(&btThreadRef, MSG_OK);
// wait the thread to finish
chThdWait(btThread);
}
}
void bluetoothCancel() {
if (!btProcessIsStarted) {
scheduleMsg(&btLogger, "The Bluetooth module init procedure was not started! Nothing to cancel!");
return;
}
if (btProcessIsRunning)
return;
// terminate thread
chThdTerminate(btThread);
btProcessIsStarted = false;
scheduleMsg(&btLogger, "The Bluetooth module init procedure is cancelled!");
}
#endif /* EFI_BLUETOOTH_SETUP */

View File

@ -0,0 +1,45 @@
/**
* @file tunerstudio.h
*
* @date Aug 26, 2013
* @author Andrey Belomutskiy, (c) 2012-2017
*/
#ifndef BLUETOOTH_H_
#define BLUETOOTH_H_
#include "main.h"
#include "tunerstudio_io.h"
// The Bluetooth setup procedure will wait 10 seconds for the user to disconnect the UART cable.
// This is required because the BT setup procedure reads a response from the module during the communication.
// Thus any bytes sent from the Console Software may interfere with the procedure.
#define BLUETOOTH_COMMAND_TIMEOUT MS2ST(10000)
// Supported Bluetooth module types
typedef enum {
BLUETOOTH_HC_06,
} bluetooth_module_e;
/**
* Start Bluetooth module initialization using UART connection:
* - wait for PC communication disconnect;
* - reconfigure the UART;
* - send AT-commands to the module;
* - restore connection to PC.
*/
void bluetoothStart(ts_channel_s *tsChannel, bluetooth_module_e moduleType, const char *baudRate, const char *name, const char *pinCode);
/**
* Cancel Bluetooth procedure
*/
void bluetoothCancel(void);
/**
* Called by runBinaryProtocolLoop() if a connection disconnect is detected.
* Bluetooth init code needs to make sure that there's no interference of the BT module and USB-UART (connected to PC)
*/
void bluetoothSoftwareDisconnectNotify();
#endif /* BLUETOOTH_H_ */

View File

@ -0,0 +1,38 @@
Bluetooth module setup procedure. User Manual.
To activate your Bluetooth module, you'll need:
1) Connect your PC to the rusEFI board using UART cable.
2) Run "rusEFI Console" software.
3) Turn on the board power and wait for the console connection.
4) Type the following command:
"bluetooth_hc06 <baud> <name> <pincode>"
Where:
- <baud> is the baud rate of the Bluetooth connection. Allowed values are: 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200.
Please set this to the baud rate currently used by your UART console.
- <name> is the name of your Bluetooth connection. It will be visible in the device list on your PC.
- <pincode> is 4-digit PIN-code needed to authorize the Bluetooth connection to your PC.
Example: "bluetooth_hc06 38400 rusefi 1234"
5) After entering the command the following text will appear:
*** Bluetooth module setup procedure ***
!Warning! Please make sure you're not currently using the BT module for communication (not paired)!
TO START THE PROCEDURE: PLEASE DISCONNECT YOUR PC COM-PORT FROM THE BOARD NOW!
After that please don't turn off the board power and wait for ~15 seconds to complete. Then reconnect to the board!
6) If you ignore this message and do nothing, the Bluetooth secup procedure will be cancelled in 10 seconds.
You can also use "bluetooth_cancel" command to cancel it.
7) If you disconnect the UART cable or close the software, then the procedure will begin.
8) It takes up to 15 seconds to complete. The Bluetooth LED may blink several times during the procedure - it's normal.
9) After that, you may restore the UART connection to your PC or start using Bluetooth module.
*** Developers Section ***
How it works, in two words:
- adds 2 new commands: "bluetooth_hc06(baud, name, pincode)" and "bluetooth_cancel";
- adds stopTsPort() to tunerstudio_io - needed to change the baud rate on fly;
- added bluetoothSoftwareDisconnectNotify() handler to runBinaryProtocolLoop() - to detect UART disconnects;
- added a thread with btThreadEntryPoint():
- It will wait up to 10 seconds for the user to disconnect the UART cable.
This is required because the BT setup procedure reads a response from the module during the communication - using the same UART.
Thus any bytes sent from the Console Software may interfere with the procedure.
- added bluetoothStart() which processes user input and creates a command list;
- added runCommands() where all the Bluetooth magic happens!

View File

@ -73,6 +73,7 @@
#include "console_io.h"
#include "crc.h"
#include "fl_protocol.h"
#include "bluetooth.h"
#include <string.h>
#include "engine_configuration.h"
@ -167,6 +168,13 @@ static void setTsSpeed(int value) {
printTsStats();
}
#if EFI_BLUETOOTH_SETUP || defined(__DOXYGEN__)
// Bluetooth HC-06 module initialization start (it waits for disconnect and then communicates to the module)
static void bluetoothHC06(const char *baudRate, const char *name, const char *pinCode) {
bluetoothStart(&tsChannel, BLUETOOTH_HC_06, baudRate, name, pinCode);
}
#endif /* EFI_BLUETOOTH_SETUP */
void tunerStudioDebug(const char *msg) {
#if EFI_TUNER_STUDIO_VERBOSE || defined(__DOXYGEN__)
scheduleMsg(&tsLogger, "%s", msg);
@ -452,6 +460,10 @@ void runBinaryProtocolLoop(ts_channel_s *tsChannel, bool isConsoleRedirect) {
if (received != 1) {
// tunerStudioError("ERROR: no command");
#if EFI_BLUETOOTH_SETUP || defined(__DOXYGEN__)
// assume there's connection loss and notify the bluetooth init code
bluetoothSoftwareDisconnectNotify();
#endif /* EFI_BLUETOOTH_SETUP */
continue;
}
onDataArrived();
@ -828,6 +840,13 @@ void startTunerStudioConnectivity(void) {
addConsoleAction("tsinfo", printTsStats);
addConsoleAction("reset_ts", resetTs);
addConsoleActionI("set_ts_speed", setTsSpeed);
#if EFI_BLUETOOTH_SETUP || defined(__DOXYGEN__)
// Usage: "bluetooth_hc06 <baud> <name> <pincode>"
// Example: "bluetooth_hc06 38400 rusefi 1234"
addConsoleActionSSS("bluetooth_hc06", bluetoothHC06);
addConsoleAction("bluetooth_cancel", bluetoothCancel);
#endif /* EFI_BLUETOOTH_SETUP */
chThdCreateStatic(tsThreadStack, sizeof(tsThreadStack), NORMALPRIO, (tfunc_t)tsThreadEntryPoint, NULL);
}

View File

@ -1,3 +1,4 @@
TUNERSTUDIO_SRC_CPP = $(PROJECT_DIR)/console/binary/tunerstudio_io.cpp \
$(PROJECT_DIR)/console/binary/tunerstudio.cpp
$(PROJECT_DIR)/console/binary/tunerstudio.cpp \
$(PROJECT_DIR)/console/binary/bluetooth.cpp

View File

@ -124,6 +124,36 @@ void startTsPort(ts_channel_s *tsChannel) {
#endif /* EFI_PROD_CODE */
}
bool stopTsPort(ts_channel_s *tsChannel) {
#if EFI_PROD_CODE || defined(__DOXYGEN__)
#if EFI_USB_SERIAL || defined(__DOXYGEN__)
if (isCommandLineConsoleOverTTL()) {
#if 0
usb_serial_stop();
#endif
// don't stop USB!
return false;
} else
#endif
{
if (boardConfiguration->useSerialPort) {
// todo: disable Rx/Tx pads?
#if TS_UART_DMA_MODE
uartStop(TS_DMA_UART_DEVICE);
#else
sdStop(TS_SERIAL_UART_DEVICE);
#endif /* TS_UART_DMA_MODE */
}
}
tsChannel->channel = (BaseChannel *) NULL;
return true;
#else /* EFI_PROD_CODE */
// don't stop simulator!
return false;
#endif /* EFI_PROD_CODE */
}
void sr5WriteData(ts_channel_s *tsChannel, const uint8_t * buffer, int size) {
efiAssertVoid(getRemainingStack(chThdGetSelfX()) > 64, "tunerStudioWriteData");
#if EFI_SIMULATOR || defined(__DOXYGEN__)

View File

@ -90,6 +90,7 @@ typedef struct {
void startTsPort(ts_channel_s *tsChannel);
bool stopTsPort(ts_channel_s *tsChannel);
// that's 1 second
#define BINARY_IO_TIMEOUT MS2ST(1000)