SAE J1939 protocol free to use for embedded systems or PC with CAN-bus

Overview

Open SAE J1939

SAE J1939 is a protocol for shaping the CAN-bus message in a specific way that suits industrial vehicles such as tractors, machinery, trucks and more.

SAE J1939 is a very easy protocol to use, but there is a lack of information about SAE J1939, due to the cost of the protocol document, available how to shape a CAN-bus message according to SAE J1939 protocol standard. So therefore I’m writing a SAE J1939 protocol available for free to use on any embedded systems such as STM32, Arduino, AVR, PIC etc or PC.

To learn to build on this project, you need first to understand SAE J1939. I have written this project in C language because C is an industry standard. The C language dialect I have chosen is C99 and I don't use dynamical memory allocation in this library. So it will work with MISRA C standard.

With this library, you can communicate with valves, engines, actuators, machinery, hardware and all other things that are suitable for heavy industrial mobile applications. I have build up a basic structure of the project and I hope that other users will send pull request of their C code for extra functionality to SAE J1939 standard because SAE J1939 is a huge standard.

Getting started

The first thing you need to know is to read the document Open SAE J1939.pdf inside the Documentation folder. Learn the structure of the project, else you won't be able to understand SAE J1939. After you have got a basic understanding of the project, you are able to build on it. Keep it simple and follow the SAE J1939 standard!

After you have understand the structure of the project, then select processor choice in Processor_choice.h file. Here you can select for example STM32, Arduino, PIC, AVR etc. or if you want to run it on PC first, then select PROCESSOR_CHOICE 0 and run some examples. That's the debugging mode for internal CAN feedback.

How to use the project

  • Step 1: Download this repository
  • Step 2: Go to Processor_choice.h and select your processor, if it's not avaiable, please write code for it and send me a pull request
  • Step 3: Copy over the Src folder to your project folder inside your IDE. Rename Src to for example Open SAE J1939. That's a good name.
  • Step 4: Past the header files inside your application code. This is just an example.
#include <stdlib.h>
#include <stdio.h>

#include "ISO_11783/ISO_11783-7_Application_Layer/Application_Layer.h"
#include "Open_SAE_J1939/Open_SAE_J1939.h"
#include "SAE_J1939/SAE_J1939-71_Application_Layer/Application_Layer.h"
#include "SAE_J1939/SAE_J1939-73_Diagnostics_Layer/Diagnostics_Layer.h"
#include "SAE_J1939/SAE_J1939-81_Network_Management_Layer/Network_Management_Layer.h"
  • Step 5: Create the J1939 j1939 = {0}; inside your application code. You can see inside the examples how I have done
  • Step 6: Set the other ECU addresses to broadcast address 0xFF
/* Important to sent all non-address to 0xFF - Else we cannot use ECU address 0x0 because this library remembers the ECU addresses. */
for(uint8_t i = 0; i < 255; i++)
	j1939.other_ECU_address[i] = 0xFF; /* 0xFF is not an ECU address, only a broadcast address according to SAE J1939 */
	
  • Step 7: Set your ECU address between 0x0 to 0xFD. I select 0x80
j1939.this_ECU_address = 0x80;
  • Step 8: Create NAME. It's a SAE J1939 standard for sending out the NAME of the ECU at the start up. Don't forget to look in SAE J1939 Enums folder for more predefined fields for NAME
/* Set NAME for ECU 1 */
j1939.this_name.identity_number = 100;                                          /* From 0 to 2097151 */
j1939.this_name.manufacturer_code = 300;                                        /* From 0 to 2047 */
j1939.this_name.function_instance = 10;                                         /* From 0 to 31 */
j1939.this_name.ECU_instance = 2;                                               /* From 0 to 7 */
j1939.this_name.function = FUNCTION_VDC_MODULE;                                 /* From 0 to 255 */
j1939.this_name.vehicle_system = 100;                                           /* From 0 to 127 */
j1939.this_name.arbitrary_address_capable = 0;                                  /* From 0 to 1 */
j1939.this_name.industry_group = INDUSTRY_GROUP_CONSTRUCTION;                   /* From 0 to 7 */
j1939.this_name.vehicle_system_instance = 10;                                   /* From 0 to 15 */

Step 9: Broadcast the NAME

SAE_J1939_Response_Request_Address_Claimed(&j1939);                             /* This function send out the NAME to all ECU */
  • Step 10: Implement your reading function inside a while loop
while(1) {
	/* Read incoming messages */
	Open_SAE_J1939_Listen_For_Messages(&j1939);
	/* Your application code here */
	....
	....
	....
}

Now you can use the Open SAE J1939 library

The structure of the project

a

SAE J1939 functionality

  • SAE J1939:21 Transport Layer
    • Acknowledgement
    • Request
    • Transport Protocol Connection Management
    • Transport Protocol Data Transfer
  • SAE J1939:71 Application Layer
    • Request Component Identification
    • Request ECU Identification
    • Request Software Identification
  • SAE J1939:73 Diagnostics Layer
    • DM1
    • DM2
    • DM3
    • DM14
    • DM15
    • DM16
  • SAE J1939:81 Network Management Layer
    • Address Claimed
    • Commanded Address
    • Address Not Claimed
    • Delete Address

Extra functionality

  • ISO 11783 Tractors And Machinery For Agriculture And Forestry
    • ISO 11783-7 Implement Messages Application Layer
      • Auxiliary Valve Command
      • Auxiliary Valve Estimated Flow
      • Auxiliary Valve Measured Position
      • General Purpose Valve Command
      • General Purpose Valve Estimated Flow

Questions and answers

  • Q: Can this library be used with C++?
    • A: Yes it can be used with C++
  • Q: I want to build on this library, what should I do?
    • A: First you need to know C99 and bitwise operations. Then you need to understand the SAE J1939:21 Transport Layer structure. Don't forget to update the PDF with your new functionality.
  • Q: Can I use this on my Arduino?
    • A: Yes, this C code is 100% pure C code and only using C standard library and also the code does not take account of what hardware you are using.
  • Q: Do I need to install the library for to use the library?
    • A: No, just copy over the .c and .h files to your project and compile. I have used this with QT framework.
  • Q: This project is quite old now and not so much updates, is it still worth to use it?
    • A: Yes, this library only updates when I or other includes more functionality from SAE J1939. The reason why I wrote this in C99 is because it's an industry standard and will you will always be able to compile this library and use it.
  • Q: What is your plan with the library?
    • A: To make SAE J1939 available for everybody
  • Q: I don't have CAN-bus, but can I use this library anyway with UART, USB, WiFi etc?
    • A: Yes. This is only a way to shape a massage in a specific way.
  • Q: Can I send data with this library, even if I don't have CAN-bus?
    • A: Yes. There are something called DM14 transmit request, DM15 status response and DM16 binary transfer. Use that if you want to transfer data in an industrial way.
