Quantcast
Channel: EdiabasLib Wiki Rss Feed
Viewing all 162 articles
Browse latest View live

Updated Wiki: Deep OBD for BMW

$
0
0

Deep OBD for BMW

This page describes how to use Deep OBD for BMW.
Download app from Google Play: https://play.google.com/store/apps/details?id=de.holeschak.bmw_deep_obd
Table of contents:

Supported adapters

Deep OBD for BMW supports several OBD II adapters:
  • Standard FTDI based USB "INPA compatible" D-CAN/K-Line adapters (all protocols)
  • ELM327 based Bluetooth and WiFi adapters. Recommended ELM327 versions are 1.4b, 1.5 and origin 2.1, which are based on PIC18F2480 processor (no MCP2515 chip) (D-CAN protocol only)
  • Custom Bluetooth D-CAN/K-Line adapter (BMW-FAST protocol over D-CAN and K-Line)
  • ELM327 based adapters with Replacement firmware for ELM327 D-CAN and K-Line (all protocols!)
  • ENET WiFi adapters (for BMW F-models)

First start

At the first start of Deep OBD for BMW you will be asked to download the ECU files. The file package is very large (100MB) and requires approximately 1GB on the external SDCard after extraction.
In the next step a configuration (*.cccfg file) must be created. The easiest way to do so is to use the configuration generator. For complex scenarios you could manually create configuration files (see HowTo create BMW deep OBD pages). After loading and compiling the configuration file, all tabs included in the file will be visible on the main page.
Before connecting to the vehicle a Bluetooth adapter has to be selected (or you will be asked when connecting). It's recommended to pair the adapter in the android Bluetooth menu before using it in Deep OBD for BMW, because this way a connection password could be assigned.

E61Bt.cccfgSelect Bluetooth device

The main menu

The application has a configuration menu with the following options:
  • Device: With this menu the Bluetooth adapter could be selected. If the device is not coupled already, searching for new devices is possible. This menu is only enabled if a configuration with interface type BLUETOOTH has been selected.
  • Adapter configuration: When using a FTDI USB or Bluetooth (non ELM327) adapter, this menu item opens the adapter configuration page. The following settings are available (depending from adapter type):
    • CAN baud rate: (500kbit/100kbit) or K-Line (CAN off)
    • Separation time: Separation time between CAN telegrams. The default is 0, only change this value if there are communication problems.
    • Block size: Size of CAN telegram blocks. The default is 0, only change this value if there are communication problems.
    • Firmware update: If a new firmware is available for the adapter, the update could be initiated with this button.
  • Configuration generator: Simple XML configuration files could be generated automatically using the informations obtained from the vehicle. This menu opens the configuration generator which allows to create new or modify existing XML files by simply selecting the ECU and job informations.
  • Configuration: This menu allows the selection of the configuration file (*.cccfg file). When using the configuration generator the configuration is selected automatically. After selection the file will be compiled.
  • Ediabas tool: This is a port of the tool32.exe windows application. Selecting the menu will open the Ediabas tool page.
  • Storage media: If the default storage media for the ECU files is not appropriate, a different media could be selected in this sub menu. The application storage directory on the media will be always fixed to de.holeschak.bmw_deep_obd.
  • Download ECU files: Since the BMW ECU files are very large (100MB), they are not included in the application package. When starting the application for the first time the ECU file download is requested automatically. With this menu entry the file download could be initiated manually if the ECU files are damaged.
  • Data logging: Selecting this menu entry will open a sub menu with multiple data logging options:
    • Create trace file: If the checkbox of this menu is active, a ifh.trc file will be created when the application is connected. The trace file will be created in the Log subdirectory.
    • Append trace file: If this checkbox is enabled the trace file is always appended. Otherwise the trace file will be overridden after selection of a new configuration or restart of the application.
    • Log data: This checkbox enables logging of the display data to a log file. Only those lines are logged, that have a log_tag property in the configuration file. The logfile property in the page node has to be specified as well to activate logging. When using the configuration generatorlog_tag is set by default to the job name and logfile to the ECU name. Data will be logged in the Log subdirectory.
  • Online help: Displays this help page.
  • App info: Displays the app version and unique id.
Menu
Below are some screenshots from the example E61 configuration:

Motor pageMotor pageMotor pageMotor page

Log and trace files location

The location of the log and trace files depends from the Android version.
Beginning with Android KitKat (4.4) writing to the external SdCard is not possible any more. For older Android versions log and trace files are stored in a subdirectory relative to de.holeschak.bmw_deep_obd on the external SDCard. For KitKat and above the data could be found in the directory Android\data\de.holeschak.bmw_deep_obd\files of the external SDCard.
The standard log files are stored in the subdirectory Log, whereas the Ediabas tool uses the subdirectory LogEdiabasTool and the configuration generator the subdirectory LogConfigTool.

Background image

It's possible to replace the background image. Simply store a custom Background.jpg file in the subdirectory Images of the current de.holeschak.bmw_deep_obd data directory.

Updated Wiki: Page specification

$
0
0

Defining pages for Deep OBD for BMW

Each page (tab) is defined in a single XML (*.ccpage) file. A general documentation of all XML tags could be found in the BmwDeepObd.xsd file. The documentation will be displayed in the XML editor when the xsd is added as xs:shema in the XML file.
Table of contents:

Simple jobs

If only some EDIABAS jobs with fixed arguments are required for one display page, the XML code is relative simple. Below is the example code to display climate data for a E61 vehicle:

<?xml version="1.0" encoding="utf-8" ?>
<fragment xmlns="http://www.holeschak.de/BmwDeepObd"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://www.holeschak.de/BmwDeepObd ../BmwDeepObd.xsd">
  <page name ="tab_ihk">
    <strings>
      <string name="tab_ihk">Climate</string>
      <string name="label_ihk_in_temp">Indoor temperature [°C]:</string>
      <string name="label_ihk_in_temp_delay">Indoor temperature delayed [°C]:</string>
      <string name="label_ihk_out_temp">Outdoor temperature [°C]:</string>
      <string name="label_ihk_setpoint">Setpoint [°C]:</string>
      <string name="label_ihk_heat_ex_temp">Heat exchanger temperature [°C]:</string>
      <string name="label_ihk_heat_ex_setpoint">Heat exchanger setpoint [°C]:</string>
      <string name="label_ihk_heat_ex_actuator">Heat exchanger actuator [%]:</string>
      <string name="label_ihk_main_actuator">Main actuator [%]:</string>
      <string name="label_ihk_evap_temp">Evaporator temperature [°C]:</string>
      <string name="label_ihk_press_sense">Pressure sensor [bar]:</string>
      <string name="label_ihk_circ_air_left">Circulating air left [%]:</string>
      <string name="label_ihk_circ_air_right">Circulating air right [%]:</string>
      <string name="label_ihk_defrost">Defrost [%]:</string>
      <string name="label_ihk_vent">Ventilation [%]:</string>
      <string name="label_ihk_cold_air">Cold air [%]:</string>
      <string name="label_ihk_legroom">Leg room [%]:</string>
      <string name="label_ihk_refrig_comp">Refrigerating compressor [%]:</string>
    </strings>
    <strings lang="de">
      <string name="tab_ihk">Klima</string>
      <string name="label_ihk_in_temp">Innentemperatur [°C]:</string>
      <string name="label_ihk_in_temp_delay">Innentemperatur verzögert [°C]:</string>
      <string name="label_ihk_out_temp">Außentemperatur [°C]:</string>
      <string name="label_ihk_setpoint">Sollwert [°C]:</string>
      <string name="label_ihk_heat_ex_temp">Wärmetauschertemperatur [°C]:</string>
      <string name="label_ihk_heat_ex_setpoint">Wärmetauschersollwert [°C]:</string>
      <string name="label_ihk_heat_ex_actuator">Wärmetauscherstellgröße [%]:</string>
      <string name="label_ihk_main_actuator">Hauptstellgröße [%]:</string>
      <string name="label_ihk_evap_temp">Verdampfertemperatur [°C]:</string>
      <string name="label_ihk_press_sense">Drucksensor [bar]:</string>
      <string name="label_ihk_circ_air_left">Umluft links [%]:</string>
      <string name="label_ihk_circ_air_right">Umluft rechts [%]:</string>
      <string name="label_ihk_defrost">Abtauen [%]:</string>
      <string name="label_ihk_vent">Belüftung [%]:</string>
      <string name="label_ihk_cold_air">Kaltluft [%]:</string>
      <string name="label_ihk_legroom">Fußraum [%]:</string>
      <string name="label_ihk_refrig_comp">Kältemittelverdichter [%]:</string>
    </strings>
    <jobs sgbd="d_klima">
      <job name="STATUS_REGLERGROESSEN" results="STAT_TINNEN_WERT;STAT_TINNEN_VERZOEGERT_WERT;STAT_TAUSSEN_WERT;STAT_SOLL_LI_KORRIGIERT_WERT;STAT_WT_RE_WERT;STAT_WTSOLL_RE_WERT;STAT_YWT_RE_WERT;STAT_Y_RE_WERT">
        <display name="label_ihk_in_temp" result="STAT_TINNEN_WERT" format="6.1R" />
        <display name="label_ihk_in_temp_delay" result="STAT_TINNEN_VERZOEGERT_WERT" format="6.1R" />
        <display name="label_ihk_out_temp" result="STAT_TAUSSEN_WERT" format="6.1R" />
        <display name="label_ihk_setpoint" result="STAT_SOLL_LI_KORRIGIERT_WERT" format="6.1R" />
        <display name="label_ihk_heat_ex_temp" result="STAT_WT_RE_WERT" format="6.1R" />
        <display name="label_ihk_heat_ex_setpoint" result="STAT_WTSOLL_RE_WERT" format="6.1R" />
        <display name="label_ihk_heat_ex_actuator" result="STAT_YWT_RE_WERT" format="3L" />
        <display name="label_ihk_main_actuator" result="STAT_Y_RE_WERT" format="3L" />
      </job>
      <job name="STATUS_ANALOGEINGAENGE" results="STAT_TEMP_VERDAMFER_WERT;STAT_DRUCKSENSOR_WERT">
        <display name="label_ihk_evap_temp" result="STAT_TEMP_VERDAMFER_WERT" format="6.1R" />
        <display name="label_ihk_press_sense" result="STAT_DRUCKSENSOR_WERT" format="6.1R" />
      </job>
      <job name="STATUS_MOTOR_KLAPPENPOSITION" results="STAT_FRISCHLUFT_UMLUFT_LI_WERT;STAT_FRISCHLUFT_UMLUFT_RE_WERT;STAT_DEFROST_WERT;STAT_BELUEFTUNG_WERT;STAT_KALTLUFT_WERT;STAT_FUSSRAUM_WERT">
        <display name="label_ihk_circ_air_left" result="STAT_FRISCHLUFT_UMLUFT_LI_WERT" format="3L" />
        <display name="label_ihk_circ_air_right" result="STAT_FRISCHLUFT_UMLUFT_RE_WERT" format="3L" />
        <display name="label_ihk_defrost" result="STAT_DEFROST_WERT" format="3L" />
        <display name="label_ihk_vent" result="STAT_BELUEFTUNG_WERT" format="3L" />
        <display name="label_ihk_cold_air" result="STAT_KALTLUFT_WERT" format="3L" />
        <display name="label_ihk_legroom" result="STAT_FUSSRAUM_WERT" format="3L" />
      </job>
      <job name="STATUS_IO" results="STAT_STEUERUNG_KMV_WERT">
        <display name="label_ihk_refrig_comp" result="STAT_STEUERUNG_KMV_WERT" format="3L" />
      </job>
    </jobs>
  </page>
</fragment>

The pagename property specifies the title of the page and is a reference to the strings nodes. With logfile a log file name could be specified, that allows to log the display data.
The strings nodes contains the all the string used on this display page. If the current language is not matching the lang tag, the default language (without tag) is used. The lang property could be either the short form e.g. 'de' or the long one 'de-DE'.

The jobs node groups all EDIABAS job to execute. The property sgbd specifies the name of the group (.grp) or the sgbd (.prg) file to use.
Within the jobs node multiple job nodes specify the EDIABAS jobs to execute. They contain the following properties:
  • name: Name of the job to execute
  • args_first: Allows to specify semicolon separated job arguments for the first job call.
  • args: Allows to specify semicolon separated job arguments. If this is the first call and args_first is present args_first will be used instead.
  • result: Allows to specify the required results. If omitted, all results will be generated, which may require more processing time.
  • log_tag=<tag name>: Adding this property allows to log the display data to a log file when activating the Log data menu in the application. The logfile property in the page node has to be specified as well to activate logging.
  • Each display node specifies one line of the display output. Name is again a reference to the text translation in the strings nodes. With result the EDIABAS job result name is selected, that contains the data. The format property allows to format the result with the EDIABAS aspiResultText format specification EDIABAS result types and formats.
The page node can optionally contain display nodes like the job node. They will be only used for User defined code.
This is how the resulting page will look like:

Climate page

Reading errors

With the read_errors node it's possible to read an error summary of all ECUs. Simply list all ECU names and the corresponding sgbd file names in a separate ecu node, like in the example below.
The error message is generated by the sgbd file and is in the language of the sgbd.
The page also allows to selectively reset ECU errors.

<?xml version="1.0" encoding="utf-8" ?>
<fragment xmlns="http://www.holeschak.de/BmwDeepObd"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://www.holeschak.de/BmwDeepObd ../BmwDeepObd.xsd">
  <page name ="tab_errors">
    <strings>
      <string name="tab_errors">Errors</string>

      <string name="ACSM">ACSM Crash security module</string>
      <string name="CAS">CAS Car access system</string>
      <string name="CCCBO">CCC-BO Front panel</string>
      <string name="CCCGW">CCC-GW Gateway</string>
      <string name="DDE">DDE Diesel elektronic</string>
      <string name="DSC">DSC Dynamic stability control</string>
      <string name="EKPS">EKPS Fuel pump control</string>
      <string name="IHK">IHK Integrated heating climate automatic</string>
      <string name="KBM">KBM Chassis basic module</string>
      <string name="KGM">KGM Chassis gateway module</string>
      <string name="KOMBI">KOMBI Combination instrument</string>
      <string name="PDC">PDC Park distance control</string>
      <string name="RLS">RLS Rain main beam sensor</string>
      <string name="EPS">EPS Electric power steering</string>
      <string name="ULF">ULF Universal hands-free system</string>
      <string name="FZD">FZD Roof switch unit</string>
    </strings>
    <strings lang="de">
      <string name="tab_errors">Fehler</string>

      <string name="ACSM">ACSM Crash-Sicherheits-Modul</string>
      <string name="CAS">CAS Car Access System</string>
      <string name="CCCBO">CCC-BO Bedienoberfläche</string>
      <string name="CCCGW">CCC-GW Gateway</string>
      <string name="DDE">DDE Diesel Elektronik</string>
      <string name="DSC">DSC Dynamische Stabilitätskontrolle</string>
      <string name="EKPS">EKPS Kraftstoffpumpensteuerung</string>
      <string name="IHK">IHK Integrierte Heiz-Klima-Automatik</string>
      <string name="KBM">KBM Karosserie-Basismodul</string>
      <string name="KGM">KGM Karosserie-Gateway-Modul</string>
      <string name="KOMBI">KOMBI Instrumentenkombination</string>
      <string name="PDC">PDC Park-Distance-Control</string>
      <string name="RLS">RLS Regen-Fahrlicht-Sensor</string>
      <string name="EPS">EPS Elektromechanische Servolenkung</string>
      <string name="ULF">ULF Universale Ladefreisprechelektronik</string>
      <string name="FZD">FZD Funtionszentrum Dach</string>
    </strings>
    <read_errors>
      <ecu name="CAS" sgbd="d_cas" />
      <ecu name="DDE" sgbd="d_motor" />
      <ecu name="EKPS" sgbd="d_ekp" />
      <ecu name="DSC" sgbd="d_dsc" />
      <ecu name="ACSM" sgbd="d_sim" />
      <ecu name="CCCBO" sgbd="d_mmi" />
      <ecu name="CCCGW" sgbd="d_mostgw" />
      <ecu name="IHK" sgbd="d_klima" />
      <ecu name="KBM" sgbd="d_kbm" />
      <ecu name="KGM" sgbd="d_zgm" />
      <ecu name="KOMBI" sgbd="d_kombi" />
      <ecu name="PDC" sgbd="d_pdc" />
      <ecu name="RLS" sgbd="d_rls" />
      <ecu name="EPS" sgbd="d_eps" />
      <ecu name="ULF" sgbd="d_ispb" />
      <ecu name="FZD" sgbd="d_fzd" />
    </read_errors>
  </page>
</fragment>

In the ecu node the property name is a link to a string node and sgbd is the name of the sgbd file. The output looks similar to this page:

Erros E90

User defined code

If the jobs and display output is getting more complex, user defined code will be required. In this case a C# class could be added to a code node, which defines a set of optional callback functions. If the show_warnings property is set to true, also warnings will be reported during compilation of the code.

<code show_warnigs="true">
      <![CDATA[
    class PageClass
    {
        public void CreateLayout(ActivityMain activity, JobReader.PageInfo pageInfo, LinearLayout pageLayout)
        {
        }

        public void DestroyLayout(JobReader.PageInfo pageInfo)
        {
        }

        public void UpdateLayout(JobReader.PageInfo pageInfo, bool pageValid, bool threadActive)
        {
        }

        public void ExecuteJob(EdiabasNet ediabas, ref Dictionary<string, EdiabasNet.ResultData> resultDict, bool firstCall)
        {
        }

        public string FormatResult(JobReader.PageInfo pageInfo, Dictionary<string, EdiabasNet.ResultData> resultDict, string resultName)
        {
        }

        public string FormatErrorResult(JobReader.PageInfo pageInfo, EdiabasThread.EdiabasErrorReport errorReport, string defaultMessage)
        {
        }

        public void UpdateResultList(JobReader.PageInfo pageInfo, Dictionary<string, EdiabasNet.ResultData> resultDict, List<TableResultItem> resultList)
        {
        }
    }
      ]]>
    </code>

Formatting results (FormatResult)

