Teensy 4.0 / High Voltage Heater

I tested all 3 of my HVH heaters and on all three of them at 19200 baud, at ID 27 (HEX), it finally popped some response when sending a brute force write to all of the IDs using 1,85, 0, 8. FF down the line on all other response ids, but

Heater one returned a 0 at ID 27(HEX)
Heater two returned a 21 (HEX) at ID 27(HEX)
Heater three returned a 28 (HEX) at ID 27(HEX)

Not sure where to go from here.
 
Not sure where to go from here.
Yeah, I concur...
Looked through both LIN Description Files that you shared in message #101, buth ID 39 (DEC), 27 (HEX) is not mentioned as an ID that returns data (or can be sent data to, for that matter).
It is interesting though that all 3 heaters return a different CRC value. It could mean that we have to deal with 3 different firmware versions, which is not to our advantage.
It would be nice if your source of the HVH100 LDF, also has an LDF of the HVH50.

I'll keep chewing on this.
Paul
 
Sorry, this started as a thread about the serial plotter issue I was having on a high voltage heater. I renamed the post.
 
Last edited:
OK! So I reinstated the original Open Inverter code with some modifications and hooked everything up to water, 320V and 12V and ground. I had the controller run through all IDs on the lin.order command and used ID 39 for the lin.response, since this is the only ID that does not return -1. Power set for 1000, Temp set for 100 and UDC in was around 320V.

Code:
#include "lin_bus.h"

// Create an IntervalTimer object
IntervalTimer myTimer;

int ledState = LOW;                // ledState used to set the LED
unsigned long interval = 200000;   // interval at which to blinkLED to run every 0.2 seconds

LIN lin;

int lin_cs = 32; // cs and serial port set for skpang LIN / FDCAN board
int led1 = 23;
int lin_fault = 28;

uint16_t Power = 1000; // set to required power
uint8_t  Temperature = 100; //set to required temperature
uint16_t tmpheater = 0;
uint16_t udcheater = 0;
uint16_t powerheater = 0;

uint8_t CRC = 0;
uint8_t orderID = 0;
//uint8_t responseID = 0;

uint8_t data[8];

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(lin_fault,INPUT);
  pinMode(lin_cs, OUTPUT);
  digitalWrite(lin_cs, HIGH); // enable MCP2004 LIN transceiver
  digitalWrite(LED_BUILTIN, HIGH);
 
  Serial.begin(115200);
  //Serial.print("HVH50 Heater demo");
 
  //lin.begin(&Serial3, 9600);
  lin.begin(&Serial3, 19200); /// Change to this for 19200 /////
  delay(1000);
  pinMode(led1,OUTPUT);
    digitalWrite(LED_BUILTIN, LOW);
 
  myTimer.begin(blinkLED, interval);
}

void loop() {
  // heater
  SendLin();
  delay(1000); // wait 1000ms
  //Serial.print(" Heater test\n");

}

void blinkLED() {
  ledState = !ledState;
 
  digitalWrite(LED_BUILTIN, ledState);
  digitalWrite(led1, ledState);
}

  static void SendLin()
{
   for (orderID = 0; orderID < 64; orderID++) {

   static bool read = true;
   uint8_t data[8];
   delay(1000); // wait 1000ms
   uint8_t lindata[] = {uint8_t(Power/40), uint8_t(Temperature+40), 0, 8};
   lin.order(orderID, lindata, 4, lin2x);
   delay(100);
  if (lin.response(39, data, 8, lin2x) >=0) // -1 indicates crc error, 19200
     {
     tmpheater = data[1] - 40;
     udcheater = data[4] | (data[5] & 3) << 8;
     powerheater =((data[5] >> 2) | (data[6] << 8)) * 20;
     Serial.print("orderID:");
     Serial.print(orderID);
     Serial.print(",");
     Serial.print("Temp:");
     Serial.print(tmpheater);
     Serial.print(",");
     Serial.print("Udc:");
     Serial.print(udcheater);
     Serial.print(",");
     Serial.print("Power:");
     Serial.println(powerheater);
     Serial.print("CRC:");
     Serial.print(CRC);
     Serial.print(",");
     }
   else if (read)
   {
      lin.order(orderID, lindata, 4, lin2x);
   }
   else
   {
      uint8_t lindata[] = {uint8_t(Power/40), uint8_t(Temperature+40), 0, 8};
      lin.order(orderID, lindata, 4, lin2x);
      //Serial.print("\n Sending power and temperature");
   }

   read = !read;
  }
}

The Serial Monitor began working finally and the readings looked like this.

