Thank you tonton81,
I am so stupid, I could not see the whole codes but stuck around CAN setting.
must correct basic logic coding part first before asking question.....
Thank you tonton81,
I am so stupid, I could not see the whole codes but stuck around CAN setting.
must correct basic logic coding part first before asking question.....
Hello tonton81,
We have been using Teensy 3.X boards for a while now with Collin80's FlexCan_Library. In his library there is a CANListener class that has a frameHandler function that can be declared in a user defined class so that the user's own library can have access to the received frames.
We have just started using a Teensy 4.0 on our setup and we had the need to switch to your library which from what I read here it is really well maintained!
In order to implement a similar behaviour to what we had before I think that we should use one of the ext_output functions. I have checked your TeensyCan library also but I can't seem to understand how should I implement this in my own class.
Below is the way we used to do it with Collin80's library:
Then on the main sketch we did something like this:Code:class TSB_CAN : public CANListener { public: TSB_CAN(); void receive_Message(CAN_message_t &frame); bool frameHandler(CAN_message_t &frame, int mailbox, uint8_t controller); //overrides the parent version so we can actually do something }; bool TSB_CAN::frameHandler(CAN_message_t &frame, int mailbox, uint8_t controller) { //printFrame(frame, mailbox); receive_Message(frame); return true; } void TSB_CAN::receive_Message(CAN_message_t &frame) { switch(frame.id) { case 0x609: //save message payload break; } }
Code:TSB_CAN canMessageHandler; void setup(void){ Can0.begin(1000000); // Inicialise CAN BUS with 1 Mb/s speed Can0.attachObj(&canMessageHandler); canMessageHandler.attachGeneralHandler(); } void loop(void) { // If you want to print something that is avalible on the CAN Bus check the CAN_TSB.h to see the structer used. // As an example lets print the battery current Serial.println(canMessageHandler.device.variable); }
just add this to your library after including flexcan header:
and enable MB/FIFO interrupts in setup, the function will receive all frames, unless you use filters, then the mailbox/fifo will only stream your filtered IDsCode:void ext_output1(const CAN_message_t &msg) { //do whatever with message }
If it's for a library, thats the way to go. If you are doing it from the sketch like above, either works. you can use onRecieve to set your sketch callback, but the background handler is always unused until you define it like i mentioned, either in sketch or library
don't forget, to differentiate which bus the frame came from, use msg.bus and it will return 1,2 or 3, depending on what you setup (CAN1, CAN2, CAN3)
What if I want that function to be part of my own C++ class so that I can do an Object Oriented Callback Interface? Is there any possibility to do so with this library?
Last edited by tecnico.solarboat; 01-23-2021 at 02:49 PM.
sorry i dont understand how that works, but maybe i can look at how Collin did it and see if i can port it over
If you can have a look that would be nice, check this example.
Can you try this patch? Originally it only supported 31 mailboxes max, as Teensy 3.x had 16 mailboxes, bit 31 was used for the global handler. Now it should support up to 64 mailboxes with a general handler.
Also if the mailbox handler was specified the generalhandler wouldn't fire, in case you did specify both ways, both will activate now.
Serial monitor:
Code:ID: FADE Data: 80 40 0 3 7 1 1 <------------------- CANListener MB 99 OVERRUN: 0 LEN: 7 EXT: 1 TS: 58671 ID: FADE Buffer: 80 40 0 3 7 1 1 <------- FlexCAN_T4 callback ID: FADE Data: 81 0 1 0 9 1 1 MB 99 OVERRUN: 0 LEN: 7 EXT: 1 TS: 5044 ID: FADE Buffer: 81 0 1 0 9 1 1 ID: FADE Data: 80 80 7 4 0 1 1 MB 99 OVERRUN: 0 LEN: 7 EXT: 1 TS: 53021 ID: FADE Buffer: 80 80 7 4 0 1 1 ID: FADE Data: 80 40 0 A 0 1 1 MB 99 OVERRUN: 0 LEN: 7 EXT: 1 TS: 7888 ID: FADE Buffer: 80 40 0 A 0 1 1 ID: FADE Data: 80 80 0 A 0 1 1 MB 99 OVERRUN: 0 LEN: 7 EXT: 1 TS: 36067 ID: FADE Buffer: 80 80 0 A 0 1 1 ID: FADE Data: 80 80 2 0 8 1 1 MB 99 OVERRUN: 0 LEN: 7 EXT: 1 TS: 2446 ID: FADE Buffer: 80 80 2 0 8 1 1 ID: FADE Data: 80 40 9 0 1 1 1 MB 99 OVERRUN: 0 LEN: 7 EXT: 1 TS: 23012 ID: FADE Buffer: 80 40 9 0 1 1 1 ID: FADE Data: 81 0 8 2 0 1 1 MB 99 OVERRUN: 0 LEN: 7 EXT: 1 TS: 35028 ID: FADE Buffer: 81 0 8 2 0 1 1
First of all thank you very much for you willingness to help! I can confirm that this works in a Teensy 3.5 with a Kvaser generating random CAN data. I have another Teensy 3.2 board with me but the transceiver on it is not working... When I'm able to test it with other boards I can let you know, but I'm pretty sure that if it works on 3.5 and 4.X (I suppose you test on that) it will work on the rest of them as well.
Can you explain what is the diference between using FIFO and Mailboxes? I think that with FIFO we can assume that the messages are in order. On the other hand with MB this is not guaranteed. Is this line of though right? I have tested this patched version with both and it worked with both also.
Will this patched version be added to the TeensyDuino?
On another note I noticed that the library allows to define CAN1 on Teensy 3.2 and 3.5, I think that the following code (FlexCAN_T4 line 53) should be made in 2 ifs one for 3.2 and 3.5 and another for the 3.6:
Once again THAK YOU VERY MUCH!!Code:#if defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__) if ( _bus == CAN1 ) _CAN1 = this; if ( _bus == CAN0 ) _CAN0 = this; #endif
for the define, thats just a pointer, _CAN1 wont compile on T3.2 anyways
FIFO allows ordered receptions, mailboxes can receive in any order as long as a slot is empty. you can have FIFO and mailboxes combined for example, assign a mailbox to receive a filtered ID in it's own callback, so a separate callback will fire when your critical frame is received. with fifo alone you have only 1 callback essentially. In either case Teensy is fast enough to receive all critical frames without filters unless you are in non interrupt mode or your loop code is causing delays..
At least for me, with Paltformio if I declare
it compiles for Teensy 3.2 and 3.5 but it obviously does not do anything.Code:FlexCAN_T4<CAN1, RX_SIZE_256, TX_SIZE_16> Can0;
Thank you very much for the explanation!
Indeed, it compiled in the arduino IDE as well I see, I just don't wanna add much code bloat. Going ahead after compilation should result in undefined behaviour though should the wrong one be used. I suppose a cleaner solution is to ifdef and give a warning if _bus is not identified in hardware rather than sprinkle more ifdef else's all over the place
You can try this?
added checks:
Code:#if defined(__MK20DX256__) || defined(__MK64FX512__) static_assert(_bus == CAN0, "Only CAN0 works on Teensy 3.2/3.5"); #endif #if defined(__MK66FX1M0__) static_assert(_bus == CAN0 || _bus == CAN1, "Only CAN0 & CAN1 works on Teensy 3.6"); #endif #if defined(__IMXRT1062__) static_assert(_bus == CAN1 || _bus == CAN2 || _bus == CAN3, "Only CAN1 & CAN2 & CAN3 works on Teensy 4.0/4.1"); #endif
It works as expected! Both on Teensy 3.2 and 3.5.
Compiler throws:
Only CAN0 works on Teensy 3.2/3.5
static_assert(_bus == CAN0, "Only CAN0 works on Teensy 3.2/3.5");
^
*** [.pio/build/teensy35/src/main.cpp.o] Error 1
By the way, trying to declare CAN2 on T3.6 although it gives an error it is not the same fancy error as in the other case. But for me it is fine, as long as we get an error it's fine. It just says that "CAN2 was not declared in this scope".
Yeah, that would require defining CAN2, CAN3, asserts should work as is:
Just added em, try to break CANListener and if you can't I will update it on github :PCode:typedef enum CAN_DEV_TABLE { #if defined(__IMXRT1062__) CAN0 = (uint32_t)0x0, <------------- This was added to support the static_assert instead of a compiler crash saying it wasn't in scope for T4.x CAN1 = (uint32_t)0x401D0000, CAN2 = (uint32_t)0x401D4000, CAN3 = (uint32_t)0x401D8000 #endif #if defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__) CAN0 = (uint32_t)0x40024000, CAN1 = (uint32_t)0x400A4000, <-------- CAN2 could be added after here like above, like so CAN2 = (uint32_t)0x0, CAN3 = (uint32_t)0x0, #endif } CAN_DEV_TABLE;
Last edited by tonton81; 01-23-2021 at 09:41 PM.
Thank you, tonton81,
Since I could not do a good job with FIFO, I went back to mail box stuff anyway.
So far I can send and receive OBD CAN message with extended 29 bit CAN communication.
Nevertheless, my goal is not getting PID parameters such as engine speed, engine coolant temperature, but longer messages which requires multi-frame (ISO-15765-2).
In order to handle multi-frame stuff, Teensy has to receive a multiple consecutive frames after sending flow control from Teensy.
Therefore I probably have to go back to FIFO again. I will read through FlexCAN_T4 library and try to understand how to use.
Anyway following code works with my vehicle.
Code:// 29bit extended OBD CAN Sketch // get Service$01 PID$0C Engine Speed // #include <FlexCAN_T4.h> #include <SPI.h> #include <Wire.h> #include <Adafruit_GFX.h> #include <Adafruit_SSD1306.h> #include <ADC.h> #define SCREEN_WIDTH 128 // OLED display width, in pixels #define SCREEN_HEIGHT 64 // OLED display height, in pixels // Declaration for an SSD1306 display connected to I2C (SDA, SCL pins) #define OLED_RESET 4 // Reset pin # (or -1 if sharing Arduino reset pin) Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); #define NUMFLAKES 10 // Number of snowflakes in the animation example FlexCAN_T4<CAN2, RX_SIZE_256, TX_SIZE_16> can2; #define LOGO_HEIGHT 16 #define LOGO_WIDTH 16 static const unsigned char PROGMEM logo_bmp[] = { B00000000, B11000000, B00000001, B11000000, B00000001, B11000000, B00000011, B11100000, B11110011, B11100000, B11111110, B11111000, B01111110, B11111111, B00110011, B10011111, B00011111, B11111100, B00001101, B01110000, B00011011, B10100000, B00111111, B11100000, B00111111, B11110000, B01111100, B11110000, B01110000, B01110000, B00000000, B00110000 }; int engineCoolantTemp = 0; // Save the data here int engineRPM = 0;// Save the data here void setup(){ while (!Serial && millis() < 5000); // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3D for 128x64 delay(200); Serial.println(F("SSD1306 allocation failed")); for(;;); // Don't proceed, loop forever } Serial.begin(115200); can2.begin(); can2.setBaudRate(500000); //can2.setFIFOFilter(REJECT_ALL); //can2.setFIFOFilter(0, 0x18DAF111, EXT); // Extended CANID Target address F1(Tester), Sender 11(ENG ECU) can2.setMB(MB10,TX,EXT); // Set mailbox as transmit can2.setMB(MB4,RX,EXT); // Set mailbox as receiving extended frames. can2.setMaxMB(16); can2.mailboxStatus(); // view current configuration //can2.enableFIFO(); //can2.enableFIFOInterrupt(); can2.enableMBInterrupt(MB4); can2.onReceive(canSniff); } const long loopDelay1 = 50; // Make a request every 500ms unsigned long timeNow1 = 0; void loop(){ can2.events(); if (millis() > timeNow1 + loopDelay1) { timeNow1 = millis(); canTx_OBD(); // Query data from CAN BUS via OBD //canTx_UDS(); // Query data from CAN BUS via UDS } } void canSniff (const CAN_message_t &msg){ // Global callback to catch any CAN frame coming in if (msg.buf[1] == 0x41){ if (msg.buf[2] ==0x0C){ // SID$01 PID$0C Engine Speed //engineCoolantTemp = msg.buf[3] - 40; // Offset -40(degC) engineRPM = (msg.buf[3]*0x100 + msg.buf[4]) /4; Serial.println(" "); //Serial.printf("OBD: Engine Coolant Temp: %d c", engineCoolantTemp); Serial.printf("OBD: Engine Speed: %d rpm", engineRPM); } } display.setTextColor(WHITE); display.clearDisplay(); display.setTextSize(1); // Normal 1:1 pixel scale display.setTextColor(SSD1306_WHITE); // Draw white text display.setCursor(0, 0); // Start at top-left corner display.println(F("CAN_ID:")); display.setCursor(60,0); display.setTextColor(WHITE); display.print(msg.id, HEX); for ( uint8_t i = 0; i < 8; i++ ) { display.setCursor(15*i ,15); display.print(msg.buf[i],HEX); Serial.print(" "); } display.setTextSize(2); // Normal 1:1 pixel scale display.setCursor(10, 35); //display.print(engineCoolantTemp,DEC); display.print(engineRPM, DEC); display.setCursor(70, 35); //display.print("degC"); display.print("RPM"); display.display(); } void canTx_OBD(){ // Request function to ask for Engine Coolant Temp via OBD request CAN_message_t msgTx, msgRx; msgTx.buf[0] = 0x02; // Data Length 2byte msgTx.buf[1] = 0x01; // Service$01 msgTx.buf[2] = 0x0C; // PID $05 Engine Coolant Temperature msgTx.buf[3] = 0x55; // Padding msgTx.buf[4] = 0x55; msgTx.buf[5] = 0x55; msgTx.buf[6] = 0x55; msgTx.buf[7] = 0x55; msgTx.len = 8; // number of bytes in request //msgTx.flags.extended = 0; // 11 bit header, not 29 bit msgTx.flags.extended = 1; // 29 bit header, not 11 bit msgTx.flags.remote = 0; //msgTx.id = 0x7E0; // request header for OBD // Physical Addressing Request to Engine ECU msgTx.id = 0x18DB33F1; // request header for OBD Functional Addressing request to all emission related ECUs. can2.write(msgTx); Serial.println("canTx_OBD REQ sent"); } void canTx_UDS(){ // Request function to ask for Engine Coolant Temp via UDS request CAN_message_t msgTx, msgRx; msgTx.buf[0] = 0x03; // Data Length msgTx.buf[1] = 0x22; // SID$22 Request parameter by Data Identifier msgTx.buf[2] = 0xf4; // msgTx.buf[3] = 0x05; // PID$05 is Engine Coolant Temperature msgTx.buf[4] = 0; msgTx.buf[5] = 0; msgTx.buf[6] = 0; msgTx.buf[7] = 0; msgTx.len = 8; // number of bytes in request //msgTx.flags.extended = 0; // 11 bit header, not 29 bit msgTx.flags.extended = 1; // 29 bit header, not 11 bit msgTx.flags.remote = 0; //msgTx.id = 0x7E0; // request header for OBD msgTx.id = 0x18DB33F1; // request header for OBD Functional Addressing request to all emission related ECUs. can2.write(msgTx); Serial.println("canTx_UDS REQ sent"); } void testdrawchar(void) { display.clearDisplay(); display.setTextSize(1); // Normal 1:1 pixel scale display.setTextColor(SSD1306_WHITE); // Draw white text display.setCursor(0, 0); // Start at top-left corner display.cp437(true); // Use full 256 char 'Code Page 437' font // Not all the characters will fit on the display. This is normal. // Library will draw what it can and the rest will be clipped. for(int16_t i=0; i<256; i++) { if(i == '\n') display.write(' '); else display.write(i); } display.display(); delay(2000); }
So it does look like the SDHC basic write speed I've tried with test sketches is better than OK, but only if I keep the file open. The easy method is the too slow method, where you open a file, write, and close it on every write burst.
I would like to be able to get the SD file object to be global, so that I can write to it from various functions. I instantiated the object before the setup() function, and it surprisingly compiled, but it's not accessible by any function. If I instantiate the file in the setup function, which is kind of where it logically belongs, it's not accessible even in the loop(). Any hints on that?
Hi tonton81 - Couple of questions from the FIFO Interrupts example - loop code below.
1. How often does CAN.events() have to be called? I want to put some other code in loop() but it's not clear when things start to go south.
2. What's the purpose of the timeout routine?
3. Why isn't this thread a sticky?
void loop() {
Can0.events();
static uint32_t timeout = millis();
if ( millis() - timeout > 200 ) {
CAN_message_t msg;
msg.id = random(0x1,0x7FE);
for ( uint8_t i = 0; i < 8; i++ ) msg.buf[i] = i + 1;
Can0.write(msg);
timeout = millis();
}
events() dequeues while the interrupt queues. so depending on your delays, if you let the queue build up to max you'll just be tossing frames after. you could also do a while(Can0.events()); and it'll dequeue everything in queue before continuing loop.
timeout means after 200ms the transmit repeats
if you dont want to rely on your loop() code if its got delays, remove the events() call and you will get the messages directly in callback without using the queue method
Hello,
Apologies if this has already been answered but I'm struggling to send or receive when the baud rate is set to 95,000 bps. I've tried all of the clock speeds using setClock (8,16,20,24,...) but still without success. Other speeds such as 33,333 and 500,000 work just fine. I really can't see what I'm doing wrong. Any help would be greatly appreciated. Many thanks!
Code:#include <FlexCAN_T4.h> FlexCAN_T4<CAN2, RX_SIZE_256, TX_SIZE_16> can2; // can2 port FlexCAN_T4<CAN1, RX_SIZE_256, TX_SIZE_16> can1; // can1 port int led = 13; IntervalTimer timer; uint8_t d=0; void setup(void) { pinMode(led, OUTPUT); digitalWrite(led,HIGH); Serial.begin(115200); delay(1000); Serial.println("Teensy 4.0 Triple CAN test"); digitalWrite(led,LOW); can2.begin(); can2.setClock(CLK_60MHz); can2.setBaudRate(95000); // 95kbps data rate can2.enableFIFO(); can2.enableFIFOInterrupt(); can2.onReceive(FIFO, canSniff20); can2.mailboxStatus(); can1.begin(); can2.setClock(CLK_60MHz); can1.setBaudRate(95000); // 95kbps data rate can1.enableFIFO(); can1.enableFIFOInterrupt(); can1.onReceive(FIFO, canSniff20); can1.mailboxStatus(); timer.begin(sendframe, 500000); // Send frame every 500ms } void sendframe() { CAN_message_t msg2; msg2.id = 0x401; for ( uint8_t i = 0; i < 8; i++ ) { msg2.buf[i] = i + 1; } msg2.buf[0] = d++; msg2.seq = 1; can2.write(MB15, msg2); // write to can2 msg2.id = 0x402; msg2.buf[1] = d++; can1.write(msg2); // write to can1 } void canSniff20(const CAN_message_t &msg) { // global callback Serial.print("T4: "); Serial.print("MB "); Serial.print(msg.mb); Serial.print(" OVERRUN: "); Serial.print(msg.flags.overrun); Serial.print(" BUS "); Serial.print(msg.bus); Serial.print(" LEN: "); Serial.print(msg.len); Serial.print(" EXT: "); Serial.print(msg.flags.extended); Serial.print(" REMOTE: "); Serial.print(msg.flags.remote); Serial.print(" TS: "); Serial.print(msg.timestamp); Serial.print(" ID: "); Serial.print(msg.id, HEX); Serial.print(" IDHIT: "); Serial.print(msg.idhit); Serial.print(" Buffer: "); for ( uint8_t i = 0; i < msg.len; i++ ) { Serial.print(msg.buf[i], HEX); Serial.print(" "); } Serial.println(); } void loop() { can2.events(); can1.events(); }
Try this:
I made an ESP32 version of this CAN library and the closest match it shows on the ESP32 is 95238. So when I put that on teensy @ 60MHz peripheral clock, they're both talking to each otherCode:can1.setClock(CLK_60MHz); can1.setBaudRate(95238);
Last edited by tonton81; 01-29-2021 at 03:20 PM.
Instead of using MailBox, I started using FIFO and it seems to be working.
Therefore I started to handle with multi-frame messages. Since my vehicle does not support VIN (Vehicle Identification Number), Calibration ID is selected for the beginning.
Calibration ID is Service$09 InfoType$04. Calibration ID consists of 16 ASCII characters and response message from ECU requires multi-frame because of the message length.
With the Vehicle Spy software ISO-15765-2 option usage, Teensy can receive multi-frame message, but with the actual vehicle Teensy cannot. Teensy can only receive First Frame response message and Teensy sends Flow Control but cannot receive Consecutive message from the ECU. My FIFO handling for the consecutive message may be wrong.
Code:/********************************************************************************* * Teensy4.0 + MCP2562 CAN Transceiver + Adafruit OLED * 500kbps CAN communication speed * 2021 JAN 30 * * Service$09 InfoType$04 CALID Read * * ********************************************************************************/ #include <FlexCAN_T4.h> #include <SPI.h> #include <Wire.h> #include <Adafruit_GFX.h> #include <Adafruit_SSD1306.h> #include <ADC.h> #include <ADC_util.h> #include <Bounce.h> // Bounce library makes button change detection easy const int channel = 1; int Req_msgTxid; int val6, val7, val8, val9; int Stat_FC=0; // Flow Control request status int disp_mode; int seq_Num=0; int CF_Num; int CF_Max; int sid09inftyp=0; int f_sid09calid_multi; String str_A; String dtc_buf6pre; String calid_buf1, calid_buf2, calid_buf3, calid_buf4, calid_buf5, calid_buf6, calid_buf7, calid_buf8; String calid_buf9, calid_buf10, calid_buf11, calid_buf12, calid_buf13, calid_buf14, calid_buf15, calid_buf16, calid_buf17; String cal_buf1, cal_buf2, cal_buf3, cal_buf4, cal_buf5, cal_buf6, cal_buf7, cal_buf8, cal_buf9, cal_buf10; String cal_buf11,cal_buf12, cal_buf13, cal_buf14, cal_buf15, cal_buf16; // CALID is maximum 16 ASCC characters. #define SCREEN_WIDTH 128 // OLED display width, in pixels #define SCREEN_HEIGHT 64 // OLED display height, in pixels // Declaration for an SSD1306 display connected to I2C (SDA, SCL pins) #define OLED_RESET 4 // Reset pin # (or -1 if sharing Arduino reset pin) Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); #define NUMFLAKES 10 // Number of snowflakes in the animation example unsigned long curr, prev, next, interval; #define LOGO_HEIGHT 16 #define LOGO_WIDTH 16 FlexCAN_T4<CAN1, RX_SIZE_256, TX_SIZE_16> can1; FlexCAN_T4<CAN2, RX_SIZE_256, TX_SIZE_16> can2; CAN_message_t msg; static const unsigned char PROGMEM logo_bmp[] = { B00000000, B11000000, B00000001, B11000000, B00000001, B11000000, B00000011, B11100000, B11110011, B11100000, B11111110, B11111000, B01111110, B11111111, B00110011, B10011111, B00011111, B11111100, B00001101, B01110000, B00011011, B10100000, B00111111, B11100000, B00111111, B11110000, B01111100, B11110000, B01110000, B01110000, B00000000, B00110000 }; void setup(void) { prev = 0; // Initialize previous execution time interval = 1000; // reset execution interval // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3D for 128x64 Serial.println(F("SSD1306 allocation failed")); for(;;); // Don't proceed, loop forever } while (!Serial && millis() < 5000); Serial.begin(115200); can2.begin(); can2.setBaudRate(500000); //can2.setMBFilter(REJECT_ALL); can2.setFIFOFilter(REJECT_ALL); can2.setFIFOFilter(0, 0x18DAF111, EXT); // Extended CANID Target address F1(Tester), Sender 11(ENG ECU) can2.setMB(MB10,TX); // Set mailbox as transmit can2.setMaxMB(16); can2.mailboxStatus(); // view current configuration can2.enableFIFO(); can2.enableFIFOInterrupt(); //can2.enableMBInterrupt(MB4); can2.onReceive(FIFO, canSniff); } const long loopDelay1 =500; unsigned long timeNow1 = 0; unsigned long timeNow2 = 0; void loop() { /* * Requesting Serivice Identifier routine */ if (millis() > timeNow1 + loopDelay1) // Send the request every 100ms { timeNow1 = millis(); if(Stat_FC ==0){ can_SID09_TX(); } } if(Stat_FC ==1){ delay(10); can_FC_TX(); } else if(Stat_FC ==2){ // consider doing something } if ( can2.read(msg)) { Serial.print("CAN2 "); Serial.print("MB: "); Serial.print(msg.mb); Serial.print(" ID: 0x"); Serial.print(msg.id, HEX ); Serial.print(" EXT: "); Serial.print(msg.flags.extended ); Serial.print(" LEN: "); Serial.print(msg.len); Serial.print(" DATA: "); for ( uint8_t i = 0; i < 8; i++ ) { Serial.print(msg.buf[i]); Serial.print(" "); } Serial.print(" TS: "); Serial.println(msg.timestamp); } } void testdrawchar(void) { display.clearDisplay(); display.setTextSize(1); // Normal 1:1 pixel scale display.setTextColor(SSD1306_WHITE); // Draw white text display.setCursor(0, 0); // Start at top-left corner display.cp437(true); // Use full 256 char 'Code Page 437' font // Not all the characters will fit on the display. This is normal. // Library will draw what it can and the rest will be clipped. for(int16_t i=0; i<256; i++) { if(i == '\n') display.write(' '); else display.write(i); } display.display(); } // Response Message process routine // void canSniff (const CAN_message_t &msg){ // Global callback - prints out the received message in HEX + saves TW into a global variable if(msg.id == 0x18DAF111){ Serial.println(" "); Serial.print("MB: "); Serial.print(msg.mb); Serial.print(" ID: 0x"); Serial.print(msg.id, HEX); Serial.print(" EXT: "); Serial.print(msg.flags.extended); Serial.print(" LEN: "); Serial.print(msg.len); Serial.print(" DATA: "); for (uint8_t i = 0; i < 8; i++) { Serial.print(msg.buf[i], HEX); Serial.print(" "); } } if (msg.buf[0] > 0x0F & msg.buf[2] == 0x49){ // Service$09 Positive Response message and First Frame. CF_Max = 2; f_sid09calid_multi = 1; // SID$09 calid process if(msg.buf[3] == 4){ // Means Info Type == 02 calid. InfoType == 04 CALID. // ignore msg.buf[4]. because this buffer is always 0x01.Number of data item. calid_buf1 = msg.buf[5]; calid_buf2 = msg.buf[6]; calid_buf3 = msg.buf[7]; // calid buffer is fixed 17 byte. Stat_FC = 1; } } else if(f_sid09calid_multi ==1 & msg.buf[0] > 0x20 & Stat_FC ==2 ){ // Means CF: Consecutive Frame and Buf[0] is sequence number seq_Num = msg.buf[0]; // if(seq_Num == 0x21){ // Sequence Number is 1. calid_buf4 = msg.buf[1]; calid_buf5 = msg.buf[2]; calid_buf6 = msg.buf[3]; calid_buf7 = msg.buf[4]; calid_buf8 = msg.buf[5]; calid_buf9 = msg.buf[6]; calid_buf10 = msg.buf[7]; CF_Num = 1; } if(seq_Num == 0x22 ){ // Sequence Number is 2. calid_buf11 = msg.buf[1]; calid_buf12 = msg.buf[2]; calid_buf13 = msg.buf[3]; calid_buf14 = msg.buf[4]; calid_buf15 = msg.buf[5]; calid_buf16 = msg.buf[6]; calid_buf17 = msg.buf[7]; CF_Num = 2; } if( CF_Num == CF_Max){ if(Stat_FC == 2){ Stat_FC=0; CF_Num = 0; f_sid09calid_multi = 0; } } } if(msg.id == 0x18DAF111){ display.setTextColor(WHITE); display.clearDisplay(); display.setTextSize(1); // Normal 1:1 pixel scale display.setTextColor(SSD1306_WHITE); // Draw white text display.setCursor(0, 0); // Start at top-left corner display.println(F("CAN_ID:")); display.setCursor(60,0); display.setTextColor(WHITE); display.print(msg.id, HEX); } for ( uint8_t i = 0; i < 8; i++ ) { display.setCursor(15*i ,15); display.print(msg.buf[i],HEX); Serial.print(" "); } display.display(); display.setCursor(0, 30); display.print(calid_buf1); display.setCursor(6, 30); display.print(calid_buf2); display.setCursor(12, 30); display.print(calid_buf3); display.setCursor(18, 30); display.print(calid_buf4); display.setCursor(24, 30); display.print(calid_buf5); display.setCursor(30, 30); display.print(calid_buf6); display.setCursor(36, 30); display.print(calid_buf7); display.setCursor(42, 30); display.print(calid_buf8); display.setCursor(48, 30); display.print(calid_buf9); display.setCursor(54, 30); display.print(calid_buf10); display.setCursor(60, 30); display.print(calid_buf11); display.setCursor(66, 30); display.print(calid_buf12); display.setCursor(72, 30); display.print(calid_buf13); display.setCursor(78, 30); display.print(calid_buf14); display.setCursor(84, 30); display.print(calid_buf15); display.setCursor(90, 30); display.print(calid_buf16); //display.setCursor(96, 30); //display.print(calid_buf17); display.display(); } void can_SID09_TX(){ // Sendo a request to get calid from ECU CAN_message_t msgTx, msgRx; msgTx.buf[0] = 0x02; msgTx.buf[1] = 0x09; // SID$09 Request Info Type$02 calid msgTx.buf[2] = 0x04; // 02 is Info Type $02 CALID $04 msgTx.buf[3] = 0x55; // 0x55 is padding msgTx.buf[4] = 0x55; msgTx.buf[5] = 0x55; msgTx.buf[6] = 0x55; msgTx.buf[7] = 0x55; msgTx.len = 8; // number of bytes in request msgTx.flags.extended = 1; // 11 bit header, not 29 bit msgTx.flags.remote = 0; //msgTx.id = 0x7E0; // requesting Service$09 use only 7E0 for testing Toyota //msgTx.id = 0x18DA11F1; // Honda msgTx.id = 0x18DB33F1; can2.write(msgTx); } void can_FC_TX(){ // Flow Control Command CAN_message_t msgTx, msgRx; msgTx.buf[0] = 0x30; // Flow Control msgTx.buf[1] = 0x00; // Block Size msgTx.buf[2] = 0x00; // STMin msgTx.buf[3] = 0x00; // Padding msgTx.buf[4] = 0x00; msgTx.buf[5] = 0x00; msgTx.buf[6] = 0x00; msgTx.buf[7] = 0x00; msgTx.len = 8; // number of bytes in request //msgTx.flags.extended = 0; // 11 bit header, not 29 bit msgTx.flags.extended = 1; // 29 bit header, not 11 bit msgTx.flags.remote = 0; //msgTx.id = 0x7E0; // request header for OBD // Physical Addressing Request to Engine ECU msgTx.id = 0x18DB33F1; // request header for OBD Functional Addressing request to all emission related ECUs. can2.write(msgTx); Stat_FC = 2; // Flow Control sent //Serial.println("canTx_OBD FC sent"); }