Giter VIP home page Giter VIP logo

vanbus's Introduction

PSA (Peugeot, Citroën) VAN bus reader/writer for Arduino-ESP8266 and ESP32


Reading and writing packets from/to PSA vehicles' VAN bus.

📝 Table of Contents

🎈 Description

This module allows you to receive and transmit packets on the "VAN" bus of your Peugeot or Citroen vehicle.

VAN bus is pretty similar to CAN bus. It was used in many cars (Peugeot, Citroen) made by PSA.

In the beginning of 2000's the PSA group (Peugeot and Citroen) used VAN bus as a communication protocol between the various comfort-related equipment. Later, around 2005, they started to replace this protocol in their newer cars with the CAN bus protocol, however some models had VAN bus inside them until 2009. This overview lists vehicles that are supposedly fitted with a VAN (comfort) bus.

Both the ESP8266 / ESP8285 and ESP32 platforms are supported by this library.

🔌 Schematics

You can usually find the VAN bus on pins 2 and 3 of ISO block "A" of your head unit (car radio). See https://en.wikipedia.org/wiki/Connectors_for_car_audio and https://github.com/morcibacsi/esp32_rmt_van_rx#schematics .

There are various possibilities to hook up a ESP8266/ESP32 based board to your vehicle's VAN bus:

  1. Use a MCP2551 transceiver, connected with its CANH and CANL pins to the vehicle's VAN bus. As the MCP2551 has 5V logic, a 5V ↔ 3.3V level converter is needed to connect the CRX / RXD / R pin of the transceiver, via the level converter, to a GPIO pin of your ESP8266/ESP32 board. For transmitting packets, also connect the CTX / TXD / D pins of the transceiver, via the level converter, to a GPIO pin of your ESP8266/ESP32 board.

    A board with the MCP2551 transceiver can be ordered e.g. here or here.

    Example schema using a Wemos D1 mini (ESP8266 based):

schema

Example schema using a LilyGO TTGO T7 Mini32 (ESP32 based):

schema

👉 Notes:

  • The two terminator resistors R3 and R4 (2 x 100 Ohm, near the CANH and CANL pins) on this transceiver board are meant for operating inside a CAN bus network, but are not necessary on a VAN bus. In fact, they may even cause the other equipment on the bus to malfunction. If you experience problems in the vehicle equipment, you may want to remove (unsolder) these terminator resistors. See also this issue.
  • CANH of the transceiver is connected to VAN BAR (DATA B), CANL to VAN (DATA). This may seem illogical but in practice it turns out this works best.
  • The clamping circuit (D1, D2, R1) seems to (somehow) help in reducing the amount of bit errors (packet CRC errors).
  1. Use a SN65HVD230 transceiver, connected with its CANH and CANL pins to the vehicle's VAN bus. The SN65HVD230 transceiver already has 3.3V logic, so it is possible to directly connect the CRX / RXD / R pin of the transceiver to a GPIO pin of your ESP8266/ESP32 board. For transmitting packets, also connect the CTX / TXD / D pins of the transceiver to a GPIO pin of your ESP8266/ESP32 board.

    A board with the SN65HVD230 transceiver can be ordered e.g. here or here.

schema

👉 Notes:

  • The terminator resistor R2 (120 Ohm, near the CANH and CANL pins) on this transceiver board is meant for operating inside a CAN bus network, but is not necessary on a VAN bus. In fact, it may even cause the other equipment on the bus to malfunction. If you experience problems in the vehicle equipment, you may want to remove (unsolder) the R2 terminator resistor. See also this issue.
  • CANH of the transceiver is connected to VAN BAR (DATA B), CANL to VAN (DATA). This may seem illogical but in practice it turns out this works best.
  • The clamping circuit (D1, D2, R1) seems to (somehow) help in reducing the amount of bit errors (packet CRC errors).
  1. The simplest schematic is not to use a transceiver at all, but connect the VAN DATA line to GrouND using two 4.7 kOhm resistors. Connect the GPIO pin of your ESP8266/ESP32 board to the 1:2 voltage divider that is thus formed by the two resistors. This is only for receiving packets, not for transmitting. Results may vary.