For special formatting of the result data, the callback FormatResult could be used. For each result of the EDIABAS results this function will be called with resultName set to the current result name. If the display node is a subnode of a job node the job name is prefixed with # as separator to the result name. The function will be only called if there is noformat property in the display node. Here is an example from the motor page:

        public string FormatResult(JobReader.PageInfo pageInfo, Dictionary<string, EdiabasNet.ResultData> resultDict, string resultName)
        {
            string result = string.Empty;
            bool found;

            switch (resultName)
            {
                case "STATUS_MESSWERTBLOCK_LESEN#STAT_STRECKE_SEIT_ERFOLGREICHER_REGENERATION_WERT":
                    result = string.Format(ActivityMain.Culture, "{0,6:0.0}", ActivityMain.GetResultDouble(resultDict, resultName, out found) / 1000.0);
                    if (!found) result = string.Empty;
                    break;

                case "STATUS_MESSWERTBLOCK_LESEN#STAT_OELDRUCKSCHALTER_EIN_WERT":
                    result = ((ActivityMain.GetResultDouble (resultDict, resultName, out found) > 0.5) && found) ? "1" : "0";
                    if (!found) result = string.Empty;
                    break;

                case "STATUS_MESSWERTBLOCK_LESEN#STAT_REGENERATIONSANFORDERUNG_WERT":
                    result = ((ActivityMain.GetResultDouble (resultDict, resultName, out found) < 0.5) && found) ? "1" : "0";
                    if (!found) result = string.Empty;
                    break;

                case "STATUS_MESSWERTBLOCK_LESEN#STAT_EGT_st_WERT":
                    result = ((ActivityMain.GetResultDouble (resultDict, resultName, out found) > 1.5) && found) ? "1" : "0";
                    if (!found) result = string.Empty;
                    break;

                case "STATUS_MESSWERTBLOCK_LESEN#STAT_REGENERATION_BLOCKIERUNG_UND_FREIGABE_WERT":
                    result = ((ActivityMain.GetResultDouble (resultDict, resultName, out found) < 0.5) && found) ? "1" : "0";
                    if (!found) result = string.Empty;
                    break;
            }
            return result;
        }

Formatting error results (FormatErrorResult)

For special formatting of the error result data, the callback FormatErrorResult could be used. For each error entry this function will be called with defaultMessage set to the default error message output.
Here is an example from the errors page, that adds a RPM value to the error message. You have to add a results property to the ecu node specifying the results you want to be generated by the FS_LESEN_DETAIL job.

<read_errors>
      <ecu name="CAS" sgbd="d_cas" />
      <ecu name="DDE" sgbd="d_motor" results="F_UW_KM;F_UW_ANZ" />
    </read_errors>
    <code show_warnigs="true">
      <![CDATA[
    class PageClass
    {
        public string FormatErrorResult(JobReader.PageInfo pageInfo, EdiabasThread.EdiabasErrorReport errorReport, string defaultMessage)
        {
            string message = defaultMessage;
            switch (errorReport.EcuName)
            {
                case "DDE":
                {
                    string detailText = string.Empty;
                    foreach (Dictionary<string, EdiabasNet.ResultData> errorDetail in errorReport.ErrorDetailSet)
                    {
                        string rpmText = ActivityMain.FormatResultDouble(errorDetail, "F_UW1_WERT", "{0,6:0.0}");
                        if (rpmText.Length > 0)
                        {
                            if (detailText.Length == 0)
                            {
                                detailText += rpmText + " 1/min";
                            }
                        }
                    }
                    if (detailText.Length > 0)
                    {
                        message += "\r\n" + detailText;
                    }
                    break;
                }
            }
            return message;
        }
    }
      ]]>
  </code>

Control output of the page (UpdateResultList)

Sometimes you want to dynamically control the number and the content of the output lines.
If the callback UpdateResultList is defined, you could directly fill the contents of the resultListAdapter which displays the results of the page. In this example from the (standard) Adapter page the adapter configuration result will be displayed. Additionally only one column for output is used by setting the second argument of resultListAdapter.Items.Add to null. With ActivityMain.GetPageString it's possible to retrieve a string from the translation table.

        public void UpdateResultList(JobReader.PageInfo pageInfo, Dictionary<string, EdiabasNet.ResultData> resultDict, List<TableResultItem> resultList)
        {
            int result = configResult;

            if (result > 0)
            {
                resultList.Add(new TableResultItem(ActivityMain.GetPageString(pageInfo, "adapter_config_ok"), null));
            }
            else if (result == 0)
            {
                resultList.Add(new TableResultItem(ActivityMain.GetPageString(pageInfo, "adapter_config_error"), null));
            }
        }

Executing own jobs (ExecuteJob)

If more than one job has to be executed or the job requires special arguments, ediabas.ExecuteJob could be called in the ExecuteJob callback. Here is an example from the adapter page for calling a list of jobs. EdiabasThread.MergeResultDictionarys adds the results of the current job to the internal job list. The callback ExecuteJob will be executed in it's own thread. When using ExecuteJob it's recommended to add the display nodes to the page node because no job nodes will be present.

    class PageClass
    {
        private class EdiabasJob
        {
            private string jobName;
            private string jobArgs;
            private string resultRequests;

            public EdiabasJob(string jobName, string jobArgs, string resultRequests)
            {
                this.jobName = jobName;
                this.jobArgs = jobArgs;
                this.resultRequests = resultRequests;
            }

            public string JobName
            {
                get
                {
                    return jobName;
                }
            }

            public string JobArgs
            {
                get
                {
                    return jobArgs;
                }
            }

            public string ResultRequests
            {
                get
                {
                    return resultRequests;
                }
            }
        }

        static private readonly EdiabasJob[] jobArray =
            {
                new EdiabasJob("ADAPTER_CMD",
                    "0xFE;0xFE",
                    string.Empty
                    ),
                new EdiabasJob("ADAPTER_CMD",
                    "0x80;0x00",
                    string.Empty
                    ),
                new EdiabasJob("ADAPTER_CMD",
                    "0x81;0x00",
                    string.Empty
                    ),
                new EdiabasJob("ADAPTER_CMD",
                    "0x82;0x00",
                    string.Empty
                    ),
            };

        public void ExecuteJob(EdiabasNet ediabas, ref Dictionary<string, EdiabasNet.ResultData> resultDict, bool firstCall)
        {
            int index = 0;
            foreach (EdiabasJob job in jobArray)
            {
                ediabas.ArgString = job.JobArgs;
                ediabas.ArgBinaryStd = null;
                ediabas.ResultsRequests = job.ResultRequests;

                ediabas.ExecuteJob(job.JobName);

                List<Dictionary<string, EdiabasNet.ResultData>> resultSets = ediabas.ResultSets;
                if (resultSets != null && resultSets.Count >= 2)
                {
                    EdiabasThread.MergeResultDictionarys(ref resultDict, resultSets[1], string.Format("{0}_", index));
                }
                index++;
            }
        }
    }

Adding controls to the layout

The standard layout only allows to display information, but there is no way to control outputs. With the callbacks CreateLayout, DestroyLayout and UpdateLayout there is a possibility to add own controls to the layout (in most cases buttons).
In this example from the AdapterCustom.ccpage buttons will be added to control the CAN block size, CAN separation time and the CAN mode. The CreateLayout adds the controls, DestroyLayout removes the controls and UpdateLayout is used to modify the state of the controls (depending form the connection state).
For every button there is a Click delegate that allows to set a global variable which is used for EDIABAS job control.

        private Button buttonBlockSize;
        private Button buttonSepTime0;
        private Button buttonSepTime1;
        private Button buttonCan500;
        private Button buttonCan100;
        private Button buttonCanOff;
        private int adapterCmd = -1;
        private int adapterValue;
        private int blockSize = 0;

        public void CreateLayout(ActivityMain activity, JobReader.PageInfo pageInfo, LinearLayout pageLayout)
        {
            LinearLayout buttonLayout = new LinearLayout(activity);
            buttonLayout.Orientation = Orientation.Vertical;

            LinearLayout.LayoutParams buttonLayoutParams = new LinearLayout.LayoutParams(
                ViewGroup.LayoutParams.MatchParent,
                ViewGroup.LayoutParams.WrapContent);
            buttonLayoutParams.Weight = 1;

            buttonBlockSize = new Button(activity);
            buttonBlockSize.Text = string.Format("{0}: {1}", ActivityMain.GetPageString(pageInfo, "button_adapter_config_block_size"), blockSize);
            buttonBlockSize.Click += delegate
            {
                blockSize += 2;
                if (blockSize > 8)
                {
                    blockSize = 0;
                }
                adapterCmd = 0x00;
                adapterValue = blockSize;
                buttonBlockSize.Text = string.Format("{0}: {1}", ActivityMain.GetPageString(pageInfo, "button_adapter_config_block_size"), blockSize);
            };
            buttonLayout.AddView(buttonBlockSize, buttonLayoutParams);

            buttonSepTime0 = new Button(activity);
            buttonSepTime0.Text = ActivityMain.GetPageString(pageInfo, "button_adapter_config_sep_time0");
            buttonSepTime0.Click += delegate
            {
                adapterCmd = 0x01;
                adapterValue = 0x00;
            };
            buttonLayout.AddView(buttonSepTime0, buttonLayoutParams);

            buttonSepTime1 = new Button(activity);
            buttonSepTime1.Text = ActivityMain.GetPageString(pageInfo, "button_adapter_config_sep_time1");
            buttonSepTime1.Click += delegate
            {
                adapterCmd = 0x01;
                adapterValue = 0x01;
            };
            buttonLayout.AddView(buttonSepTime1, buttonLayoutParams);

            buttonCan500 = new Button(activity);
            buttonCan500.Text = ActivityMain.GetPageString(pageInfo, "button_adapter_config_can_500");
            buttonCan500.Click += delegate
            {
                adapterCmd = 0x02;
                adapterValue = 0x01;
            };
            buttonLayout.AddView(buttonCan500, buttonLayoutParams);

            buttonCan100 = new Button(activity);
            buttonCan100.Text = ActivityMain.GetPageString(pageInfo, "button_adapter_config_can_100");
            buttonCan100.Click += delegate
            {
                adapterCmd = 0x02;
                adapterValue = 0x09;
            };
            buttonLayout.AddView(buttonCan100, buttonLayoutParams);

            buttonCanOff = new Button(activity);
            buttonCanOff.Text = ActivityMain.GetPageString(pageInfo, "button_adapter_config_can_off");
            buttonCanOff.Click += delegate
            {
                adapterCmd = 0x02;
                adapterValue = 0x00;
            };
            buttonLayout.AddView(buttonCanOff, buttonLayoutParams);

            LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
                ViewGroup.LayoutParams.MatchParent,
                ViewGroup.LayoutParams.WrapContent);
            pageLayout.AddView(buttonLayout, layoutParams);

            adapterCmd = -1;
        }

        public void DestroyLayout(JobReader.PageInfo pageInfo)
        {
            if (buttonBlockSize != null)
            {
                buttonBlockSize.Dispose();
                buttonBlockSize = null;
            }
            if (buttonSepTime0 != null)
            {
                buttonSepTime0.Dispose();
                buttonSepTime0 = null;
            }
            if (buttonSepTime1 != null)
            {
                buttonSepTime1.Dispose();
                buttonSepTime1 = null;
            }
            if (buttonCan500 != null)
            {
                buttonCan500.Dispose();
                buttonCan500 = null;
            }
            if (buttonCan100 != null)
            {
                buttonCan100.Dispose();
                buttonCan100 = null;
            }
            if (buttonCanOff != null)
            {
                buttonCanOff.Dispose();
                buttonCanOff = null;
            }
            //Android.Util.Log.Info("Custom", "Destroyed");
        }

        public void UpdateLayout(JobReader.PageInfo pageInfo, bool pageValid, bool threadActive)
        {
            if ((buttonCan500 == null) || (buttonCan100 == null) || (buttonCanOff == null))
            {
                return;
            }

            bool enabled = pageValid && threadActive;
            buttonBlockSize.Enabled = enabled;
            buttonSepTime0.Enabled = enabled;
            buttonSepTime1.Enabled = enabled;
            buttonCan500.Enabled = enabled;
            buttonCan100.Enabled = enabled;
            buttonCanOff.Enabled = enabled;
        }
    }


The resulting page will look like this:

AdapterConfigSmall.png
(Adapter page)

Grouping pages

If the same of pages are required in multiple configuration, it's useful to group the together. This could be done with *.ccpages files. Simply include the *.ccpage files withing the pages node. The specifified path is relative to the *.ccpages file location. The file has the following layout:

<?xml version="1.0" encoding="utf-8" ?>
<fragment xmlns="http://www.holeschak.de/BmwDeepObd"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://www.holeschak.de/BmwDeepObd ../BmwDeepObd.xsd">
  <pages>
    <include filename="Axis.ccpage"/>
    <include filename="Motor.ccpage"/>
    <include filename="../AdapterCustom.ccpage"/>
  </pages>
</fragment>

The configuration file

Now all *.page or *.pages can added to a configuration file (*.cccfg). This file could be loaded by BWM deep OBD. In the global node of the file the following properties could be specified:
  • ecu_path: Directory of the ecu files (*.grp and *.prg) relative to the configuration file.
  • log_path: Directory for the data logging files. Logging could be enabled by adding a log_tag property to the display node of the *.page file. If the directory is not existing it will be created.
  • append_log: Setting this property to true will always append the log file.
  • interface: Specify the communication interface in this property. Possible values are BLUETOOTH , ENET, ELMWIFI and FTDI.

<?xml version="1.0" encoding="utf-8"?>
<fragment xmlns="http://www.holeschak.de/BmwDeepObd"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://www.holeschak.de/BmwDeepObd ../BmwDeepObd.xsd">
  <global ecu_path="../Ecu" log_path="Log" append_log="true" interface="BLUETOOTH" />
  <include filename="E61.ccpages"/>
</configuration>

Updated Wiki: Home

$
0
0
Project Description
.NET BMW Ediabas interpreter library

Features

This .NET assembly is small and fast replacement for the BWM Ediabas toolset.
It's running on all platforms that support .NET framework (Windows, Windows CE, Mono).
The code is speed optimized, but improved for multiple calls of the same job.
This means the first job call is slow and the next are faster.

The library can directly read and interpret .GRP and .PRG files, the internal interface is similar to the EDIABAS API or the Tool32.exe GUI interface.
At the moment the D-CAN, BMW-FAST, KWP-2000*, KWP-2000 BMW, DS2, DS1, Concept 3, ISO9141 (Concept 2) and Concept 1 concepts are supported. If you send me EDIABAS log files from other concepts I could add them if possible.

For testing there is a console application EdiabasTest with command line parameters.
More informations could be found in the Documentation section.

Binary Compatibility

A binary compatible api32.dll wrapper is existing, it's possible to replace the existing EDIABAS api32.dll with the EdiabasLib api32.dll and the applications are still working (The dll requires .NET framework 4.0 or higher and VS2015 C++ runtime to be installed)!
This has been tested with Tool32, INPA and Rheingold. Since EdiabasNet is ignoring the EDIABAS.INI file you have to put your own EdiabasLib.config in the api32.dll directory.

A compatible apiNET32.dll is also available, so it should be easy to port existing .NET applications that use the original EDIABAS library.

Android

Now there is also a library existing that is working with Mono for Android. For communication either FTDI USB or Bluetooth Serial Port Protocol (SSP) protocol could be used.

Deep OBD for BMW

Additionally an Android application Deep OBD for BMW is existing, that is configurable via XML. Generation of XML code could be simplified with the integrated configuration generator.
Download app from Google Play: https://play.google.com/store/apps/details?id=de.holeschak.bmw_deep_obd
Deep OBD for BMW supports several OBD II adapters:
  • Standard FTDI based USB "INPA compatible" D-CAN/K-Line adapters (all protocols)
  • ELM327 based Bluetooth and WiFi adapters. Recommended ELM327 versions are 1.4b, 1.5 and origin 2.1, which are based on PIC18F2480 processor (no MCP2515 chip) (D-CAN protocol only)
  • ELM327 based adapters with Replacement firmware for ELM327 D-CAN and K-Line (all protocols!). Programmed adapters are now available.
Bluetooth adapter topENET adapter

BMW deep OBD

Hints

At the moment most BEST/1 commands are implemented, but a few are still missing.
The implemented commands are automatically tested and compared with EDIABAS output.
Because I have no BEST/1 command specification some commands are only guessed. If someone could supply me with a BEST/1 specification I could improve the library.

Updated Wiki: ENET WiFi Adapter

$
0
0

ENET WiFi Adapter

For the BMW F-models there is a WiFi adapter available, that allows to communicate directly using the BMW ENET protocol.
It is based on the hardware of an A5-V11 3G/4G Router. The adapter has the following features:
  • MediaTek/Ralink RT5350F processor with 350MHz
  • DC/DC converter for improved power consumption
  • OpenWrt operating system
  • Luci web interface for configuration and status display.
  • Firmware update possible over the web interface
  • DHCP server
  • ESSID: Deep OBD BMW
  • Default Wifi password: deepobdbmw
  • Default IP address: 192.168.100.1
  • Default root password: root
ENET adapter closedENET adapter openWeb interface

Buy an adapter

The ENET WiFi adapter will be available on EBAY soon!

Factory reset

If the adapter gets unreachable after a misconfiguration there is a possibility to perform a factory reset.
You have to open the adapter and press the reset button after the adapter has booted.

Use the adapter with INPA, Tool32 or ISTA-D

You could use the Bluetooth adapter on a windows PC with INPA or Tool32 as a replacement for an ENET adapter cable. The following steps are required to establish the connection:
  1. Install .NET framework 4.0 or higher and VS2015 C++ runtime
  2. Connect the ENET adapter with the PC. The PC automatically gets and IP address from the adapter DHCP server.
  3. Rename the api32.dll in the C:\Ediabas\bin and C:\ISTA-D\Ediabas\bin directory.
  4. Copy Api32.dll and EdiabasLib.config to the C:\Ediabas\bin and C:\ISTA-D\Ediabas\bin directory.
  5. For ISTA-D: In Administration -> VCI Config select as Interface type: Ediabas default settings (ediabas.ini)
  6. Modify the following entries in EdiabasLib.config:
<add key="Interface" value="ENET"/>
<add key="EnetRemoteHost" value="auto:all"/>

Updated Wiki: ENET WiFi Adapter

$
0
0

ENET WiFi Adapter

For the BMW F-models there is a WiFi adapter available, that allows to communicate directly using the BMW ENET protocol.
It is based on the hardware of an A5-V11 3G/4G Router. The adapter has the following features:
  • MediaTek/Ralink RT5350F processor with 350MHz
  • DC/DC converter for improved power consumption
  • OpenWrt operating system
  • LuCi web interface.
  • Firmware update possible over the web interface
  • DHCP server
  • ESSID: Deep OBD BMW
  • Default Wifi password: deepobdbmw
  • Default IP address: 192.168.100.1
  • Default root password: root