Code:
CRC:0,orderID:0,Temp:21,Udc:60,Power:400
CRC:0,orderID:1,Temp:21,Udc:60,Power:400
CRC:0,orderID:2,Temp:21,Udc:60,Power:400
CRC:0,orderID:3,Temp:21,Udc:60,Power:400
CRC:0,orderID:4,Temp:21,Udc:60,Power:400
CRC:0,orderID:5,Temp:21,Udc:60,Power:400
CRC:0,orderID:6,Temp:21,Udc:60,Power:400
CRC:0,orderID:7,Temp:21,Udc:60,Power:400
CRC:0,orderID:8,Temp:21,Udc:60,Power:400
CRC:0,orderID:9,Temp:21,Udc:60,Power:400
CRC:0,orderID:10,Temp:21,Udc:60,Power:400
CRC:0,orderID:11,Temp:21,Udc:60,Power:400
CRC:0,orderID:12,Temp:21,Udc:60,Power:400
CRC:0,orderID:13,Temp:21,Udc:60,Power:400
CRC:0,orderID:14,Temp:21,Udc:60,Power:400
CRC:0,orderID:15,Temp:21,Udc:60,Power:400
CRC:0,orderID:16,Temp:21,Udc:60,Power:400
CRC:0,orderID:17,Temp:21,Udc:60,Power:400
CRC:0,orderID:18,Temp:21,Udc:60,Power:400
CRC:0,orderID:19,Temp:21,Udc:60,Power:400
CRC:0,orderID:20,Temp:21,Udc:60,Power:400
CRC:0,orderID:21,Temp:21,Udc:60,Power:400
CRC:0,orderID:22,Temp:21,Udc:60,Power:400
CRC:0,orderID:23,Temp:21,Udc:60,Power:1040
CRC:0,orderID:24,Temp:21,Udc:60,Power:400
CRC:0,orderID:25,Temp:21,Udc:60,Power:400
CRC:0,orderID:26,Temp:21,Udc:60,Power:400
CRC:0,orderID:27,Temp:21,Udc:60,Power:400
CRC:0,orderID:28,Temp:21,Udc:60,Power:400
CRC:0,orderID:29,Temp:21,Udc:60,Power:400
CRC:0,orderID:30,Temp:21,Udc:60,Power:400
CRC:0,orderID:31,Temp:21,Udc:60,Power:400
CRC:0,orderID:32,Temp:21,Udc:60,Power:400
CRC:0,orderID:33,Temp:21,Udc:60,Power:400
CRC:0,orderID:34,Temp:21,Udc:60,Power:400
CRC:0,orderID:35,Temp:21,Udc:60,Power:400
CRC:0,orderID:36,Temp:21,Udc:60,Power:400
CRC:0,orderID:37,Temp:21,Udc:60,Power:400
CRC:0,orderID:38,Temp:21,Udc:60,Power:400
CRC:0,orderID:39,Temp:21,Udc:60,Power:1040
CRC:0,orderID:40,Temp:21,Udc:60,Power:400
CRC:0,orderID:41,Temp:21,Udc:60,Power:400
CRC:0,orderID:42,Temp:21,Udc:60,Power:400
CRC:0,orderID:43,Temp:21,Udc:60,Power:400
CRC:0,orderID:44,Temp:21,Udc:60,Power:400
CRC:0,orderID:45,Temp:21,Udc:60,Power:400
CRC:0,orderID:46,Temp:21,Udc:60,Power:400
CRC:0,orderID:47,Temp:21,Udc:60,Power:400
CRC:0,orderID:48,Temp:21,Udc:60,Power:400
CRC:0,orderID:49,Temp:21,Udc:60,Power:400
CRC:0,orderID:50,Temp:21,Udc:60,Power:400
CRC:0,orderID:51,Temp:21,Udc:60,Power:400
CRC:0,orderID:52,Temp:21,Udc:60,Power:400
CRC:0,orderID:53,Temp:21,Udc:60,Power:400
CRC:0,orderID:54,Temp:21,Udc:60,Power:400
CRC:0,orderID:55,Temp:21,Udc:60,Power:400
CRC:0,orderID:56,Temp:21,Udc:60,Power:400
CRC:0,orderID:57,Temp:21,Udc:60,Power:400
CRC:0,orderID:58,Temp:21,Udc:60,Power:400
CRC:0,orderID:59,Temp:21,Udc:60,Power:400
CRC:0,orderID:60,Temp:21,Udc:60,Power:1040
CRC:0,orderID:61,Temp:21,Udc:60,Power:400
CRC:0,orderID:62,Temp:21,Udc:60,Power:400
CRC:0,orderID:63,Temp:21,Udc:60,Power:400

Temp and udc and Power were not giving accurate numbers, but at ID 23, 39 and 60, the Power jumped to 1040.

I then modified the code to send the lin.order only on 23 and then only on 60 and this was the response for both IDs when no other IDs were sent:

Code:
]CRC:0,Temp:21,Udc:60,Power:960
CRC:0,Temp:21,Udc:60,Power:960
CRC:0,Temp:21,Udc:60,Power:960
CRC:0,Temp:21,Udc:60,Power:960
CRC:0,Temp:21,Udc:60,Power:960
CRC:0,Temp:21,Udc:60,Power:960
CRC:0,Temp:21,Udc:60,Power:960
CRC:0,Temp:21,Udc:60,Power:960
CRC:0,Temp:21,Udc:60,Power:960
CRC:0,Temp:21,Udc:60,Power:960
CRC:0,Temp:21,Udc:60,Power:960
CRC:0,Temp:21,Udc:60,Power:960
CRC:0,Temp:21,Udc:60,Power:960
CRC:0,Temp:21,Udc:60,Power:960

Paul, I recall that you had me modify the cpp file that resulted in shifting the bits over by one. I am going to undo that change now and see what happens.

If I use the formulas in the code with the shifted back bits, it looks like it should result in correct info, but I am a novice at binary operations. Here is my thereom:

My code was returning this at some point:

0 62 0 123 61 208 0 80

The Serial Monitor showed:

TEMP: 21 UDC: 61 POWER: 960

If I run this formula for the code:

Code:
 udcheater = data[4] | (data[5] & 3) << 8;

I get:

data[4] = 123 and 0000000001111011

data[5] = 61 and 0000000000111101

3= 0000000000000011

(data[5] & 3) = 0000000000000001
<< 8 = 0000000100000000 = 256
data[4] | (data[5] & 3) = 0000000100111101 =317

The HV coming into the heater is 317V, so I assume the outcome is correct if the bits are correctly identified and the operations are correctly set out.

I feel like I am back in math class!!!!
 
Last edited:
Hi Paul. Unfortunately not so. I am only testing one of the heaters at the moment and will try the other two today, but on the one that was returning 0s at ID 39, here is what I know at the moment.

1. On the linbus.cpp file, I modified this line per a Github suggested change from 2023:

data[i-3] = tmp[i-1]; // added the -1 for shifting one byte

and I left the commented out line:

//_stream->read(); //comment in or out

When I did this, all IDs returned an FF, including ID 27 (HEX).

2 27 FF
E7
0
3B
0
72
3A
40
0

I then uncommented back this line:

_stream->read(); //comment in or out

and left the modified line:

data[i-3] = tmp[i-1]; // added the -1 for shifting one byte

With that change, it put things back to the original look with the initial bit at 0:

0 27 0
0
3B
0
71
3B
40
0
EF

so I then went back to removing the -1 and commenting out the line you asked me to and it shifted to look like this:

0 27 0
3B
0
72
3A
40
0
EF
0

Not sure which is the right combo, but wanted you to know.

2. I am still not sure why all IDs show the following data connected or unconnected from the heater at all IDs:

With the shifted bit

0 26 FF
A6
0
54
18
0
20
8
0

You and I expected this to show zeros and I assume your code returns zeros as well with your board unconnected to anything? I am running this code again (slightly modified) to run through all IDs:

