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.
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.
{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
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.
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.
Code:
// 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;
}
Dude... That is f** awesome!! But I hardly doubt that anyone will be willing to go through the same just to get the long-press function =)) I ll keep waiting for the software solution
Kudos!! Awesome job and very simple - but you just have to come up with the idea.
Respect!
Mighty_X said:
Dude... That is f** awesome!! But I hardly doubt that anyone will be willing to go through the same just to get the long-press function =)) I ll keep waiting for the software solution
Click to expand...
Click to collapse
It is actually quiet simple. Whole thing cost me about $6 to make because I already had switches and relay. Chinese copy version of Arduino pro mini is only around $3 or less. Digital potentiometer is around $3 as well, but this can be replaced with resistor array and using 5 digital IO pins.
Digital potentiometer just makes it easier to change resistance values.
Henkdrenth said:
Kudos!! Awesome job and very simple - but you just have to come up with the idea.
Respect!
Click to expand...
Click to collapse
I wish someone cracks MCU of our device. Our device have great potential, but software is made to just barely functioning.
Hi guys i would ask your help. I have an Alfa Romeo Giulietta, Installed in the dash a nexus 7 2013 and I want use the steering wheel buttons. The car use the protocol is 15765-4 29bit and I have on Bluetooth obd reader. Can you please help me out? Thanks in advance.
Inviato dal mio FRD-L09 utilizzando Tapatalk
valk791 said:
Hi guys i would ask your help. I have an Alfa Romeo Giulietta, Installed in the dash a nexus 7 2013 and I want use the steering wheel buttons. The car use the protocol is 15765-4 29bit and I have on Bluetooth obd reader. Can you please help me out? Thanks in advance.
Inviato dal mio FRD-L09 utilizzando Tapatalk
Click to expand...
Click to collapse
You might receive suggestions posting in the appropriate forum or opening a new thread. To post here is isnt appropriate.
Amazing work.... Many thanks
Wow a nice, clean, elegant and simple solution.
I've done it little bit different (Old Style) as my car model didn't had factory Steering wheel, so I made steering wheel upgrade that left me with 6 Wires to play with (3 for 6 Media Commands and 3 for 4 Cruise control). So I ended up with dismantle steering wheel commands setting up each command different by 20kOhm in parallel to outputs So I have 6 Main commands and any combination of two+ keys simultaneously for additional commands as I get 1/2 of sum Ohm of the commands pressed. and o the other side 4 Cruise control commands (do not have cruise control in Car) both commands Directly connected GND+KEY1 for Media Controls and GND+KEY2 for cruise control.
Now I only need to think how to emulate keyboard commands so that I can navigate Home Screen and emulate Swipe.
FYI I have not seen any ROM to allow Vol +/- long press as it is reserved for Vol Repeat mode
Works great for me, just so others may also take advantage of this code, I used the below for a Honda Jazz/Fit 2010 with a Kenwood Android Auto Head Unit, I only used the CH+/- and MODE for long press as I did not want to mess with volume triggers and 8 total controls is enough for me (just), not sure if anyone else had an issue but for me the lower resistance (higher potentiometer values) were the only ones that would work with my head unit.
Code:
// 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
//Just for programming head unit
//#define button_hold_ms 3000
// Input Key Voltages with 1k pull up resistor
// Change these values to what ever your switch is giving.
#define INPUT_KEYUP_V 315
#define INPUT_KEYDOWN_V 115
#define INPUT_KEYUP_CH 691
#define INPUT_KEYDOWN_CH 501
#define INPUT_KEY_MODE 839
#define TOLERANCE_V 20
#define OFFSET 0.05
// Calculate minimum and maximum ADC values
#define MIN_KEYUP_V_VAL (int)(INPUT_KEYUP_V+OFFSET-TOLERANCE_V)
#define MAX_KEYUP_V_VAL (int)(INPUT_KEYUP_V+OFFSET+TOLERANCE_V)
#define MIN_KEYDOWN_V_VAL (int)(INPUT_KEYDOWN_V+OFFSET-TOLERANCE_V)
#define MAX_KEYDOWN_V_VAL (int)(INPUT_KEYDOWN_V+OFFSET+TOLERANCE_V)
#define MIN_KEYUP_CH_VAL (int)(INPUT_KEYUP_CH+OFFSET-TOLERANCE_V)
#define MAX_KEYUP_CH_VAL (int)(INPUT_KEYUP_CH+OFFSET+TOLERANCE_V)
#define MIN_KEYDOWN_CH_VAL (int)(INPUT_KEYDOWN_CH+OFFSET-TOLERANCE_V)
#define MAX_KEYDOWN_CH_VAL (int)(INPUT_KEYDOWN_CH+OFFSET+TOLERANCE_V)
#define MIN_KEY_MODE_VAL (int)(INPUT_KEY_MODE+OFFSET-TOLERANCE_V)
#define MAX_KEY_MODE_VAL (int)(INPUT_KEY_MODE+OFFSET+TOLERANCE_V)
// Digital Potentiometer Values
#define KEYUP_V_POT 255
#define KEYDOWN_V_POT 254
#define KEYUP_CH_POT 250
#define KEYDOWN_CH_POT 243
#define KEYUPLONG_CH_POT 239
#define KEYDOWNLONG_CH_POT 246
#define KEY_MODE_POT 94
#define KEYLONG_MODE_POT 200
#include <SPI.h>
enum KeyType { OPEN, KEYUP_V, KEYDOWN_V, KEYUP_CH, KEYDOWN_CH, KEYLONGUP_CH, KEYLONGDOWN_CH, KEY_MODE, KEYLONG_MODE };
bool pot_off;
bool debug = false;
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
if (debug) {
while (!Serial) { }
}
debugMessage("BOOT: Serial initialized");
// Configure Pins
pinMode(KEYIN, INPUT);
pinMode(CS, OUTPUT);
digitalWrite(CS, HIGH);
// SPI Initialization
SPI.begin();
DigitalPot_Shutdown(); // Start with Pot off
debugMessage("BOOT: Booted");
}
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
//debugMessage((String)keyInputValue);
KeyType tmp_button_state ;
// Decode Key Inputs
if ( (keyInputValue <= MAX_KEYUP_V_VAL) && (keyInputValue >= MIN_KEYUP_V_VAL)) // Key Up Detected
{
tmp_button_state = KEYUP_V;
}
else if ( (keyInputValue <= MAX_KEYDOWN_V_VAL) && (keyInputValue >= MIN_KEYDOWN_V_VAL)) // Key Down Detected
{
tmp_button_state = KEYDOWN_V;
}
else if ( (keyInputValue <= MAX_KEYUP_CH_VAL) && (keyInputValue >= MIN_KEYUP_CH_VAL)) // Key Pull Detected
{
tmp_button_state = KEYUP_CH;
}
else if ( (keyInputValue <= MAX_KEYDOWN_CH_VAL) && (keyInputValue >= MIN_KEYDOWN_CH_VAL)) // Key Push Detected
{
tmp_button_state = KEYDOWN_CH;
}
else if ( (keyInputValue <= MAX_KEY_MODE_VAL) && (keyInputValue >= MIN_KEY_MODE_VAL)) // Key Push Detected
{
tmp_button_state = KEY_MODE;
}
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;
}
//Button is now in open
if ( (current_button_state == OPEN)) // Key released
{
//debugMessage("STATE: OPEN");
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_CH) // If last button pressed was Keyup send keyup
{
debugMessage("ACTION: SHORT KEYUP_CH");
DigitalPot_Write(KEYUP_CH_POT);
delay(button_hold_ms);
DigitalPot_Shutdown();
}
else if (prev_button_state == KEYDOWN_CH) // If last button pressed was Keydown send keydown.
{
debugMessage("ACTION: SHORT KEYDOWN_CH");
DigitalPot_Write(KEYDOWN_CH_POT);
delay(button_hold_ms);
DigitalPot_Shutdown();
}
else if (prev_button_state == KEY_MODE) // If last button pressed was Keydown send keydown.
{
debugMessage("ACTION: SHORT KEYMODE");
DigitalPot_Write(KEY_MODE_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_CH) || (current_button_state == KEYDOWN_CH) || (current_button_state == KEY_MODE) ) // Key up or down
{
if ( (millis_button_held >= 1000) && (!over_sec_processed) ) // Over 1 second
{
if (prev_button_state == KEYUP_CH)
{
debugMessage("ACTION: LONG KEYUP_CH");
DigitalPot_Write(KEYUPLONG_CH_POT);
delay(button_hold_ms);
DigitalPot_Shutdown();
}
else if (prev_button_state == KEYDOWN_CH)
{
debugMessage("ACTION: LONG KEYDOWN_CH");
DigitalPot_Write(KEYDOWNLONG_CH_POT);
delay(button_hold_ms);
DigitalPot_Shutdown();
}
else if (prev_button_state == KEY_MODE)
{
debugMessage("ACTION: LONG KEYMODE");
DigitalPot_Write(KEYLONG_MODE_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 == KEYUP_V )
{
if (pot_off) // Write to Pot only once
{
debugMessage("ACTION: SHORT KEYUP_V");
DigitalPot_Write(KEYUP_V_POT);
}
prev_long_press = false;
}
else if ( current_button_state == KEYDOWN_V )
{
if (pot_off) // Write to Pot only once
{
debugMessage("ACTION: SHORT KEYDOWN_V");
DigitalPot_Write(KEYDOWN_V_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;
}
void debugMessage(String message) {
if (debug) {
Serial.println(message);
}
}
My car is hyundai santafe 2010 with steering wheel button, I measure the Resistance Value between button and ground by pressing each button, the result are:
- Mode: 2.10 K ohm
- Up: 434 ohm
- Down: 1.12 K ohm
- Volume Up: 4.60 K ohm
- Volume Down: 6.81 K ohm
- Map: 10.72 K ohm
- Phone On: 41.00 K ohm
- Phone Off: 18.99 K ohm
I replace the other head unit (10" monitor of Suzuki XL7), so I want to use the steering wheel control of my Santafe to control the Suzuki XL7 head unit
The Suzuki XL7 head unit use Resistance Value for each steering wheel button are:
- Mute: 56 +- 0.6 Ohm
- Volume +: 131 +- 1.3 Ohm
- Volume -: 241 +- 2.4 Ohm
- Next: 1571 +- 15.7 Ohm
- Prev: 751 +- 7.5 Ohm
- Mode: 421 +- 4.2 Ohm
I read this thread many times and prepare
- Arduino Nano.
- resistor: 1K ohm
- MCP41100
- Converter 12v to 5V.
but I still not understand some code and parameter.
sparky3387, lambitioncan you explain more detail for me
the diagram of MCP41100 to Arduino and head unit key?
// MCP41100 8 Pin connections
// CS(1) -> D10 (Arduino)
// SCK(2) -> D13 (Arduino)
// SI(3) -> D11 (Arduino)
// Vss (4) -> GND
// PA (5) -> Head Unit Key 1
// PW (6) -> GND
// PB (7) -> Open
// Vdd (8) -> 5V
The value of INPUT_KEY is voltage or Resistance Value
// Input Key Voltages with 1k pull up resistor
// Change these values to what ever your switch is giving.
#define INPUT_KEYUP_V 315
#define INPUT_KEYDOWN_V 115
#define INPUT_KEYUP_CH 691
#define INPUT_KEYDOWN_CH 501
#define INPUT_KEY_MODE 839
Do I must change the value:
#define TOLERANCE_V 20
#define OFFSET 0.05
Can you add code to measure the value ò INPUT_KEY like this link:
Resistor Ladder Steering Wheel Control Interpreter Using Arduino
I’m currently busy creating an Arduino steering wheel adapter between my ’05 Pontiac GTO steering wheel controls and the Parrot Asteroid Smart Android-powered head unit. Doing this beca…
atomic-cactus.com
How do I do, please help me.
Thank you.
Related
I (or rather, all of us...) need some code, and I've never really done any Javascript.
Could someone please code:
- Enable all controls on form 0 of a document.
- Walk through all the controls in order. For each control:
- Make a temporary string that holds the name of the control
- add a slash and the value of the control if it is a checkbox
- Walk through all the controls again
- Disable any controls:
- whose name is longer, but starts with the temp string above
- which are radiobuttons whose name is the temp-string
- done
This would disable any controls that do not apply when the user deselects a higher-level checkbox or radio-button, which would look much cleaner and cooler. I would have to spend most of today on this learning enough Javascript and fixing stupid beginner-bugs, and I would be disapointed if we don't have at least a few people here who can code this in 10 minutes.
Code can be tested by copying the form from the kitchen locally and creating a function to replace the submit placed at every checkbox or radiobutton control.
ok, consider this a beta
i did not follow your design in whole
but still i hope the functionality is the same
email me to [email protected] for any needed changes
my local time is 2:31 after midnight
uh uaah, good night
Code:
<html>
<head>
<script>
function setupDisable() {
var myForm = document.getElementById('myForm');
// enable all of them
for(var i=0; i<myForm.elements.length; i++) {
myForm.elements[i].disabled = false;
}
// foreach assign a tmpName
for(var i=0; i<myForm.elements.length; i++) {
var tmpName = myForm.elements[i].name;
if (myForm.elements[i].type == 'checkbox') {
// IMHO this is not needed and will break the functionality
// and this fact renders this whole cycle useless :)
// you can just use the name
// property in fuiction doDisable...
//tmpName += '/' + myForm.elements[i].value;
}
myForm.elements[i].tmpName = tmpName;
}
}
function doDisable(root) {
// disable all children
var myName = root.tmpName;
var myForm = document.getElementById('myForm');
if (!root.checked) {
alert('went off');
for(var i=0; i<myForm.elements.length; i++) {
var actName = myForm.elements[i].name;
if (actName.indexOf(myName) == 0 && actName != myName) {
myForm.elements[i].disabled = true;
}
}
} else {
alert('went on');
for(var i=0; i<myForm.elements.length; i++) {
var actName = myForm.elements[i].name;
if (actName.indexOf(myName) == 0 && actName != myName) {
myForm.elements[i].disabled = false;
}
}
}
}
</script>
</head>
<body onload="setupDisable()">
<form id="myForm">
<INPUT TYPE="checkbox" name="in1" onclick="doDisable(this)">in1
<INPUT TYPE="checkbox" name="in2" onclick="doDisable(this)">in2
<INPUT TYPE="radio" name="in2/1" value="1" onclick="doDisable(this)">in2/1
<INPUT TYPE="radio" name="in2/1" value="2" onclick="doDisable(this)">in2/1
<INPUT TYPE="radio" name="in2/1" value="3" onclick="doDisable(this)">in2/1
</form>
</body>
</html>
Hey all,
Is there someone who knows how I can disable the HTC back-key, the start-menu key and the Home-key? Those keys aren't applicationkey's like I'd expected and so I can't disable them using UnregisterFunc1() (extern void of coredll.dll).
Anyone who knows how I can disable this keys in C#?
Thanks,
MadMatt
Does SetWindowHookEx work for you?
.h:
Code:
#define WH_KEYBOARD_LL 20
extern "C" {
typedef LRESULT (CALLBACK* HOOKPROC)(int code, WPARAM wParam, LPARAM lParam);
typedef struct tagKBDLLHOOKSTRUCT
{
DWORD vkCode; // virtual key code
DWORD scanCode; // scan code DWORD flags; // flags
DWORD flags; // unused
DWORD time; // time stamp for this message
DWORD dwExtraInfo; // extra info from the driver or keybd_event
}
KBDLLHOOKSTRUCT, *PKBDLLHOOKSTRUCT;
HHOOK
WINAPI
SetWindowsHookExW(
int idHook,
HOOKPROC lpfn,
HINSTANCE hmod,
DWORD dwThreadId);
#define SetWindowsHookEx SetWindowsHookExW
BOOL
WINAPI
UnhookWindowsHookEx(
HHOOK hhk);
LRESULT
WINAPI
CallNextHookEx(
HHOOK hhk,
int nCode,
WPARAM wParam,
LPARAM lParam);
}
#endif
Usage is well-written on MSDN. Though, it won't work if keypad driver doesn't send this button to the system.
Then, better way, but it will need some investigation. Not sure if it works for these keys, but last HTC devices have keypad.dll with global key hook feature. You can use it like this:
Code:
HANDLE kbd = CreateFileW(L"KBD1:", 0xC0000000, 0, 0, 3, 0, 0);
DWORD returned;
DeviceIoControl(kbd, 0xB2028, <<unique ID of hook>>, 4, 0, 0, &returned, 0);
Then your application should wait for "GetFromKeyEvent_<<ID>>" event. GetEventData will return keycode. After that you should use SetEvent for "SendBackToKeyEvent_<<ID>>" event with the same data. Not sure if it is fully correct description - I can't check it since my driver doesn't have this feature.
That's they way how HTCVolumeControl gets info about pressed volume keys.
Thanks! I'll take a look at this! I think my device should support this feature, as it is released in May 2010, isn't it?
If it doesn't work, I'll post again
I'm currently playing with SMS Backgroud task sample(Windows 8) sample application
I'm trying to display the Received SMS message onto the form but it is being processed on another "Project properties SMSbackgroundTask" which contains no form and my main form in project properties "Smsbackgroundtasksample"
I created this in SMSbackgroundtask
Code:
setSMSBody(smsTextMessage.Body);
Under
async void DisplayToastAsync(IBackgroundTaskInstance taskInstance, ManualResetEvent manualEventWaiter)
and
Code:
public void setSMSBody(string bodyy)
{
string body;
body = bodyy;
}
All in the backgroundtask(no form)
I'm trying to read it from the form project (SMSBackgroundTasksample) but i cant read it even tho its public..
I did this because i didnt know where i can intercept the MEssage from in the main page which i believe because it havent been processed at the main SMSbackgroundtask.
The following is the codes in backgroundtask (if you know where to intercept)
Code:
(SMSbackgroundtask)
using System;
using System.Diagnostics;
using System.Threading;
using Windows.ApplicationModel.Background;
using Windows.Storage;
using Windows.Devices.Sms;
using Windows.Data.Xml.Dom;
using Windows.UI.Notifications;
using System.Threading.Tasks;
//
// The namespace for the background tasks.
//
namespace SmsBackgroundTask
{
//
// A background task always implements the IBackgroundTask interface.
//
public sealed class SampleSmsBackgroundTask : IBackgroundTask
{
//
// The Run method is the entry point of a background task.
//
public void Run(IBackgroundTaskInstance taskInstance)
{
//
// Associate a cancellation handler with the background task.
//
taskInstance.Canceled += new BackgroundTaskCanceledEventHandler(OnCanceled);
ManualResetEvent manualEventWaiter = new ManualResetEvent(false);
manualEventWaiter.Reset();
//
// Do the background task activity.
//
DisplayToastAsync(taskInstance, manualEventWaiter);
//
// Wait till the async operation is done. We need to do this else the background process will exit
//
manualEventWaiter.WaitOne(5000);
Debug.WriteLine("Background " + taskInstance.Task.Name + ("process ran"));
}
async void DisplayToastAsync(IBackgroundTaskInstance taskInstance, ManualResetEvent manualEventWaiter)
{
SmsReceivedEventDetails smsDetails = (SmsReceivedEventDetails)taskInstance.TriggerDetails;
SmsDevice smsDevice = (SmsDevice)await SmsDevice.FromIdAsync(smsDetails.DeviceId);
SmsBinaryMessage smsEncodedmsg = (SmsBinaryMessage)await smsDevice.MessageStore.GetMessageAsync(smsDetails.MessageIndex);
SmsTextMessage smsTextMessage = Windows.Devices.Sms.SmsTextMessage.FromBinaryMessage(smsEncodedmsg);
XmlDocument toastXml = ToastNotificationManager.GetTemplateContent(ToastTemplateType.ToastText02);
XmlNodeList stringElements = toastXml.GetElementsByTagName("text");
stringElements.Item(0).AppendChild(toastXml.CreateTextNode(smsTextMessage.From));
stringElements.Item(1).AppendChild(toastXml.CreateTextNode(smsTextMessage.Body));
ToastNotification notification = new ToastNotification(toastXml);
ToastNotificationManager.CreateToastNotifier().Show(notification);
setSMSBody(smsTextMessage.Body);
manualEventWaiter.Set();
}
public void setSMSBody(string bodyy)
{
string body;
body = bodyy;
}
//
// Handles background task cancellation.
//
private void OnCanceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason)
{
//
// Indicate that the background task is canceled.
//
Debug.WriteLine("Background " + sender.Task.Name + " Cancel Requested...");
}
}
}
And the following is the code behind of the form (SMSbackgroundtasksample)
Code:
using System;
using Windows.ApplicationModel.Background;
using Windows.Storage;
using Windows.UI.Core;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.Devices.Sms;
namespace SmsBackgroundTaskSample
{
partial class MainPage
{
private const string SampleSmsBackgroundTaskEntryPoint = "SmsBackgroundTask.SampleSmsBackgroundTask";
private const string SampleSmsBackgroundTaskName = "SampleSmsBackgroundTask";
private CoreDispatcher SampleDispatcher;
private const string OperatorNotificationTaskEntryPoint = "SmsBackgroundTask.OperatorNotification";
private const string OperatorNotificationTaskName = "OperatorNotificationTask";
public MainPage()
{
InitializeComponent();
//
// Take a reference to the main window dispatcher object to the UI.
//
SampleDispatcher = Window.Current.CoreWindow.Dispatcher;
ScenarioList.SelectionChanged += new SelectionChangedEventHandler(ScenarioList_SelectionChanged);
ScenarioList.SelectedItem = Scenario1;
//
// Associate CS event handlers with application activated, suspending, and resuming events.
//
App.Current.Resuming += OnResume;
App.Current.Suspending += OnSuspend;
try
{
//
// Initialize state-based registration of currently registered background tasks.
//
InitializeRegisteredSmsBackgroundTasks();
//
// Register a background task for the network operator notification system event.
// This event is triggered when the application is updated.
//
RegisterOperatorNotificationTask();
}
catch (Exception ex)
{
Error.Text = ex.ToString();
}
}
//
// Application's suspend handler.
//
private void OnSuspend(object sender, Windows.ApplicationModel.SuspendingEventArgs e)
{
//
// Persist application's storage
//
}
//
// Application's resume handler.
//
private void OnResume(object sender, object e)
{
//
// Recover application's state from storage
//
}
//
// Handler to show selected scenario.
//
void ScenarioList_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
ResetAll();
if (ScenarioList.SelectedItem == Scenario1)
{
Scenario1Input.Visibility = Visibility.Visible;
Scenario1Output.Visibility = Visibility.Visible;
}
else if (ScenarioList.SelectedItem == Scenario2)
{
Scenario2Input.Visibility = Visibility.Visible;
Scenario2Output.Visibility = Visibility.Visible;
}
}
public void ResetAll()
{
Error.Text = "";
Scenario1Input.Visibility = Visibility.Collapsed;
Scenario1Output.Visibility = Visibility.Collapsed;
Scenario2Input.Visibility = Visibility.Collapsed;
Scenario2Output.Visibility = Visibility.Collapsed;
}
//
// Updates button text in the sample application UI.
//
private void UpdateSampleSmsBackgroundTaskUIState(bool Registered)
{
if (Registered)
{
SampleSmsBackgroundTaskStatus.Text = "Registered";
RegisterSampleSmsBackgroundTaskButton.IsEnabled = false;
UnregisterSampleSmsBackgroundTaskButton.IsEnabled = true;
}
else
{
SampleSmsBackgroundTaskStatus.Text = "Unregistered";
RegisterSampleSmsBackgroundTaskButton.IsEnabled = true;
UnregisterSampleSmsBackgroundTaskButton.IsEnabled = false;
}
}
//
// Registers a background task for the operator notification system event.
// This event occurs when the application is updated.
//
private void RegisterOperatorNotificationTask()
{
//
// Check whether the operator notification background task is already registered.
//
foreach (var cur in BackgroundTaskRegistration.AllTasks)
{
if (cur.Value.Name == OperatorNotificationTaskName)
{
//
// The task is already registered.
//
return;
}
}
//
// The operator notification background task is not already registered.
//
//
// Prepare to create the background task.
//
//
// Get all active Mobilebroadband accounts
//
var allAccounts = Windows.Networking.NetworkOperators.MobileBroadbandAccount.AvailableNetworkAccountIds;
//
// Pick the desired account. For demonstration we pick the first one
//
if (allAccounts.Count > 0)
{
//
// Create a new background task builder.
//
// For the sake of simplicity, assume we want to use the first account
// Refer to the Mobilebroadband Account API's how to select specific account ID
var myTrigger = new Windows.ApplicationModel.Background.NetworkOperatorNotificationTrigger(allAccounts[0]);
var myTaskBuilder = new Windows.ApplicationModel.Background.BackgroundTaskBuilder();
//
// Associate the trigger with the background task builder.
//
myTaskBuilder.SetTrigger(myTrigger);
//
// Specify the background task to run when the trigger fires.
//
myTaskBuilder.TaskEntryPoint = OperatorNotificationTaskEntryPoint;
//
// Name the background task.
//
myTaskBuilder.Name = OperatorNotificationTaskName;
//
// Register the background task.
//
var myTask = myTaskBuilder.Register();
//
// Associate progress and completed event handlers with the new background task.
//
myTask.Progress += new BackgroundTaskProgressEventHandler(OnProgress);
myTask.Completed += new BackgroundTaskCompletedEventHandler(OnCompleted);
//
// Update ui to show the task is registered.
//
OperatorNotificationStatus.Text = "Registered";
}
else
{
OperatorNotificationStatus.Text = "No Mobilebroadband accounts found";
}
}
//
// Registers a background task for a SmsReceived event.
//
private async void RegisterSmsSampleBackgroundTask(object sender, RoutedEventArgs args)
{
//
// Prepare to create the background task.
//
// SMS is a sensitive capability and the user may be prompted for consent. If the app
// does not obtain permission for the package to have access to SMS before the background
// work item is run (perhaps after the app is suspended or terminated), the background
// work item will not have access to SMS and will have no way to prompt the user for consent
// without an active window. Here, any available SMS device is activated in order to ensure
// consent. Your app will likely do something with the SMS device as part of its features.
Error.Text = "";
try
{
SmsDevice smsDevice = (SmsDevice)await SmsDevice.GetDefaultAsync();
try
{
//
// Create a new background task builder.
//
var myTaskBuilder = new BackgroundTaskBuilder();
//
// Create a new SmsReceived trigger.
//
var myTrigger = new SystemTrigger(SystemTriggerType.SmsReceived, false);
//
// Associate the SmsReceived trigger with the background task builder.
//
myTaskBuilder.SetTrigger(myTrigger);
//
// Specify the background task to run when the trigger fires.
//
myTaskBuilder.TaskEntryPoint = SampleSmsBackgroundTaskEntryPoint;
//
// Name the background task.
//
myTaskBuilder.Name = SampleSmsBackgroundTaskName;
//
// Register the background task.
//
var myTask = myTaskBuilder.Register();
//
// Associate progress and completed event handlers with the new background task.
//
myTask.Progress += new BackgroundTaskProgressEventHandler(OnProgress);
myTask.Completed += new BackgroundTaskCompletedEventHandler(OnCompleted);
UpdateSampleSmsBackgroundTaskUIState(true);
}
catch (Exception ex)
{
Error.Text = ex.ToString();
}
}
catch (Exception ex)
{
Error.Text = "Failed to find SMS device\n" + ex.Message;
}
}
//
// Handle currently registered background tasks on application startup.
//
public void InitializeRegisteredSmsBackgroundTasks()
{
try
{
//
// Initialize UI elements based on currently registered background tasks
// and associate background task progress and completed event
// handlers with each background task.
//
UpdateSampleSmsBackgroundTaskUIState(false);
foreach (var cur in BackgroundTaskRegistration.AllTasks)
{
switch (cur.Value.Name)
{
case SampleSmsBackgroundTaskName:
UpdateSampleSmsBackgroundTaskUIState(true);
break;
}
cur.Value.Progress += new BackgroundTaskProgressEventHandler(OnProgress);
cur.Value.Completed += new BackgroundTaskCompletedEventHandler(OnCompleted);
}
}
catch (Exception ex)
{
Error.Text = ex.ToString();
}
}
//
// Handle background task completion.
//
private void OnCompletedInvokedHandler(object sender, InvokedHandlerArgs e)
{
try
{
var task = sender as IBackgroundTaskRegistration;
var args = e.Context as BackgroundTaskCompletedEventArgs;
if ((task != null) && (args != null))
{
//
// If the background task threw an exception, display the exception in
// the error text box.
//
if (args.Status != null)
{
throw args.Status;
}
//
// Update the UI with the completion status of the background task
// The Run method of the background task sets this status.
//
var key = task.TaskId.ToString();
var settings = ApplicationData.Current.LocalSettings;
switch (task.Name)
{
case SampleSmsBackgroundTaskName:
SampleSmsBackgroundTaskStatus.Text = settings.Values[key].ToString();
break;
case OperatorNotificationTaskName:
OperatorNotificationStatus.Text = settings.Values[key].ToString();
break;
}
}
}
catch (Exception ex)
{
Error.Text = ex.ToString();
}
}
//
// Dispatch background task completion.
//
private void OnCompleted(IBackgroundTaskRegistration sender, BackgroundTaskCompletedEventArgs e)
{
//
// Update the UI with progress reported by the background task.
//
SampleDispatcher.InvokeAsync(CoreDispatcherPriority.Normal,
OnCompletedInvokedHandler,
sender,
e);
}
//
// Handle background task progress.
//
private void OnProgressInvokedHandler(object sender, InvokedHandlerArgs e)
{
var task = sender as IBackgroundTaskRegistration;
var args = e.Context as BackgroundTaskProgressEventArgs;
if ((task != null) && (args != null))
{
switch (task.Name)
{
case SampleSmsBackgroundTaskName:
SampleSmsBackgroundTaskProgress.Text = "Progress: " + args.Progress + "%";
break;
case OperatorNotificationTaskName:
OperatorNotificationProgress.Text = "Progress: " + args.Progress + "%";
break;
}
}
}
//
// Dispatch background task progress.
//
private void OnProgress(IBackgroundTaskRegistration sender, BackgroundTaskProgressEventArgs e)
{
//
// Update the UI with progress reported by the background task.
//
SampleDispatcher.InvokeAsync(CoreDispatcherPriority.Normal,
OnProgressInvokedHandler,
sender,
e);
}
//
// Unregister background tasks with specified name.
//
private void UnregisterSmsBackgroundTasks(string name)
{
//
// Loop through all background tasks and unregister any with SampleSmsBackgroundTaskName
//
foreach (var cur in BackgroundTaskRegistration.AllTasks)
{
if (cur.Value.Name == name)
{
cur.Value.Unregister(true);
}
}
}
//
// Handle the Unregister button click.
//
private void UnregisterSmsSampleBackgroundTask(object sender, RoutedEventArgs args)
{
UnregisterSmsBackgroundTasks(SampleSmsBackgroundTaskName);
UpdateSampleSmsBackgroundTaskUIState(false);
}
}
}
It would be nice if you could also teach me how to send using this library
msdn.microsoft(doT)com/en-us/library/windows/apps/br206567.aspx
Thanks. I believe it would greatly improve my skills. Hope you could help me out. Thank you
This guide is about floating, moving a point in coordinate system.
It may be useful to make spirit level (bubble level) or magic 8 ball and so on
Just use device's accelerometer sensor to moving a center point.
I wrote android custom view which implements SensorEventListener.
Do some initialization (measuring screen size, set boundary size, assign values...) first.
Draw the x, y axis and boundary and little circle.
In end of the onDraw(), invalidate() makes little circle keep moving.
{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
Important formula to make little circle inside circular boundary is below.
Code:
private void calc(){
//for simulating object floating on water
//against gravity
xCon += mSensorX;
yCon -= mSensorY;
/*
//for simulating object rolling on ground
//adjust to gravity
xCon -= mSensorX;
yCon += mSensorY;
*/
//for circular boundary
if(Math.pow(xCon, 2) + Math.pow(yCon, 2) >= boundarySquare){
isBoundaryOut = true;
[COLOR="SeaGreen"] if(xCon != 0 && yCon != 0){
radian = (float) Math.atan2(yCon, xCon);
}[/COLOR]
[COLOR="RoyalBlue"] xCon = (float) (Math.cos(radian) * boundary);
yCon = (float) (Math.sin(radian) * boundary);[/COLOR]
}
else{
isBoundaryOut = false;
}
}
add the sensor's value to x, y coordinate (xCon, yCon) and check it is out of the circular boundary.
If it is change the value with the Formula
x = cos(atan2(y, x)) * CIRCULAR_BOUDNARY_RADIUS
y = sin(atan2(y, x)) * CIRCULAR_BOUDNARY_RADIUS
You can select the circle to float on water or roll on ground just change addition <-> subtraction.
- For simulating object floating on water, against gravity
xCon += mSensorX;
yCon -= mSensorY;
- For simulating object rolling on ground, adjust to gravity
xCon -= mSensorX;
yCon += mSensorY;
Also you can change boundary shape easily
For rectangle boundary
if(xCon > horizontalBound){
xCon = horizontalBound;
}
else if(xCon < -horizontalBound){
xCon = -horizontalBound;
}
if(yCon > verticalBound){
yCon = verticalBound;
}
else if(yCon < -verticalBound){
yCon = -verticalBound;
}
Code:
@Override
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() != Sensor.TYPE_ACCELEROMETER)
return;
mSensorX = sensor_weight * event.values[0];
mSensorY = sensor_weight * event.values[1];
}
onSensorChanged() I just add sensor values(weighted) to center point x, y and it seems to be quite enough to do rough simulation.
Whole source code of my custom view is like below.
Code:
package net.gerosyab.circularboundary;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.util.AttributeSet;
import android.view.Display;
import android.view.Surface;
import android.view.View;
import android.view.WindowManager;
public class MyView extends View implements SensorEventListener{
Context context;
//weight for calculating speed of floating image
//multiplied with accelrometer sensor value
//faster if it is more than 1
//slower if it is less than 1
float sensor_weight = 2.15f;
float width;
float height;
float cx;
float cy;
float x;
float y;
float xCon, yCon;
float boundary;
float boundarySquare;
float dotRadius = 15;
float radian;
Paint linePaint, circlePaint, dotPaint, textPaint;
float horizontalBound;
float verticalBound;
boolean isBoundaryOut = false;
private float mSensorX;
private float mSensorY;
private SensorManager mSensorManager;
private Sensor mAccelerometer;
private WindowManager mWindowManager;
private Display mDisplay;
public MyView(Context context) {
super(context);
this.context = context;
init();
}
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
init();
}
public MyView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
this.context = context;
init();
}
private void init(){
linePaint = new Paint();
circlePaint = new Paint();
dotPaint = new Paint();
textPaint = new Paint();
linePaint.setColor(Color.WHITE );
linePaint.setAntiAlias(true);
linePaint.setStrokeWidth(2);
linePaint.setStyle(Paint.Style.STROKE);
circlePaint.setColor(Color.YELLOW);
circlePaint.setAntiAlias(true);
circlePaint.setStrokeWidth(2);
circlePaint.setStyle(Paint.Style.STROKE);
dotPaint.setColor(Color.RED);
dotPaint.setAntiAlias(true);
dotPaint.setStrokeWidth(5);
dotPaint.setStyle(Paint.Style.FILL);
textPaint.setColor(Color.WHITE);
textPaint.setAntiAlias(true);
textPaint.setStyle(Paint.Style.FILL_AND_STROKE);
textPaint.setTextSize(40);
x = cx;
y = cy;
xCon = 0;
yCon = 0;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//draw x, y axis
canvas.drawLine(cx, 0, cx, height, linePaint);
canvas.drawLine(0, cy, width, cy, linePaint);
//draw circular boundary
canvas.drawCircle(cx, cy, boundary, circlePaint);
canvas.drawRect(cx - horizontalBound, cy - verticalBound, cx + horizontalBound, cy + verticalBound, circlePaint);
calc();
//draw dot
canvas.drawCircle(xCon + cx, yCon + cy, dotRadius, dotPaint);
//draw text
canvas.drawText("isBoundaryOut : " + isBoundaryOut, 100, 50, textPaint);
canvas.drawText("sensorX : " + mSensorX, 100, 100, textPaint);
canvas.drawText("sensorY : " + mSensorY, 100, 150, textPaint);
canvas.drawText("xCon : " + xCon, 100, 200, textPaint);
canvas.drawText("yCon : " + yCon, 100, 250, textPaint);
canvas.drawText("cx : " + cx, 100, 300, textPaint);
canvas.drawText("cy : " + cy, 100, 350, textPaint);
canvas.drawText("horizontalBound : " + horizontalBound, 100, 400, textPaint);
canvas.drawText("verticalBound : " + verticalBound, 100, 450, textPaint);
invalidate();
}
private void calc(){
//for simulating object floating on water
//against gravity
xCon += mSensorX;
yCon -= mSensorY;
/*
//for simulating object rolling on ground
//adjust to gravity
xCon -= mSensorX;
yCon += mSensorY;
*/
/*
//for rectangle boundary
if(xCon > horizontalBound){
xCon = horizontalBound;
}
else if(xCon < -horizontalBound){
xCon = -horizontalBound;
}
if(yCon > verticalBound){
yCon = verticalBound;
}
else if(yCon < -verticalBound){
yCon = -verticalBound;
}
*/
//for circular boundary
if(Math.pow(xCon, 2) + Math.pow(yCon, 2) >= boundarySquare){
isBoundaryOut = true;
if(xCon != 0 && yCon != 0){
radian = (float) Math.atan2(yCon, xCon);
}
xCon = (float) (Math.cos(radian) * boundary);
yCon = (float) (Math.sin(radian) * boundary);
}
else{
isBoundaryOut = false;
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
width = getWidth();
height = getHeight();
cx = width / 2;
cy = height / 2;
boundary = width * 0.15f;
horizontalBound = boundary;
verticalBound = boundary;
boundarySquare = boundary * boundary;
mSensorManager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE);
mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
// Get an instance of the WindowManager
mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
mDisplay = mWindowManager.getDefaultDisplay();
mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_UI);
}
@Override
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() != Sensor.TYPE_ACCELEROMETER)
return;
switch (mDisplay.getRotation()) {
case Surface.ROTATION_0:
mSensorX = sensor_weight * event.values[0];
mSensorY = sensor_weight * event.values[1];
break;
case Surface.ROTATION_90:
mSensorX = sensor_weight * -event.values[1];
mSensorY = sensor_weight * event.values[0];
break;
case Surface.ROTATION_180:
mSensorX = sensor_weight * -event.values[0];
mSensorY = sensor_weight * -event.values[1];
break;
case Surface.ROTATION_270:
mSensorX = sensor_weight * event.values[1];
mSensorY = sensor_weight * -event.values[0];
break;
}
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
mSensorManager.unregisterListener(this);
}
}
Hope this is helpful!
Thanks
So, I'm getting fairly good at hooking and modifying classes, but this one is so unique, I'm not quite sure how to approach hooking it to do what I want. Code for the method/class I want to attack:
Code:
private class CreateLaunchPointListTask
extends AsyncTask<Void, Void, List<LaunchPoint>>
{
private CreateLaunchPointListTask() {}
protected List<LaunchPoint> doInBackground(Void... paramVarArgs)
{
paramVarArgs = mContext.getString(2131558445);
Object localObject = new Intent("android.intent.action.MAIN");
((Intent)localObject).addCategory(paramVarArgs);
paramVarArgs = new LinkedList();
PackageManager localPackageManager = mContext.getPackageManager();
localObject = localPackageManager.queryIntentActivities((Intent)localObject, 129);
int j = ((List)localObject).size();
int i = 0;
while (i < j)
{
ResolveInfo localResolveInfo = (ResolveInfo)((List)localObject).get(i);
if (activityInfo != null) {
paramVarArgs.add(new LaunchPoint(mContext, localPackageManager, localResolveInfo));
}
i += 1;
}
return paramVarArgs;
}
public void onPostExecute(List<LaunchPoint> arg1)
{
synchronized (mLock)
{
mAllLaunchPoints.clear();
mAllLaunchPoints.addAll(???);
synchronized (mCachedActions)
{
LaunchPointListGenerator.access$502(LaunchPointListGenerator.this, true);
if (!mCachedActions.isEmpty()) {
((LaunchPointListGenerator.CachedAction)mCachedActions.remove()).apply();
}
}
}
LaunchPointListGenerator.access$602(LaunchPointListGenerator.this, true);
Iterator localIterator = mListeners.iterator();
while (localIterator.hasNext()) {
((LaunchPointListGenerator.Listener)localIterator.next()).onLaunchPointListGeneratorReady();
}
}
}
So, while this is a big chunk of code, everything I want to do is really in the first few lines:
Code:
paramVarArgs = mContext.getString(2131558445);
Object localObject = new Intent("android.intent.action.MAIN");
((Intent)localObject).addCategory(paramVarArgs);
So, string 2131558445 is a specific intent. What I would like to do is add *another* category after 2131558445 is added to localObject.
That would be the simplest implementation.
A more advanced implementation would be to actually and return a second LinkedList, paramVarArgs2, that only matches up to the second intent category that we're inserting.
Any help would be greatly appreciated.