ENET adapter closedENET adapter openWeb interface

Buy an adapter

The ENET WiFi adapter will be available on EBAY soon!

Factory reset

If the adapter gets unreachable after a misconfiguration there is a possibility to perform a factory reset.
You have to open the adapter and press the reset button after the adapter has booted.

Use the adapter with INPA, Tool32 or ISTA-D

You could use the Bluetooth adapter on a windows PC with INPA or Tool32 as a replacement for an ENET adapter cable. The following steps are required to establish the connection:
  1. Install .NET framework 4.0 or higher and VS2015 C++ runtime
  2. Connect the ENET adapter with the PC. The PC automatically gets and IP address from the adapter DHCP server.
  3. Rename the api32.dll in the C:\Ediabas\bin and C:\ISTA-D\Ediabas\bin directory.
  4. Copy Api32.dll and EdiabasLib.config to the C:\Ediabas\bin and C:\ISTA-D\Ediabas\bin directory.
  5. For ISTA-D: In Administration -> VCI Config select as Interface type: Ediabas default settings (ediabas.ini)
  6. Modify the following entries in EdiabasLib.config:
<add key="Interface" value="ENET"/>
<add key="EnetRemoteHost" value="auto:all"/>

Updated Wiki: ENET WiFi Adapter

$
0
0

ENET WiFi Adapter

For the BMW F-models there is a WiFi adapter available, that allows to communicate directly using the BMW ENET protocol.
It is based on the hardware of an A5-V11 3G/4G Router. The adapter has the following features:
  • MediaTek/Ralink RT5350F processor with 350MHz
  • DC/DC converter for improved power consumption
  • OpenWrt operating system
  • LuCi web interface
  • Firmware update possible over the web interface
  • DHCP server
  • ESSID: Deep OBD BMW
  • Default Wifi password: deepobdbmw
  • Default IP address: 192.168.100.1
  • Default root password: root
ENET adapter closedENET adapter openWeb interface

Buy an adapter

The ENET WiFi adapter will be available on EBAY soon!

Factory reset

If the adapter gets unreachable after a misconfiguration there is a possibility to perform a factory reset.
You have to open the adapter and press the reset button after the adapter has booted.

Use the adapter with INPA, Tool32 or ISTA-D

You could use the Bluetooth adapter on a windows PC with INPA or Tool32 as a replacement for an ENET adapter cable. The following steps are required to establish the connection:
  1. Install .NET framework 4.0 or higher and VS2015 C++ runtime
  2. Connect the ENET adapter with the PC. The PC automatically gets and IP address from the adapter DHCP server.
  3. Rename the api32.dll in the C:\Ediabas\bin and C:\ISTA-D\Ediabas\bin directory.
  4. Copy Api32.dll and EdiabasLib.config to the C:\Ediabas\bin and C:\ISTA-D\Ediabas\bin directory.
  5. For ISTA-D: In Administration -> VCI Config select as Interface type: Ediabas default settings (ediabas.ini)
  6. Modify the following entries in EdiabasLib.config:
<add key="Interface" value="ENET"/>
<add key="EnetRemoteHost" value="auto:all"/>

Updated Wiki: ENET WiFi Adapter

$
0
0

ENET WiFi Adapter

For the BMW F-models there is a WiFi adapter available, that allows to communicate directly using the BMW ENET protocol.
It is based on the hardware of an A5-V11 3G/4G Router. The adapter has the following features:
  • MediaTek/Ralink RT5350F processor with 350MHz
  • DC/DC converter for improved power consumption
  • OpenWrt operating system
  • LuCi web interface
  • Firmware update possible via web interface
  • DHCP server
  • ESSID: Deep OBD BMW
  • Default Wifi password: deepobdbmw
  • Default IP address: 192.168.100.1
  • Default root password: root
ENET adapter closedENET adapter openWeb interface

Buy an adapter

The ENET WiFi adapter will be available on EBAY soon!

Factory reset

If the adapter gets unreachable after a misconfiguration there is a possibility to perform a factory reset.
You have to open the adapter and press the reset button after the adapter has booted.

Use the adapter with INPA, Tool32 or ISTA-D

You could use the Bluetooth adapter on a windows PC with INPA or Tool32 as a replacement for an ENET adapter cable. The following steps are required to establish the connection:
  1. Install .NET framework 4.0 or higher and VS2015 C++ runtime
  2. Connect the ENET adapter with the PC. The PC automatically gets and IP address from the adapter DHCP server.
  3. Rename the api32.dll in the C:\Ediabas\bin and C:\ISTA-D\Ediabas\bin directory.
  4. Copy Api32.dll and EdiabasLib.config to the C:\Ediabas\bin and C:\ISTA-D\Ediabas\bin directory.
  5. For ISTA-D: In Administration -> VCI Config select as Interface type: Ediabas default settings (ediabas.ini)
  6. Modify the following entries in EdiabasLib.config:
<add key="Interface" value="ENET"/>
<add key="EnetRemoteHost" value="auto:all"/>

Updated Wiki: ENET WiFi Adapter

$
0
0

ENET WiFi Adapter

For the BMW F-models there is a WiFi adapter available, that allows to communicate directly using the BMW ENET protocol.
It is based on the hardware of an A5-V11 3G/4G Router. The adapter has the following features:
  • MediaTek/Ralink RT5350F processor with 350MHz
  • DC/DC converter for improved power consumption
  • OpenWrt operating system
  • LuCi web interface
  • Firmware update possible via web interface
  • DHCP server
  • ESSID: Deep OBD BMW
  • Default Wifi password: deepobdbmw
  • Default IP address: 192.168.100.1
  • Default root password: root
ENET adapter closedENET adapter openWeb interface

Buy an adapter

The ENET WiFi adapter will be available on EBAY soon!

Factory reset

If the adapter gets unreachable after a misconfiguration there is a possibility to perform a factory reset.
You have to open the adapter and press the reset button after the adapter has booted.

Use the adapter with INPA, Tool32 or ISTA-D

You could use the Bluetooth adapter on a windows PC with INPA or Tool32 as a replacement for an ENET adapter cable. The following steps are required to establish the connection:
  1. Install .NET framework 4.0 or higher and VS2015 C++ runtime
  2. Connect the ENET adapter with the PC. The PC automatically gets an IP address from the adapter DHCP server.
  3. Rename the api32.dll in the C:\Ediabas\bin and C:\ISTA-D\Ediabas\bin directory.
  4. Copy Api32.dll and EdiabasLib.config to the C:\Ediabas\bin and C:\ISTA-D\Ediabas\bin directory.
  5. For ISTA-D: In Administration -> VCI Config select as Interface type: Ediabas default settings (ediabas.ini)
  6. Modify the following entries in EdiabasLib.config:
<add key="Interface" value="ENET"/>
<add key="EnetRemoteHost" value="auto:all"/>


Updated Wiki: ENET WiFi Adapter

$
0
0

ENET WiFi Adapter

For the BMW F-models there is a WiFi adapter available, that allows to communicate directly using the BMW ENET protocol.
It is based on the hardware of an A5-V11 3G/4G Router. The adapter has the following features:
  • MediaTek/Ralink RT5350F processor with 350MHz
  • DC/DC converter for improved power consumption
  • OpenWrt operating system
  • LuCi web interface
  • Firmware update possible via web interface
  • DHCP server
  • ESSID: Deep OBD BMW
  • Default Wifi password: deepobdbmw
  • Default IP address: 192.168.100.1
  • Default root password: root
ENET adapter open
ENET adapter closedWeb interface

Buy an adapter

The ENET WiFi adapter will be available on EBAY soon!

Factory reset

If the adapter gets unreachable after a misconfiguration there is a possibility to perform a factory reset.
You have to open the adapter and press the reset button after the adapter has booted.

Use the adapter with INPA, Tool32 or ISTA-D

You could use the Bluetooth adapter on a windows PC with INPA or Tool32 as a replacement for an ENET adapter cable. The following steps are required to establish the connection:
  1. Install .NET framework 4.0 or higher and VS2015 C++ runtime
  2. Connect the ENET adapter with the PC. The PC automatically gets an IP address from the adapter DHCP server.
  3. Rename the api32.dll in the C:\Ediabas\bin and C:\ISTA-D\Ediabas\bin directory.
  4. Copy Api32.dll and EdiabasLib.config to the C:\Ediabas\bin and C:\ISTA-D\Ediabas\bin directory.
  5. For ISTA-D: In Administration -> VCI Config select as Interface type: Ediabas default settings (ediabas.ini)
  6. Modify the following entries in EdiabasLib.config:
<add key="Interface" value="ENET"/>
<add key="EnetRemoteHost" value="auto:all"/>

Updated Wiki: Home

$
0
0
Project Description
.NET BMW Ediabas interpreter library

Features

This .NET assembly is small and fast replacement for the BWM Ediabas toolset.
It's running on all platforms that support .NET framework (Windows, Windows CE, Mono).
The code is speed optimized, but improved for multiple calls of the same job.
This means the first job call is slow and the next are faster.

The library can directly read and interpret .GRP and .PRG files, the internal interface is similar to the EDIABAS API or the Tool32.exe GUI interface.
At the moment the D-CAN, BMW-FAST, KWP-2000*, KWP-2000 BMW, DS2, DS1, Concept 3, ISO9141 (Concept 2) and Concept 1 concepts are supported. If you send me EDIABAS log files from other concepts I could add them if possible.

For testing there is a console application EdiabasTest with command line parameters.
More informations could be found in the Documentation section.

Binary Compatibility

A binary compatible api32.dll wrapper is existing, it's possible to replace the existing EDIABAS api32.dll with the EdiabasLib api32.dll and the applications are still working (The dll requires .NET framework 4.0 or higher and VS2015 C++ runtime to be installed)!
This has been tested with Tool32, INPA and Rheingold. Since EdiabasNet is ignoring the EDIABAS.INI file you have to put your own EdiabasLib.config in the api32.dll directory.

A compatible apiNET32.dll is also available, so it should be easy to port existing .NET applications that use the original EDIABAS library.

Android

Now there is also a library existing that is working with Mono for Android. For communication either FTDI USB or Bluetooth Serial Port Protocol (SSP) protocol could be used.

Deep OBD for BMW

Additionally an Android application Deep OBD for BMW is existing, that is configurable via XML. Generation of XML code could be simplified with the integrated configuration generator.
Download app from Google Play: https://play.google.com/store/apps/details?id=de.holeschak.bmw_deep_obd
Deep OBD for BMW supports several OBD II adapters:
  • Standard FTDI based USB "INPA compatible" D-CAN/K-Line adapters (all protocols)
  • ELM327 based Bluetooth and WiFi adapters. Recommended ELM327 versions are 1.4b, 1.5 and origin 2.1, which are based on PIC18F2480 processor (no MCP2515 chip) (D-CAN protocol only)
  • ELM327 based adapters with Replacement firmware for ELM327 D-CAN and K-Line (all protocols!). Programmed adapters are now available.
Bluetooth adapter topENET adapter

BMW deep OBD

Hints

At the moment most BEST/1 commands are implemented, but a few are still missing.
The implemented commands are automatically tested and compared with EDIABAS output.
Because I have no BEST/1 command specification some commands are only guessed. If someone could supply me with a BEST/1 specification I could improve the library.

Updated Wiki: ENET WiFi Adapter

$
0
0

ENET WiFi Adapter

For the BMW F-models there is a WiFi adapter available, that allows to communicate directly using the BMW ENET protocol.
It is based on the hardware of an A5-V11 3G/4G Router. The adapter has the following features:
  • MediaTek/Ralink RT5350F processor with 350MHz
  • DC/DC converter for improved power consumption
  • OpenWrt operating system
  • LuCi web interface
  • Firmware update possible via web interface
  • DHCP server
  • ESSID: Deep OBD BMW
  • Default Wifi password: deepobdbmw
  • Default IP address: 192.168.100.1
  • Default root password: root
ENET adapter open
ENET adapter closedWeb interface

Buy an adapter

The adapters are now available!
You could buy the ENET WiFi adapter from EBAY.

Factory reset

If the adapter gets unreachable after a misconfiguration there is a possibility to perform a factory reset.
You have to open the adapter and press the reset button after the adapter has booted.

Use the adapter with INPA, Tool32 or ISTA-D

You could use the Bluetooth adapter on a windows PC with INPA or Tool32 as a replacement for an ENET adapter cable. The following steps are required to establish the connection:
  1. Install .NET framework 4.0 or higher and VS2015 C++ runtime
  2. Connect the ENET adapter with the PC. The PC automatically gets an IP address from the adapter DHCP server.
  3. Rename the api32.dll in the C:\Ediabas\bin and C:\ISTA-D\Ediabas\bin directory.
  4. Copy Api32.dll and EdiabasLib.config to the C:\Ediabas\bin and C:\ISTA-D\Ediabas\bin directory.
  5. For ISTA-D: In Administration -> VCI Config select as Interface type: Ediabas default settings (ediabas.ini)
  6. Modify the following entries in EdiabasLib.config:
<add key="Interface" value="ENET"/>
<add key="EnetRemoteHost" value="auto:all"/>

Updated Wiki: Replacement firmware for ELM327

$
0
0

Replacement firmware for ELM327

There is now a replacement firmware available for ELM327 based Bluetooth adapters, that has the following advantages over the standard firmware:
  • Faster and more stable CAN communication.
  • K-Line support (all protocols).
  • Contains a bootstrap loader that allows firmware update without opening the device.
  • Firmware updates are possible with Deep OBD for BMW.
  • Reduced power consumption due to use of sleep mode.
  • Two firmware versions are available:
    • Unmodified Bluetooth adapter: Baud rate 38400.
    • Modified Bluetooth adapter (recommended) with replaced OpenSource Bluetooth firmware: Baud rate 115200 and alterable Bluetooth pin (16 digits) and name (31 chars).
Bluetooth adapter topBluetooth adapter bottom

Buy an adapter

Adapters are available again!
You could buy the Bluetooth adapter from EBAY.
For BMW F-models use the ENET WiFi Adapter.

Factory reset

Beginning with firmware version 0.6 there is the possibility to perform a factory reset of the adapter. This resets the Bluetooth pin to 1234, the Bluetooth name to Deep OBD BMW and the mode to D-CAN.
To perform the factory reset you have to open the adapter and connect the unused pad of R26 with GND during power on.

Use the adapter with INPA, Tool32 or ISTA-D

You could use the Bluetooth adapter on a windows PC with INPA or Tool32 as a replacement for a OBD or ADS adapter. The following steps are required to establish the connection:
  1. Install .NET framework 4.0 or higher and VS2015 C++ runtime
  2. Connect the Bluetooth adapter with the PC (the default Bluetooth pin is 1234). Two COM ports are generated (incoming and outgoing).
  3. With the standard DCAN.exe from dcan_Tools (for configuration of the USB adapters) set the operation mode (D-CAN or K-LINE) of the Bluetooth adapter. For the COM port use the outgoing port.
  4. Rename the api32.dll in the C:\Ediabas\bin and C:\ISTA-D\Ediabas\bin directory.
  5. Copy Api32.dll and EdiabasLib.config to the C:\Ediabas\bin and C:\ISTA-D\Ediabas\bin directory.
  6. For ISTA-D: In Administration -> VCI Config select as Interface type: Ediabas default settings (ediabas.ini)
  7. Modify the following entries in EdiabasLib.config:
<add key="Interface" value="STD:OBD"/>
<add key="ObdComPort" value="BLUETOOTH:<Outgoing COM port>"/>

Programming of the processor

For the first programming of the processor simply attach a PICKit 3 programmer to the corresponding test points of the circuit board.
The source for the firmware could be found in the subdirectory CanAdapterElm. In this subdirectory there is also a flash tool (subdirectory UpdateLoader) that allows firmware updates using the bootstrap loader once the firmware is programed.
The latest firmware version will be always included in Deep OBD for BMW.

Updated Wiki: ENET WiFi Adapter

$
0
0

ENET WiFi Adapter

For the BMW F-models there is a WiFi adapter available, that allows to communicate directly using the BMW ENET protocol.
It is based on the hardware of an A5-V11 3G/4G Router. The adapter has the following features:
  • MediaTek/Ralink RT5350F processor with 350MHz
  • DC/DC converter for improved power consumption
  • OpenWrt operating system
  • LuCi web interface
  • Firmware update possible via web interface
  • DHCP server
  • ESSID: Deep OBD BMW
  • Default Wifi password: deepobdbmw
  • Default IP address: 192.168.100.1
  • Default root password: root
ENET adapter open
ENET adapter closedWeb interface

Buy an adapter

The adapters are now available!
You could buy the ENET WiFi adapter from EBAY.
For BMW pre F-models use the Bluetooth adapter

Factory reset

If the adapter gets unreachable after a misconfiguration there is a possibility to perform a factory reset.
You have to open the adapter and press the reset button after the adapter has booted.

Use the adapter with INPA, Tool32 or ISTA-D

You could use the Bluetooth adapter on a windows PC with INPA or Tool32 as a replacement for an ENET adapter cable. The following steps are required to establish the connection:
  1. Install .NET framework 4.0 or higher and VS2015 C++ runtime
  2. Connect the ENET adapter with the PC. The PC automatically gets an IP address from the adapter DHCP server.
  3. Rename the api32.dll in the C:\Ediabas\bin and C:\ISTA-D\Ediabas\bin directory.
  4. Copy Api32.dll and EdiabasLib.config to the C:\Ediabas\bin and C:\ISTA-D\Ediabas\bin directory.
  5. For ISTA-D: In Administration -> VCI Config select as Interface type: Ediabas default settings (ediabas.ini)
  6. Modify the following entries in EdiabasLib.config:
<add key="Interface" value="ENET"/>
<add key="EnetRemoteHost" value="auto:all"/>

Updated Wiki: Replacement firmware for ELM327

$
0
0

Replacement firmware for ELM327

There is now a replacement firmware available for ELM327 based Bluetooth adapters, that has the following advantages over the standard firmware:
  • Faster and more stable CAN communication.
  • K-Line support (all protocols).
  • Contains a bootstrap loader that allows firmware update without opening the device.
  • Firmware updates are possible with Deep OBD for BMW.
  • Reduced power consumption due to use of sleep mode.
  • Two firmware versions are available:
    • Unmodified Bluetooth adapter: Baud rate 38400.
    • Modified Bluetooth adapter (recommended) with replaced OpenSource Bluetooth firmware: Baud rate 115200 and alterable Bluetooth pin (16 digits) and name (31 chars).