Code:
#include "lin_bus.h"
// Create an IntervalTimer object
IntervalTimer myTimer;
int ledState = LOW;               // ledState used to set the LED
unsigned long interval = 200000;  // interval at which to blinkLED to run every 0.2 seconds
LIN lin;
uint16_t Power = 400; // set to required power
uint8_t Temperature = 100; //set to required temperature
int lin_cs = 32;  // pin 23 for my LIN board
int led1 = 23;
int lin_fault = 28;
uint8_t linTXdata[4] = { Power, Temperature, 0, 8 };  // 40W, 45C, heater on
uint8_t linRXdata[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
uint8_t CRC = 0;
uint8_t orderID = 0;
uint8_t responseID = 0;
void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(lin_fault, INPUT);
  pinMode(lin_cs, OUTPUT);
  digitalWrite(lin_cs, HIGH);  // enable MCP2004 LIN transceiver
  digitalWrite(LED_BUILTIN, HIGH);
  Serial.begin(115200);
  lin.begin(&Serial3, 19200);  // or
  //lin.begin(&Serial3, 9600);
  delay(1000);
  pinMode(led1, OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);
}
void loop() {
  for (orderID = 0; orderID < 64; orderID++) {
    for (responseID = 0; responseID < 64; responseID++) {
      lin.order(orderID, linTXdata, 4, lin2x);
      delay(100);
      CRC = lin.response(responseID, linRXdata, 8, lin2x);
      delay(100);
      Serial.print(orderID, HEX);
      Serial.print("\t");
      Serial.print(responseID, HEX);
      Serial.print("\t");
      Serial.println(CRC, HEX);
      for (int i = 0; i < 8; i++) {           // display the raw data
      Serial.print(linRXdata[i], HEX);
      Serial.print("\t");
      Serial.print("\t");
      Serial.print(" ");
      Serial.println();
      delay(10);
    }
  }
}
}

I get this warning when compiling and not sure why:

Code:
C:\Users\jsimo\Documents\Arduino\bruteforceallids_27\bruteforceallids_27.ino:18:26: warning: narrowing conversion of 'Power' from 'uint16_t' {aka 'short unsigned int'} to 'uint8_t' {aka 'unsigned char'} [-Wnarrowing]
   18 | uint8_t linTXdata[4] = { Power, Temperature, 0, 8 };  // 40W, 45C, heater on

It would be helpful to know if you are getting something similar on your end.

3. When connected to the heater with 12V power and ground (with or without HV running), at ID 39 (HEX 27), the code changes from:

0 27 FF
14
0
54
18
0
20
8
0

to

0 27 0
3B
0
72
3A
40
0
EF
0
 
1. On the linbus.cpp file, I modified this line per a Github suggested change from 2023:

data[i-3] = tmp[i-1]; // added the -1 for shifting one byte

and I left the commented out line:

//_stream->read(); //comment in or out

Not sure which is the right combo, but wanted you to know.
Both commenting _stream->read(); and modifying data[i-3] = tmp[i-1]; serve the same purpose: correcting the wrongly shifted byte. So you should choose either one.
2. I am still not sure why all IDs show the following data connected or unconnected from the heater at all IDs:
It would be helpful to know if you are getting something similar on your end.
When I run your code, I get this response:
19:57:44.806 -> 0 1B FF
19:57:44.806 -> 0
19:57:44.841 -> 54
19:57:44.841 -> 18
19:57:44.841 -> 0
19:57:44.873 -> 20
19:57:44.873 -> 8
19:57:44.873 -> 0
19:57:44.920 -> 0
19:57:45.128 -> 0 1C FF
19:57:45.128 -> 0
19:57:45.128 -> 54
19:57:45.128 -> 18
19:57:45.128 -> 0
19:57:45.168 -> 20
19:57:45.168 -> 8
19:57:45.168 -> 0
19:57:45.168 -> 0
Same response but correctly shifted by 1 byte [I still have //_stream->read(); commented in lin_bus.cpp].
I have now idea why our responses the same.
I get this warning when compiling and not sure why:
warning: narrowing conversion of 'Power' from 'uint16_t' {aka 'short unsigned int'} to 'uint8_t' {aka 'unsigned char'} [-Wnarrowing]
That's because uint16_t Power = 400; is 16 bits, while the array linTXdata[4] is 8 bit, hence the warning.
The Webasto spec states max coolant temp is 214C. The Power value should then be 214+40 offset = 244. That last value fits 1 byte.

Paul
 
Thanks Paul. I changed up the code to print out each of the numbered data lines [1]-[8] and this is the printout:


Code:
61,0,0,61,192,0,100,1
61,0,0,60,192,0,100,0
61,0,0,60,192,0,100,1
61,0,0,60,192,0,100,0
61,0,0,60,192,0,100,1
61,0,0,60,192,0,101,0
61,0,0,60,192,0,100,1
61,0,0,60,192,0,100,0
61,0,0,61,192,0,99,1
61,0,0,61,192,0,99,0
61,0,0,60,192,0,101,1
61,0,0,60,192,0,100,0
61,0,0,60,192,0,101,1

I am curious why the final data byte 8 goes back and forth between 0 and 1. The wiki page lists the 8 bytes out. I wonder if the 0,1 back and forth is trying to turn the heater on, but it is not appearing in the correct location.

ReadID 39)Status
4=running
Outlet temp
Scaling as above
Inlet temp-Voltage LSBVoltage MSB - 2 bits
Power LSB - 6 bits
Power MSB
1 digit=20W
Unknown

For some reason, the formula in the STM32 version used to decode the data is not giving me accurate info:

My Readout
CRC:0,Temp:19,Udc:59,Power:960

Code:
tmpheater = data[1] - 40;     
udcheater = data[4] | (data[5] & 3) << 8;     
powerheater =((data[5] >> 2) | (data[6] << 8)) * 20;

I really think that since we have found the response byte, it is now about whether it is all in the right order. Just not sure how to troubleshoot further to get responses showing heater on. I know we are close.

Interesting to me that the data readouts by each number are different that the lprintout of the inRXdata repones of:

59, 0, 114, 58, 64,0, 239, 0
 
Last edited:
I HAVE HOT WATER!!!!!!

So I went to bed last night thinking about what I was missing and woke up with the thought that there might be info hidden in DATA[0] since DATA[1] was used to calculate temp and I recall Johan mentioning that the on status would be in byte 0, so I modified the code to print out DATA[0] through DATA [8] using lin.response ID 39 and running through all of the lin.order IDs.