schema

👉 Notes:

  • This schematic seems to work well only with an ESP8266-based board, like the Wemos D1 mini. With an ESP32-based board I get a lot of CRC errors.
  • I used this schematic during many long debugging hours, but I cannot guarantee that it won't ultimately cause your car to explode! (or anything less catastrophic)

🚀 Building your Project

Before proceeding with this project, make sure you check all the following prerequisites.

Install Arduino IDE

See Arduino IDE

ESP8266-based board

An example of an ESP8266-based board is the Wemos D1 mini.

1. Install Board Package in Arduino IDE

For an ESP8266-based board you will need to install the ESP8266 Board Package.

I am currently using version 2.6.3 but other versions may also be working fine.

Follow this tutorial to install the ESP8266 Board Package.

2. Install the VAN Bus Library

In the Arduino IDE, go to the "Sketch" menu → "Include Library" → "Manage Libraries..." and install the Vehicle Area Network (VAN) bus packet reader/writer library. Hint: type "vanbus" in the search box.

For more explanation on using the Arduino library manager, you can browse to:

3. Board settings

In the Arduino IDE, go to the "Tools" menu, and choose:

  • CPU frequency: 160 MHz

Here is a picture of board settings that have been tested to work:

Board settings

ESP32-based board

An example of an ESP32-based board is the LilyGO TTGO T7 Mini32.

1. Install Board Package in Arduino IDE

For an ESP32-based board you will need the ESP32 board package installed.

I am currently using version 1.0.6 but other versions may also be working fine.

Follow this tutorial to install the ESP32 Board Package.

2. Install the VAN Bus Library

See section 'Install the VAN Bus Library', above.

3. Board settings

In the Arduino IDE, go to the "Tools" menu, and choose:

  • CPU frequency: 240 MHz

Here is a picture of board settings that have been tested to work:

Board settings

🧰 Usage

General

Add the following line to your .ino sketch:

#include <VanBus.h>

For receiving and transmitting packets:

  1. Add the following lines to your initialisation block void setup():
int TX_PIN = D3; // GPIO pin connected to VAN bus transceiver input
int RX_PIN = D2; // GPIO pin connected to VAN bus transceiver output
TVanBus::Setup(RX_PIN, TX_PIN);
  1. Add e.g. the following lines to your main loop void loop():
TVanPacketRxDesc pkt;
if (VanBus.Receive(pkt)) pkt.DumpRaw(Serial);

uint8_t rmtTemperatureBytes[] = {0x0F, 0x07, 0x00, 0x00, 0x00, 0x00, 0x70};
VanBus.SyncSendPacket(0x8A4, 0x08, rmtTemperatureBytes, sizeof(rmtTemperatureBytes));

If you only want to receive packets, you may save a few hundred precious bytes by using directly the VanBusRx object:

  1. Add the following lines to your initialisation block void setup():
int RX_PIN = D2; // GPIO pin connected to VAN bus transceiver output
VanBusRx.Setup(RX_PIN);
  1. Add the following lines to your main loop void loop():
TVanPacketRxDesc pkt;
if (VanBusRx.Receive(pkt)) pkt.DumpRaw(Serial);

VanBus object

The following methods are available for the VanBus object:

Interfaces for both receiving and transmitting of packets:

  1. void Setup(uint8_t rxPin, uint8_t txPin)
  2. void DumpStats(Stream& s, bool longForm = true)

Interfaces for receiving packets:

  1. bool Available()
  2. bool Receive(TVanPacketRxDesc& pkt, bool* isQueueOverrun = NULL)
  3. uint32_t GetRxCount()
  4. int QueueSize()
  5. int GetNQueued()
  6. int GetMaxQueued()
  7. void SetDropPolicy(int startAt, bool (*isEssential)(const TVanPacketRxDesc&) = 0)