Bluetooth adapter topBluetooth adapter bottom

Buy an adapter

Adapters are available again!
You could buy the Bluetooth adapter from EBAY.
For BMW F-models use the ENET WiFi Adapter.

Factory reset

Beginning with firmware version 0.6 there is the possibility to perform a factory reset of the adapter. This resets the Bluetooth pin to 1234, the Bluetooth name to Deep OBD BMW and the mode to D-CAN.
To perform the factory reset you have to open the adapter and connect the unused pad of R26 with GND during power on.

Use the adapter with INPA, Tool32 or ISTA-D

You could use the Bluetooth adapter on a windows PC with INPA or Tool32 as a replacement for a OBD or ADS adapter. The following steps are required to establish the connection:
  1. Install .NET framework 4.0 or higher and VS2015 C++ runtime
  2. Connect the Bluetooth adapter with the PC (the default Bluetooth pin is 1234). Two COM ports are generated (incoming and outgoing).
  3. With the standard DCAN.exe from dcan_Tools (for configuration of the USB adapters) set the operation mode (D-CAN or K-LINE) of the Bluetooth adapter. For the COM port use the outgoing port.
  4. Rename the api32.dll in the C:\Ediabas\bin and C:\ISTA-D\Ediabas\bin directory.
  5. Copy Api32.dll and EdiabasLib.config to the C:\Ediabas\bin and C:\ISTA-D\Ediabas\bin directory.
  6. For ISTA-D: In Administration -> VCI Config select as Interface type: Ediabas default settings (ediabas.ini)
  7. Modify the following entries in EdiabasLib.config:
<add key="Interface" value="STD:OBD"/>
<add key="ObdComPort" value="BLUETOOTH:<Outgoing COM port>"/>

Programming of the processor

For the first programming of the processor simply attach a PICKit 3 programmer to the corresponding test points of the circuit board.
The source for the firmware could be found in the subdirectory CanAdapterElm. In this subdirectory there is also a flash tool (subdirectory UpdateLoader) that allows firmware updates using the bootstrap loader once the firmware is programed.
The latest firmware version will be always included in Deep OBD for BMW.

Updated Wiki: ENET WiFi Adapter

$
0
0

ENET WiFi Adapter

For the BMW F-models there is a WiFi adapter available, that allows to communicate directly using the BMW ENET protocol.
It is based on the hardware of an A5-V11 3G/4G Router. The adapter has the following features:
  • MediaTek/Ralink RT5350F processor with 350MHz
  • DC/DC converter for improved power consumption
  • OpenWrt operating system
  • LuCi web interface
  • Firmware update possible via web interface
  • DHCP server
  • ESSID: Deep OBD BMW
  • Default Wifi password: deepobdbmw
  • Default IP address: 192.168.100.1
  • Default root password: root
ENET adapter open
ENET adapter closedWeb interface

Buy an adapter

At the moment all adapters are sold, new components are on the way.
You could buy the ENET WiFi adapter from EBAY.
For BMW pre F-models use the Bluetooth adapter

Factory reset

If the adapter gets unreachable after a misconfiguration there is a possibility to perform a factory reset.
You have to open the adapter and press the reset button after the adapter has booted.

Use the adapter with INPA, Tool32 or ISTA-D

You could use the Bluetooth adapter on a windows PC with INPA or Tool32 as a replacement for an ENET adapter cable. The following steps are required to establish the connection:
  1. Install .NET framework 4.0 or higher and VS2015 C++ runtime
  2. Connect the ENET adapter with the PC. The PC automatically gets an IP address from the adapter DHCP server.
  3. Rename the api32.dll in the C:\Ediabas\bin and C:\ISTA-D\Ediabas\bin directory.
  4. Copy Api32.dll and EdiabasLib.config to the C:\Ediabas\bin and C:\ISTA-D\Ediabas\bin directory.
  5. For ISTA-D: In Administration -> VCI Config select as Interface type: Ediabas default settings (ediabas.ini)
  6. Modify the following entries in EdiabasLib.config:
<add key="Interface" value="ENET"/>
<add key="EnetRemoteHost" value="auto:all"/>


Updated Wiki: Replacement firmware for ELM327

$
0
0

Replacement firmware for ELM327

There is now a replacement firmware available for ELM327 based Bluetooth adapters, that has the following advantages over the standard firmware:
  • Faster and more stable CAN communication.
  • K-Line support (all protocols).
  • Contains a bootstrap loader that allows firmware update without opening the device.
  • Firmware updates are possible with Deep OBD for BMW.
  • Reduced power consumption due to use of sleep mode.
  • Two firmware versions are available:
    • Unmodified Bluetooth adapter: Baud rate 38400.
    • Modified Bluetooth adapter (recommended) with replaced OpenSource Bluetooth firmware: Baud rate 115200 and alterable Bluetooth pin (16 digits) and name (31 chars).
Bluetooth adapter topBluetooth adapter bottom

Buy an adapter

All Adapters are sold at the moment, new ones are on the way.
You could buy the Bluetooth adapter from EBAY.
For BMW F-models use the ENET WiFi Adapter.

Factory reset

Beginning with firmware version 0.6 there is the possibility to perform a factory reset of the adapter. This resets the Bluetooth pin to 1234, the Bluetooth name to Deep OBD BMW and the mode to D-CAN.
To perform the factory reset you have to open the adapter and connect the unused pad of R26 with GND during power on.

Use the adapter with INPA, Tool32 or ISTA-D

You could use the Bluetooth adapter on a windows PC with INPA or Tool32 as a replacement for a OBD or ADS adapter. The following steps are required to establish the connection:
  1. Install .NET framework 4.0 or higher and VS2015 C++ runtime
  2. Connect the Bluetooth adapter with the PC (the default Bluetooth pin is 1234). Two COM ports are generated (incoming and outgoing).
  3. With the standard DCAN.exe from dcan_Tools (for configuration of the USB adapters) set the operation mode (D-CAN or K-LINE) of the Bluetooth adapter. For the COM port use the outgoing port.
  4. Rename the api32.dll in the C:\Ediabas\bin and C:\ISTA-D\Ediabas\bin directory.
  5. Copy Api32.dll and EdiabasLib.config to the C:\Ediabas\bin and C:\ISTA-D\Ediabas\bin directory.
  6. For ISTA-D: In Administration -> VCI Config select as Interface type: Ediabas default settings (ediabas.ini)
  7. Modify the following entries in EdiabasLib.config:
<add key="Interface" value="STD:OBD"/>
<add key="ObdComPort" value="BLUETOOTH:<Outgoing COM port>"/>

Programming of the processor

For the first programming of the processor simply attach a PICKit 3 programmer to the corresponding test points of the circuit board.
The source for the firmware could be found in the subdirectory CanAdapterElm. In this subdirectory there is also a flash tool (subdirectory UpdateLoader) that allows firmware updates using the bootstrap loader once the firmware is programed.
The latest firmware version will be always included in Deep OBD for BMW.

Updated Wiki: Page specification

$
0
0

Defining pages for Deep OBD for BMW

Each page (tab) is defined in a single XML (*.ccpage) file. A general documentation of all XML tags could be found in the BmwDeepObd.xsd file. The documentation will be displayed in the XML editor when the xsd is added as xs:shema in the XML file.
Table of contents:

Simple jobs

If only some EDIABAS jobs with fixed arguments are required for one display page, the XML code is relative simple. Below is the example code to display climate data for a E61 vehicle:

<?xml version="1.0" encoding="utf-8" ?>
<fragment xmlns="http://www.holeschak.de/BmwDeepObd"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://www.holeschak.de/BmwDeepObd ../BmwDeepObd.xsd">
  <page name ="tab_ihk">
    <strings>
      <string name="tab_ihk">Climate</string>
      <string name="label_ihk_in_temp">Indoor temperature [°C]:</string>
      <string name="label_ihk_in_temp_delay">Indoor temperature delayed [°C]:</string>
      <string name="label_ihk_out_temp">Outdoor temperature [°C]:</string>
      <string name="label_ihk_setpoint">Setpoint [°C]:</string>
      <string name="label_ihk_heat_ex_temp">Heat exchanger temperature [°C]:</string>
      <string name="label_ihk_heat_ex_setpoint">Heat exchanger setpoint [°C]:</string>
      <string name="label_ihk_heat_ex_actuator">Heat exchanger actuator [%]:</string>
      <string name="label_ihk_main_actuator">Main actuator [%]:</string>
      <string name="label_ihk_evap_temp">Evaporator temperature [°C]:</string>
      <string name="label_ihk_press_sense">Pressure sensor [bar]:</string>
      <string name="label_ihk_circ_air_left">Circulating air left [%]:</string>
      <string name="label_ihk_circ_air_right">Circulating air right [%]:</string>
      <string name="label_ihk_defrost">Defrost [%]:</string>
      <string name="label_ihk_vent">Ventilation [%]:</string>
      <string name="label_ihk_cold_air">Cold air [%]:</string>
      <string name="label_ihk_legroom">Leg room [%]:</string>
      <string name="label_ihk_refrig_comp">Refrigerating compressor [%]:</string>
    </strings>
    <strings lang="de">
      <string name="tab_ihk">Klima</string>
      <string name="label_ihk_in_temp">Innentemperatur [°C]:</string>
      <string name="label_ihk_in_temp_delay">Innentemperatur verzögert [°C]:</string>
      <string name="label_ihk_out_temp">Außentemperatur [°C]:</string>
      <string name="label_ihk_setpoint">Sollwert [°C]:</string>
      <string name="label_ihk_heat_ex_temp">Wärmetauschertemperatur [°C]:</string>
      <string name="label_ihk_heat_ex_setpoint">Wärmetauschersollwert [°C]:</string>
      <string name="label_ihk_heat_ex_actuator">Wärmetauscherstellgröße [%]:</string>
      <string name="label_ihk_main_actuator">Hauptstellgröße [%]:</string>
      <string name="label_ihk_evap_temp">Verdampfertemperatur [°C]:</string>
      <string name="label_ihk_press_sense">Drucksensor [bar]:</string>
      <string name="label_ihk_circ_air_left">Umluft links [%]:</string>
      <string name="label_ihk_circ_air_right">Umluft rechts [%]:</string>
      <string name="label_ihk_defrost">Abtauen [%]:</string>
      <string name="label_ihk_vent">Belüftung [%]:</string>
      <string name="label_ihk_cold_air">Kaltluft [%]:</string>
      <string name="label_ihk_legroom">Fußraum [%]:</string>
      <string name="label_ihk_refrig_comp">Kältemittelverdichter [%]:</string>
    </strings>
    <jobs sgbd="d_klima">
      <job name="STATUS_REGLERGROESSEN" results="STAT_TINNEN_WERT;STAT_TINNEN_VERZOEGERT_WERT;STAT_TAUSSEN_WERT;STAT_SOLL_LI_KORRIGIERT_WERT;STAT_WT_RE_WERT;STAT_WTSOLL_RE_WERT;STAT_YWT_RE_WERT;STAT_Y_RE_WERT">
        <display name="label_ihk_in_temp" result="STAT_TINNEN_WERT" format="6.1R" />
        <display name="label_ihk_in_temp_delay" result="STAT_TINNEN_VERZOEGERT_WERT" format="6.1R" />
        <display name="label_ihk_out_temp" result="STAT_TAUSSEN_WERT" format="6.1R" />
        <display name="label_ihk_setpoint" result="STAT_SOLL_LI_KORRIGIERT_WERT" format="6.1R" />
        <display name="label_ihk_heat_ex_temp" result="STAT_WT_RE_WERT" format="6.1R" />
        <display name="label_ihk_heat_ex_setpoint" result="STAT_WTSOLL_RE_WERT" format="6.1R" />
        <display name="label_ihk_heat_ex_actuator" result="STAT_YWT_RE_WERT" format="3L" />
        <display name="label_ihk_main_actuator" result="STAT_Y_RE_WERT" format="3L" />
      </job>
      <job name="STATUS_ANALOGEINGAENGE" results="STAT_TEMP_VERDAMFER_WERT;STAT_DRUCKSENSOR_WERT">
        <display name="label_ihk_evap_temp" result="STAT_TEMP_VERDAMFER_WERT" format="6.1R" />
        <display name="label_ihk_press_sense" result="STAT_DRUCKSENSOR_WERT" format="6.1R" />
      </job>
      <job name="STATUS_MOTOR_KLAPPENPOSITION" results="STAT_FRISCHLUFT_UMLUFT_LI_WERT;STAT_FRISCHLUFT_UMLUFT_RE_WERT;STAT_DEFROST_WERT;STAT_BELUEFTUNG_WERT;STAT_KALTLUFT_WERT;STAT_FUSSRAUM_WERT">
        <display name="label_ihk_circ_air_left" result="STAT_FRISCHLUFT_UMLUFT_LI_WERT" format="3L" />
        <display name="label_ihk_circ_air_right" result="STAT_FRISCHLUFT_UMLUFT_RE_WERT" format="3L" />
        <display name="label_ihk_defrost" result="STAT_DEFROST_WERT" format="3L" />
        <display name="label_ihk_vent" result="STAT_BELUEFTUNG_WERT" format="3L" />
        <display name="label_ihk_cold_air" result="STAT_KALTLUFT_WERT" format="3L" />
        <display name="label_ihk_legroom" result="STAT_FUSSRAUM_WERT" format="3L" />
      </job>
      <job name="STATUS_IO" results="STAT_STEUERUNG_KMV_WERT">
        <display name="label_ihk_refrig_comp" result="STAT_STEUERUNG_KMV_WERT" format="3L" />
      </job>
    </jobs>
  </page>
</fragment>

The pagename property specifies the title of the page and is a reference to the strings nodes. With logfile a log file name could be specified, that allows to log the display data. If the symbol {D} is used inside the log file name, it will be replaced by the current date and time.
The strings nodes contains the all the string used on this display page. If the current language is not matching the lang tag, the default language (without tag) is used. The lang property could be either the short form e.g. 'de' or the long one 'de-DE'.

The jobs node groups all EDIABAS job to execute. The property sgbd specifies the name of the group (.grp) or the sgbd (.prg) file to use.
Within the jobs node multiple job nodes specify the EDIABAS jobs to execute. They contain the following properties:
  • name: Name of the job to execute
  • args_first: Allows to specify semicolon separated job arguments for the first job call.
  • args: Allows to specify semicolon separated job arguments. If this is the first call and args_first is present args_first will be used instead.
  • result: Allows to specify the required results. If omitted, all results will be generated, which may require more processing time.
  • log_tag=<tag name>: Adding this property allows to log the display data to a log file when activating the Log data menu in the application. The logfile property in the page node has to be specified as well to activate logging.
  • Each display node specifies one line of the display output. Name is again a reference to the text translation in the strings nodes. With result the EDIABAS job result name is selected, that contains the data. The format property allows to format the result with the EDIABAS aspiResultText format specification EDIABAS result types and formats.
The page node can optionally contain display nodes like the job node. They will be only used for User defined code.
This is how the resulting page will look like:

Climate page

Reading errors

With the read_errors node it's possible to read an error summary of all ECUs. Simply list all ECU names and the corresponding sgbd file names in a separate ecu node, like in the example below.
The error message is generated by the sgbd file and is in the language of the sgbd.
The page also allows to selectively reset ECU errors.

<?xml version="1.0" encoding="utf-8" ?>
<fragment xmlns="http://www.holeschak.de/BmwDeepObd"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://www.holeschak.de/BmwDeepObd ../BmwDeepObd.xsd">
  <page name ="tab_errors">
    <strings>
      <string name="tab_errors">Errors</string>

      <string name="ACSM">ACSM Crash security module</string>
      <string name="CAS">CAS Car access system</string>
      <string name="CCCBO">CCC-BO Front panel</string>
      <string name="CCCGW">CCC-GW Gateway</string>
      <string name="DDE">DDE Diesel elektronic</string>
      <string name="DSC">DSC Dynamic stability control</string>
      <string name="EKPS">EKPS Fuel pump control</string>
      <string name="IHK">IHK Integrated heating climate automatic</string>
      <string name="KBM">KBM Chassis basic module</string>
      <string name="KGM">KGM Chassis gateway module</string>
      <string name="KOMBI">KOMBI Combination instrument</string>
      <string name="PDC">PDC Park distance control</string>
      <string name="RLS">RLS Rain main beam sensor</string>
      <string name="EPS">EPS Electric power steering</string>
      <string name="ULF">ULF Universal hands-free system</string>
      <string name="FZD">FZD Roof switch unit</string>
    </strings>
    <strings lang="de">
      <string name="tab_errors">Fehler</string>

      <string name="ACSM">ACSM Crash-Sicherheits-Modul</string>
      <string name="CAS">CAS Car Access System</string>
      <string name="CCCBO">CCC-BO Bedienoberfläche</string>
      <string name="CCCGW">CCC-GW Gateway</string>
      <string name="DDE">DDE Diesel Elektronik</string>
      <string name="DSC">DSC Dynamische Stabilitätskontrolle</string>
      <string name="EKPS">EKPS Kraftstoffpumpensteuerung</string>
      <string name="IHK">IHK Integrierte Heiz-Klima-Automatik</string>
      <string name="KBM">KBM Karosserie-Basismodul</string>
      <string name="KGM">KGM Karosserie-Gateway-Modul</string>
      <string name="KOMBI">KOMBI Instrumentenkombination</string>
      <string name="PDC">PDC Park-Distance-Control</string>
      <string name="RLS">RLS Regen-Fahrlicht-Sensor</string>
      <string name="EPS">EPS Elektromechanische Servolenkung</string>
      <string name="ULF">ULF Universale Ladefreisprechelektronik</string>
      <string name="FZD">FZD Funtionszentrum Dach</string>
    </strings>
    <read_errors>
      <ecu name="CAS" sgbd="d_cas" />
      <ecu name="DDE" sgbd="d_motor" />
      <ecu name="EKPS" sgbd="d_ekp" />
      <ecu name="DSC" sgbd="d_dsc" />
      <ecu name="ACSM" sgbd="d_sim" />
      <ecu name="CCCBO" sgbd="d_mmi" />
      <ecu name="CCCGW" sgbd="d_mostgw" />
      <ecu name="IHK" sgbd="d_klima" />
      <ecu name="KBM" sgbd="d_kbm" />
      <ecu name="KGM" sgbd="d_zgm" />
      <ecu name="KOMBI" sgbd="d_kombi" />
      <ecu name="PDC" sgbd="d_pdc" />
      <ecu name="RLS" sgbd="d_rls" />
      <ecu name="EPS" sgbd="d_eps" />
      <ecu name="ULF" sgbd="d_ispb" />
      <ecu name="FZD" sgbd="d_fzd" />
    </read_errors>
  </page>