Comments
  • Problem with read multiframe package

    Problem with read multiframe package

    i tryed to send for example DM35 (50 bytes) from PCAN-Explorer (from 0xF9 - PCANExplorer to 0x80 - GD32F105 board). PCAN sends 18ec80f9 8 10 32 00 08 ff 00 9f 00 (RTS frame). Your src send back 18ecf980 8 11 32 00 08 ff 00 9f 00 (CTS frame) and transfer stopped....strange i read this manual https://www.simmasoftware.com/j1939-presentation.pdf (36 page) and i see that CTS have different structure than yours. also it has different structure of ACK frame (at end of the message) i change your CTS message to (18ecf980 8 11 32 01 ff ff 00 9f 00) and PCAN Explorer now send data transfer frames

    where is truth?)

    opened by KnightRUS 17
  • Callbacks for user identify new application layer messages received

    Callbacks for user identify new application layer messages received

    Hi Daniel.

    Don't you think it would be interesting to have user-initiated callbacks to be called when certain packets were received by the application layer? For example, here: void SAE_J1939_Read_Transport_Protocol_Data_Transfer(J1939 j1939, uint8_t SA, uint8_t data[]) { / Save the sequence data / j1939->from_other_ecu_tp_dt.sequence_number = data[0]; j1939->from_other_ecu_tp_dt.from_ecu_address = SA; uint8_t index = data[0] - 1; for (uint8_t i = 1; i < 8; i++) j1939->from_other_ecu_tp_dt.data[index*7 + i-1] = data[i]; / For every package, we send 7 bytes of data where the first byte data[0] is the sequence number / / Check if we have completed our message - Return = Not completed / if (j1939->from_other_ecu_tp_cm.number_of_packages != j1939->from_other_ecu_tp_dt.sequence_number || j1939->from_other_ecu_tp_cm.number_of_packages == 0) return; / Our message are complete - Build it and call it complete_data[total_message_size] / uint32_t PGN = j1939->from_other_ecu_tp_cm.PGN_of_the_packeted_message; uint16_t total_message_size = j1939->from_other_ecu_tp_cm.total_message_size; uint8_t complete_data[total_message_size]; uint16_t inserted_bytes = 0; for (uint8_t i = 0; i < j1939->from_other_ecu_tp_dt.sequence_number; i++) for (uint8_t j = 0; j < 7; j++) if (inserted_bytes < total_message_size) complete_data[inserted_bytes++] = j1939->from_other_ecu_tp_dt.data[i*7 + j]; / Send an end of message ACK back / if(j1939->from_other_ecu_tp_cm.control_byte == CONTROL_BYTE_TP_CM_RTS) SAE_J1939_Send_Acknowledgement(j1939, SA, CONTROL_BYTE_TP_CM_EndOfMsgACK, GROUP_FUNCTION_VALUE_NORMAL, PGN); / Check what type of function that message want this ECU to do / switch (PGN) { case PGN_COMMANDED_ADDRESS: SAE_J1939_Read_Commanded_Address(j1939, complete_data); / Insert new name and new address to this ECU / break; case PGN_DM1: SAE_J1939_Read_Response_Request_DM1(j1939, SA, complete_data, complete_data[8]); / Sequence number is the last index / break; case PGN_DM2: SAE_J1939_Read_Response_Request_DM2(j1939, SA, complete_data, complete_data[8]); / Sequence number is the last index / break; case PGN_DM16: SAE_J1939_Read_Binary_Data_Transfer_DM16(j1939, SA, complete_data); break; case PGN_SOFTWARE_IDENTIFICATION: SAE_J1939_Read_Response_Request_Software_Identification(j1939, SA, complete_data); break; case PGN_ECU_IDENTIFICATION: SAE_J1939_Read_Response_Request_ECU_Identification(j1939, SA, complete_data); break; case PGN_COMPONENT_IDENTIFICATION: SAE_J1939_Read_Response_Request_Component_Identification(j1939, SA, complete_data); break; / Add more here / } / Delete TP DT and TP CM */ memset(&j1939->from_other_ecu_tp_dt, 0, sizeof(j1939->from_other_ecu_tp_dt)); memset(&j1939->from_other_ecu_tp_cm, 0, sizeof(j1939->from_other_ecu_tp_cm));}

    It would be nice to have a callback to inform that new Software identification was received, after calling the SAE_J1939_Read_Response_Request_Software_Identification function.

    What do you think about it?

    opened by gustavowd 8
  • Why valor Open_SAE_J1939_Listen_For_Messages() in multiple places of the code

    Why valor Open_SAE_J1939_Listen_For_Messages() in multiple places of the code

    Hi Daniel. Thank you very much for your open source code for the j1939 protocol. It will be very useful for many people. However, I have a question regarding your API. Why do you call the Open_SAE_J1939_Listen_For_Messages() function in the loop and multiple times in the example requests if the function is in the stm32 interrupt callback? Will the function not be called whenever a frame comes through the CAN network? I'm starting to develop j1939 devices with your API and I would like to understand why call the function multiple times out of the interrupt. I intend to use an rtos and synchronize the requests by queues and semaphores.

    Thanks in advance. Gustavo

    opened by gustavowd 7
  • Enabled multiple DM1 and DM2 messages to be read and written.

    Enabled multiple DM1 and DM2 messages to be read and written.

    Updated J1939 Structure in Structs.h to have 10 element array for all DTCs so multiple values can be read and written Fixed active DTC count calculation

    Updated TP message formatting in DM1.c and DM2.c

    • Determines number of Active DTCs from other ECU from message size. Calc automates active messages so relying on extra non standard byte with active count is not required.
    • Decodes DTCs with loop, stores up to 10 DTCs in J1939 data structure so multiple values can be evaluated
    • Calculates message size and frames for transport TP based on number of active this ECU DTCs
    • Adds ability to loads this_ecu_tp_dt.data structure with up to 10 DTCs from the local ecu

    Fixed detection of no-fault condition to match J1939 DM1 message standards (in DM1.c and DM2.c)

    • Sets active message count to 0 when DM1 message FECA contains a single DTC where all values are zero

    Removed assignment of FMI to FMI_NOT_AVAILABLE (31) when requested to clear stored DM2 codes in DM3.c

    • FMI status of 31 is intended to be used as a general error condition if no other pre-defined FMI value applies
    • No longer required since DM1 and DM2 now use the standard all zero DTC message to indicate no active codes
    opened by tptGit 3
  • DM1/DM2 - Active DTC Count and Multiple Active Message Processing

    DM1/DM2 - Active DTC Count and Multiple Active Message Processing

    Forgive my potentially rough code, i'm not a proficient C programmer. But i'm quite good with CANbus.

    I believe the number of active DTC count when more than 1 is not accurate, nor is the condition for clearing the number of active messages.

    In any FECA DMx message, the first two bytes are the lamp codes, followed by 4 byes for each DTC When receiving FECA normally it assumes there is 1 code, which is fine, but when receiving multiple codes the number of active codes should case PGN_DM1: SAE_J1939_Read_Response_Request_DM1(j1939, SA, complete_data, (total_message_size-2)/4); /* Sequence number is the last index */ break;

    When all codes are clear, the DM1 protocol requires the ECU to send an additional FECA message with all zeros for the SPN, FMI and OC. So the best way to identify no active messages would be like this: /* Check if we have no fault cause */ if (errors_dm1_active == 1 && j1939->from_other_ecu_dm.dm1.SPN == 0) j1939->from_other_ecu_dm.errors_dm1_active = 0; else j1939->from_other_ecu_dm.errors_dm1_active = errors_dm1_active;

    FMI 31 (FMI_NOT_AVAILABLE) is reserved for a generic but undefined "condition exists" This may be just a confusingly named enumeration. Might be better to be something like FMI_UNDEFINED_CONDITION or something to avoid confusion.

    To decode all the DTC messages, the code might look a little like this:

    for (uint8_t i = 0; i < errors_dm1_active; i++){ j1939->from_other_ecu_dm.dm1.SPN = ((data[(i*4)+4] & 0b11100000) << 11) | (data[(i*4)+3] << 8) | data[(i*4)+2]; j1939->from_other_ecu_dm.dm1.FMI = data[(i*4)+4] & 0b00011111; j1939->from_other_ecu_dm.dm1.SPN_conversion_method = data[(i*4)+5] >> 7; j1939->from_other_ecu_dm.dm1.occurrence_count = data[(i*4)+5] & 0b01111111; j1939->from_other_ecu_dm.dm1.from_ecu_address = SA; }

    Obviously the J1939 structure only has space to assign a value to 1 SPN, but maybe that could be updated to be an array of SPNs? I think the code might also need to handle if the number of active SPN's is less than the previous number, it would need to clear the values from the array that might remain.

    Thank you for considering.

    opened by tptGit 3
  • Time triggered message transmission

    Time triggered message transmission

    Super useful stuff, Daniel! Thank you for sharing it. Just want to make an issue for a new feature - Time triggered message transmission, as many of J1939 messages are not requested, but time triggered. In documentation this parameter is often named as "Repetition Rate" or "Transmission Rate".

    As far as I understand, for this feature to work ENUM_PGN_CODES enumerator should be transformed into the data structure with at least these fields:

    • PGN - same hex numbers as it is now.
    • Repetition Rate - number representing time in milliseconds.
    • Next Transmission Time - stores timestamp value when the next transmission should be executed. Optionally DLC (Data Length Code) can be added to the structure.

    And also one function for looping all transmit messages is needed, which can be called similarly to Open_SAE_J1939_Listen_For_Messages(J1939* j1939) function (I mean in infinite loop).

    Implementation part of this post is only my thoughts, maybe it's not an efficient way to program.

    opened by LHSmicius 3
  • STM32 Issues Compiling and Debugging

    STM32 Issues Compiling and Debugging

    I am using STM32IDE and the STM32L432KC MCU, I am trying to use the J1939 protocol stack to read and talk with a battery. But I am having issues when I am trying to initialize the CAN and my thread crashes on STM32_PLC_CAN_GET_ID_Data. Am I not using the library correctly??

    /* USER CODE BEGIN Header / /*


    • @file : main.c
    • @brief : Main program body

    /* USER CODE END Header / / Includes ------------------------------------------------------------------*/ #include "main.h"

    /* Private includes ----------------------------------------------------------/ / USER CODE BEGIN Includes */

    #include "Hardware.h" #include <stdlib.h> #include <stdio.h>

    #include "ISO_11783/ISO_11783-7_Application_Layer/Application_Layer.h" #include "Open_SAE_J1939/Open_SAE_J1939.h" #include "SAE_J1939/SAE_J1939-71_Application_Layer/Application_Layer.h" #include "SAE_J1939/SAE_J1939-73_Diagnostics_Layer/Diagnostics_Layer.h" #include "SAE_J1939/SAE_J1939-81_Network_Management_Layer/Network_Management_Layer.h"

    /* USER CODE END Includes */

    /* Private variables ---------------------------------------------------------*/ CAN_HandleTypeDef hcan1;

    /* Private function prototypes -----------------------------------------------*/ void SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_CAN1_Init(void);

    /* USER CODE */ void STM32_PLC_Start_CAN(CAN_HandleTypeDef hcan, J1939 j1939); void STM32_PLC_CAN_Get_ID_Data(uint32_t ID, uint8_t data[], bool is_new_message); static CAN_HandleTypeDef *can_handler; static J1939 *j1939_handler; HAL_StatusTypeDef STM32_PLC_CAN_Transmit(uint8_t TxData[], CAN_TxHeaderTypeDef *TxHeader); static void Create_CAN_Filter(CAN_HandleTypeDef *hcan); static void Create_CAN_Interrupt(CAN_HandleTypeDef hcan); / USER CODE END */

    /**

    • @brief The application entry point.
    • @retval int */ int main(void) {

    /* MCU Configuration--------------------------------------------------------*/

    /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init();

    /* Configure the system clock / SystemClock_Config(); / Initialize all configured peripherals */ MX_GPIO_Init(); MX_CAN1_Init();

    /* USER CODE BEGIN WHILE / / Create our J1939 structure with two ECU */ J1939 j1939_1 = {0}; J1939 j1939_2 = {0};

    /* Important to sent all non-address to 0xFF - Else we cannot use ECU address 0x0 */
    for(uint8_t i = 0; i < 255; i++){
    	j1939_1.other_ECU_address[i] = 0xFF;
    	j1939_2.other_ECU_address[i] = 0xFF;
    }
    STM32_PLC_Start_CAN(&hcan1, &j1939_1);
    //Open_SAE_J1939_Startup_ECU(&j1939_1);
    /* Set the ECU address */
    j1939_1.information_this_ECU.this_ECU_address = 0x80;												/* From 0 to 253 because 254 = error address and 255 = broadcast address */
    j1939_2.information_this_ECU.this_ECU_address = 0xf8;
    
    /* This is important because length_of_each_field is not a SAE J1939 standard. The software need to know how large field it is from the beginning */
    j1939_2.from_other_ecu_identifications.ecu_identification.length_of_each_field = 30;
    
    /* Set the ECU Identification */
    j1939_1.information_this_ECU.this_identifications.ecu_identification.length_of_each_field = 30;
    char ecu_part_number[20] = "ABC-1100P-XXXX10";
    char ecu_serial_number[20] = "1-200-K-10M";
    char ecu_location[20] = "Under bridge";
    char ecu_type[20] = "Model G";
    for(uint8_t i = 0; i < 20; i++){
    	j1939_1.information_this_ECU.this_identifications.ecu_identification.ecu_part_number[i] = (uint8_t) ecu_part_number[i];
    	j1939_1.information_this_ECU.this_identifications.ecu_identification.ecu_serial_number[i] = (uint8_t) ecu_serial_number[i];
    	j1939_1.information_this_ECU.this_identifications.ecu_identification.ecu_location[i] = (uint8_t) ecu_location[i];
    	j1939_1.information_this_ECU.this_identifications.ecu_identification.ecu_type[i] = (uint8_t) ecu_type[i];
    }
    
    /* Request Software Identification from ECU 2 to ECU 1 */
    SAE_J1939_Send_Request(&j1939_2, 0x80, PGN_ECU_IDENTIFICATION);
    
    /* Response request from ECU 1 perspective - Don't worry, in real CAN applications you don't need this mess. */
    //Open_SAE_J1939_Listen_For_Messages(&j1939_1);
    Open_SAE_J1939_Listen_For_Messages(&j1939_2);
    //Open_SAE_J1939_Listen_For_Messages(&j1939_1);
    
    /* Read response request from ECU 1 to ECU 2 */
    for(uint8_t i = 0; i < 15; i++)
    	Open_SAE_J1939_Listen_For_Messages(&j1939_2);
    
    /* Display what ECU 2 got */
    printf("Length of each field = %i\nECU part number = %s\nECU serial number = %s\nECU location = %s\nECU type = %s\nFrom ECU address 0x%X"
    		,j1939_2.from_other_ecu_identifications.ecu_identification.length_of_each_field
    		,j1939_2.from_other_ecu_identifications.ecu_identification.ecu_part_number
    		,j1939_2.from_other_ecu_identifications.ecu_identification.ecu_serial_number
    		,j1939_2.from_other_ecu_identifications.ecu_identification.ecu_location
    		,j1939_2.from_other_ecu_identifications.ecu_identification.ecu_type
    		,j1939_2.from_other_ecu_identifications.ecu_identification.from_ecu_address);
    
    return 0;
    

    }

    /**

    • @brief System Clock Configuration
    • @retval None */ void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

    /** Configure the main internal regulator output voltage / if (HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1) != HAL_OK) { Error_Handler(); } /* Configure LSE Drive Capability / HAL_PWR_EnableBkUpAccess(); __HAL_RCC_LSEDRIVE_CONFIG(RCC_LSEDRIVE_LOW); /* Initializes the RCC Oscillators according to the specified parameters

    • in the RCC_OscInitTypeDef structure. / RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSE|RCC_OSCILLATORTYPE_MSI; RCC_OscInitStruct.LSEState = RCC_LSE_ON; RCC_OscInitStruct.MSIState = RCC_MSI_ON; RCC_OscInitStruct.MSICalibrationValue = 0; RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_6; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); } /* Initializes the CPU, AHB and APB buses clocks */ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_MSI; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

    if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK) { Error_Handler(); } /** Enable MSI Auto calibration */ HAL_RCCEx_EnableMSIPLLMode(); }

    /**

    • @brief CAN1 Initialization Function
    • @param None
    • @retval None */ static void MX_CAN1_Init(void) {

    /* USER CODE BEGIN CAN1_Init 0 */

    /* USER CODE END CAN1_Init 0 */

    /* USER CODE BEGIN CAN1_Init 1 */

    /* USER CODE END CAN1_Init 1 / hcan1.Instance = CAN1; hcan1.Init.Prescaler = 1; hcan1.Init.Mode = CAN_MODE_NORMAL; hcan1.Init.SyncJumpWidth = CAN_SJW_1TQ; hcan1.Init.TimeSeg1 = CAN_BS1_13TQ; hcan1.Init.TimeSeg2 = CAN_BS2_2TQ; hcan1.Init.TimeTriggeredMode = DISABLE; hcan1.Init.AutoBusOff = DISABLE; hcan1.Init.AutoWakeUp = DISABLE; hcan1.Init.AutoRetransmission = DISABLE; hcan1.Init.ReceiveFifoLocked = DISABLE; hcan1.Init.TransmitFifoPriority = DISABLE; if (HAL_CAN_Init(&hcan1) != HAL_OK) { Error_Handler(); } / USER CODE BEGIN CAN1_Init 2 */

    /* USER CODE END CAN1_Init 2 */

    }

    /**

    • @brief GPIO Initialization Function
    • @param None
    • @retval None */ static void MX_GPIO_Init(void) {

    /* GPIO Ports Clock Enable */ __HAL_RCC_GPIOC_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE();

    }

    /* USER CODE BEGIN 4 */ void STM32_PLC_Start_CAN(CAN_HandleTypeDef *hcan, J1939 *j1939) { can_handler = hcan; j1939_handler = j1939; Create_CAN_Filter(hcan); if (HAL_CAN_Start(hcan) != HAL_OK) Error_Handler(); Create_CAN_Interrupt(hcan); }

    HAL_StatusTypeDef STM32_PLC_CAN_Transmit(uint8_t TxData[], CAN_TxHeaderTypeDef *TxHeader) { uint32_t TxMailbox; return HAL_CAN_AddTxMessage(can_handler, TxHeader, TxData, &TxMailbox); }

    /* Returns true if the message data is new / void STM32_PLC_CAN_Get_ID_Data(uint32_t ID, uint8_t data[], bool* is_new_message) { CAN_RxHeaderTypeDef RxHeader = {0}; uint8_t RxData[8] = {0}; HAL_StatusTypeDef status = HAL_CAN_GetRxMessage(can_handler, CAN_RX_FIFO0, &RxHeader, RxData); if (status != HAL_OK) Error_Handler();

    /* Check the length of the data */
    if(RxHeader.DLC == 0){
    	*is_new_message = false;
    	return;
    }
    
    /* Read ID */
    if(RxHeader.IDE == CAN_ID_STD)
    	*ID = RxHeader.StdId;
    else
    	*ID = RxHeader.ExtId;
    
    /* Read data */
    memcpy(data, RxData, 8);
    
    /* Leave the function by saying that the message is new */
    *is_new_message = true;
    

    }

    /* Interrupt handler that read message */ void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan) { Open_SAE_J1939_Listen_For_Messages(j1939_handler); }

    static void Create_CAN_Interrupt(CAN_HandleTypeDef hcan) { / Don't forget to check NVIC in CAN -> NVIC Settings -> CAN RX0 interrupt */ if (HAL_CAN_ActivateNotification(hcan, CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK) Error_Handler(); }

    static void Create_CAN_Filter(CAN_HandleTypeDef *hcan) { CAN_FilterTypeDef sFilterConfig; sFilterConfig.FilterBank = 0; sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK; sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT; sFilterConfig.FilterIdHigh = 0x0000; sFilterConfig.FilterIdLow = 0x0000; sFilterConfig.FilterMaskIdHigh = 0x0000; sFilterConfig.FilterMaskIdLow = 0x0000; sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0; sFilterConfig.FilterActivation = ENABLE; sFilterConfig.SlaveStartFilterBank = 14;

    if (HAL_CAN_ConfigFilter(hcan, &sFilterConfig) != HAL_OK)
    	Error_Handler();
    

    }

    /* USER CODE END 4 */

    /**

    • @brief This function is executed in case of error occurrence.
    • @retval None / void Error_Handler(void) { / USER CODE BEGIN Error_Handler_Debug / / User can add his own implementation to report the HAL error return state / __disable_irq(); while (1) { } / USER CODE END Error_Handler_Debug */ }

    #ifdef USE_FULL_ASSERT /**

    • @brief Reports the name of the source file and the source line number
    •     where the assert_param error has occurred.
      
    • @param file: pointer to the source file name
    • @param line: assert_param error line source number
    • @retval None */ void assert_failed(uint8_t file, uint32_t line) { / USER CODE BEGIN 6 / / User can add his own implementation to report the file name and line number, ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) / / USER CODE END 6 / } #endif / USE_FULL_ASSERT */
    opened by Ra13fael 2
  • DM1 and DM2 Multiple Messages

    DM1 and DM2 Multiple Messages

    Updated J1939 Structure in Structs.h to have 10 element array for all DTCs so multiple values can be read and written

    Updated TP message formatting in DM1.c and DM2.c

    • Determines number of Active DTCs from other ECU from message size. Calc automates active messages so relying on extra non standard byte with active count is not required.
    • Decodes DTCs with loop, stores up to 10 DTCs in J1939 data structure so multiple values can be evaluated
    • Calculates message size and frames for transport TP based on number of active this ECU DTCs
    • Adds ability to loads this_ecu_tp_dt.data structure with up to 10 DTCs from the local ecu

    Fixed detection of no-fault condition to match J1939 DM1 message standards (in DM1.c and DM2.c)

    • Sets active message count to 0 when DM1 message FECA contains a single DTC where all values are zero

    Removed assignment of FMI to FMI_NOT_AVAILABLE (31) when requested to clear stored DM2 codes in DM3.c

    • FMI status of 31 is intended to be used as a general error condition if no other pre-defined FMI value applies
    • No longer required since DM1 and DM2 now use the standard all zero DTC message to indicate no active codes

    Added Several PGNs to Enum_PGN.h list

    opened by tptGit 1
  • HAL implementation

    HAL implementation

    Hi Daniel,

    first of all thanks for your software! I am planning to use it for a project in a Lecture with students. We will be using the Arduino platform and I will try to develop the HAL for the Arduino platform.

    I see that the implementation of the HAL is done through conditional compilation. If I want to add a new implementation, source code from a specific platform would be added in the corresponding PROCESSOR_CHOICE macro in CAN_Transmit_Receive.c . When you want to scale this it can get messy as you are mixing all the hardware-specific implementations in the same file. In addition, you will need to add the respective include directives for the API for the respective hardware platform.

    Wouldnt it be better if the HAL interface implemented polymorphism for each specific implementation? Then each implementation would reside in its own source file. The build system could then select the HAL source files depending on the target platform.

    Regards Victor

    opened by vChavezB 1
  • MCP2515 support

    MCP2515 support

    Daniel, Thanks for doing this. Fills a large open-source gap. I'm planning to use an ATMEGA 328P with an MCP2515 CAN controller. It looks like currently the only supported controller is QT USB. Is this correct?

    opened by GreenEllipsis 1
  • Problems importing to Keil

    Problems importing to Keil

    When building with keil I'm having some trouble... Don't know if I'm doing something wrong :/

    Rebuild started: Project: BLUEPILL_CAN *** Using Compiler 'V5.06 update 7 (build 960)', folder: 'C:\Keil_v5\ARM\ARMCC\Bin' Rebuild target 'BLUEPILL_CAN' assembling startup_stm32f103xb.s... compiling stm32f1xx_it.c... compiling stm32f1xx_hal_msp.c... compiling main.c... compiling stm32f1xx_hal.c... compiling stm32f1xx_hal_gpio_ex.c... compiling stm32f1xx_hal_can.c... compiling stm32f1xx_hal_rcc_ex.c... compiling stm32f1xx_hal_gpio.c... compiling stm32f1xx_hal_rcc.c... compiling stm32f1xx_hal_cortex.c... compiling stm32f1xx_hal_pwr.c... compiling stm32f1xx_hal_dma.c... compiling stm32f1xx_hal_flash.c... compiling stm32f1xx_hal_exti.c... compiling stm32f1xx_hal_flash_ex.c... compiling stm32f1xx_hal_tim_ex.c... compiling stm32f1xx_hal_tim.c... compiling stm32f1xx_hal_uart.c... compiling Request.c... ..\Core\Inc\Open_J1939\SAE_J1939\SAE_J1939-21_Transport_Layer../../ISO_11783/ISO_11783-7_Application_Layer/../../SAE_J1939/SAE_J1939-21_Transport_Layer/../SAE_J1939-71_Application_Layer/Application_Layer.h(13): error: #5: cannot open source input file "../SAE_J1939-21_Transport_Layer/Transport_Layer.h": No such file or directory #include "../SAE_J1939-21_Transport_Layer/Transport_Layer.h" ..\Core\Inc\Open_J1939\SAE_J1939\SAE_J1939-21_Transport_Layer\Request.c: 0 warnings, 1 error compiling Acknowledgement.c... compiling Transport_Protocol_Connection_Management.c... compiling Transport_Protocol_Data_Transfer.c... compiling Request_Component_Identification.c... compiling Request_ECU_Identification.c... compiling Request_Software_Identification.c... compiling DM16.c... compiling system_stm32f1xx.c... compiling DM15.c... ..\Core\Inc\Open_J1939\SAE_J1939\SAE_J1939-73_Diagnostics_Layer\DM15.c(18): error: #18: expected a ")" response_data[1] = (number_of_allowed_bytes >> 3) | (0b1 << 4) | (status << 1) | 0b1; /* bit 5 and 1 are reserved / ..\Core\Inc\Open_J1939\SAE_J1939\SAE_J1939-73_Diagnostics_Layer\DM15.c(18): error: #65: expected a ";" response_data[1] = (number_of_allowed_bytes >> 3) | (0b1 << 4) | (status << 1) | 0b1; / bit 5 and 1 are reserved / ..\Core\Inc\Open_J1939\SAE_J1939\SAE_J1939-73_Diagnostics_Layer\DM15.c(34): error: #65: expected a ";" j1939->from_other_ecu_dm.dm15.status = (data[1] >> 1) & 0b0000111; ..\Core\Inc\Open_J1939\SAE_J1939\SAE_J1939-73_Diagnostics_Layer\DM15.c: 0 warnings, 3 errors compiling DM14.c... ..\Core\Inc\Open_J1939\SAE_J1939\SAE_J1939-73_Diagnostics_Layer\DM14.c(18): error: #65: expected a ";" data[1] = (number_of_requested_bytes >> 3) | (pointer_type << 4) | (command << 1) | 0b1; ..\Core\Inc\Open_J1939\SAE_J1939\SAE_J1939-73_Diagnostics_Layer\DM14.c(34): error: #18: expected a ")" uint16_t number_of_requested_bytes = ((data[1] & 0b11100000) << 3) | data[0]; ..\Core\Inc\Open_J1939\SAE_J1939\SAE_J1939-73_Diagnostics_Layer\DM14.c(35): error: #65: expected a ";" uint8_t pointer_type = (data[1] >> 4) & 0b0001; ..\Core\Inc\Open_J1939\SAE_J1939\SAE_J1939-73_Diagnostics_Layer\DM14.c(36): error: #65: expected a ";" uint8_t command = (data[1] >> 1) & 0b0000111; ..\Core\Inc\Open_J1939\SAE_J1939\SAE_J1939-73_Diagnostics_Layer\DM14.c(63): warning: #188-D: enumerated type mixed with another type return status; ..\Core\Inc\Open_J1939\SAE_J1939\SAE_J1939-73_Diagnostics_Layer\DM14.c: 1 warning, 4 errors compiling DM3.c... compiling DM2.c... ..\Core\Inc\Open_J1939\SAE_J1939\SAE_J1939-73_Diagnostics_Layer\DM2.c(30): error: #18: expected a ")" data[4] = ((j1939->this_dm.dm2.SPN >> 11) & 0b11100000) | j1939->this_dm.dm2.FMI; ..\Core\Inc\Open_J1939\SAE_J1939\SAE_J1939-73_Diagnostics_Layer\DM2.c(44): error: #18: expected a ")" data[4] = ((j1939->this_dm.dm2.SPN >> 11) & 0b11100000) | j1939->this_dm.dm2.FMI; ..\Core\Inc\Open_J1939\SAE_J1939\SAE_J1939-73_Diagnostics_Layer\DM2.c(62): error: #65: expected a ";" j1939->from_other_ecu_dm.dm2.SAE_lamp_status_red_stop = (data[0] >> 4) & 0b00000011; ..\Core\Inc\Open_J1939\SAE_J1939\SAE_J1939-73_Diagnostics_Layer\DM2.c(63): error: #65: expected a ";" j1939->from_other_ecu_dm.dm2.SAE_lamp_status_amber_warning = (data[0] >> 2) & 0b00000011; ..\Core\Inc\Open_J1939\SAE_J1939\SAE_J1939-73_Diagnostics_Layer\DM2.c(64): error: #65: expected a ";" j1939->from_other_ecu_dm.dm2.SAE_lamp_status_protect_lamp = data[0] & 0b00000011; ..\Core\Inc\Open_J1939\SAE_J1939\SAE_J1939-73_Diagnostics_Layer\DM2.c(66): error: #65: expected a ";" j1939->from_other_ecu_dm.dm2.SAE_flash_lamp_red_stop = (data[1] >> 4) & 0b00000011; ..\Core\Inc\Open_J1939\SAE_J1939\SAE_J1939-73_Diagnostics_Layer\DM2.c(67): error: #65: expected a ";" j1939->from_other_ecu_dm.dm2.SAE_flash_lamp_amber_warning = (data[1] >> 2) & 0b00000011; ..\Core\Inc\Open_J1939\SAE_J1939\SAE_J1939-73_Diagnostics_Layer\DM2.c(68): error: #65: expected a ";" j1939->from_other_ecu_dm.dm2.SAE_flash_lamp_protect_lamp = data[1] & 0b00000011; ..\Core\Inc\Open_J1939\SAE_J1939\SAE_J1939-73_Diagnostics_Layer\DM2.c(69): error: #18: expected a ")" j1939->from_other_ecu_dm.dm2.SPN = ((data[4] & 0b11100000) << 11) | (data[3] << 8) | data[2]; ..\Core\Inc\Open_J1939\SAE_J1939\SAE_J1939-73_Diagnostics_Layer\DM2.c(70): error: #65: expected a ";" j1939->from_other_ecu_dm.dm2.FMI = data[4] & 0b00011111; ..\Core\Inc\Open_J1939\SAE_J1939\SAE_J1939-73_Diagnostics_Layer\DM2.c(72): error: #65: expected a ";" j1939->from_other_ecu_dm.dm2.occurrence_count = data[5] & 0b01111111; ..\Core\Inc\Open_J1939\SAE_J1939\SAE_J1939-73_Diagnostics_Layer\DM2.c: 0 warnings, 11 errors compiling DM1.c... ..\Core\Inc\Open_J1939\SAE_J1939\SAE_J1939-73_Diagnostics_Layer\DM1.c(30): error: #18: expected a ")" data[4] = ((j1939->this_dm.dm1.SPN >> 11) & 0b11100000) | j1939->this_dm.dm1.FMI; ..\Core\Inc\Open_J1939\SAE_J1939\SAE_J1939-73_Diagnostics_Layer\DM1.c(44): error: #18: expected a ")" data[4] = ((j1939->this_dm.dm1.SPN >> 11) & 0b11100000) | j1939->this_dm.dm1.FMI; ..\Core\Inc\Open_J1939\SAE_J1939\SAE_J1939-73_Diagnostics_Layer\DM1.c(62): error: #65: expected a ";" j1939->from_other_ecu_dm.dm1.SAE_lamp_status_red_stop = (data[0] >> 4) & 0b00000011; ..\Core\Inc\Open_J1939\SAE_J1939\SAE_J1939-73_Diagnostics_Layer\DM1.c(63): error: #65: expected a ";" j1939->from_other_ecu_dm.dm1.SAE_lamp_status_amber_warning = (data[0] >> 2) & 0b00000011; ..\Core\Inc\Open_J1939\SAE_J1939\SAE_J1939-73_Diagnostics_Layer\DM1.c(64): error: #65: expected a ";" j1939->from_other_ecu_dm.dm1.SAE_lamp_status_protect_lamp = data[0] & 0b00000011; ..\Core\Inc\Open_J1939\SAE_J1939\SAE_J1939-73_Diagnostics_Layer\DM1.c(66): error: #65: expected a ";" j1939->from_other_ecu_dm.dm1.SAE_flash_lamp_red_stop = (data[1] >> 4) & 0b00000011; ..\Core\Inc\Open_J1939\SAE_J1939\SAE_J1939-73_Diagnostics_Layer\DM1.c(67): error: #65: expected a ";" j1939->from_other_ecu_dm.dm1.SAE_flash_lamp_amber_warning = (data[1] >> 2) & 0b00000011; ..\Core\Inc\Open_J1939\SAE_J1939\SAE_J1939-73_Diagnostics_Layer\DM1.c(68): error: #65: expected a ";" j1939->from_other_ecu_dm.dm1.SAE_flash_lamp_protect_lamp = data[1] & 0b00000011; ..\Core\Inc\Open_J1939\SAE_J1939\SAE_J1939-73_Diagnostics_Layer\DM1.c(69): error: #18: expected a ")" j1939->from_other_ecu_dm.dm1.SPN = ((data[4] & 0b11100000) << 11) | (data[3] << 8) | data[2]; ..\Core\Inc\Open_J1939\SAE_J1939\SAE_J1939-73_Diagnostics_Layer\DM1.c(70): error: #65: expected a ";" j1939->from_other_ecu_dm.dm1.FMI = data[4] & 0b00011111; ..\Core\Inc\Open_J1939\SAE_J1939\SAE_J1939-73_Diagnostics_Layer\DM1.c(72): error: #65: expected a ";" j1939->from_other_ecu_dm.dm1.occurrence_count = data[5] & 0b01111111; ..\Core\Inc\Open_J1939\SAE_J1939\SAE_J1939-73_Diagnostics_Layer\DM1.c: 0 warnings, 11 errors compiling Address_Claimed.c... ..\Core\Inc\Open_J1939\SAE_J1939\SAE_J1939-81_Network_Management_Layer\Address_Claimed.c(46): error: #18: expected a ")" j1939->from_other_ecu_name.identity_number = ((data[2] & 0b00011111) << 16) | (data[1] << 8) | data[0]; ..\Core\Inc\Open_J1939\SAE_J1939\SAE_J1939-81_Network_Management_Layer\Address_Claimed.c(49): error: #65: expected a ";" j1939->from_other_ecu_name.ECU_instance = data[4] & 0b00000111; ..\Core\Inc\Open_J1939\SAE_J1939\SAE_J1939-81_Network_Management_Layer\Address_Claimed.c(53): error: #65: expected a ";" j1939->from_other_ecu_name.industry_group = (data[7] >> 4) & 0b0111; ..\Core\Inc\Open_J1939\SAE_J1939\SAE_J1939-81_Network_Management_Layer\Address_Claimed.c(54): error: #65: expected a ";" j1939->from_other_ecu_name.vehicle_system_instance = data[7] & 0b00001111; ..\Core\Inc\Open_J1939\SAE_J1939\SAE_J1939-81_Network_Management_Layer\Address_Claimed.c: 0 warnings, 4 errors compiling Address_Delete.c... compiling Address_Not_Claimed.c... ..\Core\Inc\Open_J1939\SAE_J1939\SAE_J1939-81_Network_Management_Layer\Address_Not_Claimed.c(33): error: #18: expected a ")" j1939->from_other_ecu_name.identity_number = ((data[2] & 0b00011111) << 16) | (data[1] << 8) | data[0]; ..\Core\Inc\Open_J1939\SAE_J1939\SAE_J1939-81_Network_Management_Layer\Address_Not_Claimed.c(36): error: #65: expected a ";" j1939->from_other_ecu_name.ECU_instance = data[4] & 0b00000111; ..\Core\Inc\Open_J1939\SAE_J1939\SAE_J1939-81_Network_Management_Layer\Address_Not_Claimed.c(40): error: #65: expected a ";" j1939->from_other_ecu_name.industry_group = (data[7] >> 4) & 0b0111; ..\Core\Inc\Open_J1939\SAE_J1939\SAE_J1939-81_Network_Management_Layer\Address_Not_Claimed.c(41): error: #65: expected a ";" j1939->from_other_ecu_name.vehicle_system_instance = data[7] & 0b00001111; ..\Core\Inc\Open_J1939\SAE_J1939\SAE_J1939-81_Network_Management_Layer\Address_Not_Claimed.c: 0 warnings, 4 errors compiling Commanded_Address.c... ..\Core\Inc\Open_J1939\SAE_J1939\SAE_J1939-81_Network_Management_Layer\Commanded_Address.c(46): error: #18: expected a ")" j1939->this_name.identity_number = ((data[2] & 0b00011111) << 16) | (data[1] << 8) | data[0]; ..\Core\Inc\Open_J1939\SAE_J1939\SAE_J1939-81_Network_Management_Layer\Commanded_Address.c(49): error: #65: expected a ";" j1939->this_name.ECU_instance = data[4] & 0b00000111; ..\Core\Inc\Open_J1939\SAE_J1939\SAE_J1939-81_Network_Management_Layer\Commanded_Address.c(53): error: #65: expected a ";" j1939->this_name.industry_group = (data[7] >> 4) & 0b0111; ..\Core\Inc\Open_J1939\SAE_J1939\SAE_J1939-81_Network_Management_Layer\Commanded_Address.c(54): error: #65: expected a ";" j1939->this_name.vehicle_system_instance = data[7] & 0b00001111; ..\Core\Inc\Open_J1939\SAE_J1939\SAE_J1939-81_Network_Management_Layer\Commanded_Address.c: 0 warnings, 4 errors compiling Listen_For_Messages.c... ..\Core\Inc\Open_J1939\Open_SAE_J1939../ISO_11783/ISO_11783-7_Application_Layer/../../SAE_J1939/SAE_J1939-21_Transport_Layer/../SAE_J1939-73_Diagnostics_Layer/../../Hardware/Memory/FLASH_EEPROM_RAM_Memory.h(14): error: #5: cannot open source input file "../../SAE_J1939/SAE_J1939_Enums/Enum_DM14_DM15.h": No such file or directory #include "../../SAE_J1939/SAE_J1939_Enums/Enum_DM14_DM15.h" ..\Core\Inc\Open_J1939\Open_SAE_J1939\Listen_For_Messages.c: 0 warnings, 1 error compiling Auxiliary_Valve_Command.c... ..\Core\Inc\Open_J1939\ISO_11783\ISO_11783-7_Application_Layer\Auxiliary_Valve_Command.c(19): error: #18: expected a ")" data[2] = (fail_safe_mode << 6) | (0b11 << 4) | valve_state; / Bit 5 and 6 are reserved / ..\Core\Inc\Open_J1939\ISO_11783\ISO_11783-7_Application_Layer\Auxiliary_Valve_Command.c(31): error: #65: expected a ";" j1939->from_other_ecu_auxiliary_valve_command[valve_number].valve_state = data[2] & 0b00001111; ..\Core\Inc\Open_J1939\ISO_11783\ISO_11783-7_Application_Layer\Auxiliary_Valve_Command.c: 0 warnings, 2 errors compiling Auxiliary_Valve_Estimated_Flow.c... ..\Core\Inc\Open_J1939\ISO_11783\ISO_11783-7_Application_Layer\Auxiliary_Valve_Estimated_Flow.c(27): error: #18: expected a ")" data[2] = (j1939->this_auxiliary_valve_estimated_flow[valve_number].fail_safe_mode << 6) | (0b11 << 4) | j1939->this_auxiliary_valve_estimated_flow[valve_number].valve_state; / Bit 5 and 6 are reserved / ..\Core\Inc\Open_J1939\ISO_11783\ISO_11783-7_Application_Layer\Auxiliary_Valve_Estimated_Flow.c(41): error: #65: expected a ";" j1939->from_other_ecu_auxiliary_valve_estimated_flow[valve_number].valve_state = data[2] & 0b00001111; ..\Core\Inc\Open_J1939\ISO_11783\ISO_11783-7_Application_Layer\Auxiliary_Valve_Estimated_Flow.c: 0 warnings, 2 errors compiling Auxiliary_Valve_Measured_Position.c... compiling General_Purpose_Valve_Estimated_Flow.c... ..\Core\Inc\Open_J1939\ISO_11783\ISO_11783-7_Application_Layer\General_Purpose_Valve_Estimated_Flow.c(27): error: #18: expected a ")" data[2] = (j1939->this_general_purpose_valve_estimated_flow.fail_safe_mode << 6) | (0b11 << 4) | j1939->this_general_purpose_valve_estimated_flow.valve_state; / Bit 5 and 6 are reserved for further use / ..\Core\Inc\Open_J1939\ISO_11783\ISO_11783-7_Application_Layer\General_Purpose_Valve_Estimated_Flow.c(44): error: #65: expected a ";" j1939->from_other_ecu_general_purpose_valve_estimated_flow.valve_state = data[2] & 0b00001111; ..\Core\Inc\Open_J1939\ISO_11783\ISO_11783-7_Application_Layer\General_Purpose_Valve_Estimated_Flow.c: 0 warnings, 2 errors compiling General_Purpose_Valve_Command.c... ..\Core\Inc\Open_J1939\ISO_11783\ISO_11783-7_Application_Layer\General_Purpose_Valve_Command.c(19): error: #18: expected a ")" data[2] = (fail_safe_mode << 6) | (0b11 << 4) | valve_state; / Bit 5 and 6 are reserved */ ..\Core\Inc\Open_J1939\ISO_11783\ISO_11783-7_Application_Layer\General_Purpose_Valve_Command.c(33): error: #65: expected a ";" j1939->from_other_ecu_general_purpose_valve_command.valve_state = data[2] & 0b00001111; ..\Core\Inc\Open_J1939\ISO_11783\ISO_11783-7_Application_Layer\General_Purpose_Valve_Command.c: 0 warnings, 2 errors compiling FLASH_EEPROM_RAM_Memory.c... compiling CAN_Network.c... ..\Core\Inc\Open_J1939\Hardware\CAN_Network\CAN_Network.c(71): warning: #223-D: function "STM32_PLC_CAN_Transmit" declared implicitly status = STM32_PLC_CAN_Transmit(data, &TxHeader); ..\Core\Inc\Open_J1939\Hardware\CAN_Network\CAN_Network.c(71): warning: #188-D: enumerated type mixed with another type status = STM32_PLC_CAN_Transmit(data, &TxHeader); ..\Core\Inc\Open_J1939\Hardware\CAN_Network\CAN_Network.c(101): warning: #223-D: function "STM32_PLC_CAN_Transmit" declared implicitly status = STM32_PLC_CAN_Transmit(PGN, &TxHeader); ..\Core\Inc\Open_J1939\Hardware\CAN_Network\CAN_Network.c(101): warning: #188-D: enumerated type mixed with another type status = STM32_PLC_CAN_Transmit(PGN, &TxHeader); ..\Core\Inc\Open_J1939\Hardware\CAN_Network\CAN_Network.c(122): warning: #223-D: function "STM32_PLC_CAN_Get_ID_Data" declared implicitly STM32_PLC_CAN_Get_ID_Data(ID, data, &is_new_message); ..\Core\Inc\Open_J1939\Hardware\CAN_Network\CAN_Network.c: 5 warnings, 0 errors "BLUEPILL_CAN\BLUEPILL_CAN.axf" - 51 Error(s), 6 Warning(s). Target not created. Build Time Elapsed: 00:00:15

    opened by kaiqued 1