Interfaces for transmitting packets:

  1. bool SyncSendPacket(uint16_t iden, uint8_t cmdFlags, const uint8_t* data, size_t dataLen, unsigned int timeOutMs = 10)
  2. bool SendPacket(uint16_t iden, uint8_t cmdFlags, const uint8_t* data, size_t dataLen, unsigned int timeOutMs = 10)
  3. uint32_t GetTxCount()

1. void Setup(uint8_t rxPin, uint8_t txPin)

Start the receiver listening on GPIO pin rxPin. The transmitter will transmit on GPIO pin txPin.

2. void DumpStats(Stream& s, bool longForm = true)

Dumps a few packet statistics on the passed stream. Passing false to the longForm parameter generates the short form.

3. bool Available()

Returns true if a VAN packet is available in the receive queue.

4. bool Receive(TVanPacketRxDesc& pkt, bool* isQueueOverrun = NULL)

Copy a VAN packet out of the receive queue, if available. Otherwise, returns false. If a valid pointer is passed to 'isQueueOverrun', will report then clear any queue overrun condition.

5. uint32_t GetRxCount()

Returns the number of received VAN packets since power-on. Counter may roll over.

6. int QueueSize()

Returns the number of VAN packets that can be queued before packets are lost.

7. int GetNQueued()

Returns the number of VAN packets currently queued.

8. int GetMaxQueued()

Returns the highest number of VAN packets that were queued.

9. void SetDropPolicy(int startAt, bool (*isEssential)(const TVanPacketRxDesc&) = 0)

Implements a simple packet drop policy for if the receive queue is starting to fill up.

Packets are dropped if the receive queue has startAt packets or more queued, unless a packet is identified as "important". To identify such packets, pass a function pointer via the isEssential parameter. The passed function is called within interrupt context, so it must have the ICACHE_RAM_ATTR attribute.

Example:

bool ICACHE_RAM_ATTR IsImportantPacket(const TVanPacketRxDesc& pkt)
{
    return
        pkt.DataLen() >= 3 &&
        (
            pkt.Iden() == CAR_STATUS1_IDEN  // Right-hand stalk button press
            || (pkt.Iden() == DEVICE_REPORT && pkt.Data()[0] == 0x8A)  // head_unit_report, head_unit_button_pressed
        );
} // IsImportantPacket

#define RX_PIN D2
#define VAN_PACKET_QUEUE_SIZE 60
VanBusRx.Setup(RX_PIN, VAN_PACKET_QUEUE_SIZE);
VanBusRx.SetDropPolicy(VAN_PACKET_QUEUE_SIZE * 8 / 10, &IsImportantPacket);

The above example will drop incoming packets if the receive queue contains 48 or more packets, unless they are recognized by IsImportantPacket.

10. bool SyncSendPacket(uint16_t iden, uint8_t cmdFlags, const uint8_t* data, size_t dataLen, unsigned int timeOutMs = 10)

Sends a packet for transmission. Returns true if the packet was successfully transmitted.

11. bool SendPacket(uint16_t iden, uint8_t cmdFlags, const uint8_t* data, size_t dataLen, unsigned int timeOutMs = 10)

Queues a packet for transmission. Returns true if the packet was successfully queued.

12. uint32_t GetTxCount()

Returns the number of VAN packets, offered for transmitting, since power-on. Counter may roll over.

VAN packets

On a VAN bus, the electrical signals are the same as CAN. However, CAN and VAN use different data encodings on the line which makes it impossible to use CAN interfaces on a VAN bus.

For background reading:

The following methods are available for TVanPacketRxDesc packet objects as obtained from VanBusRx.Receive(...):

  1. uint16_t Iden()
  2. uint8_t CommandFlags()
  3. const uint8_t* Data()
  4. int DataLen()
  5. unsigned long Millis()
  6. uint16_t Crc()
  7. bool CheckCrc()
  8. bool CheckCrcAndRepair()
  9. void DumpRaw(Stream& s, char last = '\n')
  10. const char* CommandFlagsStr()
  11. const char* AckStr()
  12. const char* ResultStr()
  13. const TIfsDebugPacket& getIfsDebugPacket()
  14. const TIsrDebugPacket& getIsrDebugPacket()