</fragment>

In the ecu node the property name is a link to a string node and sgbd is the name of the sgbd file. The output looks similar to this page:

Erros E90

User defined code

If the jobs and display output is getting more complex, user defined code will be required. In this case a C# class could be added to a code node, which defines a set of optional callback functions. If the show_warnings property is set to true, also warnings will be reported during compilation of the code.

<code show_warnigs="true">
      <![CDATA[
    class PageClass
    {
        public void CreateLayout(ActivityMain activity, JobReader.PageInfo pageInfo, LinearLayout pageLayout)
        {
        }

        public void DestroyLayout(JobReader.PageInfo pageInfo)
        {
        }

        public void UpdateLayout(JobReader.PageInfo pageInfo, bool pageValid, bool threadActive)
        {
        }

        public void ExecuteJob(EdiabasNet ediabas, ref Dictionary<string, EdiabasNet.ResultData> resultDict, bool firstCall)
        {
        }

        public string FormatResult(JobReader.PageInfo pageInfo, Dictionary<string, EdiabasNet.ResultData> resultDict, string resultName)
        {
        }

        public string FormatErrorResult(JobReader.PageInfo pageInfo, EdiabasThread.EdiabasErrorReport errorReport, string defaultMessage)
        {
        }

        public void UpdateResultList(JobReader.PageInfo pageInfo, Dictionary<string, EdiabasNet.ResultData> resultDict, List<TableResultItem> resultList)
        {
        }
    }
      ]]>
    </code>

Formatting results (FormatResult)

For special formatting of the result data, the callback FormatResult could be used. For each result of the EDIABAS results this function will be called with resultName set to the current result name. If the display node is a subnode of a job node the job name is prefixed with # as separator to the result name. The function will be only called if there is noformat property in the display node. Here is an example from the motor page:

        public string FormatResult(JobReader.PageInfo pageInfo, Dictionary<string, EdiabasNet.ResultData> resultDict, string resultName)
        {
            string result = string.Empty;
            bool found;

            switch (resultName)
            {
                case "STATUS_MESSWERTBLOCK_LESEN#STAT_STRECKE_SEIT_ERFOLGREICHER_REGENERATION_WERT":
                    result = string.Format(ActivityMain.Culture, "{0,6:0.0}", ActivityMain.GetResultDouble(resultDict, resultName, out found) / 1000.0);
                    if (!found) result = string.Empty;
                    break;

                case "STATUS_MESSWERTBLOCK_LESEN#STAT_OELDRUCKSCHALTER_EIN_WERT":
                    result = ((ActivityMain.GetResultDouble (resultDict, resultName, out found) > 0.5) && found) ? "1" : "0";
                    if (!found) result = string.Empty;
                    break;

                case "STATUS_MESSWERTBLOCK_LESEN#STAT_REGENERATIONSANFORDERUNG_WERT":
                    result = ((ActivityMain.GetResultDouble (resultDict, resultName, out found) < 0.5) && found) ? "1" : "0";
                    if (!found) result = string.Empty;
                    break;

                case "STATUS_MESSWERTBLOCK_LESEN#STAT_EGT_st_WERT":
                    result = ((ActivityMain.GetResultDouble (resultDict, resultName, out found) > 1.5) && found) ? "1" : "0";
                    if (!found) result = string.Empty;
                    break;

                case "STATUS_MESSWERTBLOCK_LESEN#STAT_REGENERATION_BLOCKIERUNG_UND_FREIGABE_WERT":
                    result = ((ActivityMain.GetResultDouble (resultDict, resultName, out found) < 0.5) && found) ? "1" : "0";
                    if (!found) result = string.Empty;
                    break;
            }
            return result;
        }

Formatting error results (FormatErrorResult)

For special formatting of the error result data, the callback FormatErrorResult could be used. For each error entry this function will be called with defaultMessage set to the default error message output.
Here is an example from the errors page, that adds a RPM value to the error message. You have to add a results property to the ecu node specifying the results you want to be generated by the FS_LESEN_DETAIL job.

<read_errors>
      <ecu name="CAS" sgbd="d_cas" />
      <ecu name="DDE" sgbd="d_motor" results="F_UW_KM;F_UW_ANZ" />
    </read_errors>
    <code show_warnigs="true">
      <![CDATA[
    class PageClass
    {
        public string FormatErrorResult(JobReader.PageInfo pageInfo, EdiabasThread.EdiabasErrorReport errorReport, string defaultMessage)
        {
            string message = defaultMessage;
            switch (errorReport.EcuName)
            {
                case "DDE":
                {
                    string detailText = string.Empty;
                    foreach (Dictionary<string, EdiabasNet.ResultData> errorDetail in errorReport.ErrorDetailSet)
                    {
                        string rpmText = ActivityMain.FormatResultDouble(errorDetail, "F_UW1_WERT", "{0,6:0.0}");
                        if (rpmText.Length > 0)
                        {
                            if (detailText.Length == 0)
                            {
                                detailText += rpmText + " 1/min";
                            }
                        }
                    }
                    if (detailText.Length > 0)
                    {
                        message += "\r\n" + detailText;
                    }
                    break;
                }
            }
            return message;
        }
    }
      ]]>
  </code>

Control output of the page (UpdateResultList)

Sometimes you want to dynamically control the number and the content of the output lines.
If the callback UpdateResultList is defined, you could directly fill the contents of the resultListAdapter which displays the results of the page. In this example from the (standard) Adapter page the adapter configuration result will be displayed. Additionally only one column for output is used by setting the second argument of resultListAdapter.Items.Add to null. With ActivityMain.GetPageString it's possible to retrieve a string from the translation table.

        public void UpdateResultList(JobReader.PageInfo pageInfo, Dictionary<string, EdiabasNet.ResultData> resultDict, List<TableResultItem> resultList)
        {
            int result = configResult;

            if (result > 0)
            {
                resultList.Add(new TableResultItem(ActivityMain.GetPageString(pageInfo, "adapter_config_ok"), null));
            }
            else if (result == 0)
            {
                resultList.Add(new TableResultItem(ActivityMain.GetPageString(pageInfo, "adapter_config_error"), null));
            }
        }

Executing own jobs (ExecuteJob)

If more than one job has to be executed or the job requires special arguments, ediabas.ExecuteJob could be called in the ExecuteJob callback. Here is an example from the adapter page for calling a list of jobs. EdiabasThread.MergeResultDictionarys adds the results of the current job to the internal job list. The callback ExecuteJob will be executed in it's own thread. When using ExecuteJob it's recommended to add the display nodes to the page node because no job nodes will be present.

    class PageClass
    {
        private class EdiabasJob
        {
            private string jobName;
            private string jobArgs;
            private string resultRequests;

            public EdiabasJob(string jobName, string jobArgs, string resultRequests)
            {
                this.jobName = jobName;
                this.jobArgs = jobArgs;
                this.resultRequests = resultRequests;
            }

            public string JobName
            {
                get
                {
                    return jobName;
                }
            }

            public string JobArgs
            {
                get
                {
                    return jobArgs;
                }
            }

            public string ResultRequests
            {
                get
                {
                    return resultRequests;
                }
            }
        }

        static private readonly EdiabasJob[] jobArray =
            {
                new EdiabasJob("ADAPTER_CMD",
                    "0xFE;0xFE",
                    string.Empty
                    ),
                new EdiabasJob("ADAPTER_CMD",
                    "0x80;0x00",
                    string.Empty
                    ),
                new EdiabasJob("ADAPTER_CMD",
                    "0x81;0x00",
                    string.Empty
                    ),
                new EdiabasJob("ADAPTER_CMD",
                    "0x82;0x00",
                    string.Empty
                    ),
            };

        public void ExecuteJob(EdiabasNet ediabas, ref Dictionary<string, EdiabasNet.ResultData> resultDict, bool firstCall)
        {
            int index = 0;
            foreach (EdiabasJob job in jobArray)
            {
                ediabas.ArgString = job.JobArgs;
                ediabas.ArgBinaryStd = null;
                ediabas.ResultsRequests = job.ResultRequests;

                ediabas.ExecuteJob(job.JobName);

                List<Dictionary<string, EdiabasNet.ResultData>> resultSets = ediabas.ResultSets;
                if (resultSets != null && resultSets.Count >= 2)
                {
                    EdiabasThread.MergeResultDictionarys(ref resultDict, resultSets[1], string.Format("{0}_", index));
                }
                index++;
            }
        }
    }

Adding controls to the layout

The standard layout only allows to display information, but there is no way to control outputs. With the callbacks CreateLayout, DestroyLayout and UpdateLayout there is a possibility to add own controls to the layout (in most cases buttons).
In this example from the AdapterCustom.ccpage buttons will be added to control the CAN block size, CAN separation time and the CAN mode. The CreateLayout adds the controls, DestroyLayout removes the controls and UpdateLayout is used to modify the state of the controls (depending form the connection state).
For every button there is a Click delegate that allows to set a global variable which is used for EDIABAS job control.

        private Button buttonBlockSize;
        private Button buttonSepTime0;
        private Button buttonSepTime1;
        private Button buttonCan500;
        private Button buttonCan100;
        private Button buttonCanOff;
        private int adapterCmd = -1;
        private int adapterValue;
        private int blockSize = 0;

        public void CreateLayout(ActivityMain activity, JobReader.PageInfo pageInfo, LinearLayout pageLayout)
        {
            LinearLayout buttonLayout = new LinearLayout(activity);
            buttonLayout.Orientation = Orientation.Vertical;

            LinearLayout.LayoutParams buttonLayoutParams = new LinearLayout.LayoutParams(
                ViewGroup.LayoutParams.MatchParent,
                ViewGroup.LayoutParams.WrapContent);
            buttonLayoutParams.Weight = 1;

            buttonBlockSize = new Button(activity);
            buttonBlockSize.Text = string.Format("{0}: {1}", ActivityMain.GetPageString(pageInfo, "button_adapter_config_block_size"), blockSize);
            buttonBlockSize.Click += delegate
            {
                blockSize += 2;
                if (blockSize > 8)
                {
                    blockSize = 0;
                }
                adapterCmd = 0x00;
                adapterValue = blockSize;
                buttonBlockSize.Text = string.Format("{0}: {1}", ActivityMain.GetPageString(pageInfo, "button_adapter_config_block_size"), blockSize);
            };
            buttonLayout.AddView(buttonBlockSize, buttonLayoutParams);

            buttonSepTime0 = new Button(activity);
            buttonSepTime0.Text = ActivityMain.GetPageString(pageInfo, "button_adapter_config_sep_time0");
            buttonSepTime0.Click += delegate
            {
                adapterCmd = 0x01;
                adapterValue = 0x00;
            };
            buttonLayout.AddView(buttonSepTime0, buttonLayoutParams);

            buttonSepTime1 = new Button(activity);
            buttonSepTime1.Text = ActivityMain.GetPageString(pageInfo, "button_adapter_config_sep_time1");
            buttonSepTime1.Click += delegate
            {
                adapterCmd = 0x01;
                adapterValue = 0x01;
            };
            buttonLayout.AddView(buttonSepTime1, buttonLayoutParams);

            buttonCan500 = new Button(activity);
            buttonCan500.Text = ActivityMain.GetPageString(pageInfo, "button_adapter_config_can_500");
            buttonCan500.Click += delegate
            {
                adapterCmd = 0x02;
                adapterValue = 0x01;
            };
            buttonLayout.AddView(buttonCan500, buttonLayoutParams);

            buttonCan100 = new Button(activity);
            buttonCan100.Text = ActivityMain.GetPageString(pageInfo, "button_adapter_config_can_100");
            buttonCan100.Click += delegate
            {
                adapterCmd = 0x02;
                adapterValue = 0x09;
            };
            buttonLayout.AddView(buttonCan100, buttonLayoutParams);

            buttonCanOff = new Button(activity);
            buttonCanOff.Text = ActivityMain.GetPageString(pageInfo, "button_adapter_config_can_off");
            buttonCanOff.Click += delegate
            {
                adapterCmd = 0x02;
                adapterValue = 0x00;
            };
            buttonLayout.AddView(buttonCanOff, buttonLayoutParams);

            LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
                ViewGroup.LayoutParams.MatchParent,
                ViewGroup.LayoutParams.WrapContent);
            pageLayout.AddView(buttonLayout, layoutParams);

            adapterCmd = -1;
        }

        public void DestroyLayout(JobReader.PageInfo pageInfo)
        {
            if (buttonBlockSize != null)
            {
                buttonBlockSize.Dispose();
                buttonBlockSize = null;
            }
            if (buttonSepTime0 != null)
            {
                buttonSepTime0.Dispose();
                buttonSepTime0 = null;
            }
            if (buttonSepTime1 != null)
            {
                buttonSepTime1.Dispose();
                buttonSepTime1 = null;
            }
            if (buttonCan500 != null)
            {
                buttonCan500.Dispose();
                buttonCan500 = null;
            }
            if (buttonCan100 != null)
            {
                buttonCan100.Dispose();
                buttonCan100 = null;
            }
            if (buttonCanOff != null)
            {
                buttonCanOff.Dispose();
                buttonCanOff = null;
            }
            //Android.Util.Log.Info("Custom", "Destroyed");
        }

        public void UpdateLayout(JobReader.PageInfo pageInfo, bool pageValid, bool threadActive)
        {
            if ((buttonCan500 == null) || (buttonCan100 == null) || (buttonCanOff == null))
            {
                return;
            }

            bool enabled = pageValid && threadActive;
            buttonBlockSize.Enabled = enabled;
            buttonSepTime0.Enabled = enabled;
            buttonSepTime1.Enabled = enabled;
            buttonCan500.Enabled = enabled;
            buttonCan100.Enabled = enabled;
            buttonCanOff.Enabled = enabled;
        }
    }


The resulting page will look like this:

AdapterConfigSmall.png
(Adapter page)

Grouping pages

If the same of pages are required in multiple configuration, it's useful to group the together. This could be done with *.ccpages files. Simply include the *.ccpage files withing the pages node. The specifified path is relative to the *.ccpages file location. The file has the following layout:

<?xml version="1.0" encoding="utf-8" ?>
<fragment xmlns="http://www.holeschak.de/BmwDeepObd"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://www.holeschak.de/BmwDeepObd ../BmwDeepObd.xsd">
  <pages>
    <include filename="Axis.ccpage"/>
    <include filename="Motor.ccpage"/>
    <include filename="../AdapterCustom.ccpage"/>
  </pages>
</fragment>

The configuration file

Now all *.page or *.pages can added to a configuration file (*.cccfg). This file could be loaded by BWM deep OBD. In the global node of the file the following properties could be specified:
  • ecu_path: Directory of the ecu files (*.grp and *.prg) relative to the configuration file.
  • log_path: Directory for the data logging files. Logging could be enabled by adding a log_tag property to the display node of the *.page file. If the directory is not existing it will be created.
  • append_log: Setting this property to true will always append the log file.
  • interface: Specify the communication interface in this property. Possible values are BLUETOOTH , ENET, ELMWIFI and FTDI.

<?xml version="1.0" encoding="utf-8"?>
<fragment xmlns="http://www.holeschak.de/BmwDeepObd"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://www.holeschak.de/BmwDeepObd ../BmwDeepObd.xsd">
  <global ecu_path="../Ecu" log_path="Log" append_log="true" interface="BLUETOOTH" />
  <include filename="E61.ccpages"/>
</configuration>

Updated Wiki: Page specification

$
0
0

Defining pages for Deep OBD for BMW

Each page (tab) is defined in a single XML (*.ccpage) file. A general documentation of all XML tags could be found in the BmwDeepObd.xsd file. The documentation will be displayed in the XML editor when the xsd is added as xs:shema in the XML file.
Table of contents:

Simple jobs

If only some EDIABAS jobs with fixed arguments are required for one display page, the XML code is relative simple. Below is the example code to display climate data for a E61 vehicle:

