XirallicBolts

Flex - Sync 3 Video in Motion

Oct 23rd, 2021 (edited)
279
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 10.66 KB | None | 0 0
  1. //  XirallicBolts
  2. //  Sync 3 Front Camera / Video-in-Motion / Massage for Ford Flex
  3. //  
  4. //  Front camera display using Shift Knob +
  5. //  Toggle front/rear camera using Shift Knob -
  6. //  Activate driver heated seat / steering wheel using Eject
  7. //  
  8. //  09-4-2021  Found proper IPMB message, activate at speed
  9. //  03-1-2022  Bugfix: Heated seats shutting off (accidentally set Ignition byte to 0)
  10. //  4-10-2022  Adding massage seat request
  11. //  4-24-2022  Bugfix: Massage only activates ~1:4 times, seeing if sending Off then High corrects this
  12. //  
  13. //  Arduino Connections
  14. //  INT     2       Pink / Brown
  15. //  Relay   6       Green
  16. //  Shift+  8       Grey
  17. //  Shift-  9       Grey / White
  18. //  CS      10      White / Pink
  19. //  S1      11      White
  20. //  S0      12      Yellow
  21. //  SCK     13      Purple
  22. //
  23. //  --------------------------------
  24. //
  25. //  HS3-CAN +         Orange
  26. //  HS3-CAN -         White / Orange
  27. //  Acc 12v           Red
  28. //  Ground            White / Red
  29. //
  30. //  --------------------------------
  31. //    
  32. //  Message ID 0x109   Data:  00 00 00 00 00 00 00 00
  33. //                            ^^ ^^                     RPM (Hex, multiplied by 4)
  34. //                                  ^                   Gear (0 Park | 1 Reverse | 2 Neutral | 3 Drive | 4 Sport)
  35. //                                     ^^ ^^ ^^         Vehicle Speed
  36. //                                              ^       Ignition Mode? (2 Accessory | 5 Engine Running)
  37. //
  38. //
  39. //  Message ID 0x2A0   xx FF FF FF 10 00 1E 02     Button is PRESSED
  40. //  (Front Panel)      xx FF FF FF 10 00 1E 00     Button is HELD
  41. //                     xx FF FF FF 00 00 1E 00     Button is RELEASED
  42. //                     0x34: Eject         0x18: Sound       0x5F: Home     0x1F: Power
  43. //
  44. //  Message ID 0x35B   00 00 00 FE 80 00 00        Heated Steering Wheel
  45. //  (Climate)          00 00 01 FE 00 00 00        Driver Heated Seat
  46. //                     00 00 03 FE 00 00 00        Passenger Heated Seat
  47. //
  48. //  Message ID 0x3EE   00 08 08 1B 80 00 00 00     Request camera display
  49. //  (Image Processor)  00 00 08 1B 80 00 00 00     Cancel camera display
  50. //
  51. // Common between shift buttons connects to ground
  52. //  
  53. // CAN0.sendMsgBuf(message_ID, 0, message_LENGTH, message_DATA);
  54.  
  55.  
  56. #include <mcp_can.h>
  57. #include <SPI.h>
  58. #define CAN_INT         2
  59. #define CAN_CS          10
  60. #define CAMERA_RELAY    7     // Trigger pin on DPDT relay
  61. #define BUTTON_REQUEST  8     // Request Camera button. Connect to Ground to signal.
  62. #define BUTTON_TOGGLE   9     // Toggle front/rear camera button. Connect to Ground to signal.
  63.  
  64. MCP_CAN CAN0(CAN_CS);
  65.  
  66. byte ForceRearCamera         = 0;    // If the car is in reverse, forcibly switch to rear camera
  67. byte CameraRequestButtonHeld = 0;
  68. byte CameraToggleButtonHeld  = 0;
  69. byte CameraButtonReleased    = 0;    // Camera Request button was released, attempt to display camera if conditions are right
  70. byte CurrentGear             = 0;    // Every time 0x109 comes through, take note of current gear
  71. byte CameraViewActive        = 0;    // Are we currently in a camera view?
  72. byte HeatedSeatButtonHeld    = 0;    // Counter to track how long a given button (Eject in my case) is being held
  73. byte MassageActivated        = 0;    // On first shift out of Park, activate massage
  74. String PendingMessage      = "none";
  75. String LastMessage         = "none";
  76.  
  77. long unsigned int message_ID;
  78. unsigned char message_LENGTH = 0;
  79. unsigned char message_DATA[8];
  80. unsigned char message_Camera_Request[8] = {0x00, 0x08, 0x08, 0x1B, 0x80, 0x00, 0x00, 0x00};
  81. unsigned char message_Camera_Cancel[8] = {0x00, 0x00, 0x08, 0x1B, 0x80, 0x00, 0x00, 0x00};
  82. unsigned char message_Fake_Speed[8] = {0x09, 0x13, 0x31, 0x00, 0x00, 0x00, 0x58, 0x00};
  83. unsigned char message_Heated_Seat_Driver[8] = {0x00, 0x00, 0x01, 0xFE, 0x00, 0x00, 0x00, 0x00};
  84. unsigned char message_Heated_Seat_Passenger[8] = {0x00, 0x00, 0x03, 0xFE, 0x00, 0x00, 0x00, 0x00};
  85. unsigned char message_Heated_Wheel[8] = {0x00, 0x00, 0x00, 0xFE, 0x80, 0x00, 0x00, 0x00};
  86. // Massage ID 34E
  87. unsigned char message_Massage_Drv_Seat_Off[8] = {0x00, 0x1C, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00);
  88. unsigned char message_Massage_Drv_Back_Off[8] = {0x00, 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00);
  89. unsigned char message_Massage_Pass_Seat_Off[8] = {0x00, 0xE0, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00);
  90. unsigned char message_Massage_Pass_Back_Off[8] = {0x00, 0xC0, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00);
  91.  
  92. unsigned char message_Massage_Drv_Seat_High[8] = {0x00, 0x1C, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00};
  93. unsigned char message_Massage_Drv_Back_High[8] = {0x00, 0x18, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00};
  94. unsigned char message_Massage_Pass_Seat_High[8] = {0x00, 0xE0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00};
  95. unsigned char message_Massage_Pass_Back_High[8] = {0x00, 0xC0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00};
  96.  
  97. void setup() {
  98.   pinMode(CAMERA_RELAY, OUTPUT);
  99.   pinMode(BUTTON_REQUEST, INPUT_PULLUP);
  100.   pinMode(BUTTON_TOGGLE, INPUT_PULLUP);
  101.   pinMode(CAN_INT, INPUT);
  102.   digitalWrite(CAMERA_RELAY, HIGH);   // Default to front camera
  103.  
  104.   Serial.begin(115200);
  105.     Serial.println("XirallicBolts");
  106.     Serial.println("Front Camera and Video-in-Motion 2/19/21");
  107.     Serial.println("-------");
  108.  
  109.   if(CAN0.begin(MCP_STDEXT, CAN_500KBPS, MCP_16MHZ) == CAN_OK)
  110.     Serial.println("MCP2515 Initialized Succesfully");
  111.   else
  112.     Serial.println("Could not initialize MCP2515 (CS 10, INT 2, 500KBPS, 16MHz");  
  113.  
  114.   // Immediately send a Camera Cancel in case something got stuck on the last ignition cycle
  115.   CAN0.setMode(MCP_NORMAL);
  116.   CAN0.sendMsgBuf(0x3EE, 0, 8, message_Camera_Cancel);
  117. }
  118.  
  119. void loop() {
  120.  
  121.   if(!digitalRead(CAN_INT))
  122.   {
  123.     CAN0.readMsgBuf(&message_ID, &message_LENGTH, message_DATA);
  124.  
  125.     // Send a "Camera Cancel" if the car is shifted into Park
  126.     // Store the Current Gear for other uses.
  127.     if(message_ID == 0x109)
  128.     {
  129.       if((message_DATA[2] <= 0x0F) && (CurrentGear >= 0x10))
  130.       {
  131.         CAN0.sendMsgBuf(0x3EE, 0, 8, message_Camera_Cancel);
  132.         CameraViewActive = 0;
  133.         Serial.println("Vehicle shifted to Park. Canceling camera");
  134.       }
  135.       CurrentGear = message_DATA[2];
  136.     }
  137.  
  138.     // First time the car shifts out of Park, send a Driver Massage request
  139.     if((CurrentGear >= 0x10) && (MassageActivated == 0))
  140.     {
  141.       Serial.println("Shifted out of Park, requesting Massage");
  142.       CAN0.sendMsgBuf(0x34E, 0, 8, message_Massage_Drv_Back_Off);
  143.       delay(500);
  144.       CAN0.sendMsgBuf(0x34E, 0, 8, message_Massage_Drv_Seat_Off);
  145.       delay(500);
  146.       CAN0.sendMsgBuf(0x34E, 0, 8, message_Massage_Drv_Back_High);
  147.       delay(500);
  148.       CAN0.sendMsgBuf(0x34E, 0, 8, message_Massage_Drv_Seat_High);
  149.       delay(500);
  150.       MassageActivated = 1;
  151.     }
  152.  
  153.     // If the car is in Reverse (or Forced Rear), toggle rear camera.
  154.     if(((CurrentGear >= 0x10) && (CurrentGear <= 0x1F)) || (ForceRearCamera == 1))
  155.     {
  156.       if(ForceRearCamera == 1)
  157.         PendingMessage = "Rear camera forced by button press";
  158.       else
  159.         PendingMessage = "Rear camera forced by current gear";
  160.       digitalWrite(CAMERA_RELAY, LOW);
  161.     }
  162.  
  163.  
  164.  
  165.  
  166.     // If the car is NOT in Reverse or Forced Rear, toggle front camera.
  167.     if(((CurrentGear <= 0x0F) || (CurrentGear >= 0x20)) && (ForceRearCamera == 0))
  168.     {
  169.       PendingMessage = "Front camera selected (Vehicle not in reverse, no manual request)";
  170.       digitalWrite(CAMERA_RELAY, HIGH);
  171.     }
  172.  
  173.  
  174.  
  175.  
  176.  
  177.     // If the Camera Request is pressed and not in Camera View, request the camera.
  178.     if((CameraButtonReleased == 1) && (CameraViewActive == 0))
  179.     {
  180.       Serial.println("\nFront camera has been requested.");
  181.       if(CurrentGear != 0x01)
  182.       {
  183.         Serial.println("Vehicle is not in Park.  Sending a falsified speed message...");
  184.         CAN0.sendMsgBuf(0x109, 0, 8, message_Fake_Speed);
  185.       }
  186.       Serial.println("Sending Camera Request...");
  187.       CAN0.sendMsgBuf(0x3EE, 0, 8, message_Camera_Request);
  188.       CameraButtonReleased = 0;
  189.       CameraViewActive = 1;
  190.     }
  191.  
  192.  
  193.  
  194.  
  195.     // If the Camera Request is pressed and currently in Camera View,  cancel the camera.
  196.     if((CameraButtonReleased == 1) && (CameraViewActive == 1))
  197.     {
  198.       Serial.println("\nCamera CANCEL Requested");
  199.       CAN0.sendMsgBuf(0x3EE, 0, 8, message_Camera_Cancel);
  200.       CameraButtonReleased = 0;
  201.       CameraViewActive = 0;
  202.     }
  203.  
  204.  
  205.  
  206.  
  207.     // =======================================================================================
  208.     //
  209.     // Check for Eject button press for heated seat / steering wheel.
  210.     // Increment the counter each time it's seen.
  211.     //
  212.     if(message_ID == 0x2A0 and message_DATA[0] == 0x34 and message_DATA[4] == 0x10)
  213.     {
  214.       Serial.println("Eject button is pressed or held");
  215.       HeatedSeatButtonHeld++;
  216.     }
  217.  
  218.     // Check if Eject button was released.
  219.     if(message_ID == 0x2A0 and message_DATA[0] == 0x34 and message_DATA[4] == 0x10)
  220.     {
  221.       Serial.println("Eject button was released");
  222.       if(HeatedSeatButtonHeld >= 3)
  223.       {
  224.         Serial.println("+ Requesting heated seat (Driver)");
  225.         CAN0.sendMsgBuf(0x35E, 0, 8, message_Heated_Seat_Driver);
  226.         delay(100);
  227.         Serial.println("+ Requesting heated steering wheel");
  228.         CAN0.sendMsgBuf(0x35E, 0, 8, message_Heated_Wheel);
  229.       }
  230.  
  231.       // Regardless of outcome, reset the counter
  232.       HeatedSeatButtonHeld = 0;
  233.     }
  234.   }
  235.  
  236.  
  237.  
  238.  
  239.  
  240. // ===========================================================================================
  241. //
  242. //  Input Triggers
  243. //  Monitor the Request and Toggle inputs
  244. //
  245.  
  246.   // Check if the button is currently being pressed (Pin connected to ground)
  247.   if(digitalRead(BUTTON_REQUEST) == LOW)
  248.   {  
  249.     CameraRequestButtonHeld = 1;
  250.   }
  251.   if(digitalRead(BUTTON_TOGGLE) == LOW)
  252.   {
  253.     CameraToggleButtonHeld = 1;
  254.   }
  255.  
  256.   // React if a pressed button has been released.
  257.   if(digitalRead(BUTTON_REQUEST) == HIGH and CameraRequestButtonHeld == 1)
  258.   {
  259.     Serial.println("\nCamera Request has been released.\n");
  260.     CameraRequestButtonHeld = 0;
  261.     CameraButtonReleased = 1;
  262.   }
  263.  
  264.   if(digitalRead(BUTTON_TOGGLE) == HIGH and CameraToggleButtonHeld == 1)
  265.   {
  266.     Serial.println("\nCamera Toggle has been released.\n");
  267.     CameraToggleButtonHeld = 0;
  268.     ForceRearCamera = !ForceRearCamera;
  269.   }
  270.  
  271.  
  272.  
  273. // ===========================================================================================
  274.  
  275.  
  276.  
  277. // If there's a pending message and it's NOT a duplicate of the last message, broadcast it.
  278. // Only used for messages that tend to repeat, to help keep SerialMonitor clean.
  279.   if((PendingMessage != "none") && (PendingMessage != LastMessage))
  280.   {
  281.     Serial.println(PendingMessage);
  282.     LastMessage = PendingMessage;
  283.     PendingMessage = "none";
  284.   }
  285.  
  286. }
Add Comment
Please, Sign In to add comment