├── CAN ├── BoostedBreakCAN │ ├── lib │ │ └── x64 │ │ │ └── README.md │ ├── Analysis │ │ ├── DefaultBoostedBreakCANAnalysis.xlsx │ │ └── README.md │ ├── stdafx.cpp │ ├── stdafx.h │ ├── TraceFiles │ │ └── README.md │ ├── targetver.h │ ├── BoostedBreakCAN.sln │ ├── ConsoleInterface.h │ ├── BoostedBreakCAN.vcxproj.filters │ ├── README.md │ ├── PCANBasicParameter.h │ ├── BoostedBreakCAN.h │ ├── BoostedCANMsg.h │ ├── main.cpp │ ├── BoostedBreakCAN.vcxproj │ ├── PCANBasicDriver.h │ ├── PCANBasicUtility.h │ ├── BoostedBreakCAN.cpp │ ├── PCANBasicParameter.cpp │ └── PCANBasicDriver.cpp ├── README.md └── BoostedCANMessageTable.md ├── BLE └── README.md ├── README.md └── FAQ └── README.md /CAN/BoostedBreakCAN/lib/x64/README.md: -------------------------------------------------------------------------------- 1 | ### PCANBasic.lib should exist here. 2 | -------------------------------------------------------------------------------- /CAN/BoostedBreakCAN/Analysis/DefaultBoostedBreakCANAnalysis.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axkrysl47/BoostedBreak/HEAD/CAN/BoostedBreakCAN/Analysis/DefaultBoostedBreakCANAnalysis.xlsx -------------------------------------------------------------------------------- /CAN/BoostedBreakCAN/stdafx.cpp: -------------------------------------------------------------------------------- 1 | // stdafx.cpp : source file that includes just the standard includes 2 | // PCANBasicExample.pch will be the pre-compiled header 3 | // stdafx.obj will contain the pre-compiled type information 4 | 5 | #include "stdafx.h" 6 | 7 | 8 | -------------------------------------------------------------------------------- /CAN/BoostedBreakCAN/stdafx.h: -------------------------------------------------------------------------------- 1 | // stdafx.h : include file for standard system include files, 2 | // or project specific include files that are used frequently, 3 | // but are changed infrequently 4 | 5 | #pragma once 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include "targetver.h" -------------------------------------------------------------------------------- /CAN/BoostedBreakCAN/Analysis/README.md: -------------------------------------------------------------------------------- 1 | ### Analysis spreadsheet files should go here. 2 | #### PCAN Trace File Example 3 | From the [PEAK CAN TRC File Format Specification](https://www.peak-system.com/produktcd/Pdf/English/PEAK_CAN_TRC_File_Format.pdf): 4 | ``` 5 | ;########################################################################## 6 | ; C:\TraceFile.trc 7 | ; 8 | ; CAN activities recorded by PCAN Explorer 9 | ; Start time: 11.09.2002 16:00:20.682 10 | ; PCAN-Net: PCI1 11 | ; 12 | ; Columns description: 13 | ; ~~~~~~~~~~~~~~~~~~~~~ 14 | ; +-current number in actual sample 15 | ; | +time offset of message (ms) 16 | ; | | +ID of message (hex) 17 | ; | | | +data length code 18 | ; | | | | +data bytes (hex) ... 19 | ; | | | | | 20 | ;----+- ---+--- ----+--- + -+ -- -- ... 21 | 1) 1841 0001 8 00 00 00 00 00 00 00 00 22 | 2) 1842 0008 4 ERROR 00 19 08 08 23 | 3) 1843 FFFFFFFF 4 00 00 00 04 -- -- -- -- BUSLIGHT 24 | 4) 1844 0100 3 RTR 25 | ``` 26 | 27 | -------------------------------------------------------------------------------- /CAN/BoostedBreakCAN/TraceFiles/README.md: -------------------------------------------------------------------------------- 1 | ### Trace Files should be created in this directory. 2 | #### PCAN Trace File Example 3 | From the [PEAK CAN TRC File Format Specification](https://www.peak-system.com/produktcd/Pdf/English/PEAK_CAN_TRC_File_Format.pdf): 4 | ``` 5 | ;########################################################################## 6 | ; C:\TraceFile.trc 7 | ; 8 | ; CAN activities recorded by PCAN Explorer 9 | ; Start time: 11.09.2002 16:00:20.682 10 | ; PCAN-Net: PCI1 11 | ; 12 | ; Columns description: 13 | ; ~~~~~~~~~~~~~~~~~~~~~ 14 | ; +-current number in actual sample 15 | ; | +time offset of message (ms) 16 | ; | | +ID of message (hex) 17 | ; | | | +data length code 18 | ; | | | | +data bytes (hex) ... 19 | ; | | | | | 20 | ;----+- ---+--- ----+--- + -+ -- -- ... 21 | 1) 1841 0001 8 00 00 00 00 00 00 00 00 22 | 2) 1842 0008 4 ERROR 00 19 08 08 23 | 3) 1843 FFFFFFFF 4 00 00 00 04 -- -- -- -- BUSLIGHT 24 | 4) 1844 0100 3 RTR 25 | ``` 26 | 27 | -------------------------------------------------------------------------------- /CAN/BoostedBreakCAN/targetver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // The following macros define the minimum required platform. The minimum required platform 4 | // is the earliest version of Windows, Internet Explorer etc. that has the necessary features to run 5 | // your application. The macros work by enabling all features available on platform versions up to and 6 | // including the version specified. 7 | 8 | // Modify the following defines if you have to target a platform prior to the ones specified below. 9 | // Refer to MSDN for the latest info on corresponding values for different platforms. 10 | #ifndef WINVER // Specifies that the minimum required platform is Windows Vista. 11 | #define WINVER 0x0600 // Change this to the appropriate value to target other versions of Windows. 12 | #endif 13 | 14 | #ifndef _WIN32_WINNT // Specifies that the minimum required platform is Windows Vista. 15 | #define _WIN32_WINNT 0x0600 // Change this to the appropriate value to target other versions of Windows. 16 | #endif 17 | 18 | #ifndef _WIN32_WINDOWS // Specifies that the minimum required platform is Windows 98. 19 | #define _WIN32_WINDOWS 0x0410 // Change this to the appropriate value to target Windows Me or later. 20 | #endif 21 | 22 | #ifndef _WIN32_IE // Specifies that the minimum required platform is Internet Explorer 7.0. 23 | #define _WIN32_IE 0x0700 // Change this to the appropriate value to target other versions of IE. 24 | #endif 25 | 26 | -------------------------------------------------------------------------------- /CAN/BoostedBreakCAN/BoostedBreakCAN.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.31205.134 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BoostedBreakCAN", "BoostedBreakCAN.vcxproj", "{DE08AE69-04BD-43EA-8602-B6D5528D690B}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {DE08AE69-04BD-43EA-8602-B6D5528D690B}.Debug|x64.ActiveCfg = Debug|x64 17 | {DE08AE69-04BD-43EA-8602-B6D5528D690B}.Debug|x64.Build.0 = Debug|x64 18 | {DE08AE69-04BD-43EA-8602-B6D5528D690B}.Debug|x86.ActiveCfg = Debug|Win32 19 | {DE08AE69-04BD-43EA-8602-B6D5528D690B}.Debug|x86.Build.0 = Debug|Win32 20 | {DE08AE69-04BD-43EA-8602-B6D5528D690B}.Release|x64.ActiveCfg = Release|x64 21 | {DE08AE69-04BD-43EA-8602-B6D5528D690B}.Release|x64.Build.0 = Release|x64 22 | {DE08AE69-04BD-43EA-8602-B6D5528D690B}.Release|x86.ActiveCfg = Release|Win32 23 | {DE08AE69-04BD-43EA-8602-B6D5528D690B}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {4A9490BD-A688-47B4-8BCE-026E01EE20C2} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /CAN/BoostedBreakCAN/ConsoleInterface.h: -------------------------------------------------------------------------------- 1 | /*** 2 | * BoostedBreak - BoostedBreakCAN Program 3 | * 4 | * ConsoleInterface.h 5 | * 6 | * Author: Alexander Krysl (axkrysl47) 7 | * Date: 2022/04/03 8 | **/ 9 | 10 | #pragma once 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #ifndef __CONSOLEINTERFACEH__ 17 | #define __CONSOLEINTERFACEH__ 18 | 19 | //static HANDLE hConsole; 20 | 21 | static void ConsoleInit() 22 | { 23 | //hConsole = GetStdHandle(STD_OUTPUT_HANDLE); 24 | } 25 | 26 | static void ConsoleClear() 27 | { 28 | system("cls"); 29 | } 30 | 31 | static void ConsolePause() 32 | { 33 | system("PAUSE"); 34 | } 35 | 36 | static void ConsolePrint(std::string str) 37 | { 38 | std::cout << str; 39 | } 40 | 41 | static void ConsolePrint(std::string str, int16_t xpos) 42 | { 43 | HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); 44 | CONSOLE_SCREEN_BUFFER_INFO cbsi; 45 | COORD pos; 46 | 47 | if (GetConsoleScreenBufferInfo(hConsole, &cbsi)) 48 | { 49 | pos = { xpos , cbsi.dwCursorPosition.Y }; 50 | } 51 | else 52 | { 53 | pos = { xpos, 0 }; 54 | } 55 | SetConsoleCursorPosition(hConsole, pos); 56 | 57 | std::cout << str; 58 | } 59 | 60 | static void ConsolePrint(std::string str, int16_t xpos, int16_t ypos) 61 | { 62 | HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); 63 | COORD pos = { xpos, ypos }; 64 | 65 | SetConsoleCursorPosition(hConsole, pos); 66 | 67 | std::cout << str; 68 | } 69 | 70 | static void ConsoleCursor(int16_t xpos, int16_t ypos) 71 | { 72 | HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); 73 | COORD pos = { xpos, ypos }; 74 | 75 | SetConsoleCursorPosition(hConsole, pos); 76 | } 77 | 78 | static char ConsoleInput() 79 | { 80 | return _getch(); 81 | } 82 | 83 | static void DebugConsolePrint(std::string str) 84 | { 85 | std::cout << str; 86 | } 87 | 88 | static char DebugConsoleInput() 89 | { 90 | return _getch(); 91 | } 92 | 93 | #endif //__CONSOLEINTERFACEH__ -------------------------------------------------------------------------------- /BLE/README.md: -------------------------------------------------------------------------------- 1 | # Boosted Bluetooth Low Energy 2 | ## Overview 3 | The following is the latest work-in-progress reverse-engineering breakdown of Boosted's Bluetooth Low Energy (BLE) protocol between V2/3 remotes & electronic speed controllers. 4 | 5 | ## Software Overview 6 | The Boosted Board V2/3 remotes & electronic speed controllers communicate using Bluetooth Low Energy Core Specification v4.1. Boosted, Inc. created several in-house services & characteristics, each with non-generic universally unique identifiers (UUIDs). 7 | 8 | ### Boosted Remote BLE Services 9 | The Boosted remote contains many services, characteristics, and descriptors. The following is a list of the most important ones: 10 | * `afc05da0-0cd4-11e6-a148-3e1d05defe78` "Boosted Remote" Service 11 | * `afc0653e-0cd4-11e6-a148-3e1d05defe78` "Boosted Remote Control Input" Characteristic 12 | * `0x2902` Client Characteristic Configuration Descriptor 13 | * `f4c4772c-0056-11e6-8d22-5e5517507c66` "Boosted Board" Service 14 | * `f4c47a4c-0056-11e6-8d22-5e5517507c66` "Boosted Board Speed Mode" Characteristic 15 | * `0x2904` Characteristic Presentation Format Descriptor 16 | * `f4c47e66-0056-11e6-8d22-5e5517507c66` "Boosted Board State of Charge" Characteristic 17 | * `0x2904` Characteristic Presentation Format Descriptor 18 | * `0x180A` Device Information Service 19 | * `0x2A25` Serial Number String Characteristic 20 | * `0x2902` Client Characteristic Configuration Descriptor 21 | * `0x2A27` Firmware Revision String Characteristic 22 | * `0x2902` Client Characteristic Configuration Descriptor 23 | 24 | ### Boosted Board BLE Services 25 | TODO 26 | 27 | ### Boosted BLE Connection & Security 28 | TODO 29 | 30 | ### Boosted Remote BLE Application 31 | TODO 32 | 33 | ## Hardware Overview 34 | Boosted used the Ehong EH-MC10 for all Bluetooth applications. The Boosted Remote utilized the built-in 8051 microcontroller feature on the EH-MC10 to perform all remote functions (such as throttle, button, trigger, LEDs). On the motor driver, there are two EH-MC10's; one is designated as a BLE client of the Boosted Remote, the other is designated as the BLE server for the Boosted smartphone application. The primary dsPIC microcontroller on the motor driver directs the EH-MC10s via Hayes (AT) serial commands. 35 | -------------------------------------------------------------------------------- /CAN/BoostedBreakCAN/BoostedBreakCAN.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Source Files 6 | 7 | 8 | Source Files 9 | 10 | 11 | Source Files 12 | 13 | 14 | Source Files 15 | 16 | 17 | Source Files 18 | 19 | 20 | 21 | 22 | Header Files 23 | 24 | 25 | Header Files 26 | 27 | 28 | Header Files 29 | 30 | 31 | Header Files 32 | 33 | 34 | Header Files 35 | 36 | 37 | Header Files 38 | 39 | 40 | Header Files 41 | 42 | 43 | Header Files 44 | 45 | 46 | Header Files 47 | 48 | 49 | Header Files 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | {be9e511d-bae4-41e2-b513-d799311a181c} 59 | 60 | 61 | {ae032491-d475-4aef-8dd1-5e0a84fed07f} 62 | 63 | 64 | {b783d7ba-2abd-423f-8039-577ef368da55} 65 | 66 | 67 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # __BoostedBreak__ - The Boosted Board Reverse Engineering Project 2 | ## Overview 3 | __BoostedBreak aims to be a comprehensive reverse-engineering project for Boosted Board products, created by __axkrysl47____. 4 | 5 | Currently, __BoostedBreakCAN__ is the first and only project under __BoostedBreak__ - more projects to come later. A video presentation of __BoostedBreakCAN__ in action can be found on my [YouTube page](https://www.youtube.com/watch?v=uVC6fjEU02M). 6 | 7 | __BoostedBreak__ was made as an attempt to be a spiritual successor to [__rscullin's BeamBREak__ project](https://beambreak.org/). 8 | 9 | ## __BoostedBreakCAN__ 10 | 11 | __BoostedBreakCAN__ is the latest reverse-engineering breakdown of Boosted's CAN protocol that exists between V2/3 batteries & electronic speed controllers. 12 | 13 | (A special credit goes to __David Wang__, founder of [__XR General Hospital__](https://www.xrgeneralhospital.com/), who helped source me the parts I needed to get this project off the ground.) 14 | 15 | ### Latest Release - v0.0.2 16 | v0.0.2 brings RLOD CAN Message support to __BoostedBreakCAN__, a Visual Studio C++ project that interfaces with a [PCAN-USB adapter from PEAK-System](https://www.peak-system.com/PCAN-USB.199.0.html?&L=1). 17 | 18 | ## What's Next... 19 | 20 | ### __BoostedBreakCAN__ 21 | 22 | I (__axkrysl47__) am currently in the process of acquiring more Boosted products for testing. I will be sure to update __BoostedBreakCAN__ with any new findings I make. 23 | 24 | Further, the SRB and XRB emulators, as well as 'brief mode', are not yet implemented and will require a good amount of effort to complete. If there is high enough demand, I can look to push those up my task list. 25 | 26 | ### __BoostedBreakBLE__ 27 | 28 | As soon as I acquire another remote for testing, I plan to start __BoostedBreakBLE__ to attempt to reverse-engineer Boosted's Bluetooth protocol that exists between V2/3 electronic speed controllers & remotes. 29 | 30 | ### __BoostedBreakFAQ__ 31 | 32 | I have started __BoostedBreakFAQ__, which I hope to be a one-stop-shop for all frequently asked questions regarding everything Boosted Boards. There already exist great Boosted FAQ resources in the community - what I hope to do is meaningfully add to the knowledgebase from the perspective of a firmware/embedded software engineer. 33 | 34 | ## Finally... 35 | 36 | For anyone who is interested in contributing to this project, please reach out to me either on [__XR General Hospital's__ Discord community (__@axkrysl47#8179__)](https://www.xrgeneralhospital.com/) or on the [Boosted Board reddit page (__@axkrysl47__)](https://www.reddit.com/r/boostedboards/). I will be sure to credit you with any and all contributions you make! 37 | 38 | Also, feel free to learn more about my previous projects and presentations, found on my [YouTube channel](https://www.youtube.com/channel/UCpVc9cm2N4pmNLKEEjk7v3w). 39 | -------------------------------------------------------------------------------- /CAN/BoostedBreakCAN/README.md: -------------------------------------------------------------------------------- 1 | # __BoostedBreakCAN__ Visual Studio Project 2 | __BoostedBreakCAN__ is a Visual Studio C++ console application that interfaces with a [PCAN-USB adapter from PEAK-System](https://www.peak-system.com/PCAN-USB.199.0.html?&L=1). 3 | 4 | I have uploaded an executable of the program that one may use without needing to clone the source or build in Visual Studio. If trace file configuration is failing, see __Trace Files & Analysis__ below. 5 | 6 | Additionally, I have uploaded a video presentation to YouTube showing __BoostedBreakCAN__ in action, linked [here](https://www.youtube.com/watch?v=uVC6fjEU02M). 7 | 8 | ## Installation 9 | To build this program as intended, you must first download the [PCAN-Basic API from PEAK-System](https://www.peak-system.com/PCAN-Basic.239.0.html?&L=1), and agree to the terms & conditions necessary to use their product. 10 | * Place `PCANBasic.lib` in the following path - `\BoostedBreakCAN\lib\x64\PCANBasic.lib` - and add it to the root of the Visual Studio project. 11 | * Place `PCANBasic.h` in the following path - `\BoostedBreakCAN\PCANBasic.h` - and add it to the header folder of the Visual Studio project. 12 | 13 | ## Features 14 | ### Completed Features 15 | * Latest Boosted CAN Protocol Message breakdown - reference `BoostedCANMsgInfo.h`. 16 | * Acquiring real-time data from sniffing the CANBus communications between a real Boosted V2/3 battery & electronic speed controller. 17 | * Emulating a Boosted ESC over CANBus. 18 | * Emulating a Boosted SRB with older firmware (derived from [__rscullin's BeamBREak__ project](https://beambreak.org/) python script). 19 | 20 | ### Trace Files & Analysis 21 | __BoostedBreakCAN__ utilizes the built-in PCAN-Basic trace file (`.trc`) creation of the PCAN-USB adapter. To properly use this functionality, you must declare a valid path in `main.cpp` for the PCAN-USB adapter to write the trace file to. 22 | 23 | By default, the path is `C:\BoostedBreak\BoostedBreakCAN\TraceFiles\`. 24 | 25 | After each session, __BoostedBreakCAN__ will write a trace file that contains a log of all CAN messages sent and received from the PCAN-USB adapter. 26 | You can then copy & paste the contents of the trace file - starting at the first entry - into the `defaultboostedbreakCAN.xlsx` speadsheet file in the `\BoostedBreakCAN\Anaylsis\` folder, which can decode the messages in the trace. 27 | 28 | ### Incomplete Features 29 | * Emulating a Boosted SRB with later firmware. 30 | * Emulating a Boosted XRB with latest firmware. 31 | * Implementing an easy-to-read 'brief mode'. 32 | 33 | ## Development 34 | __BoostedBreakCAN__ was developed via testing with an ESC on v2.7.2, XRB on v2.5.1, & SRB on v1.5.6. (A special credit goes to __David Wang__, founder of [__XR General Hospital__](https://www.xrgeneralhospital.com/), who helped source me the parts I needed to get this project off the ground.) 35 | 36 | ## Releases 37 | ### Latest Release - v0.0.1 38 | v0.0.1 is the initial published release of __BoostedBreakCAN__. 39 | 40 | ## Licensing 41 | This project is under exclusive copyright by default, until further notice. 42 | 43 | If you wish to clone or fork this project, please reach out to me either on [__XR General Hospital's__ Discord community (__@axkrysl47#8179__)](https://www.xrgeneralhospital.com/) or on the [Boosted Board reddit page (__@axkrysl47__)](https://www.reddit.com/r/boostedboards/). I will be sure to credit you with any and all contributions you make! 44 | -------------------------------------------------------------------------------- /CAN/BoostedBreakCAN/PCANBasicParameter.h: -------------------------------------------------------------------------------- 1 | /*** 2 | * BoostedBreak - BoostedBreakCAN Program 3 | * 4 | * PCANBasicParameter.h 5 | * 6 | * Author: Alexander Krysl (axkrysl47) 7 | * Date: 2022/04/03 8 | **/ 9 | 10 | #pragma once 11 | #include "stdafx.h" 12 | #include "PCANBasic.h" 13 | #include "PCANBasicUtility.h" 14 | 15 | #ifndef __PCANBASICPARAMETERH__ 16 | #define __PCANBASICPARAMETERH__ 17 | 18 | /// 19 | /// Shows device identifier parameter 20 | /// 21 | void GetPCAN_DEVICE_ID(TPCANHandle handle); 22 | 23 | /// 24 | /// Sets device identifier parameter 25 | /// 26 | /// 27 | void SetPCAN_DEVICE_ID(TPCANHandle handle, UINT32 iDeviceID); 28 | 29 | /// 30 | /// Shows all information about attached channels 31 | /// 32 | void GetPCAN_ATTACHED_CHANNELS(bool isFD); 33 | 34 | /// 35 | /// Shows the status of selected PCAN-Channel 36 | /// 37 | void GetPCAN_CHANNEL_CONDITION(TPCANHandle handle); 38 | 39 | /// 40 | /// Shows the status from the status LED of the USB devices 41 | /// 42 | void GetPCAN_CHANNEL_IDENTIFYING(TPCANHandle handle); 43 | 44 | /// 45 | /// De/Activates the status LED of the USB devices 46 | /// 47 | /// True to turn on; False to turn off 48 | void SetPCAN_CHANNEL_IDENTIFYING(TPCANHandle handle, bool value); 49 | 50 | /// 51 | /// Shows information about features 52 | /// 53 | void GetPCAN_CHANNEL_FEATURES(TPCANHandle handle); 54 | 55 | /// 56 | /// Shows the status from Bitrate-Adapting mode 57 | /// 58 | void GetPCAN_BITRATE_ADAPTING(TPCANHandle handle); 59 | 60 | /// 61 | /// De/Activates the Bitrate-Adapting mode 62 | /// 63 | /// True to turn on; False to turn off 64 | void SetPCAN_BITRATE_ADAPTING(TPCANHandle handle, bool isFD, TPCANBaudrate bitrate, TPCANBitrateFD bitrateFD, bool value); 65 | 66 | /// 67 | /// Shows the status from the reception of status frames 68 | /// 69 | void GetPCAN_ALLOW_STATUS_FRAMES(TPCANHandle handle); 70 | 71 | /// 72 | /// De/Activates the reception of status frames 73 | /// 74 | /// True to turn on; False to turn off 75 | void SetPCAN_ALLOW_STATUS_FRAMES(TPCANHandle handle, bool value); 76 | 77 | /// 78 | /// Shows the status from the reception of RTR frames 79 | /// 80 | void GetPCAN_ALLOW_RTR_FRAMES(TPCANHandle handle); 81 | 82 | /// 83 | /// De/Activates the reception of RTR frames 84 | /// 85 | /// True to turn on; False to turn off 86 | void SetPCAN_ALLOW_RTR_FRAMES(TPCANHandle handle, bool value); 87 | 88 | /// 89 | /// Shows the status from the reception of CAN error frames 90 | /// 91 | void GetPCAN_ALLOW_ERROR_FRAMES(TPCANHandle handle); 92 | 93 | /// 94 | /// De/Activates the reception of CAN error frames 95 | /// 96 | /// True to turn on; False to turn off 97 | void SetPCAN_ALLOW_ERROR_FRAMES(TPCANHandle handle, bool value); 98 | 99 | /// 100 | /// Shows the status from the reception of Echo frames 101 | /// 102 | void GetPCAN_ALLOW_ECHO_FRAMES(TPCANHandle handle); 103 | 104 | /// 105 | /// De/Activates the reception of Echo frames 106 | /// 107 | /// True to turn on; False to turn off 108 | void SetPCAN_ALLOW_ECHO_FRAMES(TPCANHandle handle, bool value); 109 | 110 | /// 111 | /// Shows the reception filter with a specific 11-bit acceptance code and mask 112 | /// 113 | void GetPCAN_ACCEPTANCE_FILTER_11BIT(TPCANHandle handle); 114 | 115 | /// 116 | /// Sets the reception filter with a specific 11-bit acceptance code and mask 117 | /// 118 | /// Acceptance code and mask 119 | void SetPCAN_ACCEPTANCE_FILTER_11BIT(TPCANHandle handle, UINT64 iacceptancefilter11bit); 120 | 121 | /// 122 | /// Shows the reception filter with a specific 29-bit acceptance code and mask 123 | /// 124 | void GetPCAN_ACCEPTANCE_FILTER_29BIT(TPCANHandle handle); 125 | 126 | /// 127 | /// Sets the reception filter with a specific 29-bit acceptance code and mask 128 | /// 129 | /// Acceptance code and mask 130 | void SetPCAN_ACCEPTANCE_FILTER_29BIT(TPCANHandle handle, UINT64 iacceptancefilter29bit); 131 | 132 | /// 133 | /// Shows the status of the reception filter 134 | /// 135 | void GetPCAN_MESSAGE_FILTER(TPCANHandle handle); 136 | 137 | /// 138 | /// De/Activates the reception filter 139 | /// 140 | /// Configure reception filter 141 | void SetPCAN_MESSAGE_FILTER(TPCANHandle handle, UINT32 imessagefilter); 142 | 143 | #endif 144 | -------------------------------------------------------------------------------- /CAN/README.md: -------------------------------------------------------------------------------- 1 | # Boosted Controller Area Network 2 | ## Overview 3 | The following is the latest comprehensive reverse-engineering breakdown of Boosted's CAN protocol between V2/3 batteries & electronic speed controllers. 4 | 5 | ## Software Overview 6 | The Boosted Board V2/3 CAN protocol between batteries & electronic speed controllers runs at 250kbaud with extended message IDs. The majority of Boosted CAN messages go from the SRB-or-XRB to the ESC, inferring that the ESC is the master node on any given Boosted board. 7 | 8 | ### Boosted CAN Protocol 9 | On later firmware versions (i.e. XRB v2.5.1 & ESC v2.7.2), CAN Protocol breakdown is as follows: 10 | * All messages have extended CAN IDs beginning with 8 bits `0b00010000` - hexadecimal `0x10`. 11 | * The following 20 bits - 5 hexadecimal digits - of the CAN ID denote the message type. 12 | * The final 4 bits - 1 hexadecimal digit - of the CAN ID denote a node's overflowing send counter. 13 | * CAN Message payloads contain message information and can have varying lengths (from 1 to 8 bytes). 14 | 15 | ### Example 16 | The following CAN message is an example of the ESC sending a ping/power message to the battery to command the battery to turn off, as would be the case if the user holds full reverse on the thumbwheel & holds down the power button on the remote. 17 | 18 | CAN Trace: `0x103434BA 8 0x02 0x00 0x00 0x00 0x00 0x00 0x00 0x00` 19 | * CAN ID: `0x103434BA` 20 | * Message Header Prefix: `0x10` 21 | * Message Header: `0x3434B` (ESC to BTY Ping/Power) 22 | * Node Send Counter: `0xA` (11th message sent from ESC since last overflow of counter) 23 | * LENGTH: `0x8` 24 | * PAYLOAD: `0x02 0x00 0x00 0x00 0x00 0x00 0x00 0x00` 25 | * First Byte: `0x02` (denotes a power-off command from ESC) 26 | 27 | ### Boosted CAN Protocol Message Table 28 | A complete list of reverse-engineered Boosted CAN protocol messages can be found [here (BoostedCANMessageTable.md)](https://github.com/axkrysl47/BoostedBreak/blob/main/CAN/BoostedCANMessageTable.md). 29 | 30 | ### CAN Node Behavior 31 | A battery will send messages whenever it is powered on (via button press), or if it sees enough back electromotive force on its output terminals (i.e. a connected motor is spun with non-trivial force). 32 | 33 | A battery is convinced an ESC is connected if 1) the SENSE line is shorted to ground ([see SENSE line in hardware below](#hardware-overview)), and 2) the battery is receiving ESC pings. In this state, the battery will send all messages as under expected operation. However, if the battery is unconvinced an ESC is connected, the battery will only send button state messages. 34 | 35 | The XRB will only accept ESC power commands over CAN after the ESC sends registration messages ([see the message table](https://github.com/axkrysl47/BoostedBreak/blob/main/CAN/BoostedCANMessageTable.md)). The SRB does not have this requirement. 36 | 37 | ### Note 38 | There is clear evidence that Boosted updated the Standard Range Battery (SRB)'s CAN protocol to more closely match the Extended Range Battery (XRB)'s protocol with later firmware versions. 39 | 40 | _(That is to say, I did not find the same protocol that [__rscullin's BeamBREak__](https://beambreak.org/) found on his SRB, likely due to mine being on a later firmware version.)_ 41 | 42 | ## Hardware Overview 43 | Most of the physical information of the CAN bus has already been published by [__rscullin's BeamBREak__](https://beambreak.org/), be sure to check that out as I (__axkrysl47__) credit it as my original source. 44 | 45 | I will keep accessory port information brief here. If you would like to know more, check out this [__BeamBREak__ link](https://github.com/rscullin/beambreak/tree/master/Accessory). 46 | 47 | > The Boosted Board has two CAN Buses, both running at 250kbaud. One is used for BMS<->ESC communication, and the other is used for the Accessory Port. 48 | 49 | (Source: [rscullin's BeamBREak Landing Page](https://github.com/rscullin/beambreak)) 50 | 51 | ### Primary CANBus (BMS <-> ESC) 52 | > Boosted uses a [5-Pin Higo L513AM](https://www.higoconnector.com/products/l313am-p-00-ar-1000/LK99K#title) connector, with two (larger) pins for power, and three pins for CAN/connection detection. The Battery uses a female Higo L513AM P 00 AT 1000, and the ESC uses a male Higo L513AM P 00 B0 1000. 53 | 54 | > Electrical Connections: 55 | > All of the following are based on the colors used by Higo. 56 | > * Red - Switched Battery Positive (~30-50v) 57 | > * Black - Ground 58 | > * Yellow - CAN High 59 | > * Green - CAN Low 60 | > * Blue - Connection Detection -- this is 3.3v when nothing is connected to the BMS, and pulled to ground by the ESC to let the BMS know that something is connected 61 | 62 | (Source: [rscullin's BeamBREak CAN Bus Page](https://github.com/rscullin/beambreak/tree/master/CAN%20Bus)) 63 | 64 | ### Secondary CANBus (ESC <-> Accessory) 65 | > The CAN Bus runs at 250k baud, with extended message IDs. Without an accessory connected, nothing other than a heartbeat seems to be sent on the CAN Bus. The ESC will cut 15v power after ~10 seconds of no heartbeat replies, but will continue to send heartbeat CAN frames. Without the latest ESC firmware (V2.7.2), there is no traffic on the Accessory Bus, and 15v is never supplied. 66 | 67 | (Source: [rscullin's BeamBREak CAN Bus Page](https://github.com/rscullin/beambreak/tree/master/CAN%20Bus)) 68 | 69 | 70 | -------------------------------------------------------------------------------- /CAN/BoostedBreakCAN/BoostedBreakCAN.h: -------------------------------------------------------------------------------- 1 | /*** 2 | * BoostedBreak - BoostedBreakCAN Program 3 | * 4 | * BoostedBreakCAN.h 5 | * 6 | * Author: Alexander Krysl (axkrysl47) 7 | * Date: 2022/04/03 8 | **/ 9 | 10 | #pragma once 11 | #include"stdafx.h" 12 | #include "PCANBasicDriver.h" 13 | #include "BoostedCANMsg.h" 14 | #include "BoostedCANMsgInfo.h" 15 | 16 | #ifndef __BOOSTEDBREAKCANH__ 17 | #define __BOOSTEDBREAKCANH__ 18 | 19 | #define VIEWMODE_STREAM (0) 20 | #define VIEWMODE_TABLE (1) 21 | #define VIEWMODE_BRIEF (2) 22 | 23 | #define TRANSMITMODE_NONE (3) 24 | #define TRANSMITMODE_PINGONLY (4) 25 | #define TRANSMITMODE_PINGPOWEROFF (5) 26 | #define TRANSMITMODE_EMULATEESC (6) 27 | #define TRANSMITMODE_EMULATESRB (7) 28 | #define TRANSMITMODE_EMULATEXRB (8) 29 | #define TRANSMITMODE_BEAMBREAKSRB (9) 30 | 31 | #define CURSOR_TRANSMITMODE 83, 1 32 | #define CURSOR_TABLE_ERROR 0, 46 33 | 34 | #define CURSOR_MESSAGE_COUNTER_X 6 35 | #define CURSOR_MESSAGE_LEGNTH_X 8 36 | #define CURSOR_SENDER_DESCRIPTION_X 35 37 | #define CURSOR_INTERPRETATION_X 70 38 | #define CURSOR_TRANSMITTED_X 128 39 | 40 | #define TABLE_OFFSET_Y 4 41 | 42 | class BoostedBreakCAN 43 | { 44 | private: 45 | /// 46 | /// Pointer to PCAN-Basic Class Driver 47 | /// 48 | PCANBasicDriver* m_CommPtr = nullptr; 49 | 50 | /// *** Control Thread Variables *** 51 | /// 52 | /// Thread for reading messages 53 | /// 54 | std::thread* m_ControlThread; 55 | /// 56 | /// Shows if thread run 57 | /// 58 | bool m_ControlThreadActive; 59 | 60 | /// 61 | /// State variable for receive view 62 | /// 63 | uint8_t m_ViewMode; 64 | /// 65 | /// State variable for transmit protocol 66 | /// 67 | uint8_t m_TransmitMode; 68 | 69 | /// 70 | /// Timestamp for last transmitted message. 71 | /// 72 | std::chrono::steady_clock::time_point m_LastPingTime; 73 | /// 74 | /// Timestamp for current transmit protocol timer. 75 | /// 76 | std::chrono::steady_clock::time_point m_TransmitStageTime; 77 | /// 78 | /// Counter variable for transmit protocol 79 | /// 80 | uint8_t m_LastTransmitCounter; 81 | 82 | uint8_t m_TransmitStage; 83 | 84 | public: 85 | //// Boosted Break constructor 86 | //// 87 | //BoostedBreakCAN(); 88 | 89 | // Boosted Break constructor 90 | // 91 | BoostedBreakCAN(PCANBasicDriver* pcan); 92 | 93 | // Boosted Break destructor 94 | // 95 | ~BoostedBreakCAN(); 96 | 97 | /// 98 | /// Sets the current receive view 99 | /// 100 | bool SetViewMode(uint8_t newMode); 101 | /// 102 | /// Sets the current transmit protocol 103 | /// 104 | bool SetTransmitMode(uint8_t newMode); 105 | 106 | /// 107 | /// Starts program control thread 108 | /// 109 | bool StartControlThread(); 110 | /// 111 | /// Stops program control thread. 112 | /// 113 | bool StopControlThread(); 114 | 115 | /// 116 | /// Debug Command, used for testing. 117 | /// 118 | void DebugCommand(); 119 | 120 | /// 121 | /// Gets the current receive view 122 | /// 123 | uint8_t GetViewMode(); 124 | /// 125 | /// Gets the current transmit protocol 126 | /// 127 | uint8_t GetTransmitMode(); 128 | 129 | protected: 130 | /// 131 | /// Thread function for receiving and transmitting messages 132 | /// 133 | void ControlThreadProcess(); 134 | /// 135 | /// High-level Program control function 136 | /// 137 | void ProgramControl(); 138 | /// 139 | /// Parses error condition into view 140 | /// 141 | void ParseError(TPCANStatus status); 142 | /// 143 | /// Parses received messages for view and transmission 144 | /// 145 | void ParseMessage(TPCANMsg msgCanMessage); 146 | /// 147 | /// Parses received messages for view 148 | /// 149 | void ParseMessageView(BoostedCANMsg message, BoostedCANMsgInfo info); 150 | /// 151 | /// Parses received messages for transmission 152 | /// 153 | void ParseMessageTransmit(BoostedCANMsg message); 154 | /// 155 | /// Sends messages per current protocol 156 | /// 157 | void SendMessages(std::chrono::steady_clock::time_point timeNow); 158 | /// 159 | /// Creates and transmits a BoostedCANMsg 160 | /// 161 | void TransmitBoostedCANMessage(uint32_t messageID, uint8_t messageLength, uint64_t messageBuffer); 162 | /// 163 | /// Sends ping per current protocol 164 | /// 165 | void SendPing(std::chrono::steady_clock::time_point timeNow, uint8_t param); 166 | /// 167 | /// Displays to user transmitted messages; 168 | /// 169 | void ShowSentMessage(TPCANMsg msgCanMessage); 170 | 171 | /// 172 | /// Initializes table view 173 | /// 174 | void SetTable(); 175 | 176 | /// 177 | /// List of valid Boosted CAN Message identifiers. 178 | /// 179 | const uint32_t BoostedCANMsgList[NUM_BOOSTED_CAN_MSG] = 180 | { 181 | 0x00000, 0x02402, 0x02411, 0x05415, 0x12402, 0x12411, 0x13417, 0x15415, 182 | 0x22402, 0x22411, 0x23417, 0x25415, 0x32411, 0x33417, 0x33440, 0x33441, 183 | 0x33442, 0x33443, 0x33444, 0x33445, 0x33446, 0x33447, 0x33448, 0x33449, 184 | 0x3344A, 0x3344B, 0x3344C, 0x3344D, 0x3344E, 0x3344F, 0x34316, 0x34344, 185 | 0x3434B, 0x3434C, 0x3434D, 0x3B31A, 0x3B41A, 0x33920, 0x39320 186 | }; 187 | }; 188 | 189 | #endif //__BOOSTEDBREAKCANH__ 190 | -------------------------------------------------------------------------------- /CAN/BoostedBreakCAN/BoostedCANMsg.h: -------------------------------------------------------------------------------- 1 | /*** 2 | * BoostedBreak - BoostedBreakCAN Program 3 | * 4 | * BoostedCANMsg.h 5 | * 6 | * Author: Alexander Krysl (axkrysl47) 7 | * Date: 2022/04/03 8 | **/ 9 | 10 | #pragma once 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include "PCANBasic.h" 16 | #include "PCANBasicUtility.h" 17 | 18 | #ifndef __BOOSTEDCANMSGH__ 19 | #define __BOOSTEDCANMSGH__ 20 | 21 | class BoostedCANMsg 22 | { 23 | public: 24 | uint32_t MessageID; 25 | uint8_t MessageCounter; 26 | uint8_t MessageLength; 27 | uint8_t MessageBuffer[8]; 28 | 29 | BoostedCANMsg() 30 | { 31 | MessageID = 0x00000000; 32 | MessageCounter = 0; 33 | MessageLength = 0; 34 | 35 | for (int_fast8_t i = 0; i < 8; i++) 36 | { 37 | MessageBuffer[i] = 0x00; 38 | } 39 | }; 40 | 41 | BoostedCANMsg(const TPCANMsg& CanMsg) 42 | { 43 | MessageID = (uint32_t)(((CanMsg.ID) & CanIDMessageMask) >> CanIDMessageOffset); 44 | MessageCounter = (uint8_t)(((CanMsg.ID) & CanIDCounterMask) >> CanIDCounterOffset); 45 | MessageLength = (uint8_t)(CanMsg.LEN); 46 | 47 | for (int_fast8_t i = 0; i < 8; i++) 48 | { 49 | if (i < CanMsg.LEN) 50 | { 51 | MessageBuffer[i] = CanMsg.DATA[i]; 52 | } 53 | else 54 | { 55 | MessageBuffer[i] = 0x00; 56 | } 57 | } 58 | } 59 | 60 | BoostedCANMsg(uint32_t messageID, uint8_t messageLength, uint8_t* messageBuffer) 61 | { 62 | MessageID = messageID; 63 | MessageCounter = 0; 64 | MessageLength = messageLength; 65 | 66 | for (int_fast8_t i = 0; i < 8; i++) 67 | { 68 | if (i < messageLength) 69 | { 70 | MessageBuffer[i] = messageBuffer[i]; 71 | } 72 | else 73 | { 74 | MessageBuffer[i] = 0x00; 75 | } 76 | } 77 | } 78 | 79 | BoostedCANMsg(uint32_t messageID, uint8_t messageCounter, uint8_t messageLength, uint8_t* messageBuffer) 80 | { 81 | MessageID = (messageID & (CanIDMessageMask >> CanIDMessageOffset)); 82 | MessageCounter = (messageCounter & (CanIDCounterMask >> CanIDCounterOffset)); 83 | MessageLength = (8 < messageLength) ? 8 : messageLength; 84 | 85 | for (uint_fast8_t i = 0; i < 8; i++) 86 | { 87 | if (i < MessageLength) 88 | { 89 | MessageBuffer[i] = messageBuffer[i]; 90 | } 91 | else 92 | { 93 | MessageBuffer[i] = 0x00; 94 | } 95 | } 96 | } 97 | 98 | BoostedCANMsg(uint32_t messageID, uint8_t messageCounter, uint8_t messageLength, uint64_t messageBuffer) 99 | { 100 | MessageID = (messageID & (CanIDMessageMask >> CanIDMessageOffset)); 101 | MessageCounter = (messageCounter & (CanIDCounterMask >> CanIDCounterOffset)); 102 | MessageLength = (8 < messageLength) ? 8 : messageLength; 103 | 104 | for (uint_fast8_t i = 0; i < 8; i++) 105 | { 106 | if (i < messageLength) 107 | { 108 | MessageBuffer[i] = (BYTE)((messageBuffer >> ((messageLength - i - 1) * 8)) & 0xFF); 109 | } 110 | else 111 | { 112 | MessageBuffer[i] = (BYTE)0x00; 113 | } 114 | } 115 | } 116 | 117 | TPCANMsg AsTPCANMsg() const 118 | { 119 | uint32_t canID = CanIDPrefix 120 | + ((MessageID << CanIDMessageOffset) & CanIDMessageMask) 121 | + ((MessageCounter << CanIDCounterOffset) & CanIDCounterMask); 122 | return CreateTPCANMsg(canID, PCAN_MESSAGE_EXTENDED, MessageLength, (BYTE*)MessageBuffer); 123 | } 124 | 125 | std::string AsString() 126 | { 127 | std::string output; 128 | char temp[32]; 129 | 130 | sprintf_s(temp, 32, "%05lx", MessageID); 131 | output += temp; 132 | output += " "; 133 | sprintf_s(temp, 32, "%01x", MessageCounter); 134 | output += temp; 135 | output += " "; 136 | sprintf_s(temp, 32, "%01d", MessageLength); 137 | output += temp; 138 | output += " - "; 139 | 140 | for (int_fast8_t i = 0; i < MessageLength; i++) 141 | { 142 | sprintf_s(temp, 32, "%02x", MessageBuffer[i]); 143 | output += temp; 144 | output += " "; 145 | } 146 | 147 | std::transform(output.begin(), output.end(), output.begin(), ::toupper); 148 | return output; 149 | } 150 | 151 | std::string CANIDAsString() 152 | { 153 | std::string output; 154 | char temp[32]; 155 | 156 | sprintf_s(temp, 32, "%05lx", MessageID); 157 | output += temp; 158 | output += " "; 159 | 160 | std::transform(output.begin(), output.end(), output.begin(), ::toupper); 161 | return output; 162 | } 163 | 164 | std::string CounterAsStringHex() 165 | { 166 | std::string output; 167 | char temp[32]; 168 | 169 | sprintf_s(temp, 32, "%01x", MessageCounter); 170 | output += temp; 171 | output += " "; 172 | 173 | std::transform(output.begin(), output.end(), output.begin(), ::toupper); 174 | return output; 175 | } 176 | 177 | std::string MessageBufferAsString() 178 | { 179 | std::string output; 180 | char temp[32]; 181 | 182 | for (int_fast8_t i = 0; i < MessageLength; i++) 183 | { 184 | sprintf_s(temp, 32, "%02x", MessageBuffer[i]); 185 | output += temp; 186 | } 187 | 188 | std::transform(output.begin(), output.end(), output.begin(), ::toupper); 189 | return output; 190 | } 191 | 192 | std::string MessageBufferAsStringSpaced() 193 | { 194 | std::string output; 195 | char temp[32]; 196 | 197 | for (int_fast8_t i = 0; i < MessageLength; i++) 198 | { 199 | sprintf_s(temp, 32, "%02x", MessageBuffer[i]); 200 | output += temp; 201 | output += " "; 202 | } 203 | 204 | std::transform(output.begin(), output.end(), output.begin(), ::toupper); 205 | return output; 206 | } 207 | 208 | uint64_t MessageBufferAsInteger() 209 | { 210 | uint64_t ret = 0; 211 | for (int_fast8_t i = 0; i < MessageLength; i++) 212 | { 213 | ret = ret + ((uint64_t)(MessageBuffer[i]) << (56 - (i * 8))); 214 | } 215 | return ret; 216 | } 217 | 218 | uint64_t MessageBufferAsIntegerBigEndian() 219 | { 220 | uint64_t ret = 0; 221 | for (int_fast8_t i = 0; i < MessageLength; i++) 222 | { 223 | ret = ret + ((uint64_t)(MessageBuffer[i]) << (i * 8)); 224 | } 225 | return ret; 226 | } 227 | 228 | protected: 229 | uint32_t CanIDPrefix = 0x10000000; 230 | uint32_t CanIDMessageMask = 0x00FFFFF0; 231 | uint32_t CanIDMessageOffset = 4; 232 | uint32_t CanIDCounterMask = 0x0000000F; 233 | uint32_t CanIDCounterOffset = 0; 234 | }; 235 | 236 | #endif //__BOOSTEDCANMSGH__ 237 | -------------------------------------------------------------------------------- /CAN/BoostedBreakCAN/main.cpp: -------------------------------------------------------------------------------- 1 | /*** 2 | * BoostedBreak - BoostedBreakCAN Program 3 | * 4 | * main.cpp 5 | * 6 | * Author: Alexander Krysl (axkrysl47) 7 | * Date: 2022/04/03 8 | **/ 9 | 10 | #include "stdafx.h" 11 | #include "ConsoleInterface.h" 12 | #include "PCANBasicDriver.h" 13 | #include "BoostedBreakCAN.h" 14 | 15 | #define BOOSTEDBREAKCAN_TITLE "BoostedBreak - BoostedBreakCAN " 16 | #define BOOSTEDBREAKCAN_AUTHOR "- Created by Alexander Krysl (axkrysl47) " 17 | #define BOOSTEDBREAKCAN_VERSION "v0.0.2" 18 | 19 | #define CURSOR_TRANSMITMODE_ACTIVE 86, 1 20 | 21 | void printTableHeader(BoostedBreakCAN* program); 22 | void printTableHeaderTransmitMode(BoostedBreakCAN* program); 23 | 24 | int main() 25 | { 26 | char c; 27 | 28 | // Initialize User Interface 29 | ConsoleInit(); 30 | 31 | ConsolePrint(BOOSTEDBREAKCAN_TITLE); 32 | ConsolePrint(BOOSTEDBREAKCAN_AUTHOR); 33 | ConsolePrint(BOOSTEDBREAKCAN_VERSION); 34 | ConsolePrint("\n"); 35 | 36 | // Initialize CAN Driver 37 | PCANBasicDriver* driver = new PCANBasicDriver(PCAN_USBBUS1, PCAN_BAUD_250K, true); 38 | if (driver->GetIsInitialized() == false) 39 | { 40 | ConsolePrint("PCAN-Basic could not initialize. Please check the defines in the code.\n"); 41 | ConsolePrint("Press any key to exit . . .\n"); 42 | 43 | c = ConsoleInput(); 44 | delete driver; 45 | return 0; 46 | } 47 | 48 | // Initialize CAN Driver Trace Configuration 49 | driver->ConfigureTrace(false, true, true, false, 2, 50 | "C:\\BoostedBreak\\BoostedBreakCAN\\TraceFiles", 51 | 250); 52 | if (driver->GetIsTraceConfigured() == false) 53 | { 54 | ConsolePrint("PCAN-Basic could not configure trace. Please check the defines in the code.\n"); 55 | ConsolePrint("Press Escape to exit, or press any other button to continue . . .\n"); 56 | 57 | c = ConsoleInput(); 58 | if (c == 27) 59 | { 60 | delete driver; 61 | return 0; 62 | } 63 | } 64 | else 65 | { 66 | ConsolePrint("PCAN-Basic successfully initialized.\n"); 67 | ConsolePause(); 68 | } 69 | 70 | driver->SetDriverThreadErrorLogging(false); 71 | driver->StartTrace(); 72 | driver->StartDriverThread(); 73 | ConsoleClear(); 74 | 75 | // Initialize BoostedBreakCAN Program 76 | BoostedBreakCAN* program = new BoostedBreakCAN(driver); 77 | 78 | printTableHeader(program); 79 | program->SetViewMode(VIEWMODE_TABLE); 80 | program->StartControlThread(); 81 | 82 | // Control Loop 83 | while (true) 84 | { 85 | c = _getch(); 86 | if (c == 65 || c == 97) // A key 87 | { 88 | program->SetViewMode(VIEWMODE_STREAM); 89 | } 90 | else if (c == 83 || c == 115) // S key 91 | { 92 | if (program->SetViewMode(VIEWMODE_TABLE) == true) 93 | { 94 | printTableHeader(program); 95 | } 96 | } 97 | else if (c == 68 || c == 100) // D key 98 | { 99 | program->SetViewMode(VIEWMODE_BRIEF); 100 | } 101 | else if (c == 81 || c == 113) // Q key 102 | { 103 | if (program->SetTransmitMode(TRANSMITMODE_NONE) == true) 104 | { 105 | printTableHeaderTransmitMode(program); 106 | } 107 | } 108 | else if (c == 87 || c == 119) // W key 109 | { 110 | if (program->SetTransmitMode(TRANSMITMODE_PINGONLY) == true) 111 | { 112 | printTableHeaderTransmitMode(program); 113 | } 114 | } 115 | else if (c == 69 || c == 101) // E key 116 | { 117 | if (program->SetTransmitMode(TRANSMITMODE_PINGPOWEROFF) == true) 118 | { 119 | printTableHeaderTransmitMode(program); 120 | } 121 | } 122 | else if (c == 82 || c == 114) // R key 123 | { 124 | if (program->SetTransmitMode(TRANSMITMODE_EMULATEESC) == true) 125 | { 126 | printTableHeaderTransmitMode(program); 127 | } 128 | } 129 | else if (c == 84 || c == 116) // T key 130 | { 131 | if (program->SetTransmitMode(TRANSMITMODE_EMULATESRB) == true) 132 | { 133 | printTableHeaderTransmitMode(program); 134 | } 135 | } 136 | else if (c == 89 || c == 121) // Y key 137 | { 138 | if (program->SetTransmitMode(TRANSMITMODE_EMULATEXRB) == true) 139 | { 140 | printTableHeaderTransmitMode(program); 141 | } 142 | } 143 | else if (c == 85 || c == 117) // U key 144 | { 145 | if (program->SetTransmitMode(TRANSMITMODE_BEAMBREAKSRB) == true) 146 | { 147 | printTableHeaderTransmitMode(program); 148 | } 149 | } 150 | else if (c == 46 || c == 62 ) // . key 151 | { 152 | program->DebugCommand(); 153 | } 154 | else if (c == 27) // Escape key 155 | { 156 | break; 157 | } 158 | } 159 | 160 | // De-initialize Program. 161 | ConsolePrint("\n"); 162 | program->StopControlThread(); 163 | driver->StopDriverThread(); 164 | delete program; 165 | delete driver; 166 | return 0; 167 | } 168 | 169 | void printTableHeader(BoostedBreakCAN* program) 170 | { 171 | SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), { 0, 0 }); 172 | ConsolePrint(BOOSTEDBREAKCAN_TITLE); 173 | ConsolePrint(BOOSTEDBREAKCAN_VERSION); 174 | ConsolePrint(" Press [Escape] to Exit. \n"); 175 | ConsolePrint("View Modes: Stream[A] | Table[S] | Brief[D] |-| Active Transmit Mode: \n"); 176 | ConsolePrint("Transmit Modes: None[Q] | ESC Ping[W] | ESC Power Off[E] | Emulate ESC[R] | Emulate SRB[T] | Emulate XRB[Y] | BeamBreak SRB[U]\n"); 177 | 178 | printTableHeaderTransmitMode(program); 179 | } 180 | 181 | void printTableHeaderTransmitMode(BoostedBreakCAN* program) 182 | { 183 | uint8_t transmitMode = program->GetTransmitMode(); 184 | 185 | if (transmitMode == TRANSMITMODE_NONE) 186 | { 187 | ConsolePrint("Off ", CURSOR_TRANSMITMODE_ACTIVE); 188 | } 189 | else if (transmitMode == TRANSMITMODE_PINGONLY) 190 | { 191 | ConsolePrint("Pinging... ", CURSOR_TRANSMITMODE_ACTIVE); 192 | } 193 | else if (transmitMode == TRANSMITMODE_PINGPOWEROFF) 194 | { 195 | ConsolePrint("Pinging Power Off... ", CURSOR_TRANSMITMODE_ACTIVE); 196 | } 197 | else if (transmitMode == TRANSMITMODE_EMULATEESC) 198 | { 199 | ConsolePrint("Emulating ESC... ", CURSOR_TRANSMITMODE_ACTIVE); 200 | } 201 | else if (transmitMode == TRANSMITMODE_EMULATESRB) 202 | { 203 | ConsolePrint("SRB not yet implemented. ", CURSOR_TRANSMITMODE_ACTIVE); 204 | } 205 | else if (transmitMode == TRANSMITMODE_EMULATEXRB) 206 | { 207 | ConsolePrint("XRB not yet implemented. ", CURSOR_TRANSMITMODE_ACTIVE); 208 | } 209 | else if (transmitMode == TRANSMITMODE_BEAMBREAKSRB) 210 | { 211 | ConsolePrint("Emulating SRB (BeamBreak)...", CURSOR_TRANSMITMODE_ACTIVE); 212 | } 213 | } 214 | -------------------------------------------------------------------------------- /CAN/BoostedBreakCAN/BoostedBreakCAN.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 16.0 23 | Win32Proj 24 | {de08ae69-04bd-43ea-8602-b6d5528d690b} 25 | LookUpChannel 26 | 10.0 27 | BoostedBreakCAN 28 | 29 | 30 | 31 | Application 32 | true 33 | v142 34 | Unicode 35 | 36 | 37 | Application 38 | false 39 | v142 40 | true 41 | Unicode 42 | 43 | 44 | Application 45 | true 46 | v142 47 | Unicode 48 | 49 | 50 | Application 51 | false 52 | v142 53 | true 54 | Unicode 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | true 76 | 77 | 78 | false 79 | 80 | 81 | true 82 | 83 | 84 | false 85 | 86 | 87 | 88 | Level3 89 | true 90 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 91 | true 92 | 93 | 94 | Console 95 | true 96 | 97 | 98 | 99 | 100 | Level3 101 | true 102 | true 103 | true 104 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 105 | true 106 | 107 | 108 | Console 109 | true 110 | true 111 | true 112 | 113 | 114 | 115 | 116 | Level3 117 | true 118 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 119 | true 120 | 121 | 122 | Console 123 | true 124 | 125 | 126 | 127 | 128 | Level3 129 | true 130 | true 131 | true 132 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 133 | true 134 | 135 | 136 | Console 137 | true 138 | true 139 | true 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | -------------------------------------------------------------------------------- /CAN/BoostedBreakCAN/PCANBasicDriver.h: -------------------------------------------------------------------------------- 1 | /*** 2 | * BoostedBreak - BoostedBreakCAN Program 3 | * 4 | * PCANBasicDriver.h 5 | * 6 | * Author: Alexander Krysl (axkrysl47) 7 | * Date: 2022/04/03 8 | **/ 9 | 10 | #pragma once 11 | #include "stdafx.h" 12 | #include "PCANBasic.h" 13 | #include "PCANBasicUtility.h" 14 | #include "PCANBasicParameter.h" 15 | 16 | #ifndef __PCANBASICDRIVERH__ 17 | #define __PCANBASICDRIVERH__ 18 | 19 | #define MESSAGE_QUEUE_SIZE (16) 20 | 21 | class PCANBasicDriver 22 | { 23 | private: 24 | // *** Look Up Channel Variables *** 25 | /// 26 | /// Sets a TPCANDevice value. The input can be numeric, in hexadecimal or decimal format, or as string denoting 27 | /// a TPCANDevice value name. 28 | /// 29 | LPCSTR DeviceType = "PCAN_USB"; 30 | /// 31 | /// Sets value in range of a double. The input can be hexadecimal or decimal format. 32 | /// 33 | LPCSTR DeviceID = ""; 34 | /// 35 | /// Sets a zero-based index value in range of a double. The input can be hexadecimal or decimal format. 36 | /// 37 | LPCSTR ControllerNumber = ""; 38 | /// 39 | /// Sets a valid Internet Protocol address 40 | /// 41 | LPCSTR IPAddress = ""; 42 | 43 | // *** PCAN-Basic Variables *** 44 | /// 45 | /// Sets the PCANHandle (Hardware Channel) 46 | /// 47 | TPCANHandle PcanHandle = PCAN_USBBUS1; 48 | /// 49 | /// Sets the desired connection mode (CAN = false / CAN-FD = true) 50 | /// 51 | bool IsFD = false; 52 | /// 53 | /// Sets the bitrate for normal CAN devices 54 | /// 55 | TPCANBaudrate Bitrate = PCAN_BAUD_250K; 56 | /// 57 | /// Sets the bitrate for CAN FD devices. 58 | /// Example - Bitrate Nom: 1Mbit/s Data: 2Mbit/s: 59 | /// "f_clock_mhz=20, nom_brp=5, nom_tseg1=2, nom_tseg2=1, nom_sjw=1, data_brp=2, data_tseg1=3, data_tseg2=1, data_sjw=1" 60 | /// 61 | TPCANBitrateFD BitrateFD = const_cast("f_clock_mhz=20, nom_brp=5, nom_tseg1=2, nom_tseg2=1, nom_sjw=1, data_brp=2, data_tseg1=3, data_tseg2=1, data_sjw=1"); 62 | 63 | // *** Trace File Variables *** 64 | /// 65 | /// Sets if trace continue after reaching maximum size for the first file 66 | /// 67 | bool TraceFileSingle = false; 68 | /// 69 | /// Set if date will be add to filename 70 | /// 71 | bool TraceFileDate = true; 72 | /// 73 | /// Set if time will be add to filename 74 | /// 75 | bool TraceFileTime = true; 76 | /// 77 | /// Set if existing tracefile overwrites when a new trace session is started 78 | /// 79 | bool TraceFileOverwrite = false; 80 | /// 81 | /// Sets the size (megabyte) of an tracefile 82 | /// Example - 100 = 100 megabyte 83 | /// Range between 1 and 100 84 | /// 85 | UINT32 TraceFileSize = 2; 86 | /// 87 | /// Sets a fully-qualified and valid path to an existing directory. In order to use the default path 88 | /// (calling process path) an empty string must be set. 89 | /// 90 | LPCSTR TracePath = "C:\\BoostedBreak\\BoostedBreakCAN\\TraceFiles"; 91 | /// 92 | /// Timerinterval (ms) for reading 93 | /// 94 | int TimerInterval = 250; 95 | 96 | /// *** Listening Thread Variables *** 97 | /// 98 | /// Thread for reading messages 99 | /// 100 | std::thread* m_DriverThread; 101 | /// 102 | /// Shows if thread run 103 | /// 104 | bool m_DriverThreadActive; 105 | 106 | /// *** Message Queue Variables *** 107 | /// 108 | /// Structure to receive messages 109 | /// 110 | std::deque* m_ReceiveQueue; 111 | /// 112 | /// Structure to receive messages in FD mode 113 | /// 114 | std::deque* m_ReceiveQueueFD; 115 | 116 | /// 117 | /// Structure to transmit messages 118 | /// 119 | std::deque* m_TransmitQueue; 120 | /// 121 | /// Structure to transmit messages in FD mode 122 | /// 123 | std::deque* m_TransmitQueueFD; 124 | 125 | /// 126 | /// Flag declaring if Driver Thread can log errors to output 127 | /// 128 | bool m_DriverThreadErrorLogFlag; 129 | /// 130 | /// Flag declaring if PCAN-Basic Module is initialized 131 | /// 132 | bool m_IsInitialized = false; 133 | /// 134 | /// Flag declaring if PCAN-Basic Tracing is initialized 135 | /// 136 | bool m_IsTraceConfigured = false; 137 | 138 | public: 139 | // PCAN-Basic Class constructor 140 | // 141 | PCANBasicDriver(TPCANHandle handle, TPCANBaudrate bitrate, bool showOutput); 142 | 143 | // PCAN-Basic Class destructor 144 | // 145 | ~PCANBasicDriver(); 146 | 147 | /// 148 | /// Describing if PCAN-Basic Module is initialized 149 | /// 150 | bool GetIsInitialized(); 151 | /// 152 | /// Describing if PCAN-Basic Module is initialized 153 | /// 154 | bool GetIsTraceConfigured(); 155 | 156 | /// 157 | /// Sets Driver Thread error logging flag 158 | /// 159 | bool SetDriverThreadErrorLogging(bool flag); 160 | 161 | /// 162 | /// Explicitly configures Trace variables 163 | /// 164 | bool ConfigureTrace(bool singleFileOnly, bool showDate, bool showTime, bool overwriteEnabled, 165 | uint32_t fileSizeMegabytes, LPCSTR path, int32_t interval); 166 | 167 | /// 168 | /// Retrieves current PCAN-Basic Driver Status. 169 | /// 170 | TPCANStatus GetDriverStatus(); 171 | 172 | /// 173 | /// Starts the PCAN-Basic Driver thread 174 | /// 175 | bool StartDriverThread(); 176 | /// 177 | /// Stops the PCAN-Basic Driver thread 178 | /// 179 | bool StopDriverThread(); 180 | 181 | /// 182 | /// Acquires CAN message from receive queue 183 | /// 184 | bool Receive(TPCANMsg* msgCanMessage); 185 | /// 186 | /// Acquires CAN FD message from receive queue 187 | /// 188 | bool ReceiveFD(TPCANMsgFD* msgCanMessageFD); 189 | /// 190 | /// Inserts CAN message into transmit queue 191 | /// 192 | bool Transmit(TPCANMsg msgCanMessage); 193 | /// 194 | /// Inserts CAN FD message into transmit queue 195 | /// 196 | bool TransmitFD(TPCANMsgFD msgCanMessageFD); 197 | /// 198 | /// Transmits a CAN message immediately - WARNING: May disrupt Driver Thread 199 | /// 200 | TPCANStatus TransmitImmediate(TPCANMsg msgCanMessage); 201 | /// 202 | /// Transmits a CAN Flexible Data message immediately - WARNING: May disrupt Driver Thread 203 | /// 204 | TPCANStatus TransmitImmediateFD(TPCANMsgFD msgCanMessageFD); 205 | 206 | /// 207 | /// Activates the PCAN-Basic tracing process 208 | /// 209 | /// Returns true if no error occurr 210 | bool StartTrace(); 211 | /// 212 | /// Deactivates the PCAN-Basic tracing process 213 | /// 214 | void StopTrace(); 215 | 216 | /// 217 | /// Looks up available PCAN-Basic Channels 218 | /// 219 | void TestLookUpChannels(); 220 | /// 221 | /// Explicitly sets pre-defined parameters 222 | /// 223 | void TestGetSetParameter(); 224 | /// 225 | /// Tests writing messages over PCAN-Basic 226 | /// 227 | void TestManualWrite(); 228 | /// 229 | /// Begins Trace File routine. 230 | /// 231 | void TestTraceFiles(); 232 | 233 | private: 234 | /// 235 | /// Thread function for processing received and to-transmit messages 236 | /// 237 | void DriverThreadProcess(); 238 | /// 239 | /// Reads available PCAN-Basic messages 240 | /// 241 | void ReceiveProcess(); 242 | /// 243 | /// Transmits queued PCAN-Basic messages 244 | /// 245 | void TransmitProcess(); 246 | 247 | /// 248 | /// Configures the way how trace files are formatted 249 | /// 250 | bool SetTraceConfiguration(); 251 | 252 | /// 253 | /// Shows/prints the configurable parameters for this sample and information about them 254 | /// 255 | void ShowConfigurationHelp(); 256 | 257 | /// 258 | /// Shows/prints the configured paramters 259 | /// 260 | void ShowCurrentConfiguration(); 261 | }; 262 | 263 | #endif //__PCANBASICDRIVERH__ 264 | -------------------------------------------------------------------------------- /CAN/BoostedBreakCAN/PCANBasicUtility.h: -------------------------------------------------------------------------------- 1 | /*** 2 | * BoostedBreak - BoostedBreakCAN Program 3 | * 4 | * PCANBasicUtility.h 5 | * 6 | * Author: Alexander Krysl (axkrysl47) 7 | * Date: 2022/04/03 8 | **/ 9 | 10 | #pragma once 11 | #include "stdafx.h" 12 | #include "PCANBasic.h" 13 | 14 | #ifndef __PCANBASICUTILITYH__ 15 | #define __PCANBASICUTILITYH__ 16 | 17 | static void PCANDebugOutput(std::string str) 18 | { 19 | std::cout << str; 20 | } 21 | 22 | static void PCANDebugSystemPause() 23 | { 24 | system("PAUSE"); 25 | } 26 | 27 | static void PCANDebugSystemClear() 28 | { 29 | system("cls"); 30 | } 31 | 32 | static TPCANMsg CreateTPCANMsg(DWORD id, TPCANMessageType MsgType, BYTE Len, BYTE* Data) 33 | { 34 | TPCANMsg ret; 35 | 36 | ret.ID = id; 37 | ret.MSGTYPE = MsgType; 38 | ret.LEN = Len; 39 | 40 | for (BYTE i = 0; i < 8; i++) 41 | { 42 | if (i < Len) 43 | { 44 | ret.DATA[i] = Data[i]; 45 | } 46 | else 47 | { 48 | ret.DATA[i] = 0x00; 49 | } 50 | } 51 | 52 | return ret; 53 | } 54 | 55 | static TPCANMsg CreateTPCANMsg(uint32_t id, TPCANMessageType MsgType, uint8_t Len, uint64_t Data) 56 | { 57 | TPCANMsg ret; 58 | 59 | ret.ID = (DWORD)id; 60 | ret.MSGTYPE = MsgType; 61 | ret.LEN = (BYTE)Len; 62 | 63 | for (uint8_t i = 0; i < 8; i++) 64 | { 65 | if (i < Len) 66 | { 67 | ret.DATA[i] = (BYTE)((Data >> ((Len - i - 1) * 8)) & 0xFF); 68 | } 69 | else 70 | { 71 | ret.DATA[i] = (BYTE)0x00; 72 | } 73 | } 74 | 75 | return ret; 76 | } 77 | 78 | /// 79 | /// Help Function used to get an error as text 80 | /// 81 | /// Error code to be translated 82 | /// A string buffer for the translated error (size MAX_PATH) 83 | static void GetFormattedError(TPCANStatus error, LPSTR buffer) 84 | { 85 | // Gets the text using the GetErrorText API function. If the function success, the translated error is returned. 86 | // If it fails, a text describing the current error is returned. 87 | if (CAN_GetErrorText(error, 0x09, buffer) != PCAN_ERROR_OK) 88 | sprintf_s(buffer, MAX_PATH, "An error occurred. Error-code's text (%Xh) couldn't be retrieved", error); 89 | } 90 | 91 | /// 92 | /// Shows formatted status 93 | /// 94 | /// Will be formatted 95 | static void ShowStatus(TPCANStatus status) 96 | { 97 | PCANDebugOutput("=========================================================================================\n"); 98 | char buffer[MAX_PATH]; 99 | GetFormattedError(status, buffer); 100 | PCANDebugOutput(buffer); 101 | PCANDebugOutput("\n"); 102 | PCANDebugOutput("=========================================================================================\n"); 103 | } 104 | 105 | /// 106 | /// Gets name of a TPCANHandle 107 | /// 108 | /// TPCANHandle to get name 109 | /// A string buffer for the name of the TPCANHandle (size MAX_PATH) 110 | static void GetTPCANHandleName(TPCANHandle handle, LPSTR buffer) 111 | { 112 | strcpy_s(buffer, MAX_PATH, "PCAN_NONE"); 113 | switch (handle) 114 | { 115 | case PCAN_PCIBUS1: 116 | case PCAN_PCIBUS2: 117 | case PCAN_PCIBUS3: 118 | case PCAN_PCIBUS4: 119 | case PCAN_PCIBUS5: 120 | case PCAN_PCIBUS6: 121 | case PCAN_PCIBUS7: 122 | case PCAN_PCIBUS8: 123 | case PCAN_PCIBUS9: 124 | case PCAN_PCIBUS10: 125 | case PCAN_PCIBUS11: 126 | case PCAN_PCIBUS12: 127 | case PCAN_PCIBUS13: 128 | case PCAN_PCIBUS14: 129 | case PCAN_PCIBUS15: 130 | case PCAN_PCIBUS16: 131 | strcpy_s(buffer, MAX_PATH, "PCAN_PCI"); 132 | break; 133 | 134 | case PCAN_USBBUS1: 135 | case PCAN_USBBUS2: 136 | case PCAN_USBBUS3: 137 | case PCAN_USBBUS4: 138 | case PCAN_USBBUS5: 139 | case PCAN_USBBUS6: 140 | case PCAN_USBBUS7: 141 | case PCAN_USBBUS8: 142 | case PCAN_USBBUS9: 143 | case PCAN_USBBUS10: 144 | case PCAN_USBBUS11: 145 | case PCAN_USBBUS12: 146 | case PCAN_USBBUS13: 147 | case PCAN_USBBUS14: 148 | case PCAN_USBBUS15: 149 | case PCAN_USBBUS16: 150 | strcpy_s(buffer, MAX_PATH, "PCAN_USB"); 151 | break; 152 | 153 | case PCAN_LANBUS1: 154 | case PCAN_LANBUS2: 155 | case PCAN_LANBUS3: 156 | case PCAN_LANBUS4: 157 | case PCAN_LANBUS5: 158 | case PCAN_LANBUS6: 159 | case PCAN_LANBUS7: 160 | case PCAN_LANBUS8: 161 | case PCAN_LANBUS9: 162 | case PCAN_LANBUS10: 163 | case PCAN_LANBUS11: 164 | case PCAN_LANBUS12: 165 | case PCAN_LANBUS13: 166 | case PCAN_LANBUS14: 167 | case PCAN_LANBUS15: 168 | case PCAN_LANBUS16: 169 | strcpy_s(buffer, MAX_PATH, "PCAN_LAN"); 170 | break; 171 | 172 | default: 173 | strcpy_s(buffer, MAX_PATH, "UNKNOWN"); 174 | break; 175 | } 176 | } 177 | 178 | static void FormatChannelName(TPCANHandle handle, LPSTR buffer, bool isFD) 179 | { 180 | TPCANDevice devDevice; 181 | BYTE byChannel; 182 | 183 | // Gets the owner device and channel for a PCAN-Basic handle 184 | if (handle < 0x100) 185 | { 186 | devDevice = (TPCANDevice)(handle >> 4); 187 | byChannel = (BYTE)(handle & 0xF); 188 | } 189 | else 190 | { 191 | devDevice = (TPCANDevice)(handle >> 8); 192 | byChannel = (BYTE)(handle & 0xFF); 193 | } 194 | 195 | // Constructs the PCAN-Basic Channel name and return it 196 | char handleBuffer[MAX_PATH]; 197 | GetTPCANHandleName(handle, handleBuffer); 198 | if (isFD) 199 | sprintf_s(buffer, MAX_PATH, "%s:FD %d (%Xh)", handleBuffer, byChannel, handle); 200 | else 201 | sprintf_s(buffer, MAX_PATH, "%s %d (%Xh)", handleBuffer, byChannel, handle); 202 | } 203 | 204 | /// 205 | /// Converts PCANBasic Define (wchar_t*) to char* 206 | /// 207 | /// Define to be converted 208 | /// Define as char* 209 | static char* ConvertDefinesToChar(wchar_t* define) 210 | { 211 | // Convert the wchar_t string to a char* string. Record 212 | // the length of the original string and add 1 to it to 213 | // account for the terminating null character. 214 | size_t origsize = wcslen(define) + 1; 215 | size_t convertedChars = 0; 216 | 217 | // Allocate two bytes in the multibyte output string for every wide 218 | // character in the input string (including a wide character 219 | // null). Because a multibyte character can be one or two bytes, 220 | // you should allot two bytes for each character. Having extra 221 | // space for the new string is not an error, but having 222 | // insufficient space is a potential security problem. 223 | const size_t newsize = origsize * 2; 224 | // The new string will contain a converted copy of the original 225 | // string plus the type of string appended to it. 226 | char* nstring = new char[newsize]; 227 | 228 | // Put a copy of the converted string into nstring 229 | wcstombs_s(&convertedChars, nstring, newsize, define, _TRUNCATE); 230 | return nstring; 231 | } 232 | 233 | /// 234 | /// Convert BYTE value to readable string value 235 | /// 236 | /// 237 | /// 238 | static std::string ConvertDeviceTypeToString(BYTE devicetype) 239 | { 240 | switch (devicetype) 241 | { 242 | case 0: 243 | return "PCAN_NONE"; 244 | case 1: 245 | return "PCAN_PEAKCAN"; 246 | case 2: 247 | return "PCAN_ISA"; 248 | case 3: 249 | return "PCAN_DNG"; 250 | case 4: 251 | return "PCAN_PCI"; 252 | case 5: 253 | return "PCAN_USB"; 254 | case 6: 255 | return "PCAN_PCC"; 256 | case 7: 257 | return "PCAN_VIRTUAL"; 258 | case 8: 259 | return "PCAN_LAN"; 260 | default: 261 | return ""; 262 | } 263 | } 264 | 265 | /// 266 | /// Convert uint value to readable string value 267 | /// 268 | /// 269 | /// 270 | static std::string ConvertToParameterOnOff(UINT32 value) 271 | { 272 | switch (value) 273 | { 274 | case PCAN_PARAMETER_OFF: 275 | return "PCAN_PARAMETER_OFF"; 276 | case PCAN_PARAMETER_ON: 277 | return "PCAN_PARAMETER_ON"; 278 | default: 279 | return "Status unknown: " + std::to_string(value); 280 | } 281 | } 282 | 283 | /// 284 | /// Convert uint value to readable string value 285 | /// 286 | /// 287 | /// 288 | static std::string ConvertToChannelFeatures(UINT32 value) 289 | { 290 | std::string sFeatures = ""; 291 | if ((value & FEATURE_FD_CAPABLE) == FEATURE_FD_CAPABLE) 292 | sFeatures += "FEATURE_FD_CAPABLE"; 293 | if ((value & FEATURE_DELAY_CAPABLE) == FEATURE_DELAY_CAPABLE) 294 | if (sFeatures != "") 295 | sFeatures += ", FEATURE_DELAY_CAPABLE"; 296 | else 297 | sFeatures += "FEATURE_DELAY_CAPABLE"; 298 | if ((value & FEATURE_IO_CAPABLE) == FEATURE_IO_CAPABLE) 299 | if (sFeatures != "") 300 | sFeatures += ", FEATURE_IO_CAPABLE"; 301 | else 302 | sFeatures += "FEATURE_IO_CAPABLE"; 303 | return sFeatures; 304 | } 305 | 306 | /// 307 | /// Convert uint value to readable string value 308 | /// 309 | /// 310 | /// 311 | static std::string ConvertToChannelCondition(UINT32 value) 312 | { 313 | switch (value) 314 | { 315 | case PCAN_CHANNEL_UNAVAILABLE: 316 | return "PCAN_CHANNEL_UNAVAILABLE"; 317 | case PCAN_CHANNEL_AVAILABLE: 318 | return "PCAN_CHANNEL_AVAILABLE"; 319 | case PCAN_CHANNEL_OCCUPIED: 320 | return "PCAN_CHANNEL_OCCUPIED"; 321 | case PCAN_CHANNEL_PCANVIEW: 322 | return "PCAN_CHANNEL_PCANVIEW"; 323 | default: 324 | return "Status unknow: " + std::to_string(value); 325 | } 326 | } 327 | 328 | /// 329 | /// Convert uint value to readable string value 330 | /// 331 | /// 332 | /// 333 | static std::string ConvertToFilterOpenCloseCustom(UINT32 value) 334 | { 335 | switch (value) 336 | { 337 | case PCAN_FILTER_CLOSE: 338 | return "PCAN_FILTER_CLOSE"; 339 | case PCAN_FILTER_OPEN: 340 | return "PCAN_FILTER_OPEN"; 341 | case PCAN_FILTER_CUSTOM: 342 | return "PCAN_FILTER_CUSTOM"; 343 | default: 344 | return "Status unknown: " + std::to_string(value); 345 | } 346 | } 347 | 348 | /// 349 | /// Convert bitrate c_short value to readable string 350 | /// 351 | /// Bitrate to be converted 352 | /// A string buffer for the converted bitrate (size MAX_PATH) 353 | static void ConvertBitrateToString(TPCANBaudrate bitrate, LPSTR buffer) 354 | { 355 | switch (bitrate) 356 | { 357 | case PCAN_BAUD_1M: 358 | strcpy_s(buffer, MAX_PATH, "1 MBit/sec"); 359 | break; 360 | case PCAN_BAUD_800K: 361 | strcpy_s(buffer, MAX_PATH, "800 kBit/sec"); 362 | break; 363 | case PCAN_BAUD_500K: 364 | strcpy_s(buffer, MAX_PATH, "500 kBit/sec"); 365 | break; 366 | case PCAN_BAUD_250K: 367 | strcpy_s(buffer, MAX_PATH, "250 kBit/sec"); 368 | break; 369 | case PCAN_BAUD_125K: 370 | strcpy_s(buffer, MAX_PATH, "125 kBit/sec"); 371 | break; 372 | case PCAN_BAUD_100K: 373 | strcpy_s(buffer, MAX_PATH, "100 kBit/sec"); 374 | break; 375 | case PCAN_BAUD_95K: 376 | strcpy_s(buffer, MAX_PATH, "95,238 kBit/sec"); 377 | break; 378 | case PCAN_BAUD_83K: 379 | strcpy_s(buffer, MAX_PATH, "83,333 kBit/sec"); 380 | break; 381 | case PCAN_BAUD_50K: 382 | strcpy_s(buffer, MAX_PATH, "50 kBit/sec"); 383 | break; 384 | case PCAN_BAUD_47K: 385 | strcpy_s(buffer, MAX_PATH, "47,619 kBit/sec"); 386 | break; 387 | case PCAN_BAUD_33K: 388 | strcpy_s(buffer, MAX_PATH, "33,333 kBit/sec"); 389 | break; 390 | case PCAN_BAUD_20K: 391 | strcpy_s(buffer, MAX_PATH, "20 kBit/sec"); 392 | break; 393 | case PCAN_BAUD_10K: 394 | strcpy_s(buffer, MAX_PATH, "10 kBit/sec"); 395 | break; 396 | case PCAN_BAUD_5K: 397 | strcpy_s(buffer, MAX_PATH, "5 kBit/sec"); 398 | break; 399 | default: 400 | strcpy_s(buffer, MAX_PATH, "Unknown Bitrate"); 401 | break; 402 | } 403 | } 404 | 405 | /// 406 | /// Convert bool value to readable string value 407 | /// 408 | /// Value to be converted 409 | /// A text with the converted Value 410 | static std::string ConvertBoolToString(bool value) 411 | { 412 | switch (value) 413 | { 414 | case false: 415 | return "false"; 416 | case true: 417 | return "true"; 418 | } 419 | } 420 | 421 | #endif 422 | -------------------------------------------------------------------------------- /CAN/BoostedCANMessageTable.md: -------------------------------------------------------------------------------- 1 | # Boosted CAN Message Table 2 | The following is representation of all reverse-engineered CAN messages on the latest Boosted V2/3 battery & electronic speed controller firmwares. 3 | 4 | ## Template Message 5 | * CAN ID: `0x10 [Header : 20 bits] [Counter : 4 bits]` 6 | * LENGTH: `[Len]` 7 | * DATA: `[D0] [D1] [D2] [D3] [D4] [D5] [D6] [D7]` 8 | 9 | ## Message Table 10 | | Header | Source | Len | Context | Description | Interpretation | 11 | |:-------:|:-------:|:---:|:---------:|:--------------------------- |:--------------------------------------------------------------------------------------------------------------------------------------- | 12 | |`0x02402`| ESC | `8` | Event | Version / Serial (to SRB) | `v[D6].[D7].[D0]` / `BoostedBoard[D5][D4][D3][D2][D1]` | 13 | |`0x02411`| SRB | `8` | Event | Debug Message (Continued) | ASCII Message | 14 | |`0x05415`| XRB | `8` | Event | Version Registration | `v[D2].[D3].[D4]` / `[D6:7]` = `[BTY Code]` | 15 | |`0x12402`| SRB | `1` | Event | Software/Hardware Release? | IF `[D0]` == `02`, Public? | 16 | |`0x12411`| SRB | `8` | Event | Debug Message (End) | ASCII Message | 17 | |`0x13417`| XRB | `8` | 20 ms | Debug Code (End) | Unknown (Null-terminated coded string?) | 18 | |`0x15415`| XRB | `3` | Event | Software/Hardware Release? | IF `[D2]` == `02`, Public? | 19 | |`0x22402`| SRB | `8` | Event | Unknown (Incrementer?) | `[D3:0]` = `int32_t`? / `[D4]` = `03` | 20 | |`0x22411`| SRB | `8` | Event | Debug Message (Start) | ASCII Message | 21 | |`0x23417`| XRB | `8` | 20 ms | Debug Code (Start) | Unknown (Null-terminated coded string?) | 22 | |`0x25415`| XRB | `8` | Event | Serial Registration | `BoostedBattery[D2][D3][D4][D5]` | 23 | |`0x32411`| SRB | `8` | Event | Debug Message (Address) | ASCII Message | 24 | |`0x33417`| XRB | * | Event | Registration State (to ESC) | IF `[D0:1]` == `010A`, Standby ------------------------------------------ IF `[D0:6]` == `007D0064006400`, Registration Request; [_See notes below_](#table-notes) | 25 | |`0x33440`| BTY | `8` | Event | Version | `v[D0].[D1].[D2]` | 26 | |`0x33441`| BTY | `8` | Event | Serial | `BoostedBattery[D0][D1][D2][D3]` | 27 | |`0x33442`| BTY | `8` | 250 ms | Ping | `[D2:3]` = `[BTY Code]` | 28 | |`0x33443`| BTY | `8` | 250 ms | Indentifier | IF `[D0:7]` == `D20FCA080C000000`, SRB ID ----------------------------- IF `[D0:7]` == `8110C4090D000000`, XRB ID | 29 | |`0x33445`| BTY | `8` | 20 ms | Voltages (mV) | `[D1:0]` = Lowest Cell Voltage - `[D3:2]` = Highest Cell Voltage - `[D7:4]` = Total Pack Voltage | 30 | |`0x33446`| BTY | `8` | 20 ms | Unknown (Calibration?) | `[D3:0]` = `int32_t`? / `[D7:4]` = `int32_t`? | 31 | |`0x33447`| BTY | `8` | 250 ms | Amperages (mA) | `[D3:0]` = 10 second Average Current --------------------------------- `[D7:4]` = Instantaneous Current; [_See notes below_](#table-notes) | 32 | |`0x33448`| BTY | `8` | 20 ms | Unknown (Counter?) | [_See example below_](#message-examples) | 33 | |`0x33449`| BTY | `8` | 250 ms | State of Charge | `[D4]` = Percentage; [_See example below_](#message-examples) | 34 | |`0x3344A`| BTY | `8` | 100 ms | State / Timer / Millis(LSB) | [_See example below_](#message-examples) | 35 | |`0x3344C`| SRB | `8` | Event | Button State | [_See example below_](#message-examples) | 36 | |`0x3344E`| BTY | `8` | 1000 ms | Current Timestamp | `[D6]` / `[D5]` / `[D3]`, `[D4]`, `[D2]` : `[D1]` : `[D0]` ------------------- = YYYY / MM / DD, DoW, HH : MM : SS; [_See example below_](#message-examples) | 37 | |`0x34316`| ESC | `3` | Event | Registration State (to BTY) | IF `[D0:2]` == `010C00`, BTY Registration Command ------------------ IF `[D0:2]` == `020600`, ESC Registration Notification | 38 | |`0x34344`| ESC | `8` | Event | Version / Serial (to BTY) | `v[D2].[D1].[D0]` / `BoostedBoard[D7][D6][D5][D4][D3]` | 39 | |`0x3434B`| ESC | `8` | 100 ms | Ping / Power Command | IF `[D0]` == `00`, Ping --------------------------------------------------- IF `[D0]` == `02`, Power Off (via Remote Command) | 40 | |`0x3434D`| SRB | `8` | 1000 ms* | Pairing State | IF `[D0:1]` == `0000`, Not Pairing -------------------------------------- IF `[D0:1]` == `01D7`, Pairing Mode; [_See notes below_](#table-notes) | 41 | |`0x3B31A`| ESC | `3` | Event | Mode | [_See example below_](#message-examples) | 42 | |`0x3B41A`| XRB | `8` | Event | Button / Charge State | [_See example below_](#message-examples) | 43 | |`0x33920`| ACC | `8` | Event | Accessory Registration | [_See example below_](#message-examples) | 44 | |`0x39320`| ESC | `8` | Event | Command (to ACC) | [_See example below_](#message-examples) | 45 | 46 | ### Table Notes 47 | * All numbers above are represented in hexadecimal. 48 | * Where `x < y`, `[Dx:y]` represents a big endian integer, `[Dy:x]` represents a little endian integer. 49 | * BTY denotes both the SRB and/or XRB. 50 | * ACC denotes a connected accessory. 51 | * `[BTY Code]` = `C409` for SRB or `A20F` for XRB. 52 | * `int32_t` & `int16_t` denote 32-bit & 16-bit integers, respectively. 53 | * __XRB Registration State (to ESC)__ has variable payload length. 54 | * __BTY Amperages (mA)__ are represented as negative integers during discharging or as positive integers during charging. 55 | * __SRB Pairing State__ is sent every 1 second if pairing is in progress. 56 | 57 | ## Message Examples 58 | ### `0x33448` - BTY Unknown (Counter?) 59 | ``` 60 | D0 D1 D2 D3 D4 D5 D6 D7 61 | B8 88 00 00 D8 59 00 00 62 | ^^ ^^ ^^ ^^ Counter (Little Endian) - Ex. 0x000059D8 = 23000 63 | ^^ ^^ State - 0x0000 = Unavailable?, 64 | - 0x50C8 = Active (SRB)?, 65 | - 0xB888 = Active (XRB)?, 66 | - 0x5C44 = Error (XRB)?, 67 | ``` 68 | 69 | ### `0x33449` - BTY State of Charge 70 | ``` 71 | D0 D1 D2 D3 D4 D5 D6 D7 72 | E4 0D A2 0F 59 00 05 00 73 | ^^ Charge State - 0x05 = Normal, 74 | 0x03 = `Was charging when last powered`, 75 | 0x06 = Battery Error; 76 | ^^ State of Charge Percentage - Ex. 0x59 = 3556 / 4002 = 89% 77 | ^^ ^^ Denominator (Little Endian) - Ex. 0x0FA2 = 4002 78 | ^^ ^^ Numerator (Little Endian) - Ex. 0x0DE4 = 3556 79 | ``` 80 | 81 | ### `0x3344A` - BTY State / Timer / Millis(LSB) 82 | ``` 83 | D0 D1 D2 D3 D4 D5 D6 D7 84 | 00 00 73 78 00 00 56 00 85 | ^^ Current Timestamp Milliseconds (Least Significant Byte Only) - Ex. 86 ms 86 | ^^ Power State - 0x00 = On (Startup timer), 0x02 = ESC Shutdown Command, 87 | 0x03 = Charger Disconnected, 0x05 = Power Button Held; 88 | ^^ ^^ State Timer Milliseconds (Little Endian) - Ex. 30835 ms left on Startup timer 89 | ^^ Charger Connection State (XRB Only) - 0x00 = Normal, 0x01 = Charger Connected; 90 | ``` 91 | 92 | ### `0x3344C` - SRB Button State 93 | ``` 94 | D0 D1 D2 D3 D4 D5 D6 D7 95 | 0A 00 00 00 00 00 00 00 96 | ^^ Pairing Mode Acknowledgment - 0x00 = Normal, 0x01 = Acknowledged; 97 | ^^ Button State - 0x01 = Was pressed once, 98 | 0x02 = Was pressed twice, 99 | 0x03 = Was pressed three times, 100 | 0x04 = Was pressed four times, 101 | 0x05 = Was pressed five times, 102 | 0x06 = Currently pressed now, 103 | 0x07 = Currently held down for less than 1 second, 104 | 0x08 = Currently held down for less than 2 seconds, 105 | 0x09 = Currently held down for more than 2 seconds, 106 | 0x0A = Was held down for less than 1.5 seconds, 107 | 0x0B = Was held down for less than 2 seconds, 108 | 0x0C = Was held down for more than 2 seconds; 109 | ``` 110 | 111 | ### `0x3344E` - BTY Current Timestamp 112 | Batteries seem to acquire the latest timestamp from the ESC / from the Boosted Phone Application. 113 | 114 | On occasion (likely tied to removing the battery/power source), a board will lose the current timestamp; 115 | in that case, the battery will count up from an all zeroes timestamp. 116 | 117 | ``` 118 | D0 D1 D2 D3 D4 D5 D6 D7 119 | 33 34 10 0B 05 02 16 00 120 | ^^ Year (+ 2000) - Ex. 0x16 = 22 = *2022* 121 | ^^ Month - Ex. 0x02 = 2 = *February* 122 | ^^ Day of Week - 0x00 = Sunday, 0x01 = Monday, 0x02 = Tuesday, 0x03 = Wednesday, 123 | 0x04 = Thursday, 0x05 = Friday, 0x06 Saturday; 124 | *** Day of Week seems to not always be accurate - there maybe a difference between SRB & XRB. *** 125 | ^^ Date - Ex. 0x0B = 11 = *11th* 126 | ^^ Hour - Ex. 0x10 = 16 = *4:00 PM* 127 | ^^ Minute - Ex. 0x34 = 52 128 | ^^ Second - Ex. 0x33 = 51 129 | Complete Example - 2022/02/11, Friday, 04:52:51 PM 130 | ``` 131 | 132 | ### `0x3B31A` - ESC Mode 133 | ``` 134 | D0 D1 D2 135 | 00 04 04 136 | ^^ Current ESC Mode - 0x00 = Mode 1 (Beginner), 137 | 0x01 = Mode 2 (Eco), 138 | 0x02 = Mode 3 (Expert), 139 | 0x03 = Mode 4 (Pro), 140 | 0x04 = Mode 5 (Hyper), 141 | 0x05 = Disengaged (SRB Only - Charging Acknowledgment), 142 | 0x06 = Shutting Down (SRB Only), 143 | 0x15 = Pairing Mode, 144 | 0x16 = Exited Pairing Mode; 145 | ``` 146 | 147 | ### `0x3B41A` - XRB Button / Charge State 148 | ``` 149 | D0 D1 D2 150 | 00 08 04 151 | ^^ Button State - 0x05 = Charging, 152 | 0x06 = Shutting down, 153 | 0x07 = Currently pressed now, 154 | 0x08 = Waiting to finalize button state, 155 | 0x09 = Was pressed once, 156 | 0x0A = Was pressed twice, 157 | 0x0B = Was pressed three times, 158 | 0x0C = Was pressed four times, 159 | 0x0D = Was pressed five times, 160 | 0x0E = Currently held down for less than 1 second, 161 | 0x0F = Currently held down for less than 1.5 seconds, 162 | 0x10 = Currently held down for less than 2 seconds, 163 | 0x11 = Currently held down for less than 2.5 seconds, 164 | 0x12 = Was held down for less than 1.5 seconds, 165 | 0x13 = Was held down for less than 2 seconds, 166 | 0x14 = Was held down for more than 2.5 seconds; 167 | ``` 168 | 169 | ### `0x33920` - ACC Accessory Registration 170 | Using [rscullin's BeamBREak example](https://github.com/rscullin/beambreak/tree/master/Accessory): 171 | ``` 172 | D0 D1 D2 D3 D4 D5 D6 D7 173 | FE 00 00 00 00 01 37 13 174 | ^^ ^^ Accessory Serial Number (Little Endian) - Ex. 0x1337 = BoostedBeams1337 175 | ^^ Accessory Type - 0x00 = Headlights, 0x01 Taillights; 176 | ^^ Accessory Registration Request - 0xFE 177 | ``` 178 | 179 | ### `0x33920` - ESC Command (to ACC) 180 | Using [rscullin's BeamBREak example](https://github.com/rscullin/beambreak/tree/master/Accessory): 181 | ``` 182 | D0 D1 D2 D3 D4 D5 D6 D7 183 | 00 04 22 FF 00 00 00 00 184 | ^^ Command Parameter 2 - Brightness Level 185 | - Headlight Range - 0x00-0xFF or 0-255 186 | - Taillight Range - 0x00-0x33,0x64 or 0-51,100 187 | (Taillight Braking Brightness is 100) 188 | ^^ Command Parameter 1 - Light State 189 | 0x22 = Light On, 0x23 = Light Off, 190 | 0x62 = Blink On, 0x42 = Blink Off; 191 | ^^ Command Type - 0x04 = Light Command 192 | ^^ Accessory Address - 0x00 = First Registered Accessory, 193 | 0x01 = Second Registered Accessory; 194 | ``` 195 | -------------------------------------------------------------------------------- /CAN/BoostedBreakCAN/BoostedBreakCAN.cpp: -------------------------------------------------------------------------------- 1 | /*** 2 | * BoostedBreak - BoostedBreakCAN Program 3 | * 4 | * BoostedBreakCAN.cpp 5 | * 6 | * Author: Alexander Krysl (axkrysl47) 7 | * Date: 2022/04/03 8 | **/ 9 | 10 | #include "BoostedBreakCAN.h" 11 | #include "ConsoleInterface.h" 12 | 13 | #define DISPLAY_TRANSMIT_WITH_RECEIVE 14 | #undef PRINT_TRANSMIT_MODE 15 | 16 | #define TABLE_OFFSET_Y 4 17 | 18 | #define CURSOR_TABLE_ERROR 0, 46 19 | 20 | #define CURSOR_MESSAGE_COUNTER_X 6 21 | #define CURSOR_MESSAGE_LEGNTH_X 8 22 | #define CURSOR_SENDER_DESCRIPTION_X 35 23 | #define CURSOR_INTERPRETATION_X 70 24 | #define CURSOR_TRANSMITTED_X 128 25 | 26 | #define TABLELIST_BREAK_1 14 27 | #define TABLELIST_BREAK_2 30 28 | 29 | #define PING_TIMER_MS 100 30 | #define BEAMBREAK_TIMER_MS 250 31 | #define ESC_BTY_REGISTRATION_COMMAND_TIMER_MS 3000 32 | 33 | #define ESC_VERSION_SERIAL 0x02070201EEFFC047 // ESC v2.7.2, BoostedBoard47C0FFEE 34 | 35 | BoostedBreakCAN::BoostedBreakCAN(PCANBasicDriver* pcan) 36 | { 37 | m_LastPingTime = std::chrono::high_resolution_clock::now(); 38 | m_TransmitStageTime = std::chrono::high_resolution_clock::now(); 39 | m_LastTransmitCounter = 0; 40 | m_ControlThread = nullptr; 41 | 42 | // PCAN-Basic Initialization 43 | m_CommPtr = pcan; 44 | 45 | // Default to Table Mode, not transmitting. 46 | m_ViewMode = VIEWMODE_TABLE; 47 | m_TransmitMode = TRANSMITMODE_NONE; 48 | SetTable(); 49 | 50 | m_TransmitStage = 0; 51 | } 52 | 53 | BoostedBreakCAN::~BoostedBreakCAN() 54 | { 55 | StopControlThread(); 56 | ConsolePrint("\nExiting BoostedBreak - BoostedBreakCAN Program . . .\n"); 57 | } 58 | 59 | bool BoostedBreakCAN::SetViewMode(uint8_t newViewMode) 60 | { 61 | if (newViewMode != m_ViewMode) 62 | { 63 | m_ViewMode = newViewMode; 64 | 65 | if (m_ViewMode == VIEWMODE_STREAM) 66 | { 67 | ConsoleClear(); 68 | ConsoleCursor(CURSOR_TABLE_ERROR); 69 | } 70 | else if (m_ViewMode == VIEWMODE_TABLE) 71 | { 72 | StopControlThread(); 73 | SetTable(); 74 | 75 | std::this_thread::sleep_for(std::chrono::microseconds(1000)); 76 | 77 | StartControlThread(); 78 | } 79 | else if (m_ViewMode == VIEWMODE_BRIEF) 80 | { 81 | // TODO... 82 | ConsoleCursor(CURSOR_TABLE_ERROR); 83 | ConsolePrint(" Brief mode not yet implemented (Pausing previous view mode)."); 84 | } 85 | 86 | return true; 87 | } 88 | 89 | return false; 90 | } 91 | 92 | bool BoostedBreakCAN::SetTransmitMode(uint8_t newTransmitMode) 93 | { 94 | if (newTransmitMode != m_TransmitMode) 95 | { 96 | m_TransmitStage = 0; 97 | 98 | if (newTransmitMode == TRANSMITMODE_NONE) 99 | { 100 | #ifdef PRINT_TRANSMIT_MODE 101 | ConsolePrint("Off ", CURSOR_TRANSMITMODE); 102 | #endif //PRINT_TRANSMIT_MODE 103 | m_TransmitMode = TRANSMITMODE_NONE; 104 | } 105 | else if (newTransmitMode == TRANSMITMODE_PINGONLY) 106 | { 107 | #ifdef PRINT_TRANSMIT_MODE 108 | ConsolePrint("Pinging... ", CURSOR_TRANSMITMODE); 109 | #endif //PRINT_TRANSMIT_MODE 110 | m_TransmitMode = TRANSMITMODE_PINGONLY; 111 | } 112 | else if (newTransmitMode == TRANSMITMODE_PINGPOWEROFF) 113 | { 114 | #ifdef PRINT_TRANSMIT_MODE 115 | ConsolePrint("Pinging Power Off... ", CURSOR_TRANSMITMODE); 116 | #endif //PRINT_TRANSMIT_MODE 117 | m_TransmitMode = TRANSMITMODE_PINGPOWEROFF; 118 | } 119 | else if (newTransmitMode == TRANSMITMODE_EMULATEESC) 120 | { 121 | #ifdef PRINT_TRANSMIT_MODE 122 | ConsolePrint("Emulating ESC... ", CURSOR_TRANSMITMODE); 123 | #endif //PRINT_TRANSMIT_MODE 124 | m_TransmitMode = TRANSMITMODE_EMULATEESC; 125 | } 126 | else if (newTransmitMode == TRANSMITMODE_EMULATESRB) 127 | { 128 | // TODO 129 | #ifdef PRINT_TRANSMIT_MODE 130 | ConsolePrint("SRB not yet implemented. ", CURSOR_TRANSMITMODE); 131 | #endif //PRINT_TRANSMIT_MODE 132 | m_TransmitMode = TRANSMITMODE_EMULATEESC; 133 | } 134 | else if (newTransmitMode == TRANSMITMODE_EMULATEXRB) 135 | { 136 | // TODO 137 | #ifdef PRINT_TRANSMIT_MODE 138 | ConsolePrint("XRB not yet implemented. ", CURSOR_TRANSMITMODE); 139 | #endif //PRINT_TRANSMIT_MODE 140 | m_TransmitMode = TRANSMITMODE_EMULATEESC; 141 | } 142 | else if (newTransmitMode == TRANSMITMODE_BEAMBREAKSRB) 143 | { 144 | #ifdef PRINT_TRANSMIT_MODE 145 | ConsolePrint("Emulating SRB (BeamBreak)...", CURSOR_TRANSMITMODE); 146 | #endif //PRINT_TRANSMIT_MODE 147 | m_TransmitMode = TRANSMITMODE_BEAMBREAKSRB; 148 | } 149 | } 150 | 151 | return true; 152 | } 153 | 154 | bool BoostedBreakCAN::StartControlThread() 155 | { 156 | m_ControlThreadActive = true; 157 | m_ControlThread = new std::thread(&BoostedBreakCAN::ControlThreadProcess, this); 158 | return m_ControlThreadActive; 159 | } 160 | 161 | bool BoostedBreakCAN::StopControlThread() 162 | { 163 | m_ControlThreadActive = false; 164 | if (m_ControlThread != nullptr) 165 | { 166 | m_ControlThread->join(); 167 | } 168 | m_ControlThread = nullptr; 169 | return m_ControlThreadActive; 170 | } 171 | 172 | uint8_t BoostedBreakCAN::GetViewMode() 173 | { 174 | return m_ViewMode; 175 | } 176 | 177 | uint8_t BoostedBreakCAN::GetTransmitMode() 178 | { 179 | return m_TransmitMode; 180 | } 181 | 182 | void BoostedBreakCAN::ControlThreadProcess() 183 | { 184 | while (m_ControlThreadActive) 185 | { 186 | std::this_thread::sleep_for(std::chrono::microseconds(100)); 187 | ProgramControl(); 188 | } 189 | } 190 | 191 | void BoostedBreakCAN::ProgramControl() 192 | { 193 | TPCANStatus status; 194 | TPCANMsg msgCanMessage; 195 | 196 | if (m_CommPtr == nullptr) 197 | { 198 | return; 199 | } 200 | 201 | status = m_CommPtr->GetDriverStatus(); 202 | ParseError(status); 203 | 204 | while (m_CommPtr->Receive(&msgCanMessage)) 205 | { 206 | status = m_CommPtr->GetDriverStatus(); 207 | ParseError(status); 208 | ParseMessage(msgCanMessage); 209 | } 210 | 211 | SendMessages(std::chrono::high_resolution_clock::now()); 212 | } 213 | 214 | void BoostedBreakCAN::ParseError(TPCANStatus status) 215 | { 216 | TPCANStatus prevStatus = PCAN_ERROR_ILLOPERATION; 217 | char errorText[64]; 218 | 219 | if (m_ViewMode == VIEWMODE_STREAM) 220 | { 221 | if (status != PCAN_ERROR_OK) 222 | { 223 | CAN_GetErrorText(status, 0x09, errorText); 224 | ConsolePrint("Status: "); 225 | ConsolePrint(errorText); 226 | ConsolePrint("\n"); 227 | } 228 | } 229 | else if (m_ViewMode == VIEWMODE_TABLE) 230 | { 231 | if (status != PCAN_ERROR_OK) 232 | { 233 | ConsoleCursor(CURSOR_TABLE_ERROR); 234 | 235 | CAN_GetErrorText(status, 0x09, errorText); 236 | ConsolePrint("Status: "); 237 | ConsolePrint(errorText); 238 | ConsolePrint("\n"); 239 | 240 | prevStatus = status; 241 | } 242 | else if (status == PCAN_ERROR_OK && prevStatus != PCAN_ERROR_OK) 243 | { 244 | ConsoleCursor(CURSOR_TABLE_ERROR); 245 | CAN_GetErrorText(status, 0x09, errorText); 246 | ConsolePrint(" \n"); 247 | } 248 | } 249 | } 250 | 251 | void BoostedBreakCAN::ParseMessage(TPCANMsg msgCanMessage) 252 | { 253 | BoostedCANMsg message(msgCanMessage); 254 | BoostedCANMsgInfo info(message); 255 | 256 | ParseMessageView(message, info); 257 | ParseMessageTransmit(message); 258 | } 259 | 260 | void BoostedBreakCAN::ParseMessageView(BoostedCANMsg message, BoostedCANMsgInfo info) 261 | { 262 | uint16_t cursorY; 263 | uint32_t num = 0; 264 | 265 | if (m_ViewMode == VIEWMODE_STREAM) 266 | { 267 | ConsolePrint(message.AsString()); 268 | ConsolePrint(info.Sender + " " + info.Description + "\t", CURSOR_SENDER_DESCRIPTION_X); 269 | ConsolePrint(info.Interpretation + " " "\n", CURSOR_INTERPRETATION_X); 270 | return; 271 | } 272 | else if (m_ViewMode == VIEWMODE_TABLE && info.Index <= NUM_BOOSTED_CAN_MSG) 273 | { 274 | cursorY = info.Index + TABLE_OFFSET_Y; 275 | if (TABLELIST_BREAK_1 <= info.Index) 276 | { 277 | cursorY++; 278 | } 279 | if (TABLELIST_BREAK_2 <= info.Index) 280 | { 281 | cursorY++; 282 | } 283 | 284 | ConsolePrint(message.CounterAsStringHex(), CURSOR_MESSAGE_COUNTER_X, cursorY); 285 | 286 | ConsolePrint(std::to_string(message.MessageLength), CURSOR_MESSAGE_LEGNTH_X, cursorY); 287 | if (info.Length == message.MessageLength 288 | || info.Length == LENGTH_UNKNOWN) 289 | { 290 | ConsolePrint(" "); 291 | } 292 | else 293 | { 294 | ConsolePrint("!"); 295 | } 296 | ConsolePrint(message.MessageBufferAsStringSpaced()); 297 | 298 | ConsolePrint(info.Interpretation, CURSOR_INTERPRETATION_X, cursorY); 299 | ConsolePrint(" "); 300 | } 301 | else if (m_ViewMode == VIEWMODE_BRIEF) 302 | { 303 | // TODO... 304 | } 305 | } 306 | 307 | void BoostedBreakCAN::ParseMessageTransmit(BoostedCANMsg message) 308 | { 309 | if (m_TransmitMode == TRANSMITMODE_NONE) 310 | { 311 | return; 312 | } 313 | else if (m_TransmitMode == TRANSMITMODE_PINGONLY) 314 | { 315 | return; 316 | } 317 | else if (m_TransmitMode == TRANSMITMODE_PINGPOWEROFF) 318 | { 319 | return; 320 | } 321 | else if (m_TransmitMode == TRANSMITMODE_EMULATEESC) 322 | { 323 | if (m_TransmitStage == 0 324 | && message.MessageID == 0x33417 325 | && message.MessageBuffer[0] == 0x01 326 | && message.MessageBuffer[1] == 0x0A) 327 | { 328 | m_TransmitStage = 1; 329 | //m_TransmitStageTime = std::chrono::high_resolution_clock::now(); 330 | } 331 | else if (m_TransmitStage == 2 332 | && message.MessageID == 0x25415) 333 | { 334 | m_TransmitStage = 3; 335 | } 336 | } 337 | else if (m_TransmitMode == TRANSMITMODE_EMULATESRB) 338 | { 339 | // TODO... 340 | return; 341 | } 342 | else if (m_TransmitMode == TRANSMITMODE_EMULATEXRB) 343 | { 344 | // TODO... 345 | return; 346 | } 347 | else if (m_TransmitMode == TRANSMITMODE_BEAMBREAKSRB) 348 | { 349 | if (m_TransmitStage == 0) 350 | { 351 | m_TransmitStage = 1; 352 | } 353 | } 354 | } 355 | 356 | void BoostedBreakCAN::SendMessages(std::chrono::steady_clock::time_point timeNow) 357 | { 358 | uint64_t timeDiff = std::chrono::duration_cast(timeNow - m_TransmitStageTime).count(); 359 | 360 | if (m_TransmitMode == TRANSMITMODE_NONE) 361 | { 362 | return; 363 | } 364 | else if (m_TransmitMode == TRANSMITMODE_PINGONLY) 365 | { 366 | SendPing(timeNow, 0x00); 367 | } 368 | else if (m_TransmitMode == TRANSMITMODE_PINGPOWEROFF) 369 | { 370 | SendPing(timeNow, 0x02); 371 | } 372 | else if (m_TransmitMode == TRANSMITMODE_EMULATEESC) 373 | { 374 | if (m_TransmitStage == 0) 375 | { 376 | return; 377 | } 378 | else if (m_TransmitStage == 1) 379 | { 380 | TransmitBoostedCANMessage(0x34344, 8, ESC_VERSION_SERIAL); 381 | TransmitBoostedCANMessage(0x34316, 3, 0x020600); 382 | m_TransmitStageTime = std::chrono::high_resolution_clock::now(); 383 | SendPing(timeNow, 0x00); 384 | 385 | m_TransmitStage = 2; 386 | } 387 | else if (m_TransmitStage == 2) 388 | { 389 | if (ESC_BTY_REGISTRATION_COMMAND_TIMER_MS <= timeDiff) 390 | { 391 | TransmitBoostedCANMessage(0x34316, 3, 0x010C00); 392 | m_TransmitStageTime = std::chrono::high_resolution_clock::now(); 393 | } 394 | SendPing(timeNow, 0x00); 395 | } 396 | else if (m_TransmitStage == 3) 397 | { 398 | SendPing(timeNow, 0x00); 399 | } 400 | } 401 | else if (m_TransmitMode == TRANSMITMODE_EMULATESRB) 402 | { 403 | // TODO... 404 | } 405 | else if (m_TransmitMode == TRANSMITMODE_EMULATEXRB) 406 | { 407 | // TODO... 408 | /*if (m_TransmitStage == 2) 409 | { 410 | TransmitBoostedCANMessage(0x33448, 8, 0xB8880000D8590000); 411 | }*/ 412 | } 413 | else if (m_TransmitMode == TRANSMITMODE_BEAMBREAKSRB) 414 | { 415 | TPCANMsg canMessage; 416 | 417 | if (m_TransmitStage == 0) 418 | { 419 | return; 420 | } 421 | else if (m_TransmitStage == 1) 422 | { 423 | canMessage = CreateTPCANMsg(0x0B57ED00, PCAN_MESSAGE_EXTENDED, 8, 0x0104013366343531); 424 | m_CommPtr->Transmit(canMessage); 425 | ShowSentMessage(canMessage); 426 | 427 | canMessage = CreateTPCANMsg(0x0B57ED01, PCAN_MESSAGE_EXTENDED, 8, 0xEEFFC000F78A0101); 428 | m_CommPtr->Transmit(canMessage); 429 | ShowSentMessage(canMessage); 430 | 431 | canMessage = CreateTPCANMsg(0x0B57ED03, PCAN_MESSAGE_EXTENDED, 8, 0xD20FCA080C000000); 432 | m_CommPtr->Transmit(canMessage); 433 | ShowSentMessage(canMessage); 434 | 435 | m_TransmitStageTime = std::chrono::high_resolution_clock::now(); 436 | m_TransmitStage = 2; 437 | } 438 | else if (m_TransmitStage == 2) 439 | { 440 | if (BEAMBREAK_TIMER_MS <= timeDiff) 441 | { 442 | canMessage = CreateTPCANMsg(0x0B57ED02, PCAN_MESSAGE_EXTENDED, 8, 0x0000C40900000000); 443 | m_CommPtr->Transmit(canMessage); 444 | ShowSentMessage(canMessage); 445 | 446 | canMessage = CreateTPCANMsg(0x0B57ED10, PCAN_MESSAGE_EXTENDED, 8, 0xF00CFB0CBB9B0000); 447 | m_CommPtr->Transmit(canMessage); 448 | ShowSentMessage(canMessage); 449 | 450 | canMessage = CreateTPCANMsg(0x0B57ED14, PCAN_MESSAGE_EXTENDED, 8, 0x9B07C4092A000500); 451 | m_CommPtr->Transmit(canMessage); 452 | ShowSentMessage(canMessage); 453 | 454 | canMessage = CreateTPCANMsg(0x0B57ED15, PCAN_MESSAGE_EXTENDED, 8, 0x0000000000007F00); 455 | m_CommPtr->Transmit(canMessage); 456 | ShowSentMessage(canMessage); 457 | } 458 | } 459 | } 460 | } 461 | 462 | void BoostedBreakCAN::TransmitBoostedCANMessage(uint32_t messageID, uint8_t messageLength, uint64_t messageBuffer) 463 | { 464 | BoostedCANMsg message(messageID, m_LastTransmitCounter, messageLength, messageBuffer); 465 | if (++m_LastTransmitCounter >= 0x10) 466 | { 467 | m_LastTransmitCounter = 0x00; 468 | } 469 | m_CommPtr->Transmit(message.AsTPCANMsg()); 470 | #ifdef DISPLAY_TRANSMIT_WITH_RECEIVE 471 | ShowSentMessage(message.AsTPCANMsg()); 472 | #endif //DISPLAY_TRANSMIT_WITH_RECEIVE 473 | } 474 | 475 | void BoostedBreakCAN::SendPing(std::chrono::steady_clock::time_point timeNow, uint8_t param) 476 | { 477 | uint64_t timeDiff = std::chrono::duration_cast(timeNow - m_LastPingTime).count(); 478 | 479 | if (PING_TIMER_MS <= timeDiff) 480 | { 481 | uint8_t messageBuffer[8] = { param, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; 482 | BoostedCANMsg message(0x3434B, m_LastTransmitCounter, 8, messageBuffer); 483 | if (++m_LastTransmitCounter >= 0x10) 484 | { m_LastTransmitCounter = 0x00; } 485 | m_CommPtr->Transmit(message.AsTPCANMsg()); 486 | 487 | m_LastPingTime = std::chrono::high_resolution_clock::now(); 488 | 489 | ShowSentMessage(message.AsTPCANMsg()); 490 | } 491 | } 492 | 493 | void BoostedBreakCAN::ShowSentMessage(TPCANMsg msgCanMessage) 494 | { 495 | ParseMessage(msgCanMessage); 496 | ConsolePrint("[TX]", CURSOR_TRANSMITTED_X); 497 | } 498 | 499 | void BoostedBreakCAN::SetTable() 500 | { 501 | uint16_t cursorY; 502 | uint8_t defaultLength = 8; 503 | uint8_t defaultMsg[8] = {0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20}; 504 | 505 | ConsoleClear(); 506 | 507 | for (int_fast8_t i = 0; i < NUM_BOOSTED_CAN_MSG; i++) 508 | { 509 | uint32_t messageID = BoostedCANMsgList[i]; 510 | 511 | BoostedCANMsg message(messageID, defaultLength, defaultMsg); 512 | BoostedCANMsgInfo info(message); 513 | 514 | cursorY = info.Index + TABLE_OFFSET_Y; 515 | if (TABLELIST_BREAK_1 <= info.Index) 516 | { 517 | cursorY++; 518 | } 519 | if (TABLELIST_BREAK_2 <= info.Index) 520 | { 521 | cursorY++; 522 | } 523 | 524 | ConsolePrint(message.CANIDAsString(), 0, cursorY); 525 | ConsolePrint(info.Sender + " " + info.Description, CURSOR_SENDER_DESCRIPTION_X, cursorY); 526 | } 527 | 528 | ConsolePrint("\n"); 529 | } 530 | 531 | void BoostedBreakCAN::DebugCommand() 532 | { 533 | m_TransmitStage++; 534 | } 535 | -------------------------------------------------------------------------------- /CAN/BoostedBreakCAN/PCANBasicParameter.cpp: -------------------------------------------------------------------------------- 1 | /*** 2 | * BoostedBreak - BoostedBreakCAN Program 3 | * 4 | * PCANBasicParameter.cpp 5 | * 6 | * Author: Alexander Krysl (axkrysl47) 7 | * Date: 2022/04/03 8 | **/ 9 | 10 | #include "PCANBasicParameter.h" 11 | 12 | void GetPCAN_DEVICE_ID(TPCANHandle handle) 13 | { 14 | UINT32 iDeviceID; 15 | TPCANStatus stsResult = CAN_GetValue(handle, PCAN_DEVICE_ID, &iDeviceID, sizeof(UINT32)); 16 | 17 | if (stsResult == PCAN_ERROR_OK) 18 | { 19 | PCANDebugOutput("-----------------------------------------------------------------------------------------\n"); 20 | PCANDebugOutput("Get PCAN_DEVICE_ID: "); 21 | PCANDebugOutput(std::to_string(iDeviceID)); 22 | PCANDebugOutput("\n"); 23 | PCANDebugOutput("\n"); 24 | } 25 | else 26 | ShowStatus(stsResult); 27 | } 28 | 29 | void SetPCAN_DEVICE_ID(TPCANHandle handle, UINT32 iDeviceID) 30 | { 31 | TPCANStatus stsResult = CAN_SetValue(handle, PCAN_DEVICE_ID, &iDeviceID, sizeof(UINT32)); 32 | 33 | if (stsResult == PCAN_ERROR_OK) 34 | { 35 | PCANDebugOutput("-----------------------------------------------------------------------------------------\n"); 36 | PCANDebugOutput("Set PCAN_DEVICE_ID: "); 37 | PCANDebugOutput(std::to_string(iDeviceID)); 38 | PCANDebugOutput("\n"); 39 | PCANDebugOutput("\n"); 40 | } 41 | else 42 | ShowStatus(stsResult); 43 | } 44 | 45 | 46 | void GetPCAN_ATTACHED_CHANNELS(bool isFD) 47 | { 48 | UINT32 iChannelsCount; 49 | TPCANStatus stsResult = CAN_GetValue(PCAN_NONEBUS, PCAN_ATTACHED_CHANNELS_COUNT, &iChannelsCount, sizeof(UINT32)); 50 | 51 | if (stsResult == PCAN_ERROR_OK) 52 | { 53 | TPCANChannelInformation* ciChannelInformation = new TPCANChannelInformation[iChannelsCount]; 54 | 55 | stsResult = CAN_GetValue(PCAN_NONEBUS, PCAN_ATTACHED_CHANNELS, ciChannelInformation, iChannelsCount * sizeof(TPCANChannelInformation)); 56 | 57 | if (stsResult == PCAN_ERROR_OK) 58 | { 59 | PCANDebugOutput("-----------------------------------------------------------------------------------------\n"); 60 | PCANDebugOutput("Get PCAN_ATTACHED_CHANNELS:\n"); 61 | 62 | for (int i = 0; i < (int)iChannelsCount; i++) 63 | { 64 | PCANDebugOutput("---------------------------\n"); 65 | char buffer[MAX_PATH]; 66 | GetTPCANHandleName(ciChannelInformation[i].channel_handle, buffer); 67 | if (isFD) 68 | { 69 | PCANDebugOutput("channel_handle: "); 70 | PCANDebugOutput(buffer); 71 | PCANDebugOutput("BUS"); 72 | PCANDebugOutput(std::to_string(ciChannelInformation[i].channel_handle & 0xFF)); 73 | PCANDebugOutput("\n"); 74 | 75 | } 76 | else 77 | { 78 | PCANDebugOutput("channel_handle: "); 79 | PCANDebugOutput(buffer); 80 | PCANDebugOutput("BUS"); 81 | PCANDebugOutput(std::to_string(ciChannelInformation[i].channel_handle & 0xF)); 82 | PCANDebugOutput("\n"); 83 | 84 | } 85 | PCANDebugOutput("device_type: "); 86 | PCANDebugOutput(ConvertDeviceTypeToString(ciChannelInformation[i].device_type)); 87 | PCANDebugOutput("\n"); 88 | PCANDebugOutput("controller_number: "); 89 | PCANDebugOutput(std::to_string((int)ciChannelInformation[i].controller_number)); 90 | PCANDebugOutput("\n"); 91 | PCANDebugOutput("device_features: "); 92 | PCANDebugOutput(ConvertToChannelFeatures(ciChannelInformation[i].device_features)); 93 | PCANDebugOutput("\n"); 94 | PCANDebugOutput("device_name: "); 95 | PCANDebugOutput(ciChannelInformation[i].device_name); 96 | PCANDebugOutput("\n"); 97 | PCANDebugOutput("device_id: "); 98 | PCANDebugOutput(std::to_string(ciChannelInformation[i].device_id)); 99 | PCANDebugOutput("\n"); 100 | PCANDebugOutput("channel_condition: "); 101 | PCANDebugOutput(ConvertToChannelCondition(ciChannelInformation[i].channel_condition)); 102 | PCANDebugOutput("\n"); 103 | } 104 | PCANDebugOutput("\n"); 105 | } 106 | delete[] ciChannelInformation; 107 | } 108 | if (stsResult != PCAN_ERROR_OK) 109 | ShowStatus(stsResult); 110 | 111 | } 112 | 113 | void GetPCAN_CHANNEL_CONDITION(TPCANHandle handle) 114 | { 115 | UINT32 iChannelCondition; 116 | TPCANStatus stsResult = CAN_GetValue(handle, PCAN_CHANNEL_CONDITION, &iChannelCondition, sizeof(UINT32)); 117 | 118 | if (stsResult == PCAN_ERROR_OK) 119 | { 120 | PCANDebugOutput("-----------------------------------------------------------------------------------------\n"); 121 | PCANDebugOutput("Get PCAN_CHANNEL_CONDITION: "); 122 | PCANDebugOutput(ConvertToChannelCondition(iChannelCondition)); 123 | PCANDebugOutput("\n"); 124 | PCANDebugOutput("\n"); 125 | } 126 | else 127 | ShowStatus(stsResult); 128 | } 129 | 130 | void GetPCAN_CHANNEL_IDENTIFYING(TPCANHandle handle) 131 | { 132 | UINT32 iChannelIdentifying; 133 | TPCANStatus stsResult = CAN_GetValue(handle, PCAN_CHANNEL_IDENTIFYING, &iChannelIdentifying, sizeof(UINT32)); 134 | 135 | if (stsResult == PCAN_ERROR_OK) 136 | { 137 | PCANDebugOutput("-----------------------------------------------------------------------------------------\n"); 138 | PCANDebugOutput("Get PCAN_CHANNEL_IDENTIFYING: "); 139 | PCANDebugOutput(ConvertToParameterOnOff(iChannelIdentifying)); 140 | PCANDebugOutput("\n"); 141 | PCANDebugOutput("\n"); 142 | } 143 | else 144 | ShowStatus(stsResult); 145 | } 146 | 147 | void SetPCAN_CHANNEL_IDENTIFYING(TPCANHandle handle, bool value) 148 | { 149 | UINT32 ciChannelIdentifying; 150 | if (value) 151 | ciChannelIdentifying = PCAN_PARAMETER_ON; 152 | else 153 | ciChannelIdentifying = PCAN_PARAMETER_OFF; 154 | 155 | TPCANStatus stsResult = CAN_SetValue(handle, PCAN_CHANNEL_IDENTIFYING, &ciChannelIdentifying, sizeof(UINT32)); 156 | 157 | if (stsResult == PCAN_ERROR_OK) 158 | { 159 | 160 | PCANDebugOutput("-----------------------------------------------------------------------------------------\n"); 161 | PCANDebugOutput("Set PCAN_CHANNEL_IDENTIFYING: "); 162 | PCANDebugOutput(ConvertToParameterOnOff(ciChannelIdentifying)); 163 | PCANDebugOutput("\n"); 164 | PCANDebugOutput("\n"); 165 | } 166 | else 167 | ShowStatus(stsResult); 168 | } 169 | 170 | void GetPCAN_CHANNEL_FEATURES(TPCANHandle handle) 171 | { 172 | UINT32 iChannelFeatures; 173 | TPCANStatus stsResult = CAN_GetValue(handle, PCAN_CHANNEL_FEATURES, &iChannelFeatures, sizeof(UINT32)); 174 | 175 | if (stsResult == PCAN_ERROR_OK) 176 | { 177 | PCANDebugOutput("-----------------------------------------------------------------------------------------\n"); 178 | PCANDebugOutput("Get PCAN_CHANNEL_FEATURES: "); 179 | PCANDebugOutput(ConvertToChannelFeatures(iChannelFeatures)); 180 | PCANDebugOutput("\n"); 181 | PCANDebugOutput("\n"); 182 | } 183 | else 184 | ShowStatus(stsResult); 185 | } 186 | 187 | void GetPCAN_BITRATE_ADAPTING(TPCANHandle handle) 188 | { 189 | UINT32 iBitrateAdapting; 190 | TPCANStatus stsResult = CAN_GetValue(handle, PCAN_BITRATE_ADAPTING, &iBitrateAdapting, sizeof(UINT32)); 191 | 192 | if (stsResult == PCAN_ERROR_OK) 193 | { 194 | PCANDebugOutput("-----------------------------------------------------------------------------------------\n"); 195 | PCANDebugOutput("Get PCAN_BITRATE_ADAPTING: "); 196 | PCANDebugOutput(ConvertToParameterOnOff(iBitrateAdapting)); 197 | PCANDebugOutput("\n"); 198 | PCANDebugOutput("\n"); 199 | } 200 | else 201 | ShowStatus(stsResult); 202 | } 203 | 204 | void SetPCAN_BITRATE_ADAPTING(TPCANHandle handle, bool isFD, TPCANBaudrate bitrate, TPCANBitrateFD bitrateFD, bool value) 205 | { 206 | UINT32 iBitrateAdapting; 207 | 208 | // Note: SetPCAN_BITRATE_ADAPTING requires an uninitialized channel, 209 | // 210 | CAN_Uninitialize(PCAN_NONEBUS); 211 | 212 | if (value) 213 | iBitrateAdapting = PCAN_PARAMETER_ON; 214 | else 215 | iBitrateAdapting = PCAN_PARAMETER_OFF; 216 | 217 | TPCANStatus stsResult = CAN_SetValue(handle, PCAN_BITRATE_ADAPTING, &iBitrateAdapting, sizeof(UINT32)); 218 | 219 | if (stsResult == PCAN_ERROR_OK) 220 | { 221 | PCANDebugOutput("-----------------------------------------------------------------------------------------\n"); 222 | PCANDebugOutput("Set PCAN_BITRATE_ADAPTING: "); 223 | PCANDebugOutput(ConvertToParameterOnOff(iBitrateAdapting)); 224 | PCANDebugOutput("\n"); 225 | PCANDebugOutput("\n"); 226 | } 227 | else 228 | ShowStatus(stsResult); 229 | 230 | // Channel will be connected again 231 | if (isFD) 232 | stsResult = CAN_InitializeFD(handle, bitrateFD); 233 | else 234 | stsResult = CAN_Initialize(handle, bitrate); 235 | 236 | if (stsResult != PCAN_ERROR_OK) 237 | { 238 | std::cout << "Error while re-initializing the channel.\n"; 239 | ShowStatus(stsResult); 240 | } 241 | } 242 | 243 | void GetPCAN_ALLOW_STATUS_FRAMES(TPCANHandle handle) 244 | { 245 | UINT32 iAllowStatusFrames; 246 | TPCANStatus stsResult = CAN_GetValue(handle, PCAN_ALLOW_STATUS_FRAMES, &iAllowStatusFrames, sizeof(UINT32)); 247 | 248 | if (stsResult == PCAN_ERROR_OK) 249 | { 250 | PCANDebugOutput("-----------------------------------------------------------------------------------------\n"); 251 | PCANDebugOutput("Get PCAN_ALLOW_STATUS_FRAMES: "); 252 | PCANDebugOutput(ConvertToParameterOnOff(iAllowStatusFrames)); 253 | PCANDebugOutput("\n"); 254 | PCANDebugOutput("\n"); 255 | } 256 | else 257 | ShowStatus(stsResult); 258 | } 259 | 260 | void SetPCAN_ALLOW_STATUS_FRAMES(TPCANHandle handle, bool value) 261 | { 262 | UINT32 iAllowStatusFrames; 263 | 264 | if (value) 265 | iAllowStatusFrames = PCAN_PARAMETER_ON; 266 | else 267 | iAllowStatusFrames = PCAN_PARAMETER_OFF; 268 | 269 | TPCANStatus stsResult = CAN_SetValue(handle, PCAN_ALLOW_STATUS_FRAMES, &iAllowStatusFrames, sizeof(UINT32)); 270 | 271 | if (stsResult == PCAN_ERROR_OK) 272 | { 273 | PCANDebugOutput("-----------------------------------------------------------------------------------------\n"); 274 | PCANDebugOutput("Set PCAN_ALLOW_STATUS_FRAMES: "); 275 | PCANDebugOutput(ConvertToParameterOnOff(iAllowStatusFrames)); 276 | PCANDebugOutput("\n"); 277 | PCANDebugOutput("\n"); 278 | } 279 | else 280 | ShowStatus(stsResult); 281 | } 282 | 283 | void GetPCAN_ALLOW_RTR_FRAMES(TPCANHandle handle) 284 | { 285 | UINT32 iAllowRTRFrames; 286 | TPCANStatus stsResult = CAN_GetValue(handle, PCAN_ALLOW_RTR_FRAMES, &iAllowRTRFrames, sizeof(UINT32)); 287 | 288 | if (stsResult == PCAN_ERROR_OK) 289 | { 290 | PCANDebugOutput("-----------------------------------------------------------------------------------------\n"); 291 | PCANDebugOutput("Get PCAN_ALLOW_RTR_FRAMES: "); 292 | PCANDebugOutput(ConvertToParameterOnOff(iAllowRTRFrames)); 293 | PCANDebugOutput("\n"); 294 | PCANDebugOutput("\n"); 295 | } 296 | else 297 | ShowStatus(stsResult); 298 | } 299 | 300 | void SetPCAN_ALLOW_RTR_FRAMES(TPCANHandle handle, bool value) 301 | { 302 | UINT32 iAllowRTRFrames; 303 | 304 | if (value) 305 | iAllowRTRFrames = PCAN_PARAMETER_ON; 306 | else 307 | iAllowRTRFrames = PCAN_PARAMETER_OFF; 308 | 309 | TPCANStatus stsResult = CAN_SetValue(handle, PCAN_ALLOW_RTR_FRAMES, &iAllowRTRFrames, sizeof(UINT32)); 310 | 311 | if (stsResult == PCAN_ERROR_OK) 312 | { 313 | PCANDebugOutput("-----------------------------------------------------------------------------------------\n"); 314 | PCANDebugOutput("Set PCAN_ALLOW_RTR_FRAMES: "); 315 | PCANDebugOutput(ConvertToParameterOnOff(iAllowRTRFrames)); 316 | PCANDebugOutput("\n"); 317 | PCANDebugOutput("\n"); 318 | } 319 | else 320 | ShowStatus(stsResult); 321 | } 322 | 323 | void GetPCAN_ALLOW_ERROR_FRAMES(TPCANHandle handle) 324 | { 325 | UINT32 iAllowErrorFrames; 326 | TPCANStatus stsResult = CAN_GetValue(handle, PCAN_ALLOW_ERROR_FRAMES, &iAllowErrorFrames, sizeof(UINT32)); 327 | 328 | if (stsResult == PCAN_ERROR_OK) 329 | { 330 | PCANDebugOutput("-----------------------------------------------------------------------------------------\n"); 331 | PCANDebugOutput("Get PCAN_ALLOW_ERROR_FRAMES: "); 332 | PCANDebugOutput(ConvertToParameterOnOff(iAllowErrorFrames)); 333 | PCANDebugOutput("\n"); 334 | PCANDebugOutput("\n"); 335 | } 336 | else 337 | ShowStatus(stsResult); 338 | } 339 | 340 | void SetPCAN_ALLOW_ERROR_FRAMES(TPCANHandle handle, bool value) 341 | { 342 | UINT32 iAllowErrorFrames; 343 | 344 | if (value) 345 | iAllowErrorFrames = PCAN_PARAMETER_ON; 346 | else 347 | iAllowErrorFrames = PCAN_PARAMETER_OFF; 348 | 349 | TPCANStatus stsResult = CAN_SetValue(handle, PCAN_ALLOW_ERROR_FRAMES, &iAllowErrorFrames, sizeof(UINT32)); 350 | 351 | if (stsResult == PCAN_ERROR_OK) 352 | { 353 | PCANDebugOutput("-----------------------------------------------------------------------------------------\n"); 354 | PCANDebugOutput("Set PCAN_ALLOW_ERROR_FRAMES: "); 355 | PCANDebugOutput(ConvertToParameterOnOff(iAllowErrorFrames)); 356 | PCANDebugOutput("\n"); 357 | PCANDebugOutput("\n"); 358 | } 359 | else 360 | ShowStatus(stsResult); 361 | } 362 | 363 | void GetPCAN_ALLOW_ECHO_FRAMES(TPCANHandle handle) 364 | { 365 | UINT32 iAllowEchoFrames; 366 | TPCANStatus stsResult = CAN_GetValue(handle, PCAN_ALLOW_ECHO_FRAMES, &iAllowEchoFrames, sizeof(UINT32)); 367 | 368 | if (stsResult == PCAN_ERROR_OK) 369 | { 370 | PCANDebugOutput("-----------------------------------------------------------------------------------------\n"); 371 | PCANDebugOutput("Get PCAN_ALLOW_ECHO_FRAMES: "); 372 | PCANDebugOutput(ConvertToParameterOnOff(iAllowEchoFrames)); 373 | PCANDebugOutput("\n"); 374 | PCANDebugOutput("\n"); 375 | } 376 | else 377 | ShowStatus(stsResult); 378 | } 379 | 380 | void SetPCAN_ALLOW_ECHO_FRAMES(TPCANHandle handle, bool value) 381 | { 382 | UINT32 iAllowEchoFrames; 383 | 384 | if (value) 385 | iAllowEchoFrames = PCAN_PARAMETER_ON; 386 | else 387 | iAllowEchoFrames = PCAN_PARAMETER_OFF; 388 | 389 | TPCANStatus stsResult = CAN_SetValue(handle, PCAN_ALLOW_ECHO_FRAMES, &iAllowEchoFrames, sizeof(UINT32)); 390 | 391 | if (stsResult == PCAN_ERROR_OK) 392 | { 393 | PCANDebugOutput("-----------------------------------------------------------------------------------------\n"); 394 | PCANDebugOutput("Set PCAN_ALLOW_ECHO_FRAMES: "); 395 | PCANDebugOutput(ConvertToParameterOnOff(iAllowEchoFrames)); 396 | PCANDebugOutput("\n"); 397 | PCANDebugOutput("\n"); 398 | } 399 | else 400 | ShowStatus(stsResult); 401 | } 402 | 403 | void GetPCAN_ACCEPTANCE_FILTER_11BIT(TPCANHandle handle) 404 | { 405 | UINT64 iAcceptanceFilter11Bit; 406 | TPCANStatus stsResult = CAN_GetValue(handle, PCAN_ACCEPTANCE_FILTER_11BIT, &iAcceptanceFilter11Bit, sizeof(UINT64)); 407 | 408 | if (stsResult == PCAN_ERROR_OK) 409 | { 410 | char result[MAX_PATH]; 411 | PCANDebugOutput("-----------------------------------------------------------------------------------------\n"); 412 | sprintf_s(result, sizeof(result), "%16llx", iAcceptanceFilter11Bit); 413 | PCANDebugOutput("Get PCAN_ACCEPTANCE_FILTER_11BIT: "); // << std::setfill('0') << std::setw(16) << std::hex << result << "h\n"; 414 | PCANDebugOutput(result); 415 | PCANDebugOutput("h\n"); 416 | PCANDebugOutput("\n"); 417 | } 418 | else 419 | ShowStatus(stsResult); 420 | } 421 | 422 | void SetPCAN_ACCEPTANCE_FILTER_11BIT(TPCANHandle handle, UINT64 iacceptancefilter11bit) 423 | { 424 | TPCANStatus stsResult = CAN_SetValue(handle, PCAN_ACCEPTANCE_FILTER_11BIT, &iacceptancefilter11bit, sizeof(UINT64)); 425 | 426 | if (stsResult == PCAN_ERROR_OK) 427 | { 428 | char result[MAX_PATH]; 429 | PCANDebugOutput("-----------------------------------------------------------------------------------------\n"); 430 | sprintf_s(result, sizeof(result), "%16llx", iacceptancefilter11bit); 431 | PCANDebugOutput("Set PCAN_ACCEPTANCE_FILTER_11BIT: "); 432 | PCANDebugOutput(result); 433 | PCANDebugOutput("h\n"); 434 | PCANDebugOutput("\n"); 435 | } 436 | else 437 | ShowStatus(stsResult); 438 | } 439 | 440 | void GetPCAN_ACCEPTANCE_FILTER_29BIT(TPCANHandle handle) 441 | { 442 | UINT64 iAcceptanceFilter29Bit; 443 | TPCANStatus stsResult = CAN_GetValue(handle, PCAN_ACCEPTANCE_FILTER_29BIT, &iAcceptanceFilter29Bit, sizeof(UINT64)); 444 | 445 | if (stsResult == PCAN_ERROR_OK) 446 | { 447 | char result[MAX_PATH]; 448 | PCANDebugOutput("-----------------------------------------------------------------------------------------\n"); 449 | sprintf_s(result, sizeof(result), "%16llx", iAcceptanceFilter29Bit); 450 | PCANDebugOutput("Get PCAN_ACCEPTANCE_FILTER_29BIT: "); 451 | PCANDebugOutput(result); 452 | PCANDebugOutput("h\n"); 453 | PCANDebugOutput("\n"); 454 | } 455 | else 456 | ShowStatus(stsResult); 457 | } 458 | 459 | void SetPCAN_ACCEPTANCE_FILTER_29BIT(TPCANHandle handle, UINT64 iacceptancefilter29bit) 460 | { 461 | TPCANStatus stsResult = CAN_SetValue(handle, PCAN_ACCEPTANCE_FILTER_29BIT, &iacceptancefilter29bit, sizeof(UINT64)); 462 | 463 | if (stsResult == PCAN_ERROR_OK) 464 | { 465 | char result[MAX_PATH]; 466 | PCANDebugOutput("-----------------------------------------------------------------------------------------\n"); 467 | sprintf_s(result, sizeof(result), "%16llx", iacceptancefilter29bit); 468 | PCANDebugOutput("Set PCAN_ACCEPTANCE_FILTER_29BIT: "); 469 | PCANDebugOutput(result); 470 | PCANDebugOutput("h\n"); 471 | PCANDebugOutput("\n"); 472 | } 473 | else 474 | ShowStatus(stsResult); 475 | } 476 | 477 | void GetPCAN_MESSAGE_FILTER(TPCANHandle handle) 478 | { 479 | UINT32 iMessageFilter; 480 | TPCANStatus stsResult = CAN_GetValue(handle, PCAN_MESSAGE_FILTER, &iMessageFilter, sizeof(UINT32)); 481 | 482 | if (stsResult == PCAN_ERROR_OK) 483 | { 484 | PCANDebugOutput("-----------------------------------------------------------------------------------------\n"); 485 | PCANDebugOutput("Get PCAN_MESSAGE_FILTER: "); 486 | PCANDebugOutput(ConvertToFilterOpenCloseCustom(iMessageFilter)); 487 | PCANDebugOutput("\n"); 488 | PCANDebugOutput("\n"); 489 | } 490 | else 491 | ShowStatus(stsResult); 492 | } 493 | 494 | void SetPCAN_MESSAGE_FILTER(TPCANHandle handle, UINT32 imessagefilter) 495 | { 496 | TPCANStatus stsResult = CAN_SetValue(handle, PCAN_MESSAGE_FILTER, &imessagefilter, sizeof(UINT32)); 497 | 498 | if (stsResult == PCAN_ERROR_OK) 499 | { 500 | PCANDebugOutput("-----------------------------------------------------------------------------------------\n"); 501 | PCANDebugOutput("Set PCAN_MESSAGE_FILTER: "); 502 | PCANDebugOutput(ConvertToFilterOpenCloseCustom(imessagefilter)); 503 | PCANDebugOutput("\n"); 504 | PCANDebugOutput("\n"); 505 | } 506 | else 507 | ShowStatus(stsResult); 508 | } -------------------------------------------------------------------------------- /FAQ/README.md: -------------------------------------------------------------------------------- 1 | # __BoostedBreak Frequently Asked Questions__ (Work In Progress!) 2 | 3 | ## 1. Overview 4 | The following is a list of commonly asked questions & answers as found in the Boosted Board community. 5 | 6 | The majority of from this list is a form of redundancy from Mario Parra's website Forever Boosted, which is an excellent resource on all things Boosted. 7 | 8 | ### Please check out [Forever Boosted, here](https://foreverboosted.co/)! 9 | 10 | 11 | # Table of Contents 12 | 1. [Overview](#1-overview) 13 | - [Link to Forever Boosted](#please-check-out-forever-boosted-here) 14 | 2. [Basic Information](#2-basic-information) 15 | 1. [What is a personal light electric vehicle?](#21-what-is-a-personal-light-electric-vehicle) 16 | 2. [What is an electric skateboard/longboard?](#22-what-is-an-electric-skateboardlongboard) 17 | 3. [What is/was Boosted?](#23-what-iswas-boosted) 18 | 4. [What is a Boosted Board?](#24-what-is-a-boosted-board) 19 | 5. [What is the Boosted Rev / Scooter?](#25-what-is-the-boosted-rev--scooter) 20 | 6. [What is an electric skateboard/longboard ESC / Motor Driver?](#26-what-is-an-electric-skateboardlongboard-esc--motor-driver) 21 | 7. [What is an electric skateboard/longboard battery?](#27-what-is-an-electric-skateboardlongboard-battery) 22 | 8. [What is an electric skateboard/longboard remote?](#28-what-is-an-electric-skateboardlongboard-remote)3 23 | 3. [Technical Information](#3-technical-information) 24 | 1. [What is battery cell balancing?](#31-what-is-battery-cell-balancing) 25 | 2. [What is Controller Area Network (CAN bus)?](#32-what-is-controller-area-network-can-bus) 26 | 3. [What is endianness, and what is the difference between little-endian & big-endian?](#33-what-is-endianness-and-what-is-the-difference-between-little-endian--big-endian) 27 | 4. [Parts Information](#4-parts-information) 28 | 1. [Does Boosted use different ESCs?](#41-does-boosted-use-different-escs) 29 | 2. [What motors did Boosted use, and are they interchangeable?](#42-what-motors-did-boosted-use-and-are-they-interchangeable) 30 | 3. [What battery cells did Boosted use, and are they interchangeable?](#43-what-battery-cells-did-boosted-use-and-are-they-interchangeable) 31 | 4. [What charger did Boosted use, and are they interchangeable?](#44-what-charger-did-boosted-use-and-are-they-interchangeable) 32 | 5. [What belts did Boosted use?](#45-what-belts-did-boosted-use) 33 | 6. [What decks did Boosted use, and what are their weight limits?](#46-what-decks-did-boosted-use-and-what-are-their-weight-limits) 34 | 7. [What trucks did Boosted use, and can I use third party trucks?](#47-what-trucks-did-boosted-use-and-can-i-use-third-party-trucks) 35 | 8. [What wheels did Boosted use?](#48-what-wheels-did-boosted-use) 36 | 9. [What pulleys did Boosted use?](#49-what-pulleys-did-boosted-use) 37 | 10. [What hardware did Boosted use?](#410-what-hardware-did-boosted-use) 38 | 39 | 40 | ## 2. Basic Information 41 | 42 | ### 2.1. What is a personal light electric vehicle? 43 | A personal electric vehicle (also known as personal transporter, powered transporter, electric rideable, personal mobility device, etc.) is any of a class of compact, mostly recent (21st century), motorised micromobility vehicle for transporting a single individual. They include electric skateboards, kick scooters, self-balancing unicycles and Segways. Many newer versions use recent advances in vehicle battery and electric motor-control technologies. 44 | 45 | ### 2.2. What is an electric skateboard/longboard? 46 | An electric skateboard/longboard is a personal electric vehicle that comes in the form factor of a skateboard or longboard. Generally, all electric skateboards/longboards consist of all the basic components of a skateboard/longboard (deck, trucks, wheels, etc.), plus a battery, a motor driver, motors, and more. Typically, an electric skateboard/longboard rider controls acceleration & deceleration with a throttle on a wireless remote, and makes turns in the same manner as traditional skateboards/longboards. 47 | 48 | ### 2.3. What is/was Boosted? 49 | Boosted (formerly Boosted Boards) was an American manufacturer of electric skateboards and electric scooters based in Mountain View, California. Boosted was founded in mid-2012 with financial backing by StartX by former Stanford University students Sanjay Dastoor, John Ulmen, and Matthew Tran. Boosted was widely recognized for popularizing the electric longboard, launching from an extraordinarily successful Kickstarter campaign. 50 | 51 | ### 2.4. What is a Boosted Board? 52 | A Boosted Board is an electrically motorized longboard or skateboard that was designed and manufactured by the now defunct company Boosted, Inc. Boosted created several different models of electric longboards, a list which can be found below. 53 | 54 | * _First generation_ (V1) 55 | * __Boosted Single__ 56 | * __Boosted Dual (V1)__ 57 | * __Boosted Dual+ (V1)__ 58 | * _Second generation_ (V2) 59 | * __Boosted Dual (V2)__ 60 | * __Boosted Dual+ (V2)__ 61 | * _Third generation_ (V3) 62 | * __Boosted Mini S__ 63 | * __Boosted Mini X__ 64 | * __Boosted Plus__ 65 | * __Boosted Stealth__ 66 | 67 | ### 2.5. What is the Boosted Rev / Scooter? 68 | A __Boosted Rev__ is an electrically motorized scooter that was designed and manufactured by the now defunct company Boosted, Inc. Boosted created only one electric scooter model before the company ended operations. 69 | 70 | ### 2.6. What is an electric skateboard/longboard ESC / Motor Driver? 71 | In general, the terms motor driver (MD), motor controller, electronic speed controller (ESC), are all aliases for an embedded system that controls motors. On all Boosted Boards, the ESC is secured under the deck in front of the motors. If you would like to know more about Boosted Board ESCs, check out the [BoostedBreakESC folder](). 72 | 73 | ### 2.7. What is an electric skateboard/longboard battery? 74 | In general, an electric skateboard/longboard battery is a relatively high energy (typically 100 to 1000 Watt-hours), high power (typically 1500-4000 Watts) battery designed for use in electric skateboard/longboard applications. Typically, electric skateboard/longboard batteries also consist of embedded systems that control charging, monitor discharging, perform cell balancing, and more. On all Boosted Boards, the battery is secured under the deck behind the front trucks. If you would like to know more about Boosted Board batteries, check out the [BoostedBreakSRB folder]() or the [BoostedBreakXRB folder](). 75 | 76 | ### 2.8. What is an electric skateboard/longboard remote? 77 | In general, an electric skateboard/longboard remote is a wireless remote that provides a throttle for riders of electric longboards. Typically, the remote also gives riders basic information about the state of the electric skateboard/longboard, including state of charge, current speed mode, and more. If you would like to know more about Boosted Board remotes, check out the [BoostedBreakREM folder](). 78 | 79 | 80 | ## 3. Technical Information 81 | 82 | ### 3.1. What is battery cell balancing? 83 | Battery cell balancing is the act of charging/discharging individual cells in a multi-series-cell battery such that all the cells are at a similar voltage. Put simply, individual cells in a battery need to be safely kept in a specific voltage range - battery cell balancing ensures this safety with the maximum margin of error. 84 | 85 | In concept, a Boosted board battery is a high-voltage battery, created by 'stacking up' several 'normal' voltage identical lithium ion cells. (For example, the SRB is made up of 12 separate cells in series.) Despite an engineer's best efforts, each cell discharges slightly differently depending on differences in manufacturing and how the battery itself is assembled. 86 | 87 | When a multi-series-celled battery is charged & discharged several times over, those slight differences in discharge rate compound over time; as such, the difference between the highest cell's voltage and lowest cell's voltage can grow over time. This difference is often referred to as the 'voltage delta'. 88 | 89 | General charging is the process of charging the battery as a whole to a specified voltage level. (In our SRB example, this voltage is 12 times an individual cell's charged voltage, as we have 12 cells in series.) What is important to note is the fact that the individual cells need not be at the same voltage/charge level in this case. 90 | 91 | (For example, let us consider a small 2 cell-in-series battery. Further, let us say a single cell is charged to 4 volts, so our 2 cell battery is fully charged when it is at 8 volts. While we may see 8 volts at the main terminals of our battery, the individual cells could be at 4 volts apiece (zero voltage delta), or they could be a 3 and 5 volts (2 volt delta), or they could be a 0 volts and 8 volts (8 volt delta, not good!). This information simply cannot be determined looking at the main terminals of our battery alone.) 92 | 93 | By contrast, battery balancing is the process of ensuring that all 12 cells are individually charged to their specific charged voltage. 94 | 95 | Individual cell voltage monitoring is extremely important for multi-series-cell battery safety. Each individual lithium ion cell needs to be kept in a specific voltage range: too low and the cell begins to degrade very quickly, too high, and the cell can catch fire and explode. This is why individual cell monitoring is necessary. 96 | 97 | Battery cell balancing takes cell monitoring a step further by eliminating the voltage delta, thereby mitigating the risk of cell explosion or degradation via high cell voltage delta. A battery with near-zero voltage delta requires the maximum amount of charge & discharge cycles (in other words, the maximum amount of time for cell differences to compound) before the it is back under the severe risk of cell explosion or degradation. 98 | 99 | As such, battery cell balancing is paramount to maintain the safety of a multi-cell-battery. 100 | 101 | ### 3.2. What is Controller Area Network (CAN) bus? 102 | CAN bus is a message-based serial communications protocol typically used in embedded systems where there are several nodes that all must communicate with one another (also known as a multiplex system). Using CAN bus in this design scenario generally simplifies on electrical wiring, message prioritization, and bus error handling. 103 | 104 | In the context of Boosted Boards, CAN is used for communications between the ESC and battery, as well as the ESC and the accessory port. The choice to use CAN infers that Boosted had interest in creating a multi-ESC or multi-battery electric longboard (thereby a multiplex embedded system). If you would like to know more about Boosted's CAN protocol, check out the [BoostedBreakCAN folder](https://github.com/axkrysl47/BoostedBreak/tree/main/CAN). 105 | 106 | ### 3.3. What is endianness, and what is the difference between little-endian & big-endian? 107 | Endianness is a computer science term used to describe the arrangement of multi-byte (or multiples of 8 binary digits / 8 bits) numbers. 108 | 109 | For example, take the decimal number `16,909,060`. In hexadecimal, this number is represented as `0x 01 02 03 04`, and in binary, this number is `0b 00000001 00000010 00000011 00000100`. So far, I've described this number in big-endian form - the most significant byte comes first, and the least significant byte comes last. This is generally intuitive, as we generally write numbers by most significant digit to least significant digit. 110 | 111 | In little-endian form, the opposite is true - the least significant byte comes first, while the most significant byte comes last. So, as an example, `0x 01 02 03 04` in big-endian is `0x 04 03 02 01` in little-endian. Notice that the bits inside the bytes stay in intuitive order; only the individual bytes themselves are in reverse order. 112 | 113 | At first, little-endianness seems like a unproductive concept. Big-endian numbers are easier for people to read and work with. While it is true that we write numbers in 'big-endian' order, it is very convenient to add (and perform other arithmetic operations on) numbers from least significant digit to most significant digit. For example, if we need to add two numbers, but we can only receive one digit of each at a time, we can start adding right away if we receive the least significant digits first. On the contrary, if we received digits starting from the most significant digit, we would have to back-propogate any carry-over. This is the motivation to arrange multi-byte numbers in little-endian form. 114 | 115 | For most microprocessors, the smallest numerical unit for arithmetic operations is the byte (8 bits). That is, they are designed to perform mathematic operations with groups of bytes, usually between 1 to 8 bytes. This is the reason why the bits inside each byte are not in reverse order. 116 | 117 | When there is a discussion around microprocessors regarding 8-bit, 16-bit, 32-bit, 64-bit, etc. architectures, this indicates the target binary number size of the hardware arithmetic unit inside the chip. For example, the dsPIC microcontrollers used in Boosted's XRB & ESC are 16-bit architectures, meaning they are designed in hardware around 16-bit / 2-byte mathematic operations. (To be clear, the dsPIC is still capable of performing 32-bit arithmetic, but not as quickly as a comparable 16-bit operation.) 118 | 119 | ## 4. Parts Information 120 | 121 | ### 4.1. Does Boosted use different ESCs? 122 | From Forever Boosted: 123 | > All Boosted boards, except for the V1, use the same ESC printed circuit board, which is interchangeable across all V2 & V3 boards. The speed modes are determined by the firmware. NOTE: While the longboard ESCs will technically work on the Mini boards, they use a different enclosure, so they are not a direct swap. 124 | 125 | The V1 was originally designed with single & dual motors in mind. A V1 Dual ESC will look like two ESCs, each on their own half of the whole printed circuit board. 126 | 127 | With the release of the V2, Boosted went away with single motor electric longboards, and as such consolidated their ESC design with a single dsPIC microcontroller for both motors. The original V2 was likely over-engineered for the rated amperages/power of the V2 boards; when it came time to release the V3 boards, raising the software limits on the same ESC design for the Boosted Stealth was both safe and cost-effective for Boosted. 128 | 129 | ### 4.2. What motors did Boosted use, and are they interchangeable? 130 | From Forever Boosted: 131 | 132 | The V1 boards use standard sensorless (I think) brushless 5035 192KV motors with 14T motor pulleys. 133 | > The V2 & V3 boards use brushless 5035 192KV motors with custom Hall effect sensors and a 17T motor pulley. They are interchangeable between both sides of the board (left and right) and between V2 and all V3 boards (Stealth, Plus, and Mini). 134 | 135 | The T2 motor that came with V2 and most V3 boards has been known to have motor shaft failures. The later T3 motor was manufactured to resolve the issue. 136 | 137 | I believe the choice to use 5035 motors was made such that 1) the trucks could be very similar to standard width, and 2) the smaller size more comfortably fits under the deck, leading to a sleeker, more conventional & attractive longboard design. 138 | 139 | ### 4.3. What battery cells did Boosted use, and are they interchangeable? 140 | From Forever Boosted: 141 | > The standard range (SRB) battery uses A123 26650 LiFePO4 cells in a 12S1P configuration (12 cells total) and the extended range (XRB) battery uses LG HG2 18650 Lithium Ion cells in a 13S2P configuration (26 cells total). 142 | 143 | The A123 cell for the SRB was a very reasonable choice. LiFePO4 cells are generally more stable than their Li-ion cell counterparts, leading to a less-likely-to-explode battery. Furthermore, the A123 has a highly rated discharge rate of 50 amperes, making a 12S A123 battery have a nominal power rating of 1980 watts. The only downside is that the energy rating of the SRB was under 100 watt-hours, which meant the range was at most a handful of miles. 144 | 145 | Th HG2 cell for the XRB was chosen to resolve the energy downside of the SRB. With the XRB, Boosted moved to the more popular Li-ion cell, and one with a rated continuous discharge rate of only 20 amperes. The power rating of a 13S2P HG2 battery only got up to 1872 watts, notably lower than the SRB. I suspect that Boosted went over that power specification, especially with hyper mode on the Boosted Stealth. Perhaps to compensate for this, the energy rating of the XRB is under specification, rated at 199 watt-hours, which is still double the SRB's energy rating. 146 | 147 | > All standard range batteries across all V2 & V3 boards are the same. Likewise, all extended range batteries across all V2 & V3 boards are the same. This means that the standard range battery works on all V2 & V3 boards while the extended range battery can be installed on all V2 & V3 boards, except for the Mini S as it does not fit on the deck due to the motor driver placement. The V1 battery was not designed to be removeable or swappable. NOTE: Older V2 boards need to be manually updated to ESC firmware v2.1.9 or later to work with an extended range battery. 148 | 149 | ### 4.4. What charger did Boosted use, and are they interchangeable? 150 | V2 & V3 chargers are 13S (54.6V, 2A) chargers. 151 | 152 | From Forever Boosted: 153 | > The V1 charger can also charge a standard range battery, but cannot charge an extended range battery; the V2 & V3 charger can charge all Boosted batteries. 154 | 155 | ### 4.5. What belts did Boosted use? 156 | From Forever Boosted: 157 | > V2 & V3 boards use custom Gates 225-15-3m belts lined with felt to reduce noise. V1 boards use 219-15-3m. (Belts follow the naming convention of length-width-tooth pitch) 158 | 159 | ### 4.6. What decks did Boosted use, and what are their weight limits? 160 | From Forever Boosted: 161 | > The V3 longboards (Stealth/Plus) use a slightly stiffer 38" (L)/11.3" (W) composite deck and the Mini (X/S) boards use a "Deep Dish" 29.5" (L)/11" (W) composite deck. Both have a poplar spine wrapped in triaxial fibreglass and edges reinforced with a polymer sidewall. The longboard deck also contains vibration-dampending foam. 162 | > 163 | > The V1 & V2 boards use a custom Loaded Flex 3 Vanguard (38"/98cm) deck, which is intended for speeds between 0 and 25 mph (0-40km/h). Due to the flexibility, they were not intended for higher speeds. 164 | > 165 | > All decks are rated for use by riders up to 250 lbs (113 kg). 166 | 167 | ### 4.7. What trucks did Boosted use, and can I use third party trucks? 168 | From Forever Boosted: 169 | > The V2 & V3 boards use custom 190mm (hangar width)/50° (baseplate angle) trucks with a rakeless hangar while the V1 uses 50° Caliber IIs. “Rakeless” denotes that the hanger can face either direction, but for visual reasons, it is installed with the circle facing down. The V2 trucks were cast while the V3 trucks were forged. 170 | 171 | > You can use a 180mm/50° truck on the front, such as a Paris truck from Loaded boards, but the rear truck assembly uses Boosted’s custom motor mounts. 180mm is the closest size as 190mm is not a common longboard truck width. You can also use a third-party baseplate with the V2 & V3 rear truck, such as a 50° Caliber baseplate to match the front. 172 | 173 | ### 4.8. What wheels did Boosted use? 174 | From Forever Boosted: 175 | > * __Boosted Single, Boosted Dual (V1), Boosted Dual+ (V1)__ 176 | > * Orangatang 75mm/80a In Heat wheels (orange) with custom drilled pulleys 177 | > * __Boosted Dual (V2), Boosted Dual+ (V2)__ 178 | > * Orangatang 80mm/80a Kegel wheels (orange) 179 | > * __Boosted Mini S__ 180 | > * Boosted 80mm/78a Lunar wheels (orange) 181 | > * __Boosted Mini X__ 182 | > * Boosted 80mm/78a Lunar wheels (grey) 183 | > * __Boosted Plus__ 184 | > * Boosted 85mm/78a Stratus wheels (orange) 185 | > * __Boosted Stealth__ 186 | > * Boosted 85mm/78a Stratus wheels (grey) 187 | 188 | Boosted also released the Boosted 105mm/72a '105s' wheels (black/multi-color) which were only sold separately, not standard with any given board. 189 | 190 | ### 4.9. What pulleys did Boosted use? 191 | From Forever Boosted: 192 | > V1 Boards used custom aluminum 50T pulleys that came standard with the Orangatang In Heat wheels. 193 | 194 | > Most V2/V3 Boards used a plastic 56T pulley that was compatible with all kegel cores. 195 | 196 | The Boosted Stealth and Boosted 105s came with a similar plastic 56T pulley, compatible with all kegel cores, but had metal teeth instead of plastic. 197 | 198 | ### 4.10. What hardware did Boosted use? 199 | From Forever Boosted: 200 | > Battery: The battery screws are M6 x 12mm (diameter)/20mm (length), which are 90° countersunk and take a 4mm Allen wrench. 201 | > 202 | > ESC/Motor Driver: The motor driver wing plate screws are M6 x 12mm (diameter)/18mm (length), which are 90° countersunk and take a 4mm Allen wrench. 203 | > 204 | > Motor Caps (Belt Covers): The socket cap screws for the motor cap are M4 x 0.7mm (thread pitch)/10mm (length), which take a 3mm Allen wrench (the v1 socket cap screws take a 9/64" Allen wrench). 205 | > 206 | > Skid Plates: The skid plate screws are M4 x 0.7mm (thread pitch)/6mm (length), which take a 3mm Allen wrench. 207 | > 208 | > Belt Tensioning Screws: The belt tensioning screws on the motor mounts are M4 x 0.7mm (thread pitch)/6mm (length) and take a 3mm Allen wrench. 209 | > 210 | > Truck Hardware: The stock truck hardware on boards with a standard range battery is 1.25” (length) and on extended range boards, it's 1.5” (length). 211 | > 212 | > Truck Mounting Nuts: The truck mounting nuts are standard skateboard/longbord truck mounting nuts, which #10-32 (diameter - thread count) and take a 3/8" wrench. 213 | > 214 | > Truck Kingpin Nuts: The truck mounting nuts are standard skateboard/longbord truck mounting nuts, which are 3/8"-24 (diameter - thread count) and take a 9/16" wrench. 215 | > 216 | > Wheel Pulley Bearings: The V2 & V3 pulleys use 6903-2RS bearings on the inside; the V1 uses 6804-2RS. 217 | > 218 | > Wheel Pulley Washers: The big silver wheel/drive pulley washers on v3/v2 trucks are 18.25mm (approximate inside diameter) x 25mm (outside diameter) x 0.5mm (thickness). 219 | > 220 | > Long Axle Spacers (only used on V1 & V2 trucks): The long cylindrical axle spacers are 8mm x 19mm (length). 221 | > 222 | > Wheel Bearings: The wheels use standard 10.29mm (0.405", width) skateboard/longboard bearings for 8mm axles, however, the rear wheels cannot use bearings with built-in spacers on the inside, such as Zealous. Other options, such as Bones Reds, don't have built-in spacers. 223 | > 224 | > Bearing Spacers (only used on front wheels): The bearing spacers are 8mm x 10mm (made for 8mm axles), which are commonly used on skateboards/longboards. 225 | > 226 | > Speed Rings: The speed rings sit on the inside and outside of the front wheel bearings, but only on the outside of the rear wheel bearings. They are standard skateboard/longboard speed rings. 227 | > 228 | > Axle Nuts: The axle/wheel nuts are standard skateboard/longbord axle nuts, which are 5/16"-24 (diameter - thread count) and take a 1/2" wrench. 229 | -------------------------------------------------------------------------------- /CAN/BoostedBreakCAN/PCANBasicDriver.cpp: -------------------------------------------------------------------------------- 1 | /*** 2 | * BoostedBreak - BoostedBreakCAN Program 3 | * 4 | * PCANBasicDriver.cpp 5 | * 6 | * Author: Alexander Krysl (axkrysl47) 7 | * Date: 2022/04/03 8 | **/ 9 | 10 | #include "PCANBasicDriver.h" 11 | 12 | #undef REPEAT_TRANSMIT_IN_RECEIVE 13 | 14 | PCANBasicDriver::PCANBasicDriver(TPCANHandle handle, TPCANBaudrate bitrate, bool showOutput) 15 | { 16 | m_IsInitialized = false; 17 | m_IsTraceConfigured = false; 18 | 19 | PcanHandle = handle; 20 | Bitrate = bitrate; 21 | 22 | m_DriverThread = nullptr; 23 | 24 | m_ReceiveQueue = nullptr; 25 | m_ReceiveQueueFD = nullptr; 26 | m_TransmitQueue = nullptr; 27 | m_TransmitQueueFD = nullptr; 28 | 29 | SetDriverThreadErrorLogging(showOutput); 30 | 31 | if (m_DriverThreadErrorLogFlag == true) 32 | { 33 | ShowConfigurationHelp(); // Shows information about this sample 34 | ShowCurrentConfiguration(); // Shows the current parameters configuration 35 | } 36 | 37 | TPCANStatus stsResult; 38 | // Initialization of the selected channel 39 | if (IsFD) 40 | { 41 | m_ReceiveQueueFD = new std::deque(); 42 | m_TransmitQueueFD = new std::deque(); 43 | stsResult = CAN_InitializeFD(PcanHandle, BitrateFD); 44 | } 45 | else 46 | { 47 | m_ReceiveQueue = new std::deque(); 48 | m_TransmitQueue = new std::deque(); 49 | stsResult = CAN_Initialize(PcanHandle, Bitrate); 50 | } 51 | 52 | if (stsResult != PCAN_ERROR_OK) 53 | { 54 | if (m_DriverThreadErrorLogFlag == true) 55 | { 56 | PCANDebugOutput("\n"); 57 | ShowStatus(stsResult); 58 | } 59 | return; 60 | } 61 | 62 | StopDriverThread(); 63 | m_IsInitialized = true; 64 | } 65 | 66 | PCANBasicDriver::~PCANBasicDriver() 67 | { 68 | StopDriverThread(); 69 | CAN_Uninitialize(PCAN_NONEBUS); 70 | if (IsFD) 71 | { 72 | delete m_ReceiveQueueFD; 73 | delete m_TransmitQueueFD; 74 | } 75 | else 76 | { 77 | delete m_ReceiveQueue; 78 | delete m_TransmitQueue; 79 | } 80 | m_IsInitialized = false; 81 | if (m_DriverThreadErrorLogFlag == true) 82 | { 83 | PCANDebugOutput("PCAN-Basic De-initialized.\n"); 84 | } 85 | } 86 | 87 | bool PCANBasicDriver::GetIsInitialized() 88 | { 89 | return m_IsInitialized; 90 | } 91 | 92 | bool PCANBasicDriver::GetIsTraceConfigured() 93 | { 94 | return m_IsTraceConfigured; 95 | } 96 | 97 | bool PCANBasicDriver::SetDriverThreadErrorLogging(bool flag) 98 | { 99 | m_DriverThreadErrorLogFlag = flag; 100 | return m_DriverThreadErrorLogFlag; 101 | } 102 | 103 | TPCANStatus PCANBasicDriver::GetDriverStatus() 104 | { 105 | return CAN_GetStatus(PcanHandle); 106 | } 107 | 108 | bool PCANBasicDriver::ConfigureTrace(bool singleFileOnly, bool showDate, bool showTime, bool overwriteEnabled, 109 | uint32_t fileSizeMegabytes, LPCSTR path, int32_t interval) 110 | { 111 | if (path == nullptr) 112 | { 113 | return false; 114 | } 115 | 116 | TraceFileSingle = singleFileOnly; 117 | TraceFileDate = showDate; 118 | TraceFileTime = showTime; 119 | TraceFileOverwrite = overwriteEnabled; 120 | TraceFileSize = fileSizeMegabytes; 121 | TracePath = path; 122 | TimerInterval = interval; 123 | 124 | return SetTraceConfiguration(); 125 | } 126 | 127 | bool PCANBasicDriver::StartDriverThread() 128 | { 129 | m_DriverThreadActive = true; 130 | m_DriverThread = new std::thread(&PCANBasicDriver::DriverThreadProcess, this); 131 | return m_DriverThreadActive; 132 | } 133 | 134 | bool PCANBasicDriver::StopDriverThread() 135 | { 136 | m_DriverThreadActive = false; 137 | if (m_DriverThread != nullptr) 138 | { 139 | m_DriverThread->join(); 140 | } 141 | m_DriverThread = nullptr; 142 | return m_DriverThreadActive; 143 | } 144 | 145 | bool PCANBasicDriver::Receive(TPCANMsg* msgCanMessage) 146 | { 147 | if (m_ReceiveQueue == nullptr 148 | || m_ReceiveQueue->empty() == true) 149 | { 150 | return false; 151 | } 152 | 153 | *msgCanMessage = m_ReceiveQueue->front(); 154 | m_ReceiveQueue->pop_front(); 155 | 156 | return true; 157 | } 158 | 159 | bool PCANBasicDriver::ReceiveFD(TPCANMsgFD* msgCanMessageFD) 160 | { 161 | if (m_ReceiveQueueFD == nullptr 162 | || m_ReceiveQueueFD->empty() == true) 163 | { 164 | return false; 165 | } 166 | 167 | *msgCanMessageFD = m_ReceiveQueueFD->front(); 168 | m_ReceiveQueueFD->pop_front(); 169 | 170 | return true; 171 | } 172 | 173 | bool PCANBasicDriver::Transmit(TPCANMsg msgCanMessage) 174 | { 175 | if (MESSAGE_QUEUE_SIZE <= m_TransmitQueue->size()) 176 | { 177 | return false; // Transmit Queue full. Try same message next time. 178 | } 179 | 180 | m_TransmitQueue->push_back(msgCanMessage); 181 | 182 | #ifdef REPEAT_TRANSMIT_IN_RECEIVE 183 | if (MESSAGE_QUEUE_SIZE <= m_ReceiveQueue->size()) 184 | { 185 | // We missed some messages. 186 | m_ReceiveQueue->pop_front(); 187 | m_ReceiveQueue->push_back(msgCanMessage); 188 | } 189 | else 190 | { 191 | m_ReceiveQueue->push_back(msgCanMessage); 192 | } 193 | #endif //REPEAT_TRANSMIT_IN_RECEIVE 194 | 195 | return true; 196 | } 197 | 198 | bool PCANBasicDriver::TransmitFD(TPCANMsgFD msgCanMessageFD) 199 | { 200 | if (MESSAGE_QUEUE_SIZE <= m_TransmitQueueFD->size()) 201 | { 202 | return false; // Transmit Queue full. Try same message next time. 203 | } 204 | 205 | m_TransmitQueueFD->push_back(msgCanMessageFD); 206 | 207 | #ifdef REPEAT_TRANSMIT_IN_RECEIVE 208 | if (MESSAGE_QUEUE_SIZE <= m_ReceiveQueueFD->size()) 209 | { 210 | // We missed some messages. 211 | m_ReceiveQueueFD->pop_front(); 212 | m_ReceiveQueueFD->push_back(msgCanMessageFD); 213 | } 214 | else 215 | { 216 | m_ReceiveQueueFD->push_back(msgCanMessageFD); 217 | } 218 | #endif //REPEAT_TRANSMIT_IN_RECEIVE 219 | 220 | return true; 221 | } 222 | 223 | TPCANStatus PCANBasicDriver::TransmitImmediate(TPCANMsg msgCanMessage) 224 | { 225 | return CAN_Write(PcanHandle, &msgCanMessage); 226 | } 227 | 228 | TPCANStatus PCANBasicDriver::TransmitImmediateFD(TPCANMsgFD msgCanMessageFD) 229 | { 230 | return CAN_WriteFD(PcanHandle, &msgCanMessageFD); 231 | } 232 | 233 | bool PCANBasicDriver::StartTrace() 234 | { 235 | UINT32 iStatus = PCAN_PARAMETER_ON; 236 | 237 | TPCANStatus stsResult = CAN_SetValue(PcanHandle, PCAN_TRACE_STATUS, &iStatus, sizeof(UINT32)); // We activate the tracing by setting the parameter. 238 | 239 | if (m_DriverThreadErrorLogFlag == true && stsResult != PCAN_ERROR_OK) 240 | { 241 | ShowStatus(stsResult); 242 | return false; 243 | } 244 | return true; 245 | } 246 | 247 | void PCANBasicDriver::StopTrace() 248 | { 249 | UINT32 iStatus = PCAN_PARAMETER_OFF; 250 | 251 | TPCANStatus stsResult = CAN_SetValue(PcanHandle, PCAN_TRACE_STATUS, &iStatus, sizeof(UINT32)); // We stop the tracing by setting the parameter. 252 | 253 | if (m_DriverThreadErrorLogFlag == true && stsResult != PCAN_ERROR_OK) 254 | ShowStatus(stsResult); 255 | } 256 | 257 | void PCANBasicDriver::TestLookUpChannels() 258 | { 259 | PCANDebugOutput("LookUpChannel Started...\n"); 260 | 261 | ShowCurrentConfiguration(); // Shows the current parameters configuration 262 | 263 | PCANDebugOutput("Start searching...\n"); 264 | PCANDebugSystemPause(); 265 | PCANDebugOutput("\n"); 266 | 267 | char sParameters[MAX_PATH]; 268 | if (DeviceType != "") 269 | sprintf_s(sParameters, sizeof(sParameters), "%s=%s", ConvertDefinesToChar((wchar_t*)LOOKUP_DEVICE_TYPE), DeviceType); 270 | if (DeviceID != "") 271 | { 272 | if (sParameters != "") 273 | sprintf_s(sParameters, sizeof(sParameters), "%s, ", sParameters); 274 | sprintf_s(sParameters, sizeof(sParameters), "%s%s=%s", sParameters, ConvertDefinesToChar((wchar_t*)LOOKUP_DEVICE_ID), DeviceID); 275 | } 276 | if (ControllerNumber != "") 277 | { 278 | if (sParameters != "") 279 | sprintf_s(sParameters, sizeof(sParameters), "%s, ", sParameters); 280 | sprintf_s(sParameters, sizeof(sParameters), "%s%s=%s", sParameters, ConvertDefinesToChar((wchar_t*)LOOKUP_CONTROLLER_NUMBER), ControllerNumber); 281 | } 282 | if (IPAddress != "") 283 | { 284 | if (sParameters != "") 285 | sprintf_s(sParameters, sizeof(sParameters), "%s, ", sParameters); 286 | sprintf_s(sParameters, sizeof(sParameters), "%s%s=%s", sParameters, ConvertDefinesToChar((wchar_t*)LOOKUP_IP_ADDRESS), IPAddress); 287 | } 288 | 289 | TPCANHandle handle; 290 | TPCANStatus stsResult = CAN_LookUpChannel((LPSTR)sParameters, &handle); 291 | 292 | if (stsResult == PCAN_ERROR_OK) 293 | { 294 | 295 | if (handle != PCAN_NONEBUS) 296 | { 297 | UINT32 iFeatures; 298 | stsResult = CAN_GetValue(handle, PCAN_CHANNEL_FEATURES, &iFeatures, sizeof(UINT32)); 299 | 300 | if (stsResult == PCAN_ERROR_OK) 301 | { 302 | char buffer[MAX_PATH]; 303 | FormatChannelName(handle, buffer, (iFeatures & FEATURE_FD_CAPABLE) == FEATURE_FD_CAPABLE); 304 | PCANDebugOutput("The channel handle "); 305 | PCANDebugOutput(buffer); 306 | PCANDebugOutput(" was found\n"); 307 | } 308 | else 309 | PCANDebugOutput("There was an issue retrieveing supported channel features\n"); 310 | } 311 | else 312 | PCANDebugOutput("A handle for these lookup-criteria was not found\n"); 313 | } 314 | 315 | if (m_DriverThreadErrorLogFlag == true && stsResult != PCAN_ERROR_OK) 316 | { 317 | PCANDebugOutput("There was an error looking up the device, are any hardware channels attached?\n"); 318 | ShowStatus(stsResult); 319 | } 320 | 321 | PCANDebugOutput("\n"); 322 | PCANDebugOutput("Closing...\n"); 323 | PCANDebugSystemPause(); 324 | } 325 | 326 | void PCANBasicDriver::TestGetSetParameter() 327 | { 328 | // Setting Parameters... 329 | PCANDebugOutput("Get/set parameter\n"); 330 | PCANDebugSystemPause(); 331 | PCANDebugOutput("\n"); 332 | 333 | //SetPCAN_DEVICE_ID(PcanHandle, 0xFF); 334 | //PCANDebugOutput("Fill \"GetSetParameter\"-function with parameter functions from \"PCANBasicParameter\"-Region in the code.\n"); 335 | 336 | PCANDebugOutput("\n"); 337 | PCANDebugOutput("Closing...\n"); 338 | PCANDebugSystemPause(); 339 | } 340 | 341 | void PCANBasicDriver::TestManualWrite() 342 | { 343 | TPCANStatus status; 344 | BYTE data[8]; 345 | for (BYTE i = 0; i < 8; i++) 346 | { 347 | data[i] = i; 348 | } 349 | TPCANMsg msgCanMessage = CreateTPCANMsg(0x100, PCAN_MESSAGE_EXTENDED, 8, data); 350 | 351 | // Writing messages... 352 | PCANDebugOutput("For write: "); 353 | PCANDebugSystemPause(); 354 | do 355 | { 356 | PCANDebugSystemClear(); 357 | 358 | status = CAN_Write(PcanHandle, &msgCanMessage); 359 | if (m_DriverThreadErrorLogFlag == true && status != PCAN_ERROR_OK) 360 | ShowStatus(status); 361 | else 362 | PCANDebugOutput("Message was successfully SENT\n"); 363 | 364 | PCANDebugOutput("Do you want to write again? yes[y] or any other key to close\n"); 365 | } while (_getch() == 121); 366 | } 367 | 368 | void PCANBasicDriver::TestTraceFiles() 369 | { 370 | // Trace messages. 371 | PCANDebugOutput("Starting trace: "); 372 | PCANDebugSystemPause(); 373 | if (SetTraceConfiguration()) 374 | { 375 | if (StartTrace()) 376 | { 377 | m_DriverThreadActive = true; 378 | m_DriverThread = new std::thread(&PCANBasicDriver::DriverThreadProcess, this); 379 | PCANDebugOutput("Messages are being traced.\n"); 380 | PCANDebugOutput("Stop trace and quit: "); 381 | PCANDebugSystemPause(); 382 | StopTrace(); 383 | return; 384 | } 385 | } 386 | PCANDebugOutput("\n"); 387 | PCANDebugOutput("For close: "); 388 | PCANDebugSystemPause(); 389 | } 390 | 391 | 392 | void PCANBasicDriver::DriverThreadProcess() 393 | { 394 | while (m_DriverThreadActive) 395 | { 396 | std::this_thread::sleep_for(std::chrono::microseconds(50)); 397 | ReceiveProcess(); 398 | TransmitProcess(); 399 | } 400 | } 401 | 402 | void PCANBasicDriver::ReceiveProcess() 403 | { 404 | // We read at least one time the queue looking for messages. If a message is found, we look again trying to 405 | // find more. If the queue is empty or an error occurs, we get out from the dowhile statement. 406 | TPCANStatus stsResult; 407 | TPCANMsgFD CANMsgFD; 408 | TPCANMsg CANMsg; 409 | UINT64 TimestampFD; 410 | TPCANTimestamp Timestamp; 411 | do 412 | { 413 | if (IsFD == true) 414 | { 415 | stsResult = CAN_ReadFD(PcanHandle, &CANMsgFD, &TimestampFD); 416 | if (m_DriverThreadErrorLogFlag == true 417 | && stsResult != PCAN_ERROR_OK && stsResult != PCAN_ERROR_QRCVEMPTY) 418 | { 419 | ShowStatus(stsResult); 420 | return; 421 | } 422 | else if (stsResult == PCAN_ERROR_OK) 423 | { 424 | if (MESSAGE_QUEUE_SIZE <= m_ReceiveQueueFD->size()) 425 | { 426 | m_ReceiveQueueFD->pop_front(); 427 | m_ReceiveQueueFD->push_back(CANMsgFD); 428 | } 429 | else 430 | { 431 | m_ReceiveQueueFD->push_back(CANMsgFD); 432 | } 433 | } 434 | } 435 | else 436 | { 437 | stsResult = CAN_Read(PcanHandle, &CANMsg, &Timestamp); 438 | if (m_DriverThreadErrorLogFlag == true 439 | && stsResult != PCAN_ERROR_OK && stsResult != PCAN_ERROR_QRCVEMPTY) 440 | { 441 | ShowStatus(stsResult); 442 | return; 443 | } 444 | else if (stsResult == PCAN_ERROR_OK) 445 | { 446 | if (MESSAGE_QUEUE_SIZE <= m_ReceiveQueue->size()) 447 | { 448 | // We missed some messages. 449 | m_ReceiveQueue->pop_front(); 450 | m_ReceiveQueue->push_back(CANMsg); 451 | } 452 | else 453 | { 454 | m_ReceiveQueue->push_back(CANMsg); 455 | } 456 | } 457 | } 458 | } while ((!(stsResult & PCAN_ERROR_QRCVEMPTY))); 459 | } 460 | 461 | void PCANBasicDriver::TransmitProcess() 462 | { 463 | TPCANStatus stsResult; 464 | TPCANMsgFD CANMsgFD; 465 | TPCANMsg CANMsg; 466 | 467 | if (IsFD) 468 | { 469 | while (m_TransmitQueueFD->empty() == false) 470 | { 471 | CANMsgFD = m_TransmitQueueFD->front(); 472 | stsResult = CAN_WriteFD(PcanHandle, &CANMsgFD); 473 | if (m_DriverThreadErrorLogFlag == true 474 | && stsResult != PCAN_ERROR_OK 475 | && stsResult != PCAN_ERROR_XMTFULL && stsResult != PCAN_ERROR_QXMTFULL) 476 | { 477 | ShowStatus(stsResult); 478 | return; 479 | } 480 | else if (stsResult == PCAN_ERROR_XMTFULL || stsResult == PCAN_ERROR_QXMTFULL) 481 | { 482 | return; // Transmit Queue full. Try same message next time. 483 | } 484 | else if (stsResult == PCAN_ERROR_OK) 485 | { 486 | m_TransmitQueueFD->pop_front(); 487 | } 488 | } 489 | } 490 | else 491 | { 492 | while (m_TransmitQueue->empty() == false) 493 | { 494 | CANMsg = m_TransmitQueue->front(); 495 | stsResult = CAN_Write(PcanHandle, &CANMsg); 496 | if (m_DriverThreadErrorLogFlag == true 497 | && stsResult != PCAN_ERROR_OK 498 | && stsResult != PCAN_ERROR_XMTFULL && stsResult != PCAN_ERROR_QXMTFULL) 499 | { 500 | ShowStatus(stsResult); 501 | return; 502 | } 503 | else if (stsResult == PCAN_ERROR_XMTFULL || stsResult == PCAN_ERROR_QXMTFULL) 504 | { 505 | return; // Transmit Queue full. Try same message next time. 506 | } 507 | else if (stsResult == PCAN_ERROR_OK) 508 | { 509 | m_TransmitQueue->pop_front(); 510 | } 511 | } 512 | } 513 | } 514 | 515 | bool PCANBasicDriver::SetTraceConfiguration() 516 | { 517 | m_IsTraceConfigured = false; 518 | 519 | UINT32 iSize = TraceFileSize; 520 | 521 | // Sets path to store files 522 | TPCANStatus stsResult = CAN_SetValue(PcanHandle, PCAN_TRACE_LOCATION, (void*)TracePath, sizeof(TracePath)); 523 | 524 | if (stsResult == PCAN_ERROR_OK) 525 | { 526 | // Sets the maximum size of a tracefile 527 | stsResult = CAN_SetValue(PcanHandle, PCAN_TRACE_SIZE, &iSize, sizeof(UINT32)); 528 | 529 | if (stsResult == PCAN_ERROR_OK) 530 | { 531 | UINT32 config; 532 | if (TraceFileSingle) 533 | config = TRACE_FILE_SINGLE; // Creats one file 534 | else 535 | config = TRACE_FILE_SEGMENTED; // Creats more files 536 | 537 | // Activate overwriting existing tracefile 538 | if (TraceFileOverwrite) 539 | config = config | TRACE_FILE_OVERWRITE; 540 | 541 | // Adds date to tracefilename 542 | if (TraceFileDate) 543 | config = config | TRACE_FILE_DATE; 544 | 545 | // Adds time to tracefilename 546 | if (TraceFileTime) 547 | config = config | TRACE_FILE_TIME; 548 | 549 | // Sets the config 550 | stsResult = CAN_SetValue(PcanHandle, PCAN_TRACE_CONFIGURE, &config, sizeof(int)); 551 | 552 | if (stsResult == PCAN_ERROR_OK) 553 | { 554 | m_IsTraceConfigured = true; 555 | return true; 556 | } 557 | } 558 | } 559 | if (m_DriverThreadErrorLogFlag == true) 560 | { 561 | ShowStatus(stsResult); 562 | } 563 | return false; 564 | } 565 | 566 | void PCANBasicDriver::ShowConfigurationHelp() 567 | { 568 | PCANDebugOutput("=========================================================================================\n"); 569 | PCANDebugOutput("| PCAN-Basic Class Driver |\n"); 570 | PCANDebugOutput("=========================================================================================\n"); 571 | PCANDebugOutput("Following parameters are to be adjusted before launching, according to the hardware used |\n"); 572 | PCANDebugOutput(" |\n"); 573 | PCANDebugOutput("* PcanHandle: Numeric value that represents the handle of the PCAN-Basic channel to use. |\n"); 574 | PCANDebugOutput(" See 'PCAN-Handle Definitions' within the documentation |\n"); 575 | PCANDebugOutput("* IsFD: Boolean value that indicates the communication mode, CAN (false) or CAN-FD (true)|\n"); 576 | PCANDebugOutput("* Bitrate: Numeric value that represents the BTR0/BR1 bitrate value to be used for CAN |\n"); 577 | PCANDebugOutput(" communication |\n"); 578 | PCANDebugOutput("* BitrateFD: String value that represents the nominal/data bitrate value to be used for |\n"); 579 | PCANDebugOutput(" CAN-FD communication |\n"); 580 | PCANDebugOutput("* TraceFileSingle: Boolean value that indicates if tracing ends after one file (true) or |\n"); 581 | PCANDebugOutput(" continues |\n"); 582 | PCANDebugOutput("* TraceFileDate: Boolean value that indicates if the date will be added to filename |\n"); 583 | PCANDebugOutput("* TraceFileTime: Boolean value that indicates if the time will be added to filename |\n"); 584 | PCANDebugOutput("* TraceFileOverwrite: Boolean value that indicates if existing tracefiles should be |\n"); 585 | PCANDebugOutput(" overwritten |\n"); 586 | PCANDebugOutput("* TraceFileSize: Numeric value that represents the size of a tracefile in meagabytes |\n"); 587 | PCANDebugOutput("* TracePath: string value that represents a valid path to an existing directory |\n"); 588 | PCANDebugOutput("* TimerInterval: The time, in milliseconds, to wait before trying to write a message |\n"); 589 | PCANDebugOutput("=========================================================================================\n"); 590 | PCANDebugOutput("\n"); 591 | } 592 | 593 | void PCANBasicDriver::ShowCurrentConfiguration() 594 | { 595 | PCANDebugOutput("Parameter values used\n"); 596 | PCANDebugOutput("----------------------\n"); 597 | char buffer[MAX_PATH]; 598 | FormatChannelName(PcanHandle, buffer, IsFD); 599 | PCANDebugOutput("* PCANHandle: "); 600 | PCANDebugOutput(buffer); 601 | PCANDebugOutput("\n"); 602 | if (IsFD) 603 | PCANDebugOutput("* IsFD: True\n"); 604 | else 605 | PCANDebugOutput("* IsFD: False\n"); 606 | ConvertBitrateToString(Bitrate, buffer); 607 | PCANDebugOutput("* Bitrate: "); 608 | PCANDebugOutput(buffer); 609 | PCANDebugOutput("\n"); 610 | PCANDebugOutput("* BitrateFD: "); 611 | PCANDebugOutput(BitrateFD); 612 | PCANDebugOutput("\n"); 613 | if (TraceFileSingle) 614 | PCANDebugOutput("* TraceFileSingle: True\n"); 615 | else 616 | PCANDebugOutput("* TraceFileSingle: False\n"); 617 | if (TraceFileDate) 618 | PCANDebugOutput("* TraceFileDate: True\n"); 619 | else 620 | PCANDebugOutput("* TraceFileDate: False\n"); 621 | if (TraceFileTime) 622 | PCANDebugOutput("* TraceFileTime: True\n"); 623 | else 624 | PCANDebugOutput("* TraceFileTime: False\n"); 625 | if (TraceFileOverwrite) 626 | PCANDebugOutput("* TraceFileOverwrite: True\n"); 627 | else 628 | PCANDebugOutput("* TraceFileOverwrite: False\n"); 629 | PCANDebugOutput("* TraceFileSize: "); 630 | PCANDebugOutput(std::to_string(TraceFileSize)); 631 | PCANDebugOutput(" MB\n"); 632 | if (TracePath == "") 633 | { 634 | PCANDebugOutput("* TracePath: (calling application path)\n"); 635 | } 636 | else 637 | { 638 | PCANDebugOutput("* TracePath: "); 639 | PCANDebugOutput(TracePath); 640 | PCANDebugOutput("\n"); 641 | } 642 | PCANDebugOutput("* TimerInterval: "); 643 | PCANDebugOutput(std::to_string(TimerInterval)); 644 | PCANDebugOutput("\n"); 645 | PCANDebugOutput("\n"); 646 | } 647 | --------------------------------------------------------------------------------