1. uint16_t Iden()

Returns the IDEN field of the VAN packet.

An overview of known IDEN values can be found e.g. at:

2. uint8_t CommandFlags()

Returns the 4-bit "command" FLAGS field of the VAN packet. Each VAN packet has 4 "command" flags:

  • EXT (bit 3, MSB) : always 1
  • RAK (bit 2): 1 = Requesting AcKnowledge
  • R/W (bit 1): 1 = Read operation, 0 = Write operation
  • RTR (bit 0, LSB): 1 = Remote Transmit Request

A thorough explanation is found (in French) on page 6 and 7 of http://www.educauto.org/files/file_fields/2013/11/18/mux3.pdf#page=6 .

3. const uint8_t* Data()

Returns the data field (bytes) of the VAN packet.

4. int DataLen()

Returns the number of data bytes in the VAN packet. There can be at most 28 data bytes in a VAN packet.

5. unsigned long Millis()

Packet time stamp in milliseconds.

6. uint16_t Crc()

Returns the 15-bit CRC value of the VAN packet.

7. bool CheckCrc()

Checks the CRC value of the VAN packet.

8. bool CheckCrcAndRepair()

Checks the CRC value of the VAN packet. If not, tries to repair it by flipping each bit. Returns true if the packet is OK (either before or after the repair).

9. void DumpRaw(Stream& s, char last = '\n')

Dumps the raw packet bytes to a stream. Optionally specify the last character; default is '\n' (newline).

Example of invocation:

pkt.DumpRaw(Serial);

Example of output:

Raw: #0002 ( 2/15) 11(16) 0E 4D4 RA0 82-0C-01-00-11-00-3F-3F-3F-3F-82:7B-A4 ACK OK 7BA4 CRC_OK

Example of dumping into a char array:

const char* PacketRawToStr(TVanPacketRxDesc& pkt)
{
    static char dumpBuffer[MAX_DUMP_RAW_SIZE];

    GString str(dumpBuffer);
    PrintAdapter streamer(str);
    pkt.DumpRaw(streamer, '\0');

    return dumpBuffer;
}

Note: for this, you will need to install the PrintEx library. I tested with version 1.2.0 .

10. const char* CommandFlagsStr()

Returns the "command" FLAGS field of the VAN packet as a string

Note: uses a statically allocated buffer, so don't call this method twice within the same printf invocation.

11. const char* AckStr()

Returns the ACK field of the VAN packet as a string, either "ACK" or "NO_ACK".

12. const char* ResultStr()

Returns the RESULT field of the VAN packet as a string, either "OK" or a string starting with "ERROR_".

13. const TIfsDebugPacket& getIfsDebugPacket()

Retrieves a debug structure that can be used to analyse inter-frame space events.

Only available when #define VAN_RX_ISR_DEBUGGING is uncommented (see VanBusRx.h).

14. const TIsrDebugPacket& getIsrDebugPacket()

Retrieves a debug structure that can be used to analyse (observed) bit timings.

Only available when #define VAN_RX_IFS_DEBUGGING is uncommented (see VanBusRx.h).

👷 Work to be Done

Future

Currently the library supports only 125 kbit/s VAN bus. Need to add support for different rate, like 62.5 kbit/s, which can be passed as an optional parameter to VanBusRx.Setup(...).

📖 License

This library is open-source and licensed under the MIT license.

Do whatever you like with it, but contributions are appreciated!

See also

vanbus's People

Contributors

0xcafedecaf avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

vanbus's Issues

Wrong Iden

Hello, I would like to read VAN frames from a COM2000, but when I attempt to read them, I receive strange results. For instance, I uploaded PacketParser.ino to my ESP32 and used an SN65HVD230 transceiver. I connected a USB-MUX-C3VL to send frame ID 450, and, of course, a COM2000 DAV. In the USB-MUX-C3VL software, everything works fine; I can see the status from the COM2000. However, on my ESP32 terminal, the displayed data seems incorrect, and I can't see updates from the COM2000. I'm pretty sure I messed something up, but I can't figure out what.

