[MTCD Android Head Units General] lambition:
For some reason, my MTCD unit with Malaysk Rom did not allow me to set long press function to a steering wheel button set for volume. Not sure if it is Malaysk rom or factory rom, or MCU not is causing this issue.

So, in order to fix this problem, I used an Arduino to interpret steering wheel button inputs and send different signal for short press and long press to the head unit.

Also, my car does not have steering wheel radio buttons, so I utilized cruise control buttons.

I'm sure it would be possible to do the same in the head unit's firmware it self, but I did not know where to begin, so I chose the path I know will work. :D

I check long press for buttons I will be using for volume only (Up and down) and other buttons are just passed to reflect actual button status.

This is the circuit I have built. Very simple circuit with a digital potentiometer to send different resistance for each button press.

This is the after soldering parts. Ignore wires at the bottom. I didn't realized copied version of Arduino pro mini did not come with bootloader preloaded, so I had to tap into some pins to program the chip directly first using avr programmer.

Added a 100 ohm resistor to a relay in order to protect it from higher voltage normally present in an automobile. The absolute maximum voltage of the relay I used was 15V and normal operating voltage is 12V. I did not want risk breaking it. :)

This button allows me to select between cruise control and remote control. This is what controls the relay in the circuit.

Hook up everything, and it is good to go. I used ACC power to power the circuit, since there is no reason to keep it running when radio is not on.

[YOUTUBE]K4CQEgYs5hw[/YOUTUBE]

Up -> Volume Up

Long Up (1 sec) -> Previous

2+ Sec Up -> Repeat Long Up every sec

Down -> Volume Down

Long Down (1 sec) -> Next

2+ Sec Down -> Repeat Long Down every sec

Pull -> Play/Pause

Push -> Mode

