Skip to content

3. The Arduino side of things

domnulvlad edited this page Nov 1, 2024 · 8 revisions

General info

This library has been tested well on the Arduino MEGA, UNO and Nano, on the ESP32 (and ESP32-C6) and ESP8266, and on the Raspberry Pi Pico. Please refer to the included demos for simple usage tutorials.

For an ESP32-specific version of the library, check out KLineKWP1281Lib_ESP32.

  • An additional hardware serial port is preferred (Serial1, Serial2 etc.), and the demo sketches require at least one additional serial port, as the regular Serial is used for displaying info.
  • On the UNO, which only has one hardware port, the demo sketches solve this problem with the AltSoftSerial library, as the regular SoftwareSerial library is half-duplex (cannot receive at the same time as sending; although such library can be used in the demos by setting the #define is_full_duplex to false in the configuration.h file of the demo).
  • For the ESP8266, SoftwareSerial works just fine, as its implementation is full-duplex.
  • If using the standard port Serial for KWP1281, the adapter cable must be disconnected to allow sketches to upload, and no calls to Serial.print (etc.) should be made!

Saving memory

The measurement demo sketches do not fit on the Arduino UNO by default. It is possible to reduce the size of the library by editing the options found at the top of the KLineKWP1281Lib/src/KLineKWP1281Lib.h file.

  • Set #define KWP1281_DEBUG_LEVEL to 0 to remove all debugging strings, if you don't plan on using the feature.
  • Comment out the line #define KWP1281_TEXT_TABLE_SUPPORTED to remove all measurement strings (there is a special type of measurement in a Measuring Block that returns text; disabling this will result in the string returned by getMeasurementUnits() being "EN_f25" if this special type is encountered). You can see these strings in the KLineKWP1281Lib/src/text_table_xx.h files.
  • Comment out the line #define KWP1281_FAULT_CODE_ELABORATION_SUPPORTED to remove all fault code elaboration strings; disabling this will result in the string returned by getFaultElaboration() being "EN_elb". You can see these strings in the KLineKWP1281Lib/src/fault_code_elaboration_xx.h files.
  • (!) There is also the option #define KWP1281_FAULT_CODE_DESCRIPTION_SUPPORTED. Please note that this will try to include a large table of strings, which most definitely will not work on AVR microcontrollers. It is currently only supported on other platforms, such as the ESP32. When this is disabled (by default), the string returned by getFaultDescription() will be "EN_dsc". You can see these strings in the KLineKWP1281Lib/src/fault_code_description_xx.h files.
  • (!) The same goes for the option #define KWP1281_OBD_FAULT_CODE_DESCRIPTION_SUPPORTED. When this is disabled (by default), the string returned by getFaultDescription() will be "EN_obd", if the fault was of the OBD type. You can see these strings in the KLineKWP1281Lib/src/OBD_fault_code_description_xx.h files.
  • For every one of these options, you can choose its language by commenting/uncommenting the #defines a few lines down. Please only select one language per option.

Getting started

After installing the library and setting up the necessary hardware, you can proceed to the demo sketches.

Demo sketches

Access them by navigating to File -> Examples -> KLineKWP1281Lib in the Arduino IDE.

Configuring the demos

  • When you open an example sketch, there are comments explaining what it does and information regarding connection. Read them.

  • After that, change over to the configuration.h tab. Here, you will change the settings to match your application.

  • Change the module ID and baud rate to what your target module uses. If these parameters are incorrect, connecting is not possible.
  • In the first demo sketch, the baud rate setting is commented out, because it showcases "automatic" baud rate detection.

  • Choose your hardware configuration. For example, if using the Arduino MEGA with the interface connected to the port Serial2, uncomment the option like so:

  • If you choose the Arduino UNO, you should install the AltSoftSerial library.
  • You can also use the regular SoftwareSerial library with the UNO, for which you should add the configuration manually. But then you MUST change is_full_duplex to false, as the library is half-duplex:

  • Upload the sketch. After that, open the Serial Monitor, set it to 115200 baud and observe the result.

Troubleshooting

  • If after uploading and opening the Serial Monitor nothing appears at all, ensure the Monitor's baud rate is 115200.
  • If only "Sketch started" appears and nothing else after a few seconds, enable debugging in the configuration.h file. The option debug_info will show errors and information, and debug_traffic will show the message transactions with the module. It's best to start with only #define debug_info true. Be sure to also increase the KWP1281_DEBUG_LEVEL setting in KLineKWP1281Lib.h, otherwise debug_info will have no effect.

  • If you see Protocol may not be supported and strange behavior following, there is a high probability that your module is not supported.
  • If you see Connected to module but it's followed by strange behavior such as The given buffer is too small for the incoming message/Received "Unknown"/Unexpected respons, consider changing #define is_full_duplex to false even if your serial port is full-duplex, in case your K-line interface does not echo back for some reason.

Expected demo behavior

  1. Connection_test
  • This sketch will connect to the module, display its identification and maintain the connection active.
  • It will try connecting with the baud rates defined in the possible_baud_rates array in configuration.h, trying each one of these speeds when connecting fails.
  • To stop this behavior and only try connecting with a set baud rate, uncomment the module_baud_rate definition above the array.
  • Serial Monitor output:

  1. Fault_code_test
  • This sketch will connect to the module, display its fault codes and disconnect.
  • If you have enabled KWP1281_FAULT_CODE_DESCRIPTION_SUPPORTED/KWP1281_OBD_FAULT_CODE_DESCRIPTION_SUPPORTED (as described at the top of this page), you will also see the names associated with each fault code, as seen in the screenshot below.
  • The "OBD" variant of descriptions is used when the fault code must be interpreted according to the OBD standard. Only a few modules require this, most often the Engine Control Unit. You can see such fault code at the bottom of the screenshot below.
  • In this case, the elaboration string will not be displayed, as it's likely inaccurate. Instead, it's contained in the description string, after the last : character.
  • Serial Monitor output:

  • If you see the ... and (xx/xx) after the description or elaboration, increase the size of the strings:


  • If after the number of DTCs you get the message Too many faults for the given buffer size, increase #define DTC_BUFFER_MAX_FAULT_CODES in the 02.Fault_code_test.ino file:

  1. Full_measurement_test
  • This sketch will connect to the module, read all Measuring Blocks (groups) and disconnect.
  • Serial Monitor output:

  1. Continuous_measurement_test
  • This sketch will connect to the module and read a single Measuring Block (group) continuously.
  • You can select the target group #define GROUP_TO_READ in the 04.Continuous_measurement_test.ino file:

  • Serial Monitor output:

  1. Single_measurement_test
  • This sketch will connect to the module and read a single value from a Measuring Block (group) continuously.
  • You can select the target group and measurement by changing the #define GROUP_TO_READ and #define INDEX_TO_READ in the 05.Single_measurement_test.ino file:

  • Serial Monitor output:

  1. Output_tests
  • This sketch will connect to the module, perform all output tests and disconnect.
  • You can change how many milliseconds to idle on an output test by changing the #define WAIT_TIME_MS in the 06.Output_tests.ino file:

  • If you have the option KWP1281_FAULT_CODE_DESCRIPTION_SUPPORTED enabled, you will see the currently running output test. Otherwise, the descriptions are replaced by "EN_dsc".

  • Serial Monitor output:

  • If you see the ... and (xx/xx) after the description, increase the size of the string:

Writing a sketch from scratch

All sketches need a few mandatory components, and the demos are good to build upon.

The communication functions

These will be the same for any sketch, and a safe option is to copy the communication.h file from any demo and include it in your sketch. It should contain the following functions:

  1. void beginFunction(unsigned long baud)
    • it must initialize the target serial port to work at the baud rate received as a parameter
  2. void endFunction()
    • it must stop communication on the target serial port
  3. void sendFunction(uint8_t data)
    • it must send the byte received as a parameter on the target serial port
  4. bool receiveFunction(uint8_t *data)
    • it must check if a byte is available, in which case it should read it into the variable received as reference
    • it must return true if a byte was immediately available, false otherwise

The constructor

To create an instance of the library, you must use the constructor. It will be given the communication functions and a few other parameters:

KLineKWP1281Lib diag(beginFunction, endFunction, sendFunction, receiveFunction, TX_pin, is_full_duplex, &Serial);
  • uint8_t tx_pin - must be the same pin as the chosen serial port's TX
    • mandatory
  • bool full_duplex - true for full-duplex interfaces (can receive while sending), false otherwise
    • optional - if not provided, will default to true
  • Stream *debug_port - pointer to a debugging port if desired (e.g. &Serial, &Serial1 etc.)
    • optional - if not provided, debugging information will not be printed anywhere

Runtime configuration

In setup() or at any point during execution you can do the following:

  • Add a function for displaying message transactions from the serial bus

    • for this, you should create such a function:
      void debugFunction(bool direction, uint8_t message_sequence, uint8_t message_type, uint8_t *data, size_t length)
    • parameters:
      • bool direction - true for inbound messages (received), false for outbound messages (sent)
      • uint8_t message_sequence - message sequence byte
      • uint8_t message_type - opcode byte
      • uint8_t *data - byte pointer = byte array containing the message's parameter bytes
      • size_t length - amount of bytes in the data array
    • you may display these anywhere you'd like, and in any way
    • all demos contain an example for such function, which is used when #define debug_traffic is true
    • to use, it must be attached to the library instance with the KWP1281debugFunction() function:
      diag.KWP1281debugFunction(debugFunction);
  • Add a function that executes during the initialization

    • the initialization stage consists of sending a byte at a baud rate of 5; in other words, each bit takes 200ms to send
    • by default, a regular delay(200); is used, so the processor cannot do anything during that time
    • if you wish to use that time for something else (such as updating time-sensitive parts of the code), you can create a function to be executed after sending each bit (it will be called 10 times during initialization), like so:
      void waitFunction()
    • You must make sure its execution takes precisely 200ms, otherwise connecting will fail every time!
    • to use, it must be attached to the library instance, with the custom5baudWaitFunction() function:
      diag.custom5baudWaitFunction(waitFunction);
  • Add a function that executes if a connection error occurs

    • for this, you should create such a function:
      void errorFunction(uint8_t module, unsigned long baud)
    • through the module and baud parameters, it receives the settings with which the module was connected prior to the error occurring
    • you can display an error, reconnect to the module etc.
    • do not send requests to the module inside this function, only use connect() or attemptConnect()!
    • to use, it must be attached to the library instance, with the customErrorFunction() function:
      diag.customErrorFunction(errorFunction);
    • if no function is attached (or if it is removed by passing nullptr to the customErrorFunction() function), the library will automatically reconnect to the previously connected module
  • Change communication timing

    • You are free to change the delays/timeouts at any point, although you should not do it without a valid reason.
    • timing parameters:
      • initComplementDelay (default 40)
        • milliseconds to wait before sending a complement to the initialization bytes
      • complementDelay (default 2)
        • milliseconds to wait before sending a complement to a byte
      • byteDelay (default 2)
        • milliseconds to wait before sending a byte in a block, after receiving a complement
      • blockDelay (default 10)
        • milliseconds to wait before sending a block (request)
    • timeouts:
      • initResponseTimeout (default 1000)
        • milliseconds to wait for receiving a response during initialization
      • complementResponseTimeout (default 50)
        • milliseconds to wait for receiving a complement when sending bytes in a block
      • echoTimeout (default 1000)
        • milliseconds to wait for receiving the echo to a byte that was sent
        • its value should not make any difference, it only exists so that a problematic interface will not halt the program if the serial echo cannot be received
      • responseTimeout (default 2000)
        • milliseconds to wait for receiving a response to a request
        • this timeout will only be used for the first byte of a block
      • byteTimeout (default 100)
        • milliseconds to wait for receiving a byte in a block
        • this timeout will be used for all bytes of a block, except for the first one
    • change a parameter like so:
      diag.initComplementDelay = 50;

Clone this wiki locally