Skip to content
This repository has been archived by the owner on Jan 10, 2025. It is now read-only.

Commit

Permalink
multiple filters, parsing and decoding, and refactoring code
Browse files Browse the repository at this point in the history
This commit is comprised of three major parts
	1.) Multiple filters enabled
	2.) parsing function
	3.) Decoding function

Multiple filters
	including multiple filters is rather straightforward. All you need to do is reinitialize the CAN filter structure but change the filter bank you are using. To do this is rather simple and I could have done it manually for all IDs but It would have taken a lot of space. So, in order to make the code easier I went ahead and made a function that takes in two different parameters. The first parameter is filter bank number and the second is the extended ID you want to filter. I also made a variable that is called CANIDList which is an array that holds all the IDs.I made this to make to make CAN filtering a little easier on the eyes.

Parsing function
	this function sorts the filtered extended IDs that have passed through the CAN controller. In addition, the function calls another function called canDecodeDataFrame(). This function converts the data frame from each message into either an unsigned integer or a signed integer ( this just depends on the data that is being decoded). After the data is decoded, it is then multiplied by its resolution value  ( you can also divide if you like fractions better). I didn't see any trend in how the resolution was ordered so I multiplied the decoded data manually.

Decoding function
	This is arguably the most important part of this commit. This function utilizes the equation given in the application note to decode all of the data into either an unsigned integer or a signed integer. This function was made to automate the decoding process because I noticed that there were 5 distinct ways the data was stored in a single message. With that in mind, I then created a switch statement that can order decoding based on one of the 5 unique ways data is stored. I couldn't think of any logic that could auto-detect which of the 5 decoding methods were used so I just used a parameter for the function to tell the function which decoding method is needed.

I also used a printf statement to display both 0x0CFFF048 and 0x0CFFF548 on the serial monitor. This is a simple way to show that I'm able to decode data correctly and able to filter more than one ID. For 0X0CFFF048 I utilized ChatGPT to create a single simulated data Frame and sent that data frame to the CAN bus using an Arduino Uno. The data organization in 0x0CFFF048 is referred to in my code as the first unique data organization. This means that there are 4 unique data sets each having a length of 2 bytes. Bytes 1 and 2 are the RPM, bytes 3 and 4 are TPS, bytes 5 and 6 are the Fuel Open Time, and bytes 7 and 8 are the Ignition angle. The simulated value sent under the 0x0CFFF048 ID is [0x20 0x1c 0x2B 0x2 0x9B 0x00 0x9C 0xFF]. Which should read RPM = 7200, TPS = 55.5%, Fuel Open Time = 15.5ms, and Ignition angle = -10 degrees. Luckily when printing the data to the serial monitor, I managed to decode these exact values for this ID. The second ID (0x0CFFF548) is also included because previously we decoded this data frame in person last time and had the data for the battery voltage. This means I can confirm my parsing is correct since I know what the battery voltage value should be.
  • Loading branch information
WilliamLim781 committed Dec 22, 2023
1 parent 177d9f6 commit 200bacf
Showing 1 changed file with 294 additions and 52 deletions.
346 changes: 294 additions & 52 deletions Project/DAQ_System/Program/Src/app.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,10 @@ extern UART_HandleTypeDef huart3;
extern ADC_HandleTypeDef hadc1;

#include "can.h"


extern CAN_HandleTypeDef hcan1;
CAN_TxHeaderTypeDef TxHeader;
CAN_RxHeaderTypeDef RxHeader;
CAN_FilterTypeDef CAN;
CAN_FilterTypeDef CAN_two;
uint32_t canID;


// DFR Custom Dependencies
Expand All @@ -41,61 +37,64 @@ uint32_t canID;
// CAN variables
uint8_t TxData[8] = {0};
uint8_t RxData[8];
uint8_t HexToDecData[8] = {0};
uint32_t TxMailbox;
uint32_t CanID;
float DecodeDataFrame[8] = {0};
bool CANMessageReceivedFlag = false;

