Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // XirallicBolts
- // Sync 3 Front Camera / Video-in-Motion / Massage for Ford Flex
- //
- // Front camera display using Shift Knob +
- // Toggle front/rear camera using Shift Knob -
- // Activate driver heated seat / steering wheel using Eject
- //
- // 09-4-2021 Found proper IPMB message, activate at speed
- // 03-1-2022 Bugfix: Heated seats shutting off (accidentally set Ignition byte to 0)
- // 4-10-2022 Adding massage seat request
- // 4-24-2022 Bugfix: Massage only activates ~1:4 times, seeing if sending Off then High corrects this
- //
- // Arduino Connections
- // INT 2 Pink / Brown
- // Relay 6 Green
- // Shift+ 8 Grey
- // Shift- 9 Grey / White
- // CS 10 White / Pink
- // S1 11 White
- // S0 12 Yellow
- // SCK 13 Purple
- //
- // --------------------------------
- //
- // HS3-CAN + Orange
- // HS3-CAN - White / Orange
- // Acc 12v Red
- // Ground White / Red
- //
- // --------------------------------
- //
- // Message ID 0x109 Data: 00 00 00 00 00 00 00 00
- // ^^ ^^ RPM (Hex, multiplied by 4)
- // ^ Gear (0 Park | 1 Reverse | 2 Neutral | 3 Drive | 4 Sport)
- // ^^ ^^ ^^ Vehicle Speed
- // ^ Ignition Mode? (2 Accessory | 5 Engine Running)
- //
- //
- // Message ID 0x2A0 xx FF FF FF 10 00 1E 02 Button is PRESSED
- // (Front Panel) xx FF FF FF 10 00 1E 00 Button is HELD
- // xx FF FF FF 00 00 1E 00 Button is RELEASED
- // 0x34: Eject 0x18: Sound 0x5F: Home 0x1F: Power
- //
- // Message ID 0x35B 00 00 00 FE 80 00 00 Heated Steering Wheel
- // (Climate) 00 00 01 FE 00 00 00 Driver Heated Seat
- // 00 00 03 FE 00 00 00 Passenger Heated Seat
- //
- // Message ID 0x3EE 00 08 08 1B 80 00 00 00 Request camera display
- // (Image Processor) 00 00 08 1B 80 00 00 00 Cancel camera display
- //
- // Common between shift buttons connects to ground
- //
- // CAN0.sendMsgBuf(message_ID, 0, message_LENGTH, message_DATA);
- #include <mcp_can.h>
- #include <SPI.h>
- #define CAN_INT 2
- #define CAN_CS 10
- #define CAMERA_RELAY 7 // Trigger pin on DPDT relay
- #define BUTTON_REQUEST 8 // Request Camera button. Connect to Ground to signal.
- #define BUTTON_TOGGLE 9 // Toggle front/rear camera button. Connect to Ground to signal.
- MCP_CAN CAN0(CAN_CS);
- byte ForceRearCamera = 0; // If the car is in reverse, forcibly switch to rear camera
- byte CameraRequestButtonHeld = 0;
- byte CameraToggleButtonHeld = 0;
- byte CameraButtonReleased = 0; // Camera Request button was released, attempt to display camera if conditions are right
- byte CurrentGear = 0; // Every time 0x109 comes through, take note of current gear
- byte CameraViewActive = 0; // Are we currently in a camera view?
- byte HeatedSeatButtonHeld = 0; // Counter to track how long a given button (Eject in my case) is being held
- byte MassageActivated = 0; // On first shift out of Park, activate massage
- String PendingMessage = "none";
- String LastMessage = "none";
- long unsigned int message_ID;
- unsigned char message_LENGTH = 0;
- unsigned char message_DATA[8];
- unsigned char message_Camera_Request[8] = {0x00, 0x08, 0x08, 0x1B, 0x80, 0x00, 0x00, 0x00};
- unsigned char message_Camera_Cancel[8] = {0x00, 0x00, 0x08, 0x1B, 0x80, 0x00, 0x00, 0x00};
- unsigned char message_Fake_Speed[8] = {0x09, 0x13, 0x31, 0x00, 0x00, 0x00, 0x58, 0x00};
- unsigned char message_Heated_Seat_Driver[8] = {0x00, 0x00, 0x01, 0xFE, 0x00, 0x00, 0x00, 0x00};
- unsigned char message_Heated_Seat_Passenger[8] = {0x00, 0x00, 0x03, 0xFE, 0x00, 0x00, 0x00, 0x00};
- unsigned char message_Heated_Wheel[8] = {0x00, 0x00, 0x00, 0xFE, 0x80, 0x00, 0x00, 0x00};
- // Massage ID 34E
- unsigned char message_Massage_Drv_Seat_Off[8] = {0x00, 0x1C, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00);
- unsigned char message_Massage_Drv_Back_Off[8] = {0x00, 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00);
- unsigned char message_Massage_Pass_Seat_Off[8] = {0x00, 0xE0, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00);
- unsigned char message_Massage_Pass_Back_Off[8] = {0x00, 0xC0, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00);
- unsigned char message_Massage_Drv_Seat_High[8] = {0x00, 0x1C, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00};
- unsigned char message_Massage_Drv_Back_High[8] = {0x00, 0x18, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00};
- unsigned char message_Massage_Pass_Seat_High[8] = {0x00, 0xE0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00};
- unsigned char message_Massage_Pass_Back_High[8] = {0x00, 0xC0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00};
- void setup() {
- pinMode(CAMERA_RELAY, OUTPUT);
- pinMode(BUTTON_REQUEST, INPUT_PULLUP);
- pinMode(BUTTON_TOGGLE, INPUT_PULLUP);
- pinMode(CAN_INT, INPUT);
- digitalWrite(CAMERA_RELAY, HIGH); // Default to front camera
- Serial.begin(115200);
- Serial.println("XirallicBolts");
- Serial.println("Front Camera and Video-in-Motion 2/19/21");
- Serial.println("-------");
- if(CAN0.begin(MCP_STDEXT, CAN_500KBPS, MCP_16MHZ) == CAN_OK)
- Serial.println("MCP2515 Initialized Succesfully");
- else
- Serial.println("Could not initialize MCP2515 (CS 10, INT 2, 500KBPS, 16MHz");
- // Immediately send a Camera Cancel in case something got stuck on the last ignition cycle
- CAN0.setMode(MCP_NORMAL);
- CAN0.sendMsgBuf(0x3EE, 0, 8, message_Camera_Cancel);
- }
- void loop() {
- if(!digitalRead(CAN_INT))
- {
- CAN0.readMsgBuf(&message_ID, &message_LENGTH, message_DATA);
- // Send a "Camera Cancel" if the car is shifted into Park
- // Store the Current Gear for other uses.
- if(message_ID == 0x109)
- {
- if((message_DATA[2] <= 0x0F) && (CurrentGear >= 0x10))
- {
- CAN0.sendMsgBuf(0x3EE, 0, 8, message_Camera_Cancel);
- CameraViewActive = 0;
- Serial.println("Vehicle shifted to Park. Canceling camera");
- }
- CurrentGear = message_DATA[2];
- }
- // First time the car shifts out of Park, send a Driver Massage request
- if((CurrentGear >= 0x10) && (MassageActivated == 0))
- {
- Serial.println("Shifted out of Park, requesting Massage");
- CAN0.sendMsgBuf(0x34E, 0, 8, message_Massage_Drv_Back_Off);
- delay(500);
- CAN0.sendMsgBuf(0x34E, 0, 8, message_Massage_Drv_Seat_Off);
- delay(500);
- CAN0.sendMsgBuf(0x34E, 0, 8, message_Massage_Drv_Back_High);
- delay(500);
- CAN0.sendMsgBuf(0x34E, 0, 8, message_Massage_Drv_Seat_High);
- delay(500);
- MassageActivated = 1;
- }
- // If the car is in Reverse (or Forced Rear), toggle rear camera.
- if(((CurrentGear >= 0x10) && (CurrentGear <= 0x1F)) || (ForceRearCamera == 1))
- {
- if(ForceRearCamera == 1)
- PendingMessage = "Rear camera forced by button press";
- else
- PendingMessage = "Rear camera forced by current gear";
- digitalWrite(CAMERA_RELAY, LOW);
- }
- // If the car is NOT in Reverse or Forced Rear, toggle front camera.
- if(((CurrentGear <= 0x0F) || (CurrentGear >= 0x20)) && (ForceRearCamera == 0))
- {
- PendingMessage = "Front camera selected (Vehicle not in reverse, no manual request)";
- digitalWrite(CAMERA_RELAY, HIGH);
- }
- // If the Camera Request is pressed and not in Camera View, request the camera.
- if((CameraButtonReleased == 1) && (CameraViewActive == 0))
- {
- Serial.println("\nFront camera has been requested.");
- if(CurrentGear != 0x01)
- {
- Serial.println("Vehicle is not in Park. Sending a falsified speed message...");
- CAN0.sendMsgBuf(0x109, 0, 8, message_Fake_Speed);
- }
- Serial.println("Sending Camera Request...");
- CAN0.sendMsgBuf(0x3EE, 0, 8, message_Camera_Request);
- CameraButtonReleased = 0;
- CameraViewActive = 1;
- }
- // If the Camera Request is pressed and currently in Camera View, cancel the camera.
- if((CameraButtonReleased == 1) && (CameraViewActive == 1))
- {
- Serial.println("\nCamera CANCEL Requested");
- CAN0.sendMsgBuf(0x3EE, 0, 8, message_Camera_Cancel);
- CameraButtonReleased = 0;
- CameraViewActive = 0;
- }
- // =======================================================================================
- //
- // Check for Eject button press for heated seat / steering wheel.
- // Increment the counter each time it's seen.
- //
- if(message_ID == 0x2A0 and message_DATA[0] == 0x34 and message_DATA[4] == 0x10)
- {
- Serial.println("Eject button is pressed or held");
- HeatedSeatButtonHeld++;
- }
- // Check if Eject button was released.
- if(message_ID == 0x2A0 and message_DATA[0] == 0x34 and message_DATA[4] == 0x10)
- {
- Serial.println("Eject button was released");
- if(HeatedSeatButtonHeld >= 3)
- {
- Serial.println("+ Requesting heated seat (Driver)");
- CAN0.sendMsgBuf(0x35E, 0, 8, message_Heated_Seat_Driver);
- delay(100);
- Serial.println("+ Requesting heated steering wheel");
- CAN0.sendMsgBuf(0x35E, 0, 8, message_Heated_Wheel);
- }
- // Regardless of outcome, reset the counter
- HeatedSeatButtonHeld = 0;
- }
- }
- // ===========================================================================================
- //
- // Input Triggers
- // Monitor the Request and Toggle inputs
- //
- // Check if the button is currently being pressed (Pin connected to ground)
- if(digitalRead(BUTTON_REQUEST) == LOW)
- {
- CameraRequestButtonHeld = 1;
- }
- if(digitalRead(BUTTON_TOGGLE) == LOW)
- {
- CameraToggleButtonHeld = 1;
- }
- // React if a pressed button has been released.
- if(digitalRead(BUTTON_REQUEST) == HIGH and CameraRequestButtonHeld == 1)
- {
- Serial.println("\nCamera Request has been released.\n");
- CameraRequestButtonHeld = 0;
- CameraButtonReleased = 1;
- }
- if(digitalRead(BUTTON_TOGGLE) == HIGH and CameraToggleButtonHeld == 1)
- {
- Serial.println("\nCamera Toggle has been released.\n");
- CameraToggleButtonHeld = 0;
- ForceRearCamera = !ForceRearCamera;
- }
- // ===========================================================================================
- // If there's a pending message and it's NOT a duplicate of the last message, broadcast it.
- // Only used for messages that tend to repeat, to help keep SerialMonitor clean.
- if((PendingMessage != "none") && (PendingMessage != LastMessage))
- {
- Serial.println(PendingMessage);
- LastMessage = PendingMessage;
- PendingMessage = "none";
- }
- }
Add Comment
Please, Sign In to add comment