diff --git a/reference/speeduino.ini b/reference/speeduino.ini index e80026ef..a87d6b51 100644 --- a/reference/speeduino.ini +++ b/reference/speeduino.ini @@ -448,7 +448,16 @@ page = 1 rtc_trim = scalar, S08, 123, "ppm", 1, 0, -127, +127, 0 idleAdvVss = scalar, U08, 124, "km/h", 1, 0.0, 0.0, 255, 0 mapSwitchPoint = scalar, U08, 125, "RPM", 100, 0.0, 0.0, 16320, 0 - unused2_95 = array, U08, 126, [2], "%", 1.0, 0.0, 0.0, 255, 0 + + canBMWCluster = bits, U08, 126, [0:0], "Off", "On" + canVAGCluster = bits, U08, 126, [1:1], "Off", "On" + ;These are reserved for future use, in case of more CAN broadcasting features are added + enable1Cluster = bits, U08, 126, [2:2], "Off", "On" + enable2Cluster = bits, U08, 126, [3:3], "Off", "On" + unusedClusterBits = bits, U08, 126, [4:7], "INVALID","INVALID","INVALID","INVALID","INVALID","INVALID","INVALID","INVALID","INVALID","INVALID","INVALID","INVALID","INVALID","INVALID","INVALID","INVALID" + + unused2-95 = scalar, U08, 127, "RPM", 100, 0.0, 0.0, 16320, 0 + ;Page 2 is the fuel map and axis bins only page = 2 @@ -1797,6 +1806,7 @@ menuDialog = main #if CAN_COMMANDS subMenu = can_serial3IO, "Canbus/Secondary Serial IO Interface" + subMenu = CanBcast, "CAN Broadcasting menu", { enable_intcan && intcan_available } subMenu = std_separator subMenu = Canin_config, "External Auxillary Input Channel Configuration", {enable_secondarySerial || (enable_intcan && intcan_available)} subMenu = Auxin_config, "Local Auxillary Input Channel Configuration" @@ -1804,6 +1814,7 @@ menuDialog = main ;subMenu = Canout_config, "Canbus Output Configuration" #else subMenu = serial3IO, "Canbus/Secondary Serial IO Interface" + subMenu = CanBcast, "CAN Broadcasting menu", { enable_intcan && intcan_available } subMenu = std_separator subMenu = Canin_config, "External Auxiliary Input Channel Configuration", {enable_secondarySerial || (enable_intcan && intcan_available)} subMenu = Auxin_config, "Local Auxiliary Input Channel Configuration" @@ -2211,7 +2222,7 @@ menuDialog = main #else resetControl = "If set to Serial Command, normally hold the control pin high but pull it low when the 'U' serial command is issued and reset upon receiving more data. The control pin should be connected to the Arduino's reset pin." #endif - resetControlPin = "The Arduino pin used to control resets." + resetControlPin = "The Arduino pin used to control resets." rtc_mode = "Enables the real time clock for time keeping" onboard_log_file_style = "Sdcard datalogger can be Disabled, CSV=Comma separated values, Binary is a Binary format equal to the A comand style current status" @@ -2238,6 +2249,8 @@ menuDialog = main battVCorMode = "The Battery Voltage Correction value from the table below can either be applied on the whole injection Pulse Width value, or only on the Open Time value." dwellTable = "Sets the dwell time in milliseconds based on RPM/load. This can be used to reduce stress/wear on ignition system where long dwell is not needed. And other areas can use longer dwell value if needed for stronger spark. Battery voltage correction is applied for these dwell values." useDwellMap = "In normal operation mode this is set to No and speeduino will use fixed running dwell value. But if different dwell values are required across engine RPM/load range, this can be set to Yes and separate Dwell table defines running dwell value." + canBMWCluster = "Enables CAN broadcasting for BMW E46, E39 and E38 instrument clusters with message ID's 0x316, 0x329 and 0x545" + canVAGCluster = "Enables CAN broadcasting for VAG instrument clusters with message ID's 0x280 and 0x5A0" [UserDefined] @@ -3234,6 +3247,10 @@ menuDialog = main commandButton = "Reboot to system", cmdstm32reboot commandButton = "Reboot to bootloader", cmdstm32bootloader + dialog = CanBcast, "CAN Broadcasting menu" + field = "BMW Instrument Cluster Broadcast", canBMWCluster + field = "VAG Instrument Cluster Broadcast", canVAGCluster + dialog = Auxin_north displayOnlyField = #"Secondary Serial ENABLED", blankfield, {enable_secondarySerial},{enable_secondarySerial} displayOnlyField = !"Secondary Serial DISABLED", blankfield, {enable_secondarySerial == 0},{enable_secondarySerial == 0} diff --git a/speeduino/canBroadcast.h b/speeduino/canBroadcast.h new file mode 100644 index 00000000..34e7f54c --- /dev/null +++ b/speeduino/canBroadcast.h @@ -0,0 +1,21 @@ +#ifndef CANBROADCAST_H +#define CANBROADCAST_H +#if defined(NATIVE_CAN_AVAILABLE) + +//For BMW e46/e39/e38, rover and mini other CAN instrument clusters +#define CAN_BMW_ASC1 0x153 //Rx message from ACS unit that includes speed +#define CAN_BMW_DME1 0x316 //Tx message that includes RPM +#define CAN_BMW_DME2 0x329 //Tx message that includes CLT and TPS +#define CAN_BMW_DME4 0x545 //Tx message that includes CLT and TPS +#define CAN_BMW_ICL2 0x613 +#define CAN_BMW_ICL3 0x615 + +//For VAG CAN instrument clusters +#define CAN_VAG_RPM 0x280 +#define CAN_VAG_VSS 0x5A0 + +void sendBMWCluster(); +void sendVAGCluster(); +void DashMessages(uint16_t DashMessageID); +#endif +#endif // CANBROADCAST_H diff --git a/speeduino/canBroadcast.ino b/speeduino/canBroadcast.ino new file mode 100644 index 00000000..2ef6c7ad --- /dev/null +++ b/speeduino/canBroadcast.ino @@ -0,0 +1,116 @@ +/* +Speeduino - Simple engine management for the Arduino Mega 2560 platform +Copyright (C) Josh Stewart +A full copy of the license may be found in the projects root directory +*/ + +/* +This is for handling the data broadcasted to various CAN dashes and instrument clusters. +*/ +#if defined(NATIVE_CAN_AVAILABLE) +#include "globals.h" + +void sendBMWCluster() +{ + DashMessage(CAN_BMW_DME1); + Can0.write(outMsg); + DashMessage(CAN_BMW_DME2); + Can0.write(outMsg); + DashMessage(CAN_BMW_DME4); + Can0.write(outMsg); +} + +void sendVAGCluster() +{ + DashMessage(CAN_VAG_RPM); + Can0.write(outMsg); + DashMessage(CAN_VAG_VSS); + Can0.write(outMsg); +} + +// switch case for gathering all data to message based on CAN Id. +void DashMessage(uint16_t DashMessageID) +{ + switch (DashMessageID) + { + case CAN_BMW_DME1: + outMsg.id = DashMessageID; + outMsg.len = 8; + outMsg.buf[0] = 0x05; //bitfield, Bit0 = 1 = terminal 15 on detected, Bit2 = 1 = the ASC message ASC1 was received within the last 500 ms and contains no plausibility errors + outMsg.buf[1] = 0x0C; //Indexed Engine Torque in % of C_TQ_STND TBD do torque calculation. + outMsg.buf[2] = 0x00; //lsb RPM + outMsg.buf[3] = currentStatus.RPM / 40; //msb RPM. RPM conversion is currentStatus.RPM * 6.4, but this does close enough without floats. + outMsg.buf[4] = 0x0C; //Indicated Engine Torque in % of C_TQ_STND TBD do torque calculation!! Use same as for byte 1 + outMsg.buf[5] = 0x15; //Engine Torque Loss (due to engine friction, AC compressor and electrical power consumption) + outMsg.buf[6] = 0x00; //not used + outMsg.buf[7] = 0x35; //Theorethical Engine Torque in % of C_TQ_STND after charge intervention + break; + + case CAN_BMW_DME2: + uint8_t temp_TPS; + uint8_t temp_BARO; + int16_t temp_CLT; + temp_TPS = map(currentStatus.TPS, 0, 100, 0, 254);//TPS value conversion (from 0x00 to 0xFE) + temp_CLT = (((currentStatus.coolant - CALIBRATION_TEMPERATURE_OFFSET) + 48)*4/3); //CLT conversion (actual value to add is 48.373, but close enough) + if (temp_CLT > 255) { temp_CLT = 255; } //CLT conversion can yield to higher values than what fits to byte, so limit the maximum value to 255. + temp_BARO = currentStatus.baro; + + outMsg.id = DashMessageID; + outMsg.len = 7; + outMsg.buf[0] = 0x11; //Multiplexed Information + outMsg.buf[1] = temp_CLT; + outMsg.buf[2] = temp_BARO; + outMsg.buf[3] = 0x08; //bitfield, Bit0 = 0 = Clutch released, Bit 3 = 1 = engine running + outMsg.buf[4] = 0x00; //TPS_VIRT_CRU_CAN (Not used) + outMsg.buf[5] = temp_TPS; + outMsg.buf[6] = 0x00; //bitfield, Bit0 = 0 = brake not actuated, Bit1 = 0 = brake switch system OK etc... + outMsg.buf[7] = 0x00; //not used, but set to zero just in case. + break; + + case 0x545: //fuel consumption and CEl light for BMW e46/e39/e38 instrument cluster + //fuel consumption calculation not implemented yet. But this still needs to be sent to get rid of the CEL and EML fault lights on the dash. + outMsg.id = DashMessageID; + outMsg.len = 5; + outMsg.buf[0] = 0x00; //Check engine light (binary 10), Cruise light (binary 1000), EML (binary 10000). + outMsg.buf[1] = 0x00; //LSB Fuel consumption + outMsg.buf[2] = 0x00; //MSB Fuel Consumption + if (currentStatus.coolant > 159) { outMsg.buf[3] = 0x08; } //Turn on overheat light if coolant temp hits 120 degrees celcius. + else { outMsg.buf[3] = 0x00; } //Overheat light off at normal engine temps. + outMsg.buf[4] = 0x7E; //this is oil temp + break; + + case 0x280: //RPM for VW instrument cluster + int16_t temp_RPM; + temp_RPM = currentStatus.RPM * 4; //RPM conversion + outMsg.id = DashMessageID; + outMsg.len = 8; + outMsg.buf[0] = 0x49; + outMsg.buf[1] = 0x0E; + outMsg.buf[2] = lowByte(temp_RPM); + outMsg.buf[3] = highByte(temp_RPM); + outMsg.buf[4] = 0x0E; + outMsg.buf[5] = 0x00; + outMsg.buf[6] = 0x1B; + outMsg.buf[7] = 0x0E; + break; + + case 0x5A0: //VSS for VW instrument cluster + uint16_t temp_VSS; + temp_VSS = currentStatus.vss * 133; //VSS conversion + outMsg.id = DashMessageID; + outMsg.len = 8; + outMsg.buf[0] = 0xFF; + outMsg.buf[1] = lowByte(temp_VSS); + outMsg.buf[2] = highByte(temp_VSS); + outMsg.buf[3] = 0x00; + outMsg.buf[4] = 0x00; + outMsg.buf[5] = 0x00; + outMsg.buf[6] = 0x00; + outMsg.buf[7] = 0xAD; + break; + + default: + break; + } +} +#endif \ No newline at end of file diff --git a/speeduino/globals.h b/speeduino/globals.h index d40dcb30..fc101311 100644 --- a/speeduino/globals.h +++ b/speeduino/globals.h @@ -903,7 +903,13 @@ struct config2 { byte idleAdvVss; byte mapSwitchPoint; - byte unused2_95[2]; + byte canBMWCluster : 1; + byte canVAGCluster : 1; + byte enableCluster1 : 1; + byte enableCluster2 : 1; + byte unusedClusterBits : 4; + + byte unused2_95; #if defined(CORE_AVR) }; diff --git a/speeduino/speeduino.ino b/speeduino/speeduino.ino index 8fb0b58d..e7d44364 100644 --- a/speeduino/speeduino.ino +++ b/speeduino/speeduino.ino @@ -41,6 +41,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "engineProtection.h" #include "scheduledIO.h" #include "secondaryTables.h" +#include "canBroadcast.h" #include "SD_logger.h" #include RTC_LIB_H //Defined in each boards .h file #include BOARD_H //Note that this is not a real file, it is defined in globals.h. @@ -312,6 +313,10 @@ void loop() vvtControl(); //Water methanol injection wmiControl(); + #if defined(NATIVE_CAN_AVAILABLE) + if (configPage2.canBMWCluster == true) { sendBMWCluster(); } + if (configPage2.canVAGCluster == true) { sendVAGCluster(); } + #endif #if TPS_READ_FREQUENCY == 30 readTPS(); #endif diff --git a/speeduino/updates.ino b/speeduino/updates.ino index 3de64156..a3803d07 100644 --- a/speeduino/updates.ino +++ b/speeduino/updates.ino @@ -597,6 +597,15 @@ void doUpdates() storeEEPROMVersion(20); } + if(readEEPROMVersion() == 19) + { + configPage2.canBMWCluster = 0; + configPage2.canVAGCluster = 0; + + writeAllConfig(); + storeEEPROMVersion(20); + } + //Final check is always for 255 and 0 (Brand new arduino) if( (readEEPROMVersion() == 0) || (readEEPROMVersion() == 255) ) {