<?xml version="1.0" encoding="utf-8" ?>
<fragment xmlns="http://www.holeschak.de/BmwDeepObd"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://www.holeschak.de/BmwDeepObd ../BmwDeepObd.xsd">
  <page name ="tab_ihk">
    <strings>
      <string name="tab_ihk">Climate</string>
      <string name="label_ihk_in_temp">Indoor temperature [°C]:</string>
      <string name="label_ihk_in_temp_delay">Indoor temperature delayed [°C]:</string>
      <string name="label_ihk_out_temp">Outdoor temperature [°C]:</string>
      <string name="label_ihk_setpoint">Setpoint [°C]:</string>
      <string name="label_ihk_heat_ex_temp">Heat exchanger temperature [°C]:</string>
      <string name="label_ihk_heat_ex_setpoint">Heat exchanger setpoint [°C]:</string>
      <string name="label_ihk_heat_ex_actuator">Heat exchanger actuator [%]:</string>
      <string name="label_ihk_main_actuator">Main actuator [%]:</string>
      <string name="label_ihk_evap_temp">Evaporator temperature [°C]:</string>
      <string name="label_ihk_press_sense">Pressure sensor [bar]:</string>
      <string name="label_ihk_circ_air_left">Circulating air left [%]:</string>
      <string name="label_ihk_circ_air_right">Circulating air right [%]:</string>
      <string name="label_ihk_defrost">Defrost [%]:</string>
      <string name="label_ihk_vent">Ventilation [%]:</string>
      <string name="label_ihk_cold_air">Cold air [%]:</string>
      <string name="label_ihk_legroom">Leg room [%]:</string>
      <string name="label_ihk_refrig_comp">Refrigerating compressor [%]:</string>
    </strings>
    <strings lang="de">
      <string name="tab_ihk">Klima</string>
      <string name="label_ihk_in_temp">Innentemperatur [°C]:</string>
      <string name="label_ihk_in_temp_delay">Innentemperatur verzögert [°C]:</string>
      <string name="label_ihk_out_temp">Außentemperatur [°C]:</string>
      <string name="label_ihk_setpoint">Sollwert [°C]:</string>
      <string name="label_ihk_heat_ex_temp">Wärmetauschertemperatur [°C]:</string>
      <string name="label_ihk_heat_ex_setpoint">Wärmetauschersollwert [°C]:</string>
      <string name="label_ihk_heat_ex_actuator">Wärmetauscherstellgröße [%]:</string>
      <string name="label_ihk_main_actuator">Hauptstellgröße [%]:</string>
      <string name="label_ihk_evap_temp">Verdampfertemperatur [°C]:</string>
      <string name="label_ihk_press_sense">Drucksensor [bar]:</string>
      <string name="label_ihk_circ_air_left">Umluft links [%]:</string>
      <string name="label_ihk_circ_air_right">Umluft rechts [%]:</string>
      <string name="label_ihk_defrost">Abtauen [%]:</string>
      <string name="label_ihk_vent">Belüftung [%]:</string>
      <string name="label_ihk_cold_air">Kaltluft [%]:</string>
      <string name="label_ihk_legroom">Fußraum [%]:</string>
      <string name="label_ihk_refrig_comp">Kältemittelverdichter [%]:</string>
    </strings>
    <jobs sgbd="d_klima">
      <job name="STATUS_REGLERGROESSEN" results="STAT_TINNEN_WERT;STAT_TINNEN_VERZOEGERT_WERT;STAT_TAUSSEN_WERT;STAT_SOLL_LI_KORRIGIERT_WERT;STAT_WT_RE_WERT;STAT_WTSOLL_RE_WERT;STAT_YWT_RE_WERT;STAT_Y_RE_WERT">
        <display name="label_ihk_in_temp" result="STAT_TINNEN_WERT" format="6.1R" />
        <display name="label_ihk_in_temp_delay" result="STAT_TINNEN_VERZOEGERT_WERT" format="6.1R" />
        <display name="label_ihk_out_temp" result="STAT_TAUSSEN_WERT" format="6.1R" />
        <display name="label_ihk_setpoint" result="STAT_SOLL_LI_KORRIGIERT_WERT" format="6.1R" />
        <display name="label_ihk_heat_ex_temp" result="STAT_WT_RE_WERT" format="6.1R" />
        <display name="label_ihk_heat_ex_setpoint" result="STAT_WTSOLL_RE_WERT" format="6.1R" />
        <display name="label_ihk_heat_ex_actuator" result="STAT_YWT_RE_WERT" format="3L" />
        <display name="label_ihk_main_actuator" result="STAT_Y_RE_WERT" format="3L" />
      </job>
      <job name="STATUS_ANALOGEINGAENGE" results="STAT_TEMP_VERDAMFER_WERT;STAT_DRUCKSENSOR_WERT">
        <display name="label_ihk_evap_temp" result="STAT_TEMP_VERDAMFER_WERT" format="6.1R" />
        <display name="label_ihk_press_sense" result="STAT_DRUCKSENSOR_WERT" format="6.1R" />
      </job>
      <job name="STATUS_MOTOR_KLAPPENPOSITION" results="STAT_FRISCHLUFT_UMLUFT_LI_WERT;STAT_FRISCHLUFT_UMLUFT_RE_WERT;STAT_DEFROST_WERT;STAT_BELUEFTUNG_WERT;STAT_KALTLUFT_WERT;STAT_FUSSRAUM_WERT">
        <display name="label_ihk_circ_air_left" result="STAT_FRISCHLUFT_UMLUFT_LI_WERT" format="3L" />
        <display name="label_ihk_circ_air_right" result="STAT_FRISCHLUFT_UMLUFT_RE_WERT" format="3L" />
        <display name="label_ihk_defrost" result="STAT_DEFROST_WERT" format="3L" />
        <display name="label_ihk_vent" result="STAT_BELUEFTUNG_WERT" format="3L" />
        <display name="label_ihk_cold_air" result="STAT_KALTLUFT_WERT" format="3L" />
        <display name="label_ihk_legroom" result="STAT_FUSSRAUM_WERT" format="3L" />
      </job>
      <job name="STATUS_IO" results="STAT_STEUERUNG_KMV_WERT">
        <display name="label_ihk_refrig_comp" result="STAT_STEUERUNG_KMV_WERT" format="3L" />
      </job>
    </jobs>
  </page>
</fragment>

The pagename property specifies the title of the page and is a reference to the strings nodes. With logfile a log file name could be specified, that allows to log the display data. If the symbol {D} is used inside the log file name, it will be replaced by the current date and time.
The strings nodes contains the all the string used on this display page. If the current language is not matching the lang tag, the default language (without tag) is used. The lang property could be either the short form e.g. 'de' or the long one 'de-DE'.

The jobs node groups all EDIABAS job to execute. The property sgbd specifies the name of the group (.grp) or the sgbd (.prg) file to use.
Within the jobs node multiple job nodes specify the EDIABAS jobs to execute. They contain the following properties:
  • name: Name of the job to execute
  • args_first: Allows to specify semicolon separated job arguments for the first job call.
  • args: Allows to specify semicolon separated job arguments. If this is the first call and args_first is present args_first will be used instead.
  • result: Allows to specify the required results. If omitted, all results will be generated, which may require more processing time.
  • log_tag=<tag name>: Adding this property allows to log the display data to a log file when activating the Log data menu in the application. The logfile property in the page node has to be specified as well to activate logging.
  • Each display node specifies one line of the display output. Name is again a reference to the text translation in the strings nodes. With result the EDIABAS job result name is selected, that contains the data. The format property allows to format the result with the EDIABAS aspiResultText format specification EDIABAS result types and formats.
The page node can optionally contain display nodes like the job node. They will be only used for User defined code.
This is how the resulting page will look like:

Climate page

Reading errors

With the read_errors node it's possible to read an error summary of all ECUs. Simply list all ECU names and the corresponding sgbd file names in a separate ecu node, like in the example below.
The error message is generated by the sgbd file and is in the language of the sgbd.
The page also allows to selectively reset ECU errors.

<?xml version="1.0" encoding="utf-8" ?>
<fragment xmlns="http://www.holeschak.de/BmwDeepObd"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://www.holeschak.de/BmwDeepObd ../BmwDeepObd.xsd">
  <page name ="tab_errors">
    <strings>
      <string name="tab_errors">Errors</string>

      <string name="ACSM">ACSM Crash security module</string>
      <string name="CAS">CAS Car access system</string>
      <string name="CCCBO">CCC-BO Front panel</string>
      <string name="CCCGW">CCC-GW Gateway</string>
      <string name="DDE">DDE Diesel elektronic</string>
      <string name="DSC">DSC Dynamic stability control</string>
      <string name="EKPS">EKPS Fuel pump control</string>
      <string name="IHK">IHK Integrated heating climate automatic</string>
      <string name="KBM">KBM Chassis basic module</string>
      <string name="KGM">KGM Chassis gateway module</string>
      <string name="KOMBI">KOMBI Combination instrument</string>
      <string name="PDC">PDC Park distance control</string>
      <string name="RLS">RLS Rain main beam sensor</string>
      <string name="EPS">EPS Electric power steering</string>
      <string name="ULF">ULF Universal hands-free system</string>
      <string name="FZD">FZD Roof switch unit</string>
    </strings>
    <strings lang="de">
      <string name="tab_errors">Fehler</string>

      <string name="ACSM">ACSM Crash-Sicherheits-Modul</string>
      <string name="CAS">CAS Car Access System</string>
      <string name="CCCBO">CCC-BO Bedienoberfläche</string>
      <string name="CCCGW">CCC-GW Gateway</string>
      <string name="DDE">DDE Diesel Elektronik</string>
      <string name="DSC">DSC Dynamische Stabilitätskontrolle</string>
      <string name="EKPS">EKPS Kraftstoffpumpensteuerung</string>
      <string name="IHK">IHK Integrierte Heiz-Klima-Automatik</string>
      <string name="KBM">KBM Karosserie-Basismodul</string>
      <string name="KGM">KGM Karosserie-Gateway-Modul</string>
      <string name="KOMBI">KOMBI Instrumentenkombination</string>
      <string name="PDC">PDC Park-Distance-Control</string>
      <string name="RLS">RLS Regen-Fahrlicht-Sensor</string>
      <string name="EPS">EPS Elektromechanische Servolenkung</string>
      <string name="ULF">ULF Universale Ladefreisprechelektronik</string>
      <string name="FZD">FZD Funtionszentrum Dach</string>
    </strings>
    <read_errors>
      <ecu name="CAS" sgbd="d_cas" />
      <ecu name="DDE" sgbd="d_motor" />
      <ecu name="EKPS" sgbd="d_ekp" />
      <ecu name="DSC" sgbd="d_dsc" />
      <ecu name="ACSM" sgbd="d_sim" />
      <ecu name="CCCBO" sgbd="d_mmi" />
      <ecu name="CCCGW" sgbd="d_mostgw" />
      <ecu name="IHK" sgbd="d_klima" />
      <ecu name="KBM" sgbd="d_kbm" />
      <ecu name="KGM" sgbd="d_zgm" />
      <ecu name="KOMBI" sgbd="d_kombi" />
      <ecu name="PDC" sgbd="d_pdc" />
      <ecu name="RLS" sgbd="d_rls" />
      <ecu name="EPS" sgbd="d_eps" />
      <ecu name="ULF" sgbd="d_ispb" />
      <ecu name="FZD" sgbd="d_fzd" />
    </read_errors>
  </page>
</fragment>

In the ecu node the property name is a link to a string node and sgbd is the name of the sgbd file. The output looks similar to this page:

Erros E90

User defined code

If the jobs and display output is getting more complex, user defined code will be required. In this case a C# class could be added to a code node, which defines a set of optional callback functions. If the show_warnings property is set to true, also warnings will be reported during compilation of the code.

<code show_warnigs="true">
      <![CDATA[
    class PageClass
    {
        public void CreateLayout(ActivityMain activity, JobReader.PageInfo pageInfo, LinearLayout pageLayout)
        {
        }

        public void DestroyLayout(JobReader.PageInfo pageInfo)
        {
        }

        public void UpdateLayout(JobReader.PageInfo pageInfo, bool pageValid, bool threadActive)
        {
        }

        public void ExecuteJob(EdiabasNet ediabas, ref Dictionary<string, EdiabasNet.ResultData> resultDict, bool firstCall)
        {
        }

        public string FormatResult(JobReader.PageInfo pageInfo, Dictionary<string, EdiabasNet.ResultData> resultDict, string resultName)
        {
        }

        public string FormatResult(JobReader.PageInfo pageInfo, Dictionary<string, EdiabasNet.ResultData> resultDict, string resultName, ref Android.Graphics.Color? textColor)
        {
        }

        public string FormatErrorResult(JobReader.PageInfo pageInfo, EdiabasThread.EdiabasErrorReport errorReport, string defaultMessage)
        {
        }

        public void UpdateResultList(JobReader.PageInfo pageInfo, Dictionary<string, EdiabasNet.ResultData> resultDict, List<TableResultItem> resultList)
        {
        }
    }
      ]]>
    </code>

Formatting results (FormatResult)

For special formatting of the result data, the callback FormatResult could be used. For each result of the EDIABAS results this function will be called with resultName set to the current result name. If the display node is a subnode of a job node the job name is prefixed with # as separator to the result name. The function will be only called if there is noformat property in the display node. Here is an example from the motor page:

        public string FormatResult(JobReader.PageInfo pageInfo, Dictionary<string, EdiabasNet.ResultData> resultDict, string resultName, ref Android.Graphics.Color? textColor)
        {
            string result = string.Empty;
            bool found;

            switch (resultName)
            {
                case "STATUS_MESSWERTBLOCK_LESEN#STAT_STRECKE_SEIT_ERFOLGREICHER_REGENERATION_WERT":
                    result = string.Format(ActivityMain.Culture, "{0,6:0.0}", ActivityMain.GetResultDouble(resultDict, resultName, out found) / 1000.0);
                    if (!found) result = string.Empty;
                    break;

                case "STATUS_MESSWERTBLOCK_LESEN#STAT_OELDRUCKSCHALTER_EIN_WERT":
                    result = ((ActivityMain.GetResultDouble (resultDict, resultName, out found) > 0.5) && found) ? "1" : "0";
                    if (found && result == "1")
                    {
                        textColor = Android.Graphics.Color.Red;
                    }
                    if (!found) result = string.Empty;
                    break;

                case "STATUS_MESSWERTBLOCK_LESEN#STAT_REGENERATIONSANFORDERUNG_WERT":
                    result = ((ActivityMain.GetResultDouble (resultDict, resultName, out found) < 0.5) && found) ? "1" : "0";
                    if (!found) result = string.Empty;
                    break;

                case "STATUS_MESSWERTBLOCK_LESEN#STAT_EGT_st_WERT":
                    result = ((ActivityMain.GetResultDouble (resultDict, resultName, out found) > 1.5) && found) ? "1" : "0";
                    if (!found) result = string.Empty;
                    break;

                case "STATUS_MESSWERTBLOCK_LESEN#STAT_REGENERATION_BLOCKIERUNG_UND_FREIGABE_WERT":
                    result = ((ActivityMain.GetResultDouble (resultDict, resultName, out found) < 0.5) && found) ? "1" : "0";
                    if (!found) result = string.Empty;
                    break;
            }
            return result;
        }

Formatting error results (FormatErrorResult)

For special formatting of the error result data, the callback FormatErrorResult could be used. For each error entry this function will be called with defaultMessage set to the default error message output.
Here is an example from the errors page, that adds a RPM value to the error message. You have to add a results property to the ecu node specifying the results you want to be generated by the FS_LESEN_DETAIL job.

<read_errors>
      <ecu name="CAS" sgbd="d_cas" />
      <ecu name="DDE" sgbd="d_motor" results="F_UW_KM;F_UW_ANZ" />
    </read_errors>
    <code show_warnigs="true">
      <![CDATA[
    class PageClass
    {
        public string FormatErrorResult(JobReader.PageInfo pageInfo, EdiabasThread.EdiabasErrorReport errorReport, string defaultMessage)
        {
            string message = defaultMessage;
            switch (errorReport.EcuName)
            {
                case "DDE":
                {
                    string detailText = string.Empty;
                    foreach (Dictionary<string, EdiabasNet.ResultData> errorDetail in errorReport.ErrorDetailSet)
                    {
                        string rpmText = ActivityMain.FormatResultDouble(errorDetail, "F_UW1_WERT", "{0,6:0.0}");
                        if (rpmText.Length > 0)
                        {
                            if (detailText.Length == 0)
                            {
                                detailText += rpmText + " 1/min";
                            }
                        }
                    }
                    if (detailText.Length > 0)
                    {
                        message += "\r\n" + detailText;
                    }
                    break;
                }
            }
            return message;
        }
    }
      ]]>
  </code>

Control output of the page (UpdateResultList)

Sometimes you want to dynamically control the number and the content of the output lines.
If the callback UpdateResultList is defined, you could directly fill the contents of the resultListAdapter which displays the results of the page. In this example from the (standard) Adapter page the adapter configuration result will be displayed. Additionally only one column for output is used by setting the second argument of resultListAdapter.Items.Add to null. With ActivityMain.GetPageString it's possible to retrieve a string from the translation table.

        public void UpdateResultList(JobReader.PageInfo pageInfo, Dictionary<string, EdiabasNet.ResultData> resultDict, List<TableResultItem> resultList)
        {
            int result = configResult;

            if (result > 0)
            {
                resultList.Add(new TableResultItem(ActivityMain.GetPageString(pageInfo, "adapter_config_ok"), null));
            }
            else if (result == 0)
            {
                resultList.Add(new TableResultItem(ActivityMain.GetPageString(pageInfo, "adapter_config_error"), null));
            }
        }

Executing own jobs (ExecuteJob)

If more than one job has to be executed or the job requires special arguments, ediabas.ExecuteJob could be called in the ExecuteJob callback. Here is an example from the adapter page for calling a list of jobs. EdiabasThread.MergeResultDictionarys adds the results of the current job to the internal job list. The callback ExecuteJob will be executed in it's own thread. When using ExecuteJob it's recommended to add the display nodes to the page node because no job nodes will be present.

    class PageClass
    {
        private class EdiabasJob
        {
            private string jobName;
            private string jobArgs;
            private string resultRequests;

            public EdiabasJob(string jobName, string jobArgs, string resultRequests)
            {
                this.jobName = jobName;
                this.jobArgs = jobArgs;
                this.resultRequests = resultRequests;
            }

            public string JobName
            {
                get
                {
                    return jobName;
                }
            }

            public string JobArgs
            {
                get
                {
                    return jobArgs;
                }
            }

            public string ResultRequests
            {
                get
                {
                    return resultRequests;
                }
            }
        }

        static private readonly EdiabasJob[] jobArray =
            {
                new EdiabasJob("ADAPTER_CMD",
                    "0xFE;0xFE",
                    string.Empty
                    ),
                new EdiabasJob("ADAPTER_CMD",
                    "0x80;0x00",
                    string.Empty
                    ),
                new EdiabasJob("ADAPTER_CMD",
                    "0x81;0x00",
                    string.Empty
                    ),
                new EdiabasJob("ADAPTER_CMD",
                    "0x82;0x00",
                    string.Empty
                    ),
            };

        public void ExecuteJob(EdiabasNet ediabas, ref Dictionary<string, EdiabasNet.ResultData> resultDict, bool firstCall)
        {
            int index = 0;
            foreach (EdiabasJob job in jobArray)
            {
                ediabas.ArgString = job.JobArgs;
                ediabas.ArgBinaryStd = null;
                ediabas.ResultsRequests = job.ResultRequests;

                ediabas.ExecuteJob(job.JobName);

                List<Dictionary<string, EdiabasNet.ResultData>> resultSets = ediabas.ResultSets;
                if (resultSets != null && resultSets.Count >= 2)
                {
                    EdiabasThread.MergeResultDictionarys(ref resultDict, resultSets[1], string.Format("{0}_", index));
                }
                index++;
            }
        }
    }

Adding controls to the layout