I ran this code:

Code:
#include "lin_bus.h"

// Create an IntervalTimer object
IntervalTimer myTimer;

int ledState = LOW;                // ledState used to set the LED
unsigned long interval = 200000;   // interval at which to blinkLED to run every 0.2 seconds

LIN lin;

int lin_cs = 32; // cs and serial port set for skpang LIN / FDCAN board
int led1 = 23;
int lin_fault = 28;

uint16_t Power = 40; // set to required power
uint8_t  Temperature = 85; //set to required temperature
uint16_t tmpheater = 0;
uint16_t udcheater = 0;
uint16_t powerheater = 0;

uint8_t CRC = 0;
uint8_t orderID = 0;
uint8_t responseID = 0;

//uint8_t data[8];

uint8_t linTXdata[4] = { 0, 0, 0, 0 };  // 40W, 45C, heater on
uint8_t linRXdata[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
//uint8_t CRC = 0;
//uint8_t orderID = 0;
//uint8_t responseID = 0;

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(lin_fault,INPUT);
  pinMode(lin_cs, OUTPUT);
  digitalWrite(lin_cs, HIGH); // enable MCP2004 LIN transceiver
  digitalWrite(LED_BUILTIN, HIGH);
 
  Serial.begin(115200);
  //Serial.print("HVH50 Heater demo");
 
  //lin.begin(&Serial3, 9600);
  lin.begin(&Serial3, 19200); /// Change to this for 19200 /////
  delay(1000);
  pinMode(led1,OUTPUT);
    digitalWrite(LED_BUILTIN, LOW);
 
  myTimer.begin(blinkLED, interval);
}

void loop() {
  // heater
  SendLin();
  delay(100); // wait 100ms
  //Serial.print(" Heater test\n");

}

void blinkLED() {
  ledState = !ledState;
 
  digitalWrite(LED_BUILTIN, ledState);
  digitalWrite(led1, ledState);
}

  static void SendLin()
{
   for (orderID = 0; orderID < 64; orderID++) {


   static bool read = true;
   uint8_t data[8];
   delay(100); // wait 100ms
   lin.order(orderID, linTXdata, 4, lin2x);
   delay(100);
   CRC = lin.response(39, linRXdata, 8, lin2x);
   lin.response(39, linRXdata, 8, lin2x); //>=0) // -1 indicates crc error, 19200
     {
     tmpheater = linRXdata[1] - 40;
     udcheater = linRXdata[4] | (linRXdata[5] & 3) << 8;
     powerheater =((linRXdata[5] >> 2) | (linRXdata[6] << 8)) * 20;
     Serial.print("orderID:");
     Serial.print(orderID);
     Serial.print(",");
     Serial.print("Temp:");
     Serial.print(tmpheater);
     Serial.print(",");
     Serial.print("Udc:");
     Serial.print(udcheater);
     Serial.print(",");
     Serial.print("Power:");
     Serial.println(powerheater);
     Serial.print("CRC:");
     Serial.println(CRC);
     Serial.print(linRXdata[0]);
     Serial.print(",");
     Serial.print(linRXdata[1]);
     Serial.print(",");
     Serial.print(linRXdata[2]);
     Serial.print(",");
     Serial.print(linRXdata[2]);
     Serial.print(",");
     Serial.print(linRXdata[4]);
     Serial.print(",");
     Serial.print(linRXdata[5]);
     Serial.print(",");
     Serial.print(linRXdata[6]);
     Serial.print(",");
     Serial.println(linRXdata[7]);
     Serial.print(",");
     //Serial.println(linRXdata[8]);
     Serial.println(linRXdata);
 
     }
   //else if (read)
  // {
      //lin.order(35, linTXdata, 4, lin2x);
   //}
  // else
  // {
      //uint8_t linTXdata[] = {uint8_t(Power/40), uint8_t(Temperature+40), 0, 8};
     //lin.order(35, linTXdata, 4, lin2x);
      //Serial.print("\n Sending power and temperature");
  // }

   read = !read;
  }
}

with this response:

Code:
orderID:30,Temp:19,Udc:58,Power:320
CRC:0
0,59,0,0,58,64,0,238,27
orderID:31,Temp:19,Udc:58,Power:320
CRC:0
0,59,0,0,58,64,0,238,27
orderID:32,Temp:19,Udc:58,Power:320
CRC:0
0,59,0,0,58,64,0,237,27
orderID:33,Temp:19,Udc:58,Power:320
CRC:0
0,59,0,0,58,64,0,237,27
orderID:34,Temp:19,Udc:58,Power:320
CRC:0
0,59,0,0,58,64,0,239,27
orderID:35,Temp:19,Udc:58,Power:320
CRC:0
128,59,0,0,58,64,0,110,27
orderID:36,Temp:19,Udc:58,Power:320
CRC:0
0,59,0,0,58,64,0,237,27
orderID:37,Temp:19,Udc:58,Power:320
CRC:0
0,59,0,0,58,64,0,237,27

DATA[0] showed 0s until ID 35 and it jumped to 128 at that point. Therefore, I assumed ID34 was causing the change in DATA[0].

I then modified the lin.order command to ID34 with the lin.response on ID39 and water started to heat.

Here is the code I was running:

Code:
#include "lin_bus.h"

// Create an IntervalTimer object
IntervalTimer myTimer;

int ledState = LOW;               // ledState used to set the LED
unsigned long interval = 200000;  // interval at which to blinkLED to run every 0.2 seconds

LIN lin;

uint16_t Power = 400; // set to required power
uint8_t Temperature = 100; //set to required temperature

int lin_cs = 32;  // pin 23 for my LIN board
int led1 = 23;
int lin_fault = 28;

uint8_t linTXdata[4] = { Power, Temperature, 0, 8 };  // 40W, 45C, heater on
uint8_t linRXdata[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
uint8_t CRC = 0;
uint8_t orderID = 0;
uint8_t responseID = 0;

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(lin_fault, INPUT);
  pinMode(lin_cs, OUTPUT);
  digitalWrite(lin_cs, HIGH);  // enable MCP2004 LIN transceiver
  digitalWrite(LED_BUILTIN, HIGH);

  Serial.begin(115200);

  lin.begin(&Serial3, 19200);  // or
  //lin.begin(&Serial3, 9600);
  delay(1000);
  pinMode(led1, OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);
}