/*
this is the CAN ID list for the PE3 8400 which can also be viewed from the link below
https://pe-ltd.com/assets/AN400_CAN_Protocol_C.pdf
the link also tells you what information is inside each of the CAN ID
NOTE: the Id list is in the same order as the application note from top to bottom
*/
constexpr uint32_t CanIDList[16] = {0x0CFFF048, 0x0CFFF148, 0x0CFFF248, 0x0CFFF348,
0x0CFFF448, 0x0CFFF548, 0x0CFFF648, 0x0CFFF748,
0x0CFFF848, 0x0CFFF948, 0x0CFFFA48, 0x0CFFFB48,
0x0CFFFC48, 0x0CFFFD48, 0x0CFFFE48, 0x0CFFD048 };

// CallBack functions


//Can CallBack
//Can CallBack
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan1)
{


if (HAL_CAN_GetRxMessage(hcan1, CAN_RX_FIFO0, &RxHeader, RxData) == HAL_OK)
{
CANMessageReceivedFlag = true;
canID = RxHeader.ExtId;
CanID = RxHeader.ExtId;


}
}

void cppMain() {
// function prototypes

void canFilterSetup(int FilterBankNum, uint32_t FilterExtID );
void canParseDataFrame();
void canDecodeDataFrame(float DecodeDataFrame[],int DataSet );

// Filter initialization
CAN.FilterIdHigh = 0x0CFFF048 >> 13 ;
CAN.FilterIdLow = ((0x0CFFF048 & 0x1FFF) <<3) | CAN_ID_EXT | CAN_RTR_DATA ;
CAN.FilterMaskIdHigh = 0xFFFF;
CAN.FilterMaskIdLow = 0xFFFF;
CAN.FilterFIFOAssignment = CAN_FILTER_FIFO0;
CAN.FilterBank = 10;
CAN.FilterMode = CAN_FILTERMODE_IDMASK;
CAN.FilterScale = CAN_FILTERSCALE_32BIT;
CAN.FilterActivation = CAN_FILTER_ENABLE;
CAN.SlaveStartFilterBank = 13;
HAL_CAN_ConfigFilter(&hcan1,&CAN);
// Filter initialization
CAN_two.FilterIdHigh = 0x0CFFF548 >> 13 ;
CAN_two.FilterIdLow = ((0x0CFFF548 & 0x1FFF) <<3) | CAN_ID_EXT | CAN_RTR_DATA ;
CAN_two.FilterMaskIdHigh = 0xFFFF;
CAN_two.FilterMaskIdLow = 0xFFFF;
CAN_two.FilterFIFOAssignment = CAN_FILTER_FIFO0;
CAN_two.FilterBank = 9;
CAN_two.FilterMode = CAN_FILTERMODE_IDMASK;
CAN_two.FilterScale = CAN_FILTERSCALE_32BIT;
CAN_two.FilterActivation = CAN_FILTER_ENABLE;
CAN_two.SlaveStartFilterBank = 13;
HAL_CAN_ConfigFilter(&hcan1,&CAN_two);

// handling TX message
TxHeader.ExtId = 0x123;
TxHeader.DLC = 8;
TxHeader.IDE = CAN_ID_EXT;
TxHeader.RTR = CAN_RTR_DATA;
TxHeader.TransmitGlobalTime = DISABLE;
void cppMain() {

// initializing all filters
canFilterSetup(1,CanIDList[0]);
canFilterSetup(2,CanIDList[1]);
canFilterSetup(3,CanIDList[2]);
canFilterSetup(4,CanIDList[3]);
canFilterSetup(5,CanIDList[4]);
canFilterSetup(6,CanIDList[5]);
canFilterSetup(7,CanIDList[6]);
canFilterSetup(8,CanIDList[7]);
canFilterSetup(9,CanIDList[8]);
canFilterSetup(10,CanIDList[9]);
canFilterSetup(11,CanIDList[10]);
canFilterSetup(12,CanIDList[11]);
canFilterSetup(13,CanIDList[12]);
canFilterSetup(14,CanIDList[13]);
canFilterSetup(15,CanIDList[14]);
canFilterSetup(16,CanIDList[15]);

HAL_CAN_Start(&hcan1); // starts the CAN bus
HAL_CAN_ActivateNotification( &hcan1, CAN_IT_RX_FIFO0_MSG_PENDING); // activate RX message interrupts
Expand All @@ -117,22 +116,265 @@ void cppMain() {
displacement_inches = lin_pot->DisplacementInches();


printf("\n Percentage: %f", displacement_inches);
//printf("\n Percentage: %f", displacement_inches);

if(CANMessageReceivedFlag){
__disable_irq();
TxData[0] = 1 ;
TxData[1] = 2 ;
TxData[2] = 3 ;
TxData[3] = RxData[3] ;
TxData[4] = RxData[4] ;
TxData[5] = 6 ;
TxData[6] = 0x12 ;
TxData[7] = (RxData[4] * 256 + RxData[3]) * .1;

HAL_CAN_AddTxMessage(&hcan1, &TxHeader,TxData,&TxMailbox);
CANMessageReceivedFlag = false;
canParseDataFrame();
if(CanID == 0x0CFFF048){
printf("\t\t 0x0CFFF048 \n");
printf("\r");
printf("RPM = %.2f ", DecodeDataFrame[0]);
printf("TPS = %.2f ", DecodeDataFrame[2]);
printf("Fuel Open Time = %.2f ", DecodeDataFrame[4]);
printf("Ignition Angle = %.2f \n", DecodeDataFrame[6]);
printf("\r");
}
if(CanID == 0x0CFFF548){
printf("\t\t 0x0CFFF548 \n");
printf("\r");
printf("Battery Volt = %.2f ", DecodeDataFrame[0]);
printf("Air Temp = %.2f ", DecodeDataFrame[2]);
printf("Coolant Temp = %.2f ", DecodeDataFrame[4]);
printf("Temp Type = %.2f \n", DecodeDataFrame[6]);
printf("\r");
}
__enable_irq();

}
}
}


void canFilterSetup(int FilterBankNum, uint32_t FilterExtID ){

// Filter initialization
CAN.FilterIdHigh = FilterExtID >> 13 ;
CAN.FilterIdLow = ((FilterExtID & 0x1FFF) <<3) | CAN_ID_EXT | CAN_RTR_DATA ;
CAN.FilterMaskIdHigh = 0xFFFF;
CAN.FilterMaskIdLow = 0xFFFF;
CAN.FilterFIFOAssignment = CAN_FILTER_FIFO0;
CAN.FilterBank = FilterBankNum;
CAN.FilterMode = CAN_FILTERMODE_IDMASK;
CAN.FilterScale = CAN_FILTERSCALE_32BIT;
CAN.FilterActivation = CAN_FILTER_ENABLE;
CAN.SlaveStartFilterBank = 17;
HAL_CAN_ConfigFilter(&hcan1,&CAN);
}

void canParseDataFrame(){

/*
*
the table below demonstrates the organization of data in each data type. This is specifically used for the canDecodeDataFrame() in which the data type of the particular
id you are decoding is required.
Data type | DLC | Data Breakdown | Length data type | DLC | Data breakdown | length Data type | DLC | Data Breakdown | Length
------------------------------------------- ------------------------------------------- -------------------------------------------
1 | 8 | 1 - 2 | 2 bytes 3 | 8 | 1 | 1 byte 4 | 7 | 1 - 2 | 2 bytes
| | 3 - 4 | 2 bytes | | 2 | 1 byte | | 3 - 4 | 2 bytes
| | 5 - 6 | 2 bytes | | 3 | 1 byte | | 5 - 6 | 2 bytes
| | 7 - 8 | 2 bytes | | 4 | 1 byte | | 7 | 1 bytes
-------------------------------------------- | | 5 | 1 byte --------------------------------------------
2 | 6 | 1 - 2 | 2 bytes | | 6 | 1 byte 5 | 8 | 1 - 2 | 2 bytes
| | 3 - 4 | 2 bytes | | 7 | 1 byte | | 3 - 4 | 2 bytes
| | 5 - 6 | 2 bytes | | 8 | 1 byte | | 5 | 1 byte
-------------------------------------------- ------------------------------------------ | | 6 | 1 byte
| | 7 | 1 byte
| | 8 | 1 byte
*/
switch (CanID){
case 0x0CFFF048:
canDecodeDataFrame(DecodeDataFrame, 1);
DecodeDataFrame[2] *= .1;
DecodeDataFrame[4] *= .1;
DecodeDataFrame[6] *= .1;

break;
case 0x0CFFF148:
//enter decode function
canDecodeDataFrame(DecodeDataFrame, 4);
DecodeDataFrame[0] *=.01;
DecodeDataFrame[2] *=.01;
DecodeDataFrame[4] *=.01;
break;
case 0x0CFFF248:
//enter decode function
canDecodeDataFrame(DecodeDataFrame, 1);
DecodeDataFrame[0] *= 0.001;
DecodeDataFrame[2] *= 0.001;
DecodeDataFrame[4] *= 0.001;
DecodeDataFrame[6] *= 0.001;
break;
case 0x0CFFF348:
//enter decode function
canDecodeDataFrame(DecodeDataFrame, 1);
DecodeDataFrame[0] *= 0.001;
DecodeDataFrame[2] *= 0.001;
DecodeDataFrame[4] *= 0.001;
DecodeDataFrame[6] *= 0.001;

break;
case 0x0CFFF448:
//enter decode function
canDecodeDataFrame(DecodeDataFrame, 1);
DecodeDataFrame[0] *= 0.2;
DecodeDataFrame[2] *= 0.2;
DecodeDataFrame[4] *= 0.2;
DecodeDataFrame[6] *= 0.2;
break;
case 0x0CFFF548:
//enter decode function
canDecodeDataFrame(DecodeDataFrame, 4);
DecodeDataFrame[0] *= .01;
DecodeDataFrame[2] *= 0.1;
DecodeDataFrame[4] *= 0.1;
break;
case 0x0CFFF648:
//enter decode function
canDecodeDataFrame(DecodeDataFrame, 5);
DecodeDataFrame[0] *= 0.1;
DecodeDataFrame[2] *= 0.1;
break;
case 0x0CFFF748:
//enter decode function
canDecodeDataFrame(DecodeDataFrame, 1);
DecodeDataFrame[6] *= .1;
break;
case 0x0CFFF848:
//enter decode function
canDecodeDataFrame(DecodeDataFrame, 2);
DecodeDataFrame[0] *= 0.01;
DecodeDataFrame[2] *= 0.01;
DecodeDataFrame[4] *= 0.01;
break;
case 0x0CFFF948:
//enter decode function
canDecodeDataFrame(DecodeDataFrame, 3);
for(int n = 0 ; n <= 7 ; n++){
DecodeDataFrame[n] *=.5;
}
break;
case 0x0CFFFA48:
//enter decode function
canDecodeDataFrame(DecodeDataFrame, 2);
DecodeDataFrame[0] *= 0.1;
DecodeDataFrame[2] *= 0.1;
DecodeDataFrame[4] *= 0.1;
break;
case 0x0CFFFB48:
//enter decode function
canDecodeDataFrame(DecodeDataFrame, 1);
DecodeDataFrame[0] *= 0.1;
DecodeDataFrame[2] *= 0.1;
DecodeDataFrame[4] *= 0.1;
DecodeDataFrame[6] *= 0.1;
break;
case 0x0CFFFC48:
//enter decode function
canDecodeDataFrame(DecodeDataFrame, 1);
DecodeDataFrame[0] *= 0.1;
DecodeDataFrame[2] *= 0.1;
DecodeDataFrame[4] *= 0.1;
DecodeDataFrame[6] *= 0.1;
break;
case 0x0CFFFD48:
//enter decode function
canDecodeDataFrame(DecodeDataFrame, 1);
DecodeDataFrame[0] *= 0.1;
DecodeDataFrame[2] *= 0.1;
DecodeDataFrame[4] *= 0.1;
DecodeDataFrame[6] *= 0.1;
break;
case 0x0CFFFE48:
//enter decode function
canDecodeDataFrame(DecodeDataFrame, 1);
DecodeDataFrame[0] *= 0.1;
DecodeDataFrame[2] *= 0.1;
// bytes 3 and 4 don't seem to be used
break;
case 0x0CFFD048:
//enter decode function
canDecodeDataFrame(DecodeDataFrame, 1);
DecodeDataFrame[0] *= 0.1;
DecodeDataFrame[2] *= 0.1;
DecodeDataFrame[4] *= 0.1;
DecodeDataFrame[6] *= 0.1;
break;
}

}

// this function will not incorporate resolution into the equation since resolution changes depending on the message id
void canDecodeDataFrame(float DecodeDataFrame[],int DataSet ){
float Num = 0;

/*
the equation used to decode the data frame is
Num = HighByte*256+LowByte
if (Num>32767) then
Num = Num - 65536
The equation was taken from the application note for the pe3 performance ECU (AN400 Rev C– Application Note)
*/
//resets the array for each iteration of decoding
for(int n = 0; n <= 7; n++){

DecodeDataFrame[n] = 0;
}

switch (DataSet){
case 1: // 4 unique data values 2 bytes each
for(int n = 0; n <= 6 ; n += 2){
Num = RxData[n + 1] * 256 + RxData[n];
if(Num > 32767){
Num = Num - 65536;
}
DecodeDataFrame[n] = Num; // NOTE: due to how to for loop is setup you will have the data stored into even elements (including 0)
}
break;

case 2: // 3 unique data values 2 bytes each ( 6 DLC instead of 8)
for(int n = 0; n <= 4 ; n += 2){
Num = RxData[n + 1] * 256 + RxData[n];
if(Num > 32767){
Num = Num - 65536;
}
DecodeDataFrame[n] = Num;
}
break;

case 3: // 8 unique data values 1 byte each
for(int n = 0; n <= 7; n++){
DecodeDataFrame[n] = RxData[n];
}
break;

case 4: // 4 unique data values 3 are 2 bytes and 1 is 1 byte (DLC is 7 instead of 8)
for(int n = 0; n <= 4 ; n += 2){
Num = RxData[n + 1] * 256 + RxData[n];
if(Num > 32767){
Num = Num - 65536;
}
DecodeDataFrame[n] = Num;
}
DecodeDataFrame[6] = RxData[6]; // placed at the 7th frame to be consistent with the odd spacing in the array
break;

case 5: // 6 unique data values 2 are 2 bytes and 4 are 1 byte
// changed the naming scheme for the n value to add emphais what data the for loop is manipulating
for(int TwoByteData = 0; TwoByteData <= 2 ; TwoByteData += 2){
Num = RxData[TwoByteData + 1] * 256 + RxData[TwoByteData];
if(Num > 32767){
Num = Num - 65536;
}
DecodeDataFrame[TwoByteData] = Num;
}
for(int OneByteData = 4; OneByteData <=7; OneByteData++){
DecodeDataFrame[OneByteData] = RxData[OneByteData];
}
break;
}
}

0 comments on commit 200bacf

Please sign in to comment.