The standard layout only allows to display information, but there is no way to control outputs. With the callbacks CreateLayout, DestroyLayout and UpdateLayout there is a possibility to add own controls to the layout (in most cases buttons).
In this example from the AdapterCustom.ccpage buttons will be added to control the CAN block size, CAN separation time and the CAN mode. The CreateLayout adds the controls, DestroyLayout removes the controls and UpdateLayout is used to modify the state of the controls (depending form the connection state).
For every button there is a Click delegate that allows to set a global variable which is used for EDIABAS job control.

        private Button buttonBlockSize;
        private Button buttonSepTime0;
        private Button buttonSepTime1;
        private Button buttonCan500;
        private Button buttonCan100;
        private Button buttonCanOff;
        private int adapterCmd = -1;
        private int adapterValue;
        private int blockSize = 0;

        public void CreateLayout(ActivityMain activity, JobReader.PageInfo pageInfo, LinearLayout pageLayout)
        {
            LinearLayout buttonLayout = new LinearLayout(activity);
            buttonLayout.Orientation = Orientation.Vertical;

            LinearLayout.LayoutParams buttonLayoutParams = new LinearLayout.LayoutParams(
                ViewGroup.LayoutParams.MatchParent,
                ViewGroup.LayoutParams.WrapContent);
            buttonLayoutParams.Weight = 1;

            buttonBlockSize = new Button(activity);
            buttonBlockSize.Text = string.Format("{0}: {1}", ActivityMain.GetPageString(pageInfo, "button_adapter_config_block_size"), blockSize);
            buttonBlockSize.Click += delegate
            {
                blockSize += 2;
                if (blockSize > 8)
                {
                    blockSize = 0;
                }
                adapterCmd = 0x00;
                adapterValue = blockSize;
                buttonBlockSize.Text = string.Format("{0}: {1}", ActivityMain.GetPageString(pageInfo, "button_adapter_config_block_size"), blockSize);
            };
            buttonLayout.AddView(buttonBlockSize, buttonLayoutParams);

            buttonSepTime0 = new Button(activity);
            buttonSepTime0.Text = ActivityMain.GetPageString(pageInfo, "button_adapter_config_sep_time0");
            buttonSepTime0.Click += delegate
            {
                adapterCmd = 0x01;
                adapterValue = 0x00;
            };
            buttonLayout.AddView(buttonSepTime0, buttonLayoutParams);

            buttonSepTime1 = new Button(activity);
            buttonSepTime1.Text = ActivityMain.GetPageString(pageInfo, "button_adapter_config_sep_time1");
            buttonSepTime1.Click += delegate
            {
                adapterCmd = 0x01;
                adapterValue = 0x01;
            };
            buttonLayout.AddView(buttonSepTime1, buttonLayoutParams);

            buttonCan500 = new Button(activity);
            buttonCan500.Text = ActivityMain.GetPageString(pageInfo, "button_adapter_config_can_500");
            buttonCan500.Click += delegate
            {
                adapterCmd = 0x02;
                adapterValue = 0x01;
            };
            buttonLayout.AddView(buttonCan500, buttonLayoutParams);

            buttonCan100 = new Button(activity);
            buttonCan100.Text = ActivityMain.GetPageString(pageInfo, "button_adapter_config_can_100");
            buttonCan100.Click += delegate
            {
                adapterCmd = 0x02;
                adapterValue = 0x09;
            };
            buttonLayout.AddView(buttonCan100, buttonLayoutParams);

            buttonCanOff = new Button(activity);
            buttonCanOff.Text = ActivityMain.GetPageString(pageInfo, "button_adapter_config_can_off");
            buttonCanOff.Click += delegate
            {
                adapterCmd = 0x02;
                adapterValue = 0x00;
            };
            buttonLayout.AddView(buttonCanOff, buttonLayoutParams);

            LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
                ViewGroup.LayoutParams.MatchParent,
                ViewGroup.LayoutParams.WrapContent);
            pageLayout.AddView(buttonLayout, layoutParams);

            adapterCmd = -1;
        }

        public void DestroyLayout(JobReader.PageInfo pageInfo)
        {
            if (buttonBlockSize != null)
            {
                buttonBlockSize.Dispose();
                buttonBlockSize = null;
            }
            if (buttonSepTime0 != null)
            {
                buttonSepTime0.Dispose();
                buttonSepTime0 = null;
            }
            if (buttonSepTime1 != null)
            {
                buttonSepTime1.Dispose();
                buttonSepTime1 = null;
            }
            if (buttonCan500 != null)
            {
                buttonCan500.Dispose();
                buttonCan500 = null;
            }
            if (buttonCan100 != null)
            {
                buttonCan100.Dispose();
                buttonCan100 = null;
            }
            if (buttonCanOff != null)
            {
                buttonCanOff.Dispose();
                buttonCanOff = null;
            }
            //Android.Util.Log.Info("Custom", "Destroyed");
        }

        public void UpdateLayout(JobReader.PageInfo pageInfo, bool pageValid, bool threadActive)
        {
            if ((buttonCan500 == null) || (buttonCan100 == null) || (buttonCanOff == null))
            {
                return;
            }

            bool enabled = pageValid && threadActive;
            buttonBlockSize.Enabled = enabled;
            buttonSepTime0.Enabled = enabled;
            buttonSepTime1.Enabled = enabled;
            buttonCan500.Enabled = enabled;
            buttonCan100.Enabled = enabled;
            buttonCanOff.Enabled = enabled;
        }
    }


The resulting page will look like this:

AdapterConfigSmall.png
(Adapter page)

Grouping pages

If the same of pages are required in multiple configuration, it's useful to group the together. This could be done with *.ccpages files. Simply include the *.ccpage files withing the pages node. The specifified path is relative to the *.ccpages file location. The file has the following layout:

<?xml version="1.0" encoding="utf-8" ?>
<fragment xmlns="http://www.holeschak.de/BmwDeepObd"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://www.holeschak.de/BmwDeepObd ../BmwDeepObd.xsd">
  <pages>
    <include filename="Axis.ccpage"/>
    <include filename="Motor.ccpage"/>
    <include filename="../AdapterCustom.ccpage"/>
  </pages>
</fragment>

The configuration file

Now all *.page or *.pages can added to a configuration file (*.cccfg). This file could be loaded by BWM deep OBD. In the global node of the file the following properties could be specified:
  • ecu_path: Directory of the ecu files (*.grp and *.prg) relative to the configuration file.
  • log_path: Directory for the data logging files. Logging could be enabled by adding a log_tag property to the display node of the *.page file. If the directory is not existing it will be created.
  • append_log: Setting this property to true will always append the log file.
  • interface: Specify the communication interface in this property. Possible values are BLUETOOTH , ENET, ELMWIFI and FTDI.

<?xml version="1.0" encoding="utf-8"?>
<fragment xmlns="http://www.holeschak.de/BmwDeepObd"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://www.holeschak.de/BmwDeepObd ../BmwDeepObd.xsd">
  <global ecu_path="../Ecu" log_path="Log" append_log="true" interface="BLUETOOTH" />
  <include filename="E61.ccpages"/>
</configuration>

Updated Wiki: Page specification

$
0
0

Defining pages for Deep OBD for BMW

Each page (tab) is defined in a single XML (*.ccpage) file. A general documentation of all XML tags could be found in the BmwDeepObd.xsd file. The documentation will be displayed in the XML editor when the xsd is added as xs:shema in the XML file.
Table of contents:

Simple jobs

If only some EDIABAS jobs with fixed arguments are required for one display page, the XML code is relative simple. Below is the example code to display climate data for a E61 vehicle:

<?xml version="1.0" encoding="utf-8" ?>
<fragment xmlns="http://www.holeschak.de/BmwDeepObd"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://www.holeschak.de/BmwDeepObd ../BmwDeepObd.xsd">
  <page name ="tab_ihk">
    <strings>
      <string name="tab_ihk">Climate</string>
      <string name="label_ihk_in_temp">Indoor temperature [°C]:</string>
      <string name="label_ihk_in_temp_delay">Indoor temperature delayed [°C]:</string>
      <string name="label_ihk_out_temp">Outdoor temperature [°C]:</string>
      <string name="label_ihk_setpoint">Setpoint [°C]:</string>
      <string name="label_ihk_heat_ex_temp">Heat exchanger temperature [°C]:</string>
      <string name="label_ihk_heat_ex_setpoint">Heat exchanger setpoint [°C]:</string>
      <string name="label_ihk_heat_ex_actuator">Heat exchanger actuator [%]:</string>
      <string name="label_ihk_main_actuator">Main actuator [%]:</string>
      <string name="label_ihk_evap_temp">Evaporator temperature [°C]:</string>
      <string name="label_ihk_press_sense">Pressure sensor [bar]:</string>
      <string name="label_ihk_circ_air_left">Circulating air left [%]:</string>
      <string name="label_ihk_circ_air_right">Circulating air right [%]:</string>
      <string name="label_ihk_defrost">Defrost [%]:</string>
      <string name="label_ihk_vent">Ventilation [%]:</string>
      <string name="label_ihk_cold_air">Cold air [%]:</string>
      <string name="label_ihk_legroom">Leg room [%]:</string>
      <string name="label_ihk_refrig_comp">Refrigerating compressor [%]:</string>
    </strings>
    <strings lang="de">
      <string name="tab_ihk">Klima</string>
      <string name="label_ihk_in_temp">Innentemperatur [°C]:</string>
      <string name="label_ihk_in_temp_delay">Innentemperatur verzögert [°C]:</string>
      <string name="label_ihk_out_temp">Außentemperatur [°C]:</string>
      <string name="label_ihk_setpoint">Sollwert [°C]:</string>
      <string name="label_ihk_heat_ex_temp">Wärmetauschertemperatur [°C]:</string>
      <string name="label_ihk_heat_ex_setpoint">Wärmetauschersollwert [°C]:</string>
      <string name="label_ihk_heat_ex_actuator">Wärmetauscherstellgröße [%]:</string>
      <string name="label_ihk_main_actuator">Hauptstellgröße [%]:</string>
      <string name="label_ihk_evap_temp">Verdampfertemperatur [°C]:</string>
      <string name="label_ihk_press_sense">Drucksensor [bar]:</string>
      <string name="label_ihk_circ_air_left">Umluft links [%]:</string>
      <string name="label_ihk_circ_air_right">Umluft rechts [%]:</string>
      <string name="label_ihk_defrost">Abtauen [%]:</string>
      <string name="label_ihk_vent">Belüftung [%]:</string>
      <string name="label_ihk_cold_air">Kaltluft [%]:</string>
      <string name="label_ihk_legroom">Fußraum [%]:</string>
      <string name="label_ihk_refrig_comp">Kältemittelverdichter [%]:</string>
    </strings>
    <jobs sgbd="d_klima">
      <job name="STATUS_REGLERGROESSEN" results="STAT_TINNEN_WERT;STAT_TINNEN_VERZOEGERT_WERT;STAT_TAUSSEN_WERT;STAT_SOLL_LI_KORRIGIERT_WERT;STAT_WT_RE_WERT;STAT_WTSOLL_RE_WERT;STAT_YWT_RE_WERT;STAT_Y_RE_WERT">
        <display name="label_ihk_in_temp" result="STAT_TINNEN_WERT" format="6.1R" />
        <display name="label_ihk_in_temp_delay" result="STAT_TINNEN_VERZOEGERT_WERT" format="6.1R" />
        <display name="label_ihk_out_temp" result="STAT_TAUSSEN_WERT" format="6.1R" />
        <display name="label_ihk_setpoint" result="STAT_SOLL_LI_KORRIGIERT_WERT" format="6.1R" />
        <display name="label_ihk_heat_ex_temp" result="STAT_WT_RE_WERT" format="6.1R" />
        <display name="label_ihk_heat_ex_setpoint" result="STAT_WTSOLL_RE_WERT" format="6.1R" />
        <display name="label_ihk_heat_ex_actuator" result="STAT_YWT_RE_WERT" format="3L" />
        <display name="label_ihk_main_actuator" result="STAT_Y_RE_WERT" format="3L" />
      </job>
      <job name="STATUS_ANALOGEINGAENGE" results="STAT_TEMP_VERDAMFER_WERT;STAT_DRUCKSENSOR_WERT">
        <display name="label_ihk_evap_temp" result="STAT_TEMP_VERDAMFER_WERT" format="6.1R" />
        <display name="label_ihk_press_sense" result="STAT_DRUCKSENSOR_WERT" format="6.1R" />
      </job>
      <job name="STATUS_MOTOR_KLAPPENPOSITION" results="STAT_FRISCHLUFT_UMLUFT_LI_WERT;STAT_FRISCHLUFT_UMLUFT_RE_WERT;STAT_DEFROST_WERT;STAT_BELUEFTUNG_WERT;STAT_KALTLUFT_WERT;STAT_FUSSRAUM_WERT">
        <display name="label_ihk_circ_air_left" result="STAT_FRISCHLUFT_UMLUFT_LI_WERT" format="3L" />
        <display name="label_ihk_circ_air_right" result="STAT_FRISCHLUFT_UMLUFT_RE_WERT" format="3L" />
        <display name="label_ihk_defrost" result="STAT_DEFROST_WERT" format="3L" />
        <display name="label_ihk_vent" result="STAT_BELUEFTUNG_WERT" format="3L" />
        <display name="label_ihk_cold_air" result="STAT_KALTLUFT_WERT" format="3L" />
        <display name="label_ihk_legroom" result="STAT_FUSSRAUM_WERT" format="3L" />
      </job>
      <job name="STATUS_IO" results="STAT_STEUERUNG_KMV_WERT">
        <display name="label_ihk_refrig_comp" result="STAT_STEUERUNG_KMV_WERT" format="3L" />
      </job>
    </jobs>
  </page>
</fragment>

The pagename property specifies the title of the page and is a reference to the strings nodes. With logfile a log file name could be specified, that allows to log the display data. If the symbol {D} is used inside the log file name, it will be replaced by the current date and time.
The strings nodes contains the all the string used on this display page. If the current language is not matching the lang tag, the default language (without tag) is used. The lang property could be either the short form e.g. 'de' or the long one 'de-DE'.

The jobs node groups all EDIABAS job to execute. The property sgbd specifies the name of the group (.grp) or the sgbd (.prg) file to use.
Within the jobs node multiple job nodes specify the EDIABAS jobs to execute. They contain the following properties:
  • name: Name of the job to execute
  • args_first: Allows to specify semicolon separated job arguments for the first job call.
  • args: Allows to specify semicolon separated job arguments. If this is the first call and args_first is present args_first will be used instead.
  • result: Allows to specify the required results. If omitted, all results will be generated, which may require more processing time.
  • log_tag=<tag name>: Adding this property allows to log the display data to a log file when activating the Log data menu in the application. The logfile property in the page node has to be specified as well to activate logging.
  • Each display node specifies one line of the display output. Name is again a reference to the text translation in the strings nodes. With result the EDIABAS job result name is selected, that contains the data. The format property allows to format the result with the EDIABAS aspiResultText format specification EDIABAS result types and formats.
The page node can optionally contain display nodes like the job node. They will be only used for User defined code.
This is how the resulting page will look like:

Climate page

Reading errors

With the read_errors node it's possible to read an error summary of all ECUs. Simply list all ECU names and the corresponding sgbd file names in a separate ecu node, like in the example below.
The error message is generated by the sgbd file and is in the language of the sgbd.
The page also allows to selectively reset ECU errors.

<?xml version="1.0" encoding="utf-8" ?>
<fragment xmlns="http://www.holeschak.de/BmwDeepObd"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://www.holeschak.de/BmwDeepObd ../BmwDeepObd.xsd">
  <page name ="tab_errors">
    <strings>
      <string name="tab_errors">Errors</string>

      <string name="ACSM">ACSM Crash security module</string>
      <string name="CAS">CAS Car access system</string>
      <string name="CCCBO">CCC-BO Front panel</string>
      <string name="CCCGW">CCC-GW Gateway</string>
      <string name="DDE">DDE Diesel elektronic</string>
      <string name="DSC">DSC Dynamic stability control</string>
      <string name="EKPS">EKPS Fuel pump control</string>
      <string name="IHK">IHK Integrated heating climate automatic</string>
      <string name="KBM">KBM Chassis basic module</string>
      <string name="KGM">KGM Chassis gateway module</string>
      <string name="KOMBI">KOMBI Combination instrument</string>
      <string name="PDC">PDC Park distance control</string>
      <string name="RLS">RLS Rain main beam sensor</string>
      <string name="EPS">EPS Electric power steering</string>
      <string name="ULF">ULF Universal hands-free system</string>
      <string name="FZD">FZD Roof switch unit</string>
    </strings>
    <strings lang="de">
      <string name="tab_errors">Fehler</string>

      <string name="ACSM">ACSM Crash-Sicherheits-Modul</string>
      <string name="CAS">CAS Car Access System</string>
      <string name="CCCBO">CCC-BO Bedienoberfläche</string>
      <string name="CCCGW">CCC-GW Gateway</string>
      <string name="DDE">DDE Diesel Elektronik</string>
      <string name="DSC">DSC Dynamische Stabilitätskontrolle</string>
      <string name="EKPS">EKPS Kraftstoffpumpensteuerung</string>
      <string name="IHK">IHK Integrierte Heiz-Klima-Automatik</string>
      <string name="KBM">KBM Karosserie-Basismodul</string>
      <string name="KGM">KGM Karosserie-Gateway-Modul</string>
      <string name="KOMBI">KOMBI Instrumentenkombination</string>
      <string name="PDC">PDC Park-Distance-Control</string>
      <string name="RLS">RLS Regen-Fahrlicht-Sensor</string>
      <string name="EPS">EPS Elektromechanische Servolenkung</string>
      <string name="ULF">ULF Universale Ladefreisprechelektronik</string>
      <string name="FZD">FZD Funtionszentrum Dach</string>
    </strings>
    <read_errors>
      <ecu name="CAS" sgbd="d_cas" />
      <ecu name="DDE" sgbd="d_motor" />
      <ecu name="EKPS" sgbd="d_ekp" />
      <ecu name="DSC" sgbd="d_dsc" />
      <ecu name="ACSM" sgbd="d_sim" />
      <ecu name="CCCBO" sgbd="d_mmi" />
      <ecu name="CCCGW" sgbd="d_mostgw" />
      <ecu name="IHK" sgbd="d_klima" />
      <ecu name="KBM" sgbd="d_kbm" />
      <ecu name="KGM" sgbd="d_zgm" />
      <ecu name="KOMBI" sgbd="d_kombi" />
      <ecu name="PDC" sgbd="d_pdc" />
      <ecu name="RLS" sgbd="d_rls" />
      <ecu name="EPS" sgbd="d_eps" />
      <ecu name="ULF" sgbd="d_ispb" />
      <ecu name="FZD" sgbd="d_fzd" />
    </read_errors>
  </page>
</fragment>

In the ecu node the property name is a link to a string node and sgbd is the name of the sgbd file. The output looks similar to this page:

Erros E90

User defined code

If the jobs and display output is getting more complex, user defined code will be required. In this case a C# class could be added to a code node, which defines a set of optional callback functions. If the show_warnings property is set to true, also warnings will be reported during compilation of the code.