Long Push -> Home (Using head unit's built in long press button assignment).

Following is my code. I'm sure it is not the best code, but it works. :D

// Car Steering Wheel Rmote w/ Cruise Control Buttons
// lambition
// 10/31/2016

// Using SPI controlled Microchip MCP41100 100K Digital Potentiometer for Output.
// Resistance Value calculated
// Termianl W => Ground, Terminal A => Head Unit Key Input, Terminal B => Leave open
// R_WA: Resistance between Wiper and terminal A.
// R_AB: Resistance between terminal A and B. (100k)
// R_W: Wiper resistance. 125 for 100k chip.
// R_WA(D_n) = ((R_AB * (256-D_n))/256+R_W
// 390.6 ohms per step (100k/256).

// Pin connections
// CS(1) -> 10 (CS)
// SCK(2) -> 13 (SCK)
// SI(3) -> 11 (MOSI)
// Vss (4) -> GND
// PA (5) -> Head Unit Key 1
// PW (6) -> GND
// PB (7) -> Open
// Vdd (8) -> 5V

// First byte is command, Second byte is data. MSB first.

// Command Byte
// X X C1 C0 X X P1 P0
// C1,C0 = 0,1: Write Data, 1,0: Shutdown, Ignore others.
// P1,P0 = 0,1: Select Pot 0, 1,0: Select Pot 1, 1,1: Select Both (P1 is don't care bit for MCP41xxx)

#define CMD_B 0b00010001 // Write Data, Select Pot0. Don't need any other commands.

// Map I/O Pins
#define KEYIN A0 // Key Input
#define CS 10 // Chip select

// Hold time for each button press except pull and push
#define button_hold_ms 500

/*
Input Key Resistance Values in Ohms. Toyota Highalnder Cruise Control Switches.

UP 240
DOWN 630
PULL 1540
PUSH 0

*/

// Input Key Voltages with 1k pull up resistor
// Change these values to what ever your switch is giving.
#define KEYUP_V 1
#define KEYDOWN_V 2
#define KEYPULL_V 3
#define KEYPUSH_V 0
#define VAL_PER_V 204.6
#define TOLERANCE_V 0.35
#define OFFSET 0.05

// Calculate minimum and maximum ADC values
#define MIN_KEYUP_VAL (int)((KEYUP_V+OFFSET-TOLERANCE_V)*VAL_PER_V)
#define MAX_KEYUP_VAL (int)((KEYUP_V+OFFSET+TOLERANCE_V)*VAL_PER_V)
#define MIN_KEYDOWN_VAL (int)((KEYDOWN_V+OFFSET-TOLERANCE_V)*VAL_PER_V)
#define MAX_KEYDOWN_VAL (int)((KEYDOWN_V+OFFSET+TOLERANCE_V)*VAL_PER_V)
#define MIN_KEYPULL_VAL (int)((KEYPULL_V+OFFSET-TOLERANCE_V)*VAL_PER_V)
#define MAX_KEYPULL_VAL (int)((KEYPULL_V+OFFSET+TOLERANCE_V)*VAL_PER_V)
#define MIN_KEYPUSH_VAL (int)((KEYPUSH_V+OFFSET-TOLERANCE_V)*VAL_PER_V)
#define MAX_KEYPUSH_VAL (int)((KEYPUSH_V+OFFSET+TOLERANCE_V)*VAL_PER_V)

// Digital Potentiometer Values
#define KEYUP_POT 255
#define KEYDOWN_POT 230
#define KEYLONGUP_POT 200
#define KEYLONGDOWN_POT 160
#define KEYPUSH_POT 120
#define KEYPULL_POT 0

#include <SPI.h>

enum KeyType { OPEN, KEYUP, KEYDOWN, KEYLONGUP, KEYLONGDOWN, KEYPUSH, KEYPULL };
bool pot_off;

void setup() {
// put your setup code here, to run once:

// Configure Pins
pinMode(KEYIN, INPUT);
pinMode(CS, OUTPUT);

digitalWrite(CS, HIGH);

// SPI Initialization
SPI.begin();

DigitalPot_Shutdown(); // Start with Pot off

}

void loop() {
// put your main code here, to run repeatedly:

static KeyType current_button_state = OPEN;
static KeyType prev_button_state = OPEN;
static KeyType tmp_prev_button_state = OPEN;
static unsigned long button_pressed = 0;
static unsigned long millis_button_held;
static long keyInputValue;
static bool over_sec_processed = true;
static bool prev_long_press = false;

keyInputValue = analogRead(KEYIN); // Read Analog Input

KeyType tmp_button_state ;

// Decode Key Inputs
if ( (keyInputValue <= MAX_KEYUP_VAL) && (keyInputValue >= MIN_KEYUP_VAL)) // Key Up Detected
{
tmp_button_state = KEYUP;
}
else if ( (keyInputValue <= MAX_KEYDOWN_VAL) && (keyInputValue >= MIN_KEYDOWN_VAL)) // Key Down Detected
{
tmp_button_state = KEYDOWN;
}
else if ( (keyInputValue <= MAX_KEYPULL_VAL) && (keyInputValue >= MIN_KEYPULL_VAL)) // Key Pull Detected
{
tmp_button_state = KEYPULL;
}
else if ( (keyInputValue <= MAX_KEYPUSH_VAL) && (keyInputValue >= MIN_KEYPUSH_VAL)) // Key Push Detected
{
tmp_button_state = KEYPUSH;
}
else
{
tmp_button_state = OPEN; // Mark key not pressed and Ignore out of spec values.
}

// Input State Changes
if (tmp_button_state != tmp_prev_button_state)
{
button_pressed = millis();
over_sec_processed = false;
}

if ((millis() - button_pressed) > 10) // 10 ms debounce delay
{
current_button_state = tmp_button_state;
}

tmp_prev_button_state = tmp_button_state;

if ( (current_button_state != OPEN) && (current_button_state == prev_button_state) ) // Button Held
{
millis_button_held = millis() - button_pressed;
}

if ( (current_button_state == OPEN)) // Key released
{
if ((millis_button_held < 1000) && (!prev_long_press)) // Key was pressed less than 1 second and previous button was not a long press.
{

if (prev_button_state == KEYUP) // If last button pressed was Keyup send keyup
{
DigitalPot_Write(KEYUP_POT);
delay(button_hold_ms);
DigitalPot_Shutdown();
}
else if (prev_button_state == KEYDOWN) // If last button pressed was Keydown send keydown.
{
DigitalPot_Write(KEYDOWN_POT);
delay(button_hold_ms);
DigitalPot_Shutdown();
}
else if (!pot_off) // For all other keys, shutoff pot upon releasing button, unless already off.
{
DigitalPot_Shutdown();
}
}
prev_long_press = false;
}
else if ( (current_button_state == KEYUP) || (current_button_state == KEYDOWN) ) // Key up or down
{

if ( (millis_button_held >= 1000) && (!over_sec_processed) ) // Over 1 second
{

if (prev_button_state == KEYUP)
{
DigitalPot_Write(KEYLONGUP_POT);
delay(button_hold_ms);
DigitalPot_Shutdown();
}
else if (prev_button_state == KEYDOWN)
{
DigitalPot_Write(KEYLONGDOWN_POT);
delay(button_hold_ms);
DigitalPot_Shutdown();
}

over_sec_processed = true;
prev_long_press = true;
}

if (millis_button_held >= 2000) // Over 2 seconds
{
delay(1000); // Wait 1 sec between signal
over_sec_processed = false; // Send

}
}
else if ( current_button_state == KEYPULL )
{
if (pot_off) // Write to Pot only once
{
DigitalPot_Write(KEYPULL_POT);
}
prev_long_press = false;
}
else if ( current_button_state == KEYPUSH )
{
if (pot_off) // Write to Pot only once
{
DigitalPot_Write(KEYPUSH_POT);
}
prev_long_press = false;
}

prev_button_state = current_button_state;

}

void DigitalPot_Write(const byte data)
{
SPI.beginTransaction(SPISettings(10000000, MSBFIRST, SPI_MODE0)); //10MHz, MSB First, Ouput on rising edge.
digitalWrite(CS, LOW);
SPI.transfer(CMD_B); // Send Command
SPI.transfer(data); // send Data
digitalWrite(CS, HIGH);
SPI.endTransaction();
pot_off = false;
}

void DigitalPot_Shutdown()
{
SPI.beginTransaction(SPISettings(10000000, MSBFIRST, SPI_MODE0)); //10MHz, MSB First, Ouput on rising edge.
digitalWrite(CS, LOW);
SPI.transfer(0b00100001); //Shutdown Command
SPI.transfer(0); // Dummy data
digitalWrite(CS, HIGH);
SPI.endTransaction();
pot_off = true;
}