USB-MUX-C3VL software
CaptureMUX

esp32 terminal
CaptureESP32

All the data appears to be corrupted, and I expected that all identifiers would be equal to 0x450.

PacketParser only picks up a 100% currupt packages

The parser only reads out currupt packages. Mostly the same package with NO_ACK. I tried downgrading to the same script from release 0.1.2 and parsing works again with average currption of 1%.
In both cases I tested the script without making any changes to it on the Wemos D1.
What could cause this issue?

Can the ESP respond to a message with the ACK bits?

Hi!
First, I would like to thank you for this amazing lib! It got me deeper into my car's underworld! :)

Currently I'm in a middle of a modernization program on my Peugeot 206 :)
I'm building a head unit out of a raspberry pi using the ESP8266 to make the data bridge while the OEM radio is running in parallel.
So far so good, everything is working fine, I'm able to read from the bus all the data I want and serial print it, but today I removed the multi-function display to replace it with my own coded version to show fuel consumption and, not only the radio didn't work, but my instrument panel lit up like a Christmas tree!
I was kind of expecting the radio not to work because of the missing ACK of the messages directed to it, but the behavior of the dash caught me by surprise.

So my question is, is there a way to write the ACK bits at the end of the data reception so that this doesn't happen?

Can't compile to ESP32

Hi,
I am here to report the first issue :)

I was trying to compile it to an ESP32 dev board, but it has different methods for the timers, so the following errors occured:

image

Compiling to ESP8266 was ok.

MCP2515 SPI

Hi, is there a native way to use it? Or does it require to rewrite half of the library? 🙂

Are AliExpress's SN65HVD230 boards any good?

hey
I'm looking for a cheap SN65HVD230 board. My habitual retailer doesn't sell thoses. I found many board for 1-2€ on AE, Amazon list them at 5 to almost 20€.
What link would you recommend?

Writing negative temperatures on VAN Bus

Hello,
how do I write negative temperature on VAN Bus? There is unsinged integer for the data rmtTemperatureBytes[].

uint8_t rmtTemperatureBytes[] = {0x0F, 0x07, 0x00, 0x00, 0x00, 0x00, Temperature * 2 + 0x50};

As I set Temperature variable to negative number, it is written as positive in that array.

Question: Is every VAN wires gives the same data?

Hello,

It may sound like a very confusing formulation.
But from your experience, is every VAN connector endpoint gives the same amount of data?
By that I'm asking if there's multiples VAN bus ? (Ex VAN_0 connects BSI to the Radio and communicates only data relevant for the radio, VAN_2 connects ESP to BSI and only gives data related to ESP/ABS)?
As I understood the VAN communication to the radio gives all data, is it true for every VAN wires?
I can't really have a good access to the radio connector, and the VAN radio is not enabled completly (stock radio was optional on purchase, so they added an aftermarket one)

Thank you,

writing packets to the VAN

Hi, first of all thank you for this amazing lib! I wanted to ask why you chose to limit the lib to ro from the bus. Is this feature planned for a future update and if so what are the difficulties to overcome if there are any?

Corrupt packages and interference in the bus

Hi!

I've been using this lib for a long time to read the bus messages of my Peugeot 206, but sometimes it causes all the dash lights to go crazy and lose speed and rpm information, and after waiting for a bit, everything starts working again.
One thing I noticed is fuel consumption information doesn't get picked up very often on the bus, at least while error-free. My theory is that the message is very long and very easily corrupted most of the time.

I recently upgraded the original clock to a "new" one from another 206 that is also a trip computer, and whenever the ESP8266 is connected and reading packets, fuel consumption info isn't displayed or just freezes in a value, and when I press the stalk button to change or reset the trip it doesn't do anything.
When I disconnect the SN65HVD230 and ESP8266 everything works fine as it should but things get funky whenever I connect everything back up.

I tried adding and removing the diodes and the 470 ohm resistor but nothing changed. At this point, I'm considering changing to another bus reader or adding a galvanically isolated 3.3V power supply to see if it makes a difference.

Is there anything that I'm missing in my setup?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.