Owner
Daniel Mårtensson
Consultant, M.Sci engineer. Using languages: Java(Spring Boot), C(STM32), C++(QT), MATLAB for quick testing and visualization.
Daniel Mårtensson
Arduino M-BUS Master node for Arduino MKR M-BUS Shield

Arduino M-BUS Master node for Arduino MKR M-BUS Shield This software will read out a M-BUS device connected to an Arduino MKR board equipped with our

null 6 Nov 30, 2022
Serial Data Monitor is a multiplatform (Windows, Linux, Mac, ...) tool to interactively receive/edit/monitor data and send commands to an embedded system via the serial bus

See wiki for full documentation Serial Data Monitor Description Serial Data Monitor is a multiplatform (Windows, Linux, Mac, ...) tool to interactivel

monnoliv 4 Oct 29, 2021
A CANopen protocol for all systems such as embedded, PC, etc.

Easy CANopen Easy CANopen is a protocol for shaping the CAN-bus message in a specific way that suits industrail automation. CANopen is a very difficul

Daniel Mårtensson 25 Jan 4, 2023
A place to collaborate on code for the Embedded.fm book club. Currently reading "STM32 ARM Programming for Embedded Systems".

Welcome to the Book Club Code site! This is a place for the Embedded.fm book club to collaborate and learn together. Repo Structure Guide Top-level fo