<code show_warnigs="true">
      <![CDATA[
    class PageClass
    {
        public void CreateLayout(ActivityMain activity, JobReader.PageInfo pageInfo, LinearLayout pageLayout)
        {
        }

        public void DestroyLayout(JobReader.PageInfo pageInfo)
        {
        }

        public void UpdateLayout(JobReader.PageInfo pageInfo, bool pageValid, bool threadActive)
        {
        }

        public void ExecuteJob(EdiabasNet ediabas, ref Dictionary<string, EdiabasNet.ResultData> resultDict, bool firstCall)
        {
        }

        public string FormatResult(JobReader.PageInfo pageInfo, Dictionary<string, EdiabasNet.ResultData> resultDict, string resultName)
        {
        }

        public string FormatResult(JobReader.PageInfo pageInfo, Dictionary<string, EdiabasNet.ResultData> resultDict, string resultName, ref Android.Graphics.Color? textColor)
        {
        }

        public string FormatErrorResult(JobReader.PageInfo pageInfo, EdiabasThread.EdiabasErrorReport errorReport, string defaultMessage)
        {
        }

        public void UpdateResultList(JobReader.PageInfo pageInfo, Dictionary<string, EdiabasNet.ResultData> resultDict, List<TableResultItem> resultList)
        {
        }
    }
      ]]>
    </code>

Formatting results (FormatResult)

For special formatting of the result data, the callback FormatResult could be used. For each result of the EDIABAS results this function will be called with resultName set to the current result name. If the display node is a subnode of a job node the job name is prefixed with # as separator to the result name. The function will be only called if there is noformat property in the display node. Here is an example from the motor page:

        public string FormatResult(JobReader.PageInfo pageInfo, Dictionary<string, EdiabasNet.ResultData> resultDict, string resultName, ref Android.Graphics.Color? textColor)
        {
            string result = string.Empty;
            double value;
            bool found;

            switch (resultName)
            {
                case "STATUS_MESSWERTBLOCK_LESEN#STAT_UBATT_WERT":
                    value = ActivityMain.GetResultDouble(resultDict, resultName, out found);
                    result = string.Format(ActivityMain.Culture, "{0,7:0.00}", value);
                    if (found && value < 11.0)
                    {
                        textColor = Android.Graphics.Color.Red;
                    }
                    if (!found) result = string.Empty;
                    break;

                case "STATUS_MESSWERTBLOCK_LESEN#STAT_STRECKE_SEIT_ERFOLGREICHER_REGENERATION_WERT":
                    result = string.Format(ActivityMain.Culture, "{0,6:0.0}", ActivityMain.GetResultDouble(resultDict, resultName, out found) / 1000.0);
                    if (!found) result = string.Empty;
                    break;

                case "STATUS_MESSWERTBLOCK_LESEN#STAT_OELDRUCKSCHALTER_EIN_WERT":
                    result = ((ActivityMain.GetResultDouble (resultDict, resultName, out found) > 0.5) && found) ? "1" : "0";
                    if (found && result == "1")
                    {
                        textColor = Android.Graphics.Color.Red;
                    }
                    if (!found) result = string.Empty;
                    break;

                case "STATUS_MESSWERTBLOCK_LESEN#STAT_REGENERATIONSANFORDERUNG_WERT":
                    result = ((ActivityMain.GetResultDouble (resultDict, resultName, out found) < 0.5) && found) ? "1" : "0";
                    if (!found) result = string.Empty;
                    break;

                case "STATUS_MESSWERTBLOCK_LESEN#STAT_EGT_st_WERT":
                    result = ((ActivityMain.GetResultDouble (resultDict, resultName, out found) > 1.5) && found) ? "1" : "0";
                    if (!found) result = string.Empty;
                    break;

                case "STATUS_MESSWERTBLOCK_LESEN#STAT_REGENERATION_BLOCKIERUNG_UND_FREIGABE_WERT":
                    result = ((ActivityMain.GetResultDouble (resultDict, resultName, out found) < 0.5) && found) ? "1" : "0";
                    if (!found) result = string.Empty;
                    break;
            }
            return result;
        }

Formatting error results (FormatErrorResult)

For special formatting of the error result data, the callback FormatErrorResult could be used. For each error entry this function will be called with defaultMessage set to the default error message output.
Here is an example from the errors page, that adds a RPM value to the error message. You have to add a results property to the ecu node specifying the results you want to be generated by the FS_LESEN_DETAIL job.

<read_errors>
      <ecu name="CAS" sgbd="d_cas" />
      <ecu name="DDE" sgbd="d_motor" results="F_UW_KM;F_UW_ANZ" />
    </read_errors>
    <code show_warnigs="true">
      <![CDATA[
    class PageClass
    {
        public string FormatErrorResult(JobReader.PageInfo pageInfo, EdiabasThread.EdiabasErrorReport errorReport, string defaultMessage)
        {
            string message = defaultMessage;
            switch (errorReport.EcuName)
            {
                case "DDE":
                {
                    string detailText = string.Empty;
                    foreach (Dictionary<string, EdiabasNet.ResultData> errorDetail in errorReport.ErrorDetailSet)
                    {
                        string rpmText = ActivityMain.FormatResultDouble(errorDetail, "F_UW1_WERT", "{0,6:0.0}");
                        if (rpmText.Length > 0)
                        {
                            if (detailText.Length == 0)
                            {
                                detailText += rpmText + " 1/min";
                            }
                        }
                    }
                    if (detailText.Length > 0)
                    {
                        message += "\r\n" + detailText;
                    }
                    break;
                }
            }
            return message;
        }
    }
      ]]>
  </code>

Control output of the page (UpdateResultList)

Sometimes you want to dynamically control the number and the content of the output lines.
If the callback UpdateResultList is defined, you could directly fill the contents of the resultListAdapter which displays the results of the page. In this example from the (standard) Adapter page the adapter configuration result will be displayed. Additionally only one column for output is used by setting the second argument of resultListAdapter.Items.Add to null. With ActivityMain.GetPageString it's possible to retrieve a string from the translation table.

        public void UpdateResultList(JobReader.PageInfo pageInfo, Dictionary<string, EdiabasNet.ResultData> resultDict, List<TableResultItem> resultList)
        {
            int result = configResult;

            if (result > 0)
            {
                resultList.Add(new TableResultItem(ActivityMain.GetPageString(pageInfo, "adapter_config_ok"), null));
            }
            else if (result == 0)
            {
                resultList.Add(new TableResultItem(ActivityMain.GetPageString(pageInfo, "adapter_config_error"), null));
            }
        }

Executing own jobs (ExecuteJob)

If more than one job has to be executed or the job requires special arguments, ediabas.ExecuteJob could be called in the ExecuteJob callback. Here is an example from the adapter page for calling a list of jobs. EdiabasThread.MergeResultDictionarys adds the results of the current job to the internal job list. The callback ExecuteJob will be executed in it's own thread. When using ExecuteJob it's recommended to add the display nodes to the page node because no job nodes will be present.

    class PageClass
    {
        private class EdiabasJob
        {
            private string jobName;
            private string jobArgs;
            private string resultRequests;

            public EdiabasJob(string jobName, string jobArgs, string resultRequests)
            {
                this.jobName = jobName;
                this.jobArgs = jobArgs;
                this.resultRequests = resultRequests;
            }

            public string JobName
            {
                get
                {
                    return jobName;
                }
            }

            public string JobArgs
            {
                get
                {
                    return jobArgs;
                }
            }

            public string ResultRequests
            {
                get
                {
                    return resultRequests;
                }
            }
        }

        static private readonly EdiabasJob[] jobArray =
            {
                new EdiabasJob("ADAPTER_CMD",
                    "0xFE;0xFE",
                    string.Empty
                    ),
                new EdiabasJob("ADAPTER_CMD",
                    "0x80;0x00",
                    string.Empty
                    ),
                new EdiabasJob("ADAPTER_CMD",
                    "0x81;0x00",
                    string.Empty
                    ),
                new EdiabasJob("ADAPTER_CMD",
                    "0x82;0x00",
                    string.Empty
                    ),
            };

        public void ExecuteJob(EdiabasNet ediabas, ref Dictionary<string, EdiabasNet.ResultData> resultDict, bool firstCall)
        {
            int index = 0;
            foreach (EdiabasJob job in jobArray)
            {
                ediabas.ArgString = job.JobArgs;
                ediabas.ArgBinaryStd = null;
                ediabas.ResultsRequests = job.ResultRequests;

                ediabas.ExecuteJob(job.JobName);

                List<Dictionary<string, EdiabasNet.ResultData>> resultSets = ediabas.ResultSets;
                if (resultSets != null && resultSets.Count >= 2)
                {
                    EdiabasThread.MergeResultDictionarys(ref resultDict, resultSets[1], string.Format("{0}_", index));
                }
                index++;
            }
        }
    }

Adding controls to the layout

The standard layout only allows to display information, but there is no way to control outputs. With the callbacks CreateLayout, DestroyLayout and UpdateLayout there is a possibility to add own controls to the layout (in most cases buttons).
In this example from the AdapterCustom.ccpage buttons will be added to control the CAN block size, CAN separation time and the CAN mode. The CreateLayout adds the controls, DestroyLayout removes the controls and UpdateLayout is used to modify the state of the controls (depending form the connection state).
For every button there is a Click delegate that allows to set a global variable which is used for EDIABAS job control.

        private Button buttonBlockSize;
        private Button buttonSepTime0;
        private Button buttonSepTime1;
        private Button buttonCan500;
        private Button buttonCan100;
        private Button buttonCanOff;
        private int adapterCmd = -1;
        private int adapterValue;
        private int blockSize = 0;

        public void CreateLayout(ActivityMain activity, JobReader.PageInfo pageInfo, LinearLayout pageLayout)
        {
            LinearLayout buttonLayout = new LinearLayout(activity);
            buttonLayout.Orientation = Orientation.Vertical;

            LinearLayout.LayoutParams buttonLayoutParams = new LinearLayout.LayoutParams(
                ViewGroup.LayoutParams.MatchParent,
                ViewGroup.LayoutParams.WrapContent);
            buttonLayoutParams.Weight = 1;

            buttonBlockSize = new Button(activity);
            buttonBlockSize.Text = string.Format("{0}: {1}", ActivityMain.GetPageString(pageInfo, "button_adapter_config_block_size"), blockSize);
            buttonBlockSize.Click += delegate
            {
                blockSize += 2;
                if (blockSize > 8)
                {
                    blockSize = 0;
                }
                adapterCmd = 0x00;
                adapterValue = blockSize;
                buttonBlockSize.Text = string.Format("{0}: {1}", ActivityMain.GetPageString(pageInfo, "button_adapter_config_block_size"), blockSize);
            };
            buttonLayout.AddView(buttonBlockSize, buttonLayoutParams);

            buttonSepTime0 = new Button(activity);
            buttonSepTime0.Text = ActivityMain.GetPageString(pageInfo, "button_adapter_config_sep_time0");
            buttonSepTime0.Click += delegate
            {
                adapterCmd = 0x01;
                adapterValue = 0x00;
            };
            buttonLayout.AddView(buttonSepTime0, buttonLayoutParams);

            buttonSepTime1 = new Button(activity);
            buttonSepTime1.Text = ActivityMain.GetPageString(pageInfo, "button_adapter_config_sep_time1");
            buttonSepTime1.Click += delegate
            {
                adapterCmd = 0x01;
                adapterValue = 0x01;
            };
            buttonLayout.AddView(buttonSepTime1, buttonLayoutParams);

            buttonCan500 = new Button(activity);
            buttonCan500.Text = ActivityMain.GetPageString(pageInfo, "button_adapter_config_can_500");
            buttonCan500.Click += delegate
            {
                adapterCmd = 0x02;
                adapterValue = 0x01;
            };
            buttonLayout.AddView(buttonCan500, buttonLayoutParams);

            buttonCan100 = new Button(activity);
            buttonCan100.Text = ActivityMain.GetPageString(pageInfo, "button_adapter_config_can_100");
            buttonCan100.Click += delegate
            {
                adapterCmd = 0x02;
                adapterValue = 0x09;
            };
            buttonLayout.AddView(buttonCan100, buttonLayoutParams);

            buttonCanOff = new Button(activity);
            buttonCanOff.Text = ActivityMain.GetPageString(pageInfo, "button_adapter_config_can_off");
            buttonCanOff.Click += delegate
            {
                adapterCmd = 0x02;
                adapterValue = 0x00;
            };
            buttonLayout.AddView(buttonCanOff, buttonLayoutParams);

            LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
                ViewGroup.LayoutParams.MatchParent,
                ViewGroup.LayoutParams.WrapContent);
            pageLayout.AddView(buttonLayout, layoutParams);

            adapterCmd = -1;
        }

        public void DestroyLayout(JobReader.PageInfo pageInfo)
        {
            if (buttonBlockSize != null)
            {
                buttonBlockSize.Dispose();
                buttonBlockSize = null;
            }
            if (buttonSepTime0 != null)
            {
                buttonSepTime0.Dispose();
                buttonSepTime0 = null;
            }
            if (buttonSepTime1 != null)
            {
                buttonSepTime1.Dispose();
                buttonSepTime1 = null;
            }
            if (buttonCan500 != null)
            {
                buttonCan500.Dispose();
                buttonCan500 = null;
            }
            if (buttonCan100 != null)
            {
                buttonCan100.Dispose();
                buttonCan100 = null;
            }
            if (buttonCanOff != null)
            {
                buttonCanOff.Dispose();
                buttonCanOff = null;
            }
            //Android.Util.Log.Info("Custom", "Destroyed");
        }

        public void UpdateLayout(JobReader.PageInfo pageInfo, bool pageValid, bool threadActive)
        {
            if ((buttonCan500 == null) || (buttonCan100 == null) || (buttonCanOff == null))
            {
                return;
            }

            bool enabled = pageValid && threadActive;
            buttonBlockSize.Enabled = enabled;
            buttonSepTime0.Enabled = enabled;
            buttonSepTime1.Enabled = enabled;
            buttonCan500.Enabled = enabled;
            buttonCan100.Enabled = enabled;
            buttonCanOff.Enabled = enabled;
        }
    }


The resulting page will look like this:

AdapterConfigSmall.png
(Adapter page)

Grouping pages

If the same of pages are required in multiple configuration, it's useful to group the together. This could be done with *.ccpages files. Simply include the *.ccpage files withing the pages node. The specifified path is relative to the *.ccpages file location. The file has the following layout:

<?xml version="1.0" encoding="utf-8" ?>
<fragment xmlns="http://www.holeschak.de/BmwDeepObd"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://www.holeschak.de/BmwDeepObd ../BmwDeepObd.xsd">
  <pages>
    <include filename="Axis.ccpage"/>
    <include filename="Motor.ccpage"/>
    <include filename="../AdapterCustom.ccpage"/>
  </pages>
</fragment>

The configuration file

Now all *.page or *.pages can added to a configuration file (*.cccfg). This file could be loaded by BWM deep OBD. In the global node of the file the following properties could be specified:
  • ecu_path: Directory of the ecu files (*.grp and *.prg) relative to the configuration file.
  • log_path: Directory for the data logging files. Logging could be enabled by adding a log_tag property to the display node of the *.page file. If the directory is not existing it will be created.
  • append_log: Setting this property to true will always append the log file.
  • interface: Specify the communication interface in this property. Possible values are BLUETOOTH , ENET, ELMWIFI and FTDI.

<?xml version="1.0" encoding="utf-8"?>
<fragment xmlns="http://www.holeschak.de/BmwDeepObd"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://www.holeschak.de/BmwDeepObd ../BmwDeepObd.xsd">
  <global ecu_path="../Ecu" log_path="Log" append_log="true" interface="BLUETOOTH" />
  <include filename="E61.ccpages"/>
</configuration>

Updated Wiki: Replacement firmware for ELM327

$
0
0

Replacement firmware for ELM327

There is now a replacement firmware available for ELM327 based Bluetooth adapters, that has the following advantages over the standard firmware:
  • Faster and more stable CAN communication.
  • K-Line support (all protocols).
  • Contains a bootstrap loader that allows firmware update without opening the device.
  • Firmware updates are possible with Deep OBD for BMW.
  • Reduced power consumption due to use of sleep mode.
  • Two firmware versions are available:
    • Unmodified Bluetooth adapter: Baud rate 38400.
    • Modified Bluetooth adapter (recommended) with replaced OpenSource Bluetooth firmware: Baud rate 115200 and alterable Bluetooth pin (16 digits) and name (31 chars).
Bluetooth adapter topBluetooth adapter bottom

Buy an adapter

New adapters are available!
You could buy the Bluetooth adapter from EBAY.
For BMW F-models use the ENET WiFi Adapter.

Factory reset

Beginning with firmware version 0.6 there is the possibility to perform a factory reset of the adapter. This resets the Bluetooth pin to 1234, the Bluetooth name to Deep OBD BMW and the mode to D-CAN.
To perform the factory reset you have to open the adapter and connect the unused pad of R26 with GND during power on.

Use the adapter with INPA, Tool32 or ISTA-D

You could use the Bluetooth adapter on a windows PC with INPA or Tool32 as a replacement for a OBD or ADS adapter. The following steps are required to establish the connection:
  1. Install .NET framework 4.0 or higher and VS2015 C++ runtime
  2. Connect the Bluetooth adapter with the PC (the default Bluetooth pin is 1234). Two COM ports are generated (incoming and outgoing).
  3. With the standard DCAN.exe from dcan_Tools (for configuration of the USB adapters) set the operation mode (D-CAN or K-LINE) of the Bluetooth adapter. For the COM port use the outgoing port.
  4. Rename the api32.dll in the C:\Ediabas\bin and C:\ISTA-D\Ediabas\bin directory.
  5. Copy Api32.dll and EdiabasLib.config to the C:\Ediabas\bin and C:\ISTA-D\Ediabas\bin directory.
  6. For ISTA-D: In Administration -> VCI Config select as Interface type: Ediabas default settings (ediabas.ini)
  7. Modify the following entries in EdiabasLib.config:
<add key="Interface" value="STD:OBD"/>
<add key="ObdComPort" value="BLUETOOTH:<Outgoing COM port>"/>

Programming of the processor

For the first programming of the processor simply attach a PICKit 3 programmer to the corresponding test points of the circuit board.
The source for the firmware could be found in the subdirectory CanAdapterElm. In this subdirectory there is also a flash tool (subdirectory UpdateLoader) that allows firmware updates using the bootstrap loader once the firmware is programed.
The latest firmware version will be always included in Deep OBD for BMW.
Viewing all 162 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>