void loop() {
  //for (orderID = 0; orderID < 64; orderID++) {
    //for (responseID = 0; responseID < 64; responseID++) {

      lin.order(34, linTXdata, 4, lin2x);
      delay(100);

      CRC = lin.response(39, linRXdata, 8, lin2x);
      delay(100);
      Serial.print(34, HEX);
      Serial.print("\t");
      Serial.print(39, HEX);
      Serial.print("\t");
      Serial.println(CRC, HEX);
      for (int i = 0; i < 8; i++) {           // display the raw data
      Serial.print(linRXdata[i]);
      Serial.print("\t");
      Serial.print("\t");
      Serial.print(" ");
      Serial.println();

      delay(10);
    }
  }
//}
//}

Serial Plotter:

Code:
22    27    0
128   
95   
2   
116   
91   
80   
0   
22   
22    27    0
128   
95   
2   
114   
91   
80   
0   
24   
22    27    0
32   
95   
0   
114   
91   
80   
0   
122   
22    27    0
32   
95   
0   
115   
91   
80   
0   
121


22    27    0
32   
89   
0   
117   
89   
80   
0   
127

22    27    0
32   
88   
0   
115   
88   
80   
0   
131

22    27    0
32   
84   
0   
116   
83   
80   
0   
139   

22    27    0
32   
84   
0   
115   
83   
80   
0   
140

22    27    0
32   
82   
0   
116   
81   
80   
0   
143   

22    27    0
32   
82   
0   
115   
81   
80   
0   
144

22    27    0
32   
80   
0   
116   
80   
80   
0   
146

22    27    0
32   
80   
0   
116   
79   
80   
0   
147

22    27    0
32   
79   
0   
116   
78   
80   
0   
149   


22    27    0
32   
79   
0   
115   
78   
80   
0   
150

Not sure why the 128 in the first bit drops to 32 at some point, but it did not affect the heating as far as I could tell. You can see that the final bit seems to increase over time and I am pretty sure is the temperature. I pasted examples along the way of the number increasing. With an offset of 40, I assume the temps are between 80 and 110 C. I will need to work on the formulas for the output on serial plotter, but I assume those are just for my knowledge and do not affect the heating of the water.

This was only on the VOLVO HVH50 heater out of a CX90, so I will need to sniff the other heaters for their lin.response ID and then lin.order ID, but now I have the blueprints and steps to do it.

--------------------------
THANK YOU THANK YOU THANK YOU PAUL! I would not have been able to do this without your help. I would never have gotten this without your tireless help. The lin2x fix, the linbus.cpp fix, the sketches to sniff out a response ID and just teaching me enough that I could experiment on my own to get to this place.

I will update the wiki page with the info for this VOLVO heater.
 
Last edited:
Great result! Happy to be of help in reverse engineering in what was nearly a black box [but not any longer now].
Well, I hope you get the other heaters to communicate as well! I will check the wiki page every once in a while.

Paul
 
Hi Paul. I saw your comment about the Github fix that is needed for the bit shifting. Thanks!

Also, I am embarrassed to say that the heater has not been working again and I am having trouble recreating the results I got on 3-3.

I wanted to ask this question. In the PDF manual, it discusses the Lin signal names and the bit values for sending and receiving. If I wanted my code to print those responses, how do I ask? For example, LIN-Signal Name: HVH_Status. I assume I can call up the info based on each of these signal names with some command.

Do I add a line that says lin.response(HVH_Status, lin2x) or something else?

1710602954015.png
 
Last edited:
Do I add a line that says lin.response(HVH_Status, lin2x) or something else?
Hi Jordan, no, unfortunately that doesn't work that way.
Thing is you can only send bytes (values if you like) over the LIN bus. Electrically they are just 0's and 1's. What these bits mean, is up to us.
We start with a lin.order() command and next issue a lin.response() command.
The contents of the 4 bytes of the lin.order() have been predefined by us: Power, Temperature, 0, 8. What is actually sent, is just bytes.
The same applies to the lin.response() command: we will receive 8 bytes. What those bytes actually mean (the interpretation) is up to us again. In the case of wanting to have "HVH_Status", we know we have to look at the first of the returned 8 bytes. That would be byte linRXdata[0].

What you often see is that someone puts all this definition & interpretation (bit-shifting/masking/manipulation) work in a nice library - the user of that library then only needs to issue 'high level' commands and will only receive 'high level' responses. But there is not yet an HVH50 library combined with the LIN library we are using.

Related to your code, I saw this:
C++:
uint16_t Power = 400; // set to required power

uint8_t linTXdata[4] = { Power, Temperature, 0, 8 };  // 40W, 45C, heater on
The Power value 400 doesn't fit in a byte, so it will be truncated to decimal 144.
The power value is supposed to be given in multiples of 40W according to the table on openinverter.org, so your code should be uint16_t Power = 10; // set to required power/40.
For the temperature setting there is a similar conversion.

Paul
 
Last edited:
Thanks for that explanation Paul. I was considering whether the HVH100 LDF file could be used for our purposes, but I think you are saying that the HVH50 programming may be completely different, so without the HVH50 LDF file, I am stuck with trial and error on the order command within those 4 bytes.

On another note, I switched into the other 2 heaters, which I believe come from the same type of car (Chrysler Pacifica) and on both of those heaters, the Lin.Order at ID34 produces a response more consistent with what the OpenInverter Wiki Page expects, being only the first 3 bytes show data when the heater is receiving 12V and the rest are zeros and the Lin.Response at 23 has data across several of the 8 bytes, including the first byte, which shows an 8 when 12V power is provided to the heater.

All IDs no 12V power to heater:

Code:
0    0    84    24    0    32    8    0

ID 23 with 12V power (with and without HV):

Code:
8.96.0.15.240.32.8.0.

ID 39 with 12V power (with and without HV):

Code:
115.62.63.0.0.0.0.0.

However, the CRC only returns 255 across all ID on these heaters, so no heat yet. I am getting the IDs to come to life with 12V power and also with and without HV, but not yet getting them to kick into returning a 0. For some reason, this makes me more hopeful :)
1710679448843.png