Peter Griffin 11 Jul 21, 2022
CAN-BUS sniffing for Volkswagen Golf MK7 (and most likely other MQB platform cars)

MQB-sniffer CAN-BUS sniffing for Volkswagen Golf MK7 (and most likely other MQB platform cars). Currently this is more a work log for future reference

null 22 Dec 23, 2022
CAN bus extruder, more resistant to noise,reduce a lot of wires for your 3D printer

PandaCAN is an extruder control board that connect to main board with CAN interface, more resistant to signal noise,reduce a lot of wires for your 3D printer.

Mark 87 Nov 11, 2022
GPS parser which read raw GPS messages, selects only the valid ones and sends them to CAN bus

EagleTRT GPS System for Fenice GPS parser which read raw GPS messages, selects only the valid ones and sends them to CAN bus Compiling GPS Logger gps_

E-Agle Trento Racing Team 1 Nov 11, 2021
Extension for PHP to interface efficiently with a Controller Area Network (CAN bus) 2.0A / 2.0B

PHP-CanBus Extension PHP-canbus is THE extension for PHP on Linux that allows PHP code to interface efficiently with a Controller Area Network (CAN bu

Adamczyk Piotr 5 Sep 10, 2022
Bus Reservation

Bus Reservation This is our first ever Major Project in CPP About the Project Will add about the project as soon as possible Tasks to be Completed Sig

Manideep 4 Aug 27, 2022
ESP32 bus timetable display

nyssetaulu ESP32 bus timetable display. Displays the next two arrival times of a bus to a stop, in the 10 next arrivals to that stop. Updates every 60

Esa Niemi 3 May 16, 2022
Hörmann Garage Door Opener mit ESP8266 (direkt über Bus, ohne UAP1 !)

hgdo Hörmann Garage Door Opener für Supramatic E3 und P3 Die Hörmann-Antriebe der Supramatic-3-Serie lassen sich über die Universaladapterplatine UAP1

null 23 Nov 25, 2022
Embedded Flutter runtime targeting Embedded Linux with Wayland

ivi-homescreen IVI Homescreen for Wayland Strongly Typed (C++) Lightweight Clang 11 Release Stripped = 151k GCC 9.3 Release Stripped = 168k Source run

null 170 Dec 13, 2022
Embox is a configurable RTOS designed for resource constrained and embedded systems

Embox is a configurable RTOS designed for resource constrained and embedded systems. Embox main idea is using Linux software without Linux.

Embox 877 Dec 28, 2022
Newlib for Xuantie RISC-V CPU, a lightweight C library for embedded systems.

README for GNU development tools This directory contains various GNU compilers, assemblers, linkers, debuggers, etc., plus their support routines, d

T-Head Semiconductor Co., Ltd. 5 Sep 9, 2022
F Graphics Library (FGL) is a small graphics C++ portable library for LCD displays on embedded systems

F Graphics Library (FGL) Full documentation: fgl.docsforge.com (By Filipe Chagas) F Graphics Library is a C++ library that I created for use in embedd

Filipe Chagas 9 Oct 31, 2022
Final Assignment for Embedded Real Time Operating Systems at UCSD Extension.

Final Assignment for Embedded Real Time Operating Systems at UCSD Extension. This program is for a certificate in Embedded Software Engineering at UCSD. We used FreeRTOS running on a STM32L475G Microcontroller.

Max Guerrero 2 Jun 26, 2022
A repo containing examples of embedded systems based on the STM32 micro-controller.

STM32 Embedded Development A repo containing examples of embedded systems based on the STM32 micro-controller. I use a Nucleo-F446RE and the STM32Cube

Vincent Ho 1 Jan 10, 2022
This is a project from my Embedded Systems Lab course. It's made using C and intended for the MSP430FG461 microcontroller.

This is a project from my Embedded Systems Lab course. It's made using C and intended for the MSP430FG461 microcontroller.

Ben Bruzewski 1 Dec 21, 2021
Microshell - a lightweight pure C implementation of shell emulator dedicated for embedded bare-metal systems.

MicroShell Lightweight pure C implementation of virtual shell, compatible with VT100 terminal. Support root tree, run-time mounting paths, global comm

Marcin Borowicz 110 Jan 5, 2023