From e7bc494c5335b94458170640532ff9d271318133 Mon Sep 17 00:00:00 2001 From: Andrei Date: Sun, 4 Jun 2017 15:52:44 +0300 Subject: [PATCH] Bluetooth setup, initial code --- firmware/console/binary/bluetooth.cpp | 263 +++++++++++++++++++ firmware/console/binary/bluetooth.h | 45 ++++ firmware/console/binary/bluetooth_readme.txt | 38 +++ 3 files changed, 346 insertions(+) create mode 100644 firmware/console/binary/bluetooth.cpp create mode 100644 firmware/console/binary/bluetooth.h create mode 100644 firmware/console/binary/bluetooth_readme.txt diff --git a/firmware/console/binary/bluetooth.cpp b/firmware/console/binary/bluetooth.cpp new file mode 100644 index 0000000000..8f83f97f7a --- /dev/null +++ b/firmware/console/binary/bluetooth.cpp @@ -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 "; + + 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 parameter is set to zero! The baud rate won't be set!"); + else { + // unknown baud rate + scheduleMsg(&btLogger, "Wrong 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 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 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 */ diff --git a/firmware/console/binary/bluetooth.h b/firmware/console/binary/bluetooth.h new file mode 100644 index 0000000000..87e0b69b08 --- /dev/null +++ b/firmware/console/binary/bluetooth.h @@ -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_ */ diff --git a/firmware/console/binary/bluetooth_readme.txt b/firmware/console/binary/bluetooth_readme.txt new file mode 100644 index 0000000000..9c0831b352 --- /dev/null +++ b/firmware/console/binary/bluetooth_readme.txt @@ -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 " + Where: + - 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. + - is the name of your Bluetooth connection. It will be visible in the device list on your PC. + - 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!