FWIW, I went back to the first posts and followed it through with all of the changes and discussions we had and one thing that did finally come to light was the issue between our shorter code and my longer code. I have figured out that when the code includes the lin fault pin 28 on the teensy, it returns different code from when it is not included.


without the lin fault line of code:
0,.32,.0,.0,.72,.32,.8,.0,.

Code:
int lin_fault = 28;

void setup() {
  pinMode(lin_fault,INPUT);
with the ln fault pin info included:
8,.96,.0,.15,.240,.32,.8,.0,.

Wondering if you get the same type of response when doing this on your setup.
 
Last edited:
Hi Paul. I am now convinced I got hear through dumb luck and wish to re-create it but with solid understanding and the ability to re-create it on command. I went back to the beginning and followed all of our steps again. This time, I used the the scope to help me. At this point, I have confirmed that ID 39 is the Lin Read with 7 bits showing on the scope and ID 23 is the LIN READ STATUS with 3 bits showing. This happens with Lin.Response and he heater powered on with and without HV.




Now I assumed that 34 was the proper ID for Lin.Order because when I was sending all IDs the day I got heat, the data at byte 0 jumped from 0 to 118 and then held at 32. I have not been able to recreate this, though.

Code:
orderID:33,Temp:19,Udc:58,Power:320
CRC:0
0,59,0,115,58,64,0,237,27
orderID:34,Temp:19,Udc:58,Power:320
CRC:0
0,59,0,115,58,64,0,239,27
orderID:35,Temp:19,Udc:58,Power:320
CRC:0
128,59,0,115,58,64,0,110,27
orderID:36,Temp:19,Udc:58,Power:320
CRC:0
0,59,0,115,58,64,0,237,27

I have tried 34 and 35 with no success. I am now considering whether I should be focusing on how the heater initiates and what I might have done accidentally. I am looking at timing and synch. Looking at the node attributes in the HVH100 LDF file, I see:

Code:
Node_attributes {
  HVH_100{
    LIN_protocol = "2.0" ;
    configured_NAD = 0x5F ;
    product_id = 0x0, 0x0, 0 ;
    response_error = PTC_ResponseError ;
    P2_min = 10 ms ;
    ST_min = 10 ms ;
    configurable_frames {
      HV_He_01 = 0x401C ;
      HV_Hs_01 = 0x4030 ;
      HV_Hs_02 = 0x400C ;


Schedule_tables {
 ST1 {
    HV_He_01 delay 20 ms ;
    HV_Hs_01 delay 20 ms ;
    HV_Hs_02 delay 20 ms ;
  }
 DiagRequest {
    MasterReq delay 10 ms ;
  }
 DiagResponse {
    SlaveResp delay 10 ms ;
  }
}

I am not sure if any of this needs to be incorporated into the linbus.h or cpp file or my code that is not already there.

Assuming the LDF for the HVH100 is compatible with the HVH50, the frame structure shows:

Code:
Frames {
  HV_He_01: 28, Controller, 4 {
    KL_HV_PTC_soll, 0 ;
    KL_PTC_ein, 8 ;
  }
  HV_Hs_01: 48, HVH_100, 8 {
    PTC_HV_I_ist, 0 ;
    PTC_HV_ERR, 8 ;
    PTC_HV_Status_PTC, 16 ;
    PTC_Status_UBatt, 19 ;
    PTC_ResponseError, 21 ;
    PTC_TimeOut_Fehler, 22 ;
    PTC_HV_Err_Heizkreis_1, 24 ;
    PTC_HV_Err_Heizkreis_2, 25 ;
    PTC_HV_Err_Heizkreis_3, 26 ;
    PTC_HV_Err_Leckagestrom, 27 ;
    PTC_HV_Err_Ueberstromabschaltung, 28 ;
    PTC_HV_Err_Temperaturschutz, 29 ;
    PTC_HV_Err_intern, 30 ;
    PTC_UBatt, 32 ;
    PTC_Temp_PCB, 40 ;
    PTC_HV_Heizmedium_Sensor_1, 48 ;
    PTC_HV_Heizmedium_Sensor_2, 56 ;
  }
  HV_Hs_02: 12, HVH_100, 8 {
    HVH_HV_Voltage, 32 ;
    HVH_HV_Voltage_Offset, 41 ;
    HVH_HV_Ilock_Status, 45 ;
    HVH_ParameterChange, 61 ;
    HVH_ErrMem_State, 62 ;
  }
}

With my German translator, it would seen that the ON command will appear at BIT 8, which is the first bit of the second Databyte and not the fourth one right?

Anyways, I am wondering if you had any ideas for a sketch to sniff this part out, now that we have definitive response and status IDs and try to cause some reaction on their parts.

I wonder if the 255 lin bit value for the initial/power request value needs to be sent before the heater will turn on?

1711290010130.png
 

Attachments

  • PXL_20240323_221355235.jpg
    PXL_20240323_221355235.jpg
    364.5 KB · Views: 19
Last edited:
Too bad that we don't have LDF file for the HVH50. Saw your request for info at the peak-system forum as well...
With my German translator, it would seen that the ON command will appear at BIT 8, which is the first bit of the second Databyte and not the fourth one right?
I agree.
Code:
Frames {
  HV_He_01: 28, Controller, 4 {
    KL_HV_PTC_soll, 0 ;
    KL_PTC_ein, 8 ;
  }
This tells me that the bit KL_PTC_ein starts at offset 8; that would indeed be the first bit of the second databyte.
However, I don't think we can rely on the HVH100 LDF file, since that seems to contradict with what the guys at the forum found:
- Byte 0 sets the power with a scaling factor of 40
- Byte 1 set the temperature setpoint in °C with an offset of 40
- Byte 2 is unused
- Byte 3 =8 heater on (i.e. bit 3 set)
I would focus on lin.order ID35, since it seems to lead to a different response:
Code:
orderID:35,Temp:19,Udc:58,Power:320
CRC:0
128,59,0,115,58,64,0,110,27
You may want to have a look at your code since the response on screen is 9 bytes instead of 8.

With respect to your scope picture: I don't know what to think of it. LIN responses should always be 1, 2, 4 or 8 bytes, not 3 or 7.

Paul
 
Hi Paul. I wanted to keep you updated on my progress with the HVH50 from the Chrysler Pacifica. Now that I am getting more comfortable with the coding and trying to incorporate what I have learned about what the slave is looking for and some of the clues from the HVH100 LDF, I created a new sketch using 34 as the order ID and 23 and 39 as the response IDs.

New Code:

Code:
#include "lin_bus.h"

// Create an IntervalTimer object
IntervalTimer myTimer;

int ledState = LOW;                // ledState used to set the LED
unsigned long interval = 200000;   // interval at which to blinkLED to run every 0.2 seconds

LIN lin;

int lin_cs = 32; // cs and serial port set for skpang LIN / FDCAN board
int led1 = 23;
int lin_fault = 28;
int tx_pin= 1;

uint16_t Power = 4000; // set to required power
uint8_t  Temperature = 100; //set to required temperature
uint16_t tmpheater = 0;
uint16_t udcheater = 0;
uint16_t powerheater = 0;

uint8_t CRC = 0;
uint8_t CRC2 = 0;
uint8_t orderID = 34;
uint8_t responseID = 23;
uint8_t responseID2 = 39;

uint8_t linTXdata2[4] = { 0, 0, 0, 0};  // 40W, 45C, heater on
uint8_t linRXdata[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
uint8_t linRXdata2[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(lin_fault,INPUT);
  pinMode(lin_cs, OUTPUT);
  pinMode(tx_pin, OUTPUT);
  digitalWrite(lin_cs, HIGH); // enable MCP2004 LIN transceiver
  digitalWrite(LED_BUILTIN, HIGH);
 
  Serial.begin(115200);
 
  //lin.begin(&Serial3, 9600);
  lin.begin(&Serial3, 19200); /// Change to this for 19200 /////
  delay(20);

  pinMode(led1,OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);
 
  myTimer.begin(blinkLED, interval);

  lin.order(orderID, linTXdata2, 4, lin2x);// send lin order with all zeros to wake up
  delay(20);
  lin.order(responseID, 0, 0, lin2x); // send lin order with all zeros to wake up
  delay(20);
  lin.order(responseID2, 0, 0, lin2x); // send lin order with all zeros to wake up
  delay(20);
}
void loop() {
  SendLin();
  delay(20);

}
void blinkLED() {
  ledState = !ledState;
  digitalWrite(LED_BUILTIN, ledState);
  digitalWrite(led1, ledState);
}

  static void SendLin()
{

   static bool read = true;
   uint8_t linTXdata[] = {uint8_t(Power/40), uint8_t(Temperature+40), 0, 8};
   lin.order(orderID, linTXdata, 4, lin2x);
   delay(20);
   lin.response(responseID, linRXdata, 8, lin2x);
   delay(20);
   lin.response(responseID2, linRXdata2, 8, lin2x);
   delay(20);
   CRC = lin.response(responseID, linRXdata, 8, lin2x);
   delay(20);
   CRC2 = lin.response(responseID2, linRXdata2, 8, lin2x);
   delay(20);

     {
     tmpheater = linRXdata[1] - 40;
     udcheater = linRXdata[4] | (linRXdata[5] & 3) << 8;
     powerheater =((linRXdata[5] >> 2) | (linRXdata[6] << 8)) * 20;
     Serial.print("orderID:"); 
     Serial.print(orderID);
     Serial.print(",");
     Serial.print("responseID:"); 
     Serial.print(responseID);
     Serial.print(",");
     //Serial.print("Temp:");
     //Serial.print(tmpheater);
     //Serial.print(",");
     //Serial.print("Udc:");
     //Serial.print(udcheater);
     //Serial.print(",");
     //Serial.print("Power:");
     //Serial.println(powerheater);
     Serial.print("CRC:"); 
     Serial.println(CRC);
     for (int i = 0; i < 8; i++) { // display the raw data
     Serial.print(linRXdata[i]);
     Serial.print(",");
     Serial.println();

     }
     Serial.print("orderID:"); 
     Serial.print(orderID);
     Serial.print(",");
     Serial.print("responseID2:"); 
     Serial.print(responseID2);
     Serial.print(",");
     Serial.print("CRC2:"); 
     Serial.println(CRC2);
     for (int i = 0; i < 8; i++) { // display the raw data
     Serial.print(linRXdata2[i]);
     Serial.print(",");
     Serial.println();

   read = !read;
  }
 }
}

The wakeup signals were from an OpenInverter Forum comment, but I get the same results with or without these lines commented out.

unlike the Volvo HVH, on this heater with the above code I am getting some consistent results:

Without 12V power to the heater, I get the same response across ALL ids:

Code:
0,0,88,24,0,32,8,0

with the heater receiving 12V, the readout remains the same for all IDs except for 23 and 39, which give out:

Code:
responseID:23,CRC:255
0,32,0,0,72,32,8,0

responseID:39,CRC:255
123,62,63,0,0,0,0,0

When I add the lin.order and use the last databyte with an 8, ID 23 changes to:

Code:
8,96,0,15,240,32,8,0

I wonder if this heater shows active with an 8 instead of a 4.

When I run all order IDs against ID 23, whenever I change the lin.order final databyte from 8 to a 0 or vice versa, at ID 34, the change kicks in and and it sticks from there. When I use 35 instead of 34 it kind of still works, but gives a 9 instead of an 8 in the first byte response of 23 and also did not switch off 0 after a change to 8, but when I changed to 34 I get consistent results. I have not tested with HV yet.

However, no matter what I do, the CRC remains at 255 for all response IDs. I am trying to figure out why and how it is possible to be getting a lin bus response at 23 and 39 and being able to get the change in ID 39 with the lin.order but still have it return a 255. On the Volvo heater, I always got a 0 at ID 39.

If you have any thoughts or ideas to troubleshoot this, let me know.
 
Last edited:
Hi Jordan, it seems ID 23 is the register to focus on first.
However, no matter what I do, the CRC remains at 255 for all response IDs.
Yes, that's weird.
In order to verify whether your code may have an issue, I used my homebrew LIN-slave setup.
I fabricated that setup a few weeks ago to verify the claim that there is a (now confirmed and resolvable) bug in the LIN library.
You did comment out line 463 of lin-bus.cpp like this //_stream->read();, didn't you?

With the LIN-slave I have full control over what is returned to the LIN-master.
So I modified my LIN-slave code to respond to ID 23 with 8 bytes 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 and CRC 0x02.
And your code shows that response correctly:
1711880230069.png


Allright, so we can rule out your code.

Now, what I'm wondering is whether the HVH50 sends out a classic checksum instead of an enhanced checksum? I have read about LIN V2.x slaves that do send out classic checksums ("for compatibility reasons"). I will look into that.

Paul
 
Last edited:
OK. I modified my LIN-slave to respond with a classic checksum on 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, being CRC 0x99 [153 decimal].

Now when I modify this line of your code CRC = lin.response(responseID, linRXdata, 8, lin2x); to CRC = lin.response(responseID, linRXdata, 8, lin1x);, the serial monitor shows the correct data & CRC response again:

1711886478712.png


I'm curious to hear if you see a non-255 CRC with this 1 line change.

Paul
 
You did comment out line 463 of lin-bus.cpp like this //_stream->read();, didn't you?

Yes, I did this.

I removed the lin2x from the lin response commands to test out classic checksum and it did not change the response.

Could it possibly be the delay timing? I have been using either a delay (10) or delay (20) because of the LDF file schedules:

Code:
Node_attributes {
  HVH_100{
    LIN_protocol = "2.0" ;
    configured_NAD = 0x5F ;
    product_id = 0x0, 0x0, 0 ;
    response_error = PTC_ResponseError ;
    P2_min = 10 ms ;
    ST_min = 10 ms ;
    configurable_frames {
      HV_He_01 = 0x401C ; //Master configurable frame
      HV_Hs_01 = 0x4030 ; //Slave ID1 configurable frame
      HV_Hs_02 = 0x400C ; //Slave ID2 configurable frame
    }
  }
}

Schedule_tables {
 ST1 {
    HV_He_01 delay 20 ms ; //Master
    HV_Hs_01 delay 20 ms ; //Slave ID1
    HV_Hs_02 delay 20 ms ; // Slave ID2
  }

I tested using 0-7 for the fourth databyte on ID 34 and it always returns a 0 until I use 8. Interestingly enough, once the 8 is being received, I have to send a fourth databyte 0 on ID34 to get it back to 0 and no other ID will do that. If this is all correct, it makes me think that one the heater is told to be ON, it requires and OFF from the same ID . . . again making a lot of assumptions!
 
Not sure if it matters, but when I turn off 12V power to the heater and then turn it back on, here is the reading on ID 23 over the first few seconds:

Code:
orderID:34,responseID:23,CRC:255
254,255,255,255,105,32,8,0

orderID:34,responseID:23,CRC:255
0,32,0,0,72,32,8,0

orderID:34,responseID:23,CRC:255
136,33,252,15,178,32,8,0

orderID:34,responseID:23,CRC:255
8,32,0,15,49,32,8,0

I only mention this because the LDF file indicates that 254 is the initial value for HVH100 response and 255 is the initial response for the power and temp. Again, not sure if this helps us or not to see if we are in the right ball park.

Code:
  KL_HV_PTC_soll_encoding {
    physical_value, 0, 100, 1, 0, "Unit_PerCent" ;
    logical_value, 254, "Init" ;
    logical_value, 255, "Failure" ;

Hear is the info from the HVH100 LDF for the response frame (assuming it is ID23 for me).

Code:
HV_Hs_01: 48, HVH_100, 8 {
    PTC_HV_I_ist, 0 ;   // databyte 1  (on or off)
    PTC_HV_ERR, 8 ;  // databyte 2
    PTC_HV_Status_PTC, 16 ; // databyte 3
    PTC_Status_UBatt, 19 ; // databyte 3
    PTC_ResponseError, 21 ; // databyte 3
    PTC_TimeOut_Failure, 22 ; // databyte 3
    PTC_HV_Err_Heating Circuit_1, 24 ; // databyte 4
    PTC_HV_Err_Heating Circuit_2, 25 ; // databyte 4
    PTC_HV_Err_Heating Circuit_3, 26 ;// databyte 4
    PTC_HV_Err_Leckagestrom, 27 ; // databyte 4
    PTC_HV_Err_Leakage Flow, 28 ; // databyte 4
    PTC_HV_Err_Temperature, 29 ; // databyte 4
    PTC_HV_Err_intern, 30 ; // databyte 4
    PTC_UBatt, 32 ; // databyte 5
    PTC_Temp protection_PCB, 40 ; // databyte 6 ( always 32)
    PTC_HV_Heating medium_Sensor_1, 48 ; // databyte 7 ( always 8)
    PTC_HV_Heating medium_Sensor_2, 56 ; // databyte 8  (always 0)
 
Last edited:
I removed the lin2x from the lin response commands to test out classic checksum and it did not change the response.
OK, at least we can rule out that checksum question for now.
Could it possibly be the delay timing? I have been using either a delay (10) or delay (20) because of the LDF file schedules:
Perhaps, but I don't know enough about those LIN timings whether it's mandatory timings or minimum timings.
I tested using 0-7 for the fourth databyte on ID 34 and it always returns a 0 until I use 8. Interestingly enough, once the 8 is being received, I have to send a fourth databyte 0 on ID34 to get it back to 0 and no other ID will do that. If this is all correct, it makes me think that one the heater is told to be ON, it requires and OFF from the same ID . . . again making a lot of assumptions!
It certainly looks like ID 34 is the "Write power" command register. Writing an "8" for ON and writing an "0" for OFF sounds reasonable.
And ID 23 seems to be the "Read Meas" register.

Paul
 
Lin.read is a "private" function in the library, as defined in lin-bus.h:
C++:
private:
  Stream* _stream;
  void send_break();
  void breaklength(uint8_t length);
  void breaklength_35(uint8_t length);
  void breaklength_LP(uint8_t length);
  void breaklength_LC(uint8_t length, HardwareSerial* stream);
  int addrParity(int PID);
  volatile byte dataChecksum (volatile byte* message, int length, uint16_t sum);
  void write(byte PID, byte* message, int length, int checksumtype = 1);
  int read(byte PID, byte message[], int length, int checksumtype = 1);
You are not supposed to use "private" functions, only these "public" functions:
C++:
  void begin(HardwareSerial* stream, uint16_t baudrate, uint8_t break_characters = 13);
  void order(byte PID, byte* message, int length, int checksumtype = 1);
  int response(byte PID, byte* message, int length, int checksumtype = 1);

Paul
 
Back
Top