[Guide] Floating in circular boundary (or rectangular) with accelerometer sensor - Design, Prototyping, UI, Graphics

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

Related

Javascript coder wanted for help in the kitchen...

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>

DirectShow: Video-Preview and taking photo (with working code)

Questions
As mentioned in the text below the TakePicture() method is not working properly on the HTC HD 2 device. It would be nice if someone could look at the code below and tell me if it is right or wrong what I'm doing.
Introduction
I recently asked a question on another forum about displaying a video preview and taking camera image with DirectShow. The tricky thing about the topic is, that it's very hard to find good examples and the documentation and the framework itself is very hard to understand for someone who is new to windows programming and C++ in general.
Nevertheless I managed to create a class that implements most of this features and probably works with most mobile devices. Probably because as far as I know the DirectShow implementation depends a lot on the device itself. I could only test it with the HTC HD and HTC HD2, which are known as quite incompatible.
HTC HD
- Working: Video preview, writing photo to file
- Not working: Set video resolution (CRASH), set photo resolution (LOW quality)
HTC HD 2
- Working: Set video resolution, set photo resolution
- Problematic: Video Preview rotated
- Not working: Writing photo to file
To make it easier for others by providing a working example, I decided to share everything I have got so far below. I removed all of the error handling for the sake of simplicity. As far as documentation goes, I can recommend you to read the MSDN documentation about the topic. After that the code below is pretty straight forward.
Code:
void Camera::Init()
{
CreateComObjects();
_captureGraphBuilder->SetFiltergraph(_filterGraph);
InitializeVideoFilter();
InitializeStillImageFilter();
}
Dipslay a video preview (working with any tested handheld):
Code:
void Camera::DisplayVideoPreview(HWND windowHandle)
{
IVideoWindow *_vidWin;
_filterGraph->QueryInterface(IID_IMediaControl,(void **) &_mediaControl);
_filterGraph->QueryInterface(IID_IVideoWindow, (void **) &_vidWin);
_videoCaptureFilter->QueryInterface(IID_IAMVideoControl,
(void**) &_videoControl);
_captureGraphBuilder->RenderStream(&PIN_CATEGORY_PREVIEW,
&MEDIATYPE_Video, _videoCaptureFilter, NULL, NULL);
CRect rect;
long width, height;
GetClientRect(windowHandle, &rect);
_vidWin->put_Owner((OAHWND)windowHandle);
_vidWin->put_WindowStyle(WS_CHILD | WS_CLIPSIBLINGS);
_vidWin->get_Width(&width);
_vidWin->get_Height(&height);
height = rect.Height();
_vidWin->put_Height(height);
_vidWin->put_Width(rect.Width());
_vidWin->SetWindowPosition(0,0, rect.Width(), height);
_mediaControl->Run();
}
HTC HD2: If set SetPhotoResolution() is called FindPin will return E_FAIL. If not, it will create a file full of null bytes. HTC HD: Works
void Camera::TakePicture(WCHAR *fileName)
{
CComPtr<IFileSinkFilter> fileSink;
CComPtr<IPin> stillPin;
CComPtr<IUnknown> unknownCaptureFilter;
CComPtr<IAMVideoControl> videoControl;
_imageSinkFilter.QueryInterface(&fileSink);
fileSink->SetFileName(fileName, NULL);
_videoCaptureFilter.QueryInterface(&unknownCaptureFilter);
_captureGraphBuilder->FindPin(unknownCaptureFilter, PINDIR_OUTPUT,
&PIN_CATEGORY_STILL, &MEDIATYPE_Video, FALSE, 0, &stillPin);
_videoCaptureFilter.QueryInterface(&videoControl);
videoControl->SetMode(stillPin, VideoControlFlag_Trigger);
}
Set resolution: Works great on HTC HD2. HTC HD won't allow SetVideoResolution() and only offers one low resolution photo resolution:
Code:
void Camera::SetVideoResolution(int width, int height)
{
SetResolution(true, width, height);
}
void Camera::SetPhotoResolution(int width, int height)
{
SetResolution(false, width, height);
}
void Camera::SetResolution(bool video, int width, int height)
{
IAMStreamConfig *config;
config = NULL;
if (video)
{
_captureGraphBuilder->FindInterface(&PIN_CATEGORY_PREVIEW,
&MEDIATYPE_Video, _videoCaptureFilter, IID_IAMStreamConfig,
(void**) &config);
}
else
{
_captureGraphBuilder->FindInterface(&PIN_CATEGORY_STILL,
&MEDIATYPE_Video, _videoCaptureFilter, IID_IAMStreamConfig,
(void**) &config);
}
int resolutions, size;
VIDEO_STREAM_CONFIG_CAPS caps;
config->GetNumberOfCapabilities(&resolutions, &size);
for (int i = 0; i < resolutions; i++)
{
AM_MEDIA_TYPE *mediaType;
if (config->GetStreamCaps(i, &mediaType,
reinterpret_cast<BYTE*>(&caps)) == S_OK )
{
int maxWidth = caps.MaxOutputSize.cx;
int maxHeigth = caps.MaxOutputSize.cy;
if(maxWidth == width && maxHeigth == height)
{
VIDEOINFOHEADER *info =
reinterpret_cast<VIDEOINFOHEADER*>(mediaType->pbFormat);
info->bmiHeader.biWidth = maxWidth;
info->bmiHeader.biHeight = maxHeigth;
info->bmiHeader.biSizeImage = DIBSIZE(info->bmiHeader);
config->SetFormat(mediaType);
DeleteMediaType(mediaType);
break;
}
DeleteMediaType(mediaType);
}
}
}
Other methods used to build the filter graph and create the COM objects:
v
Code:
oid Camera::CreateComObjects()
{
CoInitialize(NULL);
CoCreateInstance(CLSID_CaptureGraphBuilder, NULL, CLSCTX_INPROC_SERVER,
IID_ICaptureGraphBuilder2, (void **) &_captureGraphBuilder);
CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
IID_IGraphBuilder, (void **) &_filterGraph);
CoCreateInstance(CLSID_VideoCapture, NULL, CLSCTX_INPROC,
IID_IBaseFilter, (void**) &_videoCaptureFilter);
CoCreateInstance(CLSID_IMGSinkFilter, NULL, CLSCTX_INPROC,
IID_IBaseFilter, (void**) &_imageSinkFilter);
}
void Camera::InitializeVideoFilter()
{
_videoCaptureFilter->QueryInterface(&_propertyBag);
wchar_t deviceName[MAX_PATH] = L"\0";
GetDeviceName(deviceName);
CComVariant comName = deviceName;
CPropertyBag propertyBag;
propertyBag.Write(L"VCapName", &comName);
_propertyBag->Load(&propertyBag, NULL);
_filterGraph->AddFilter(_videoCaptureFilter,
L"Video Capture Filter Source");
}
void Camera::InitializeStillImageFilter()
{
_filterGraph->AddFilter(_imageSinkFilter, L"Still image filter");
_captureGraphBuilder->RenderStream(&PIN_CATEGORY_STILL,
&MEDIATYPE_Video, _videoCaptureFilter, NULL, _imageSinkFilter);
}
void Camera::GetDeviceName(WCHAR *deviceName)
{
HRESULT hr = S_OK;
HANDLE handle = NULL;
DEVMGR_DEVICE_INFORMATION di;
GUID guidCamera = { 0xCB998A05, 0x122C, 0x4166, 0x84, 0x6A, 0x93, 0x3E,
0x4D, 0x7E, 0x3C, 0x86 };
di.dwSize = sizeof(di);
handle = FindFirstDevice(DeviceSearchByGuid, &guidCamera, &di);
StringCchCopy(deviceName, MAX_PATH, di.szLegacyName);
}
Full header file:
Code:
#ifndef __CAMERA_H__
#define __CAMERA_H__
class Camera
{
public:
void Init();
void DisplayVideoPreview(HWND windowHandle);
void TakePicture(WCHAR *fileName);
void SetVideoResolution(int width, int height);
void SetPhotoResolution(int width, int height);
private:
CComPtr<ICaptureGraphBuilder2> _captureGraphBuilder;
CComPtr<IGraphBuilder> _filterGraph;
CComPtr<IBaseFilter> _videoCaptureFilter;
CComPtr<IPersistPropertyBag> _propertyBag;
CComPtr<IMediaControl> _mediaControl;
CComPtr<IAMVideoControl> _videoControl;
CComPtr<IBaseFilter> _imageSinkFilter;
void GetDeviceName(WCHAR *deviceName);
void InitializeVideoFilter();
void InitializeStillImageFilter();
void CreateComObjects();
void SetResolution(bool video, int width, int height);
};
#endif
Hey, in the FindInterface for the you're not checking the return code, which has to be S_OK; if not, the config is NULL and using config-> will cause your crash. If FindInterface for PIN_CATEGORY_PREVIEW is failing, try FindInterface for PIN_CATEGORY_CAPTURE.

XNA -Please Help - Collide with angle object

I'm developing a mirror for lazer beam(Ball sprite). There I'm trying to redirect the laze beam according to the ration degree of the mirror(Rectangle). How can I collide the ball to the correct angle if the colliding object is with some angle(45 deg) rather than colliding back.
Here is my complete code
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
namespace collision
{
/// <summary>
/// This is the main type for your game
/// </summary>
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
Texture2D ballTexture;
Rectangle ballBounds;
Vector2 ballPosition;
Vector2 ballVelocity;
float ballSpeed = 30f;
Texture2D blockTexture;
Rectangle blockBounds;
Vector2 blockPosition;
private Vector2 origin;
KeyboardState keyboardState;
//Font
SpriteFont Font1;
Vector2 FontPos;
private String displayText;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
/// <summary>
/// Allows the game to perform any initialization it needs to before starting to run.
/// This is where it can query for any required services and load any non-graphic
/// related content. Calling base.Initialize will enumerate through any components
/// and initialize them as well.
/// </summary>
protected override void Initialize()
{
// TODO: Add your initialization logic here
ballPosition = new Vector2(this.GraphicsDevice.Viewport.Width / 2,
this.GraphicsDevice.Viewport.Height * 0.25f);
blockPosition = new Vector2(this.GraphicsDevice.Viewport.Width / 2,
this.GraphicsDevice.Viewport.Height /2);
ballVelocity = new Vector2(0, 1);
base.Initialize();
}
/// <summary>
/// LoadContent will be called once per game and is the place to load
/// all of your content.
/// </summary>
protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch(GraphicsDevice);
ballTexture = Content.Load<Texture2D>("ball");
blockTexture = Content.Load<Texture2D>("mirror");
//create rectangles based off the size of the textures
ballBounds = new Rectangle((int)(ballPosition.X - ballTexture.Width / 2),
(int)(ballPosition.Y - ballTexture.Height / 2), ballTexture.Width, ballTexture.Height);
blockBounds = new Rectangle((int)(blockPosition.X - blockTexture.Width / 2),
(int)(blockPosition.Y - blockTexture.Height / 2), blockTexture.Width, blockTexture.Height);
origin.X = blockTexture.Width / 2;
origin.Y = blockTexture.Height / 2;
// TODO: use this.Content to load your game content here
Font1 = Content.Load<SpriteFont>("SpriteFont1");
FontPos = new Vector2(graphics.GraphicsDevice.Viewport.Width - 100, 20);
}
/// <summary>
/// UnloadContent will be called once per game and is the place to unload
/// all content.
/// </summary>
protected override void UnloadContent()
{
// TODO: Unload any non ContentManager content here
}
/// <summary>
/// Allows the game to run logic such as updating the world,
/// checking for collisions, gathering input, and playing audio.
/// </summary>
/// <param name="gameTime">Provides a snapshot of timing values.</param>
///
private float RotationAngle;
float circle = MathHelper.Pi * 2;
float angle;
protected override void Update(GameTime gameTime)
{
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
// TODO: Add your update logic here
//check for collision between the ball and the block, or if the ball is outside the bounds of the screen
if (ballBounds.Intersects(blockBounds) || !GraphicsDevice.Viewport.Bounds.Contains(ballBounds))
{
//we have a simple collision!
//if it has hit, swap the direction of the ball, and update it's position
ballVelocity = -ballVelocity;
ballPosition += ballVelocity * ballSpeed;
}
else
{
//move the ball a bit
ballPosition += ballVelocity * ballSpeed;
}
//update bounding boxes
ballBounds.X = (int)ballPosition.X;
ballBounds.Y = (int)ballPosition.Y;
blockBounds.X = (int)blockPosition.X;
blockBounds.Y = (int)blockPosition.Y;
keyboardState = Keyboard.GetState();
float val = 1.568017f/90;
if (keyboardState.IsKeyDown(Keys.Space))
RotationAngle = RotationAngle + (float)Math.PI;
if (keyboardState.IsKeyDown(Keys.Left))
RotationAngle = RotationAngle - val;
angle = (float)Math.PI / 4.0f; // 90 degrees
RotationAngle = angle;
// RotationAngle = RotationAngle % circle;
displayText = RotationAngle.ToString();
base.Update(gameTime);
}
/// <summary>
/// This is called when the game should draw itself.
/// </summary>
/// <param name="gameTime">Provides a snapshot of timing values.</param>
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
// TODO: Add your drawing code here
spriteBatch.Begin();
// Find the center of the string
Vector2 FontOrigin = Font1.MeasureString(displayText) / 2;
spriteBatch.DrawString(Font1, displayText, FontPos, Color.White, 0, FontOrigin, 1.0f, SpriteEffects.None, 0.5f);
spriteBatch.Draw(ballTexture, ballPosition, Color.White);
spriteBatch.Draw(blockTexture, blockPosition,null, Color.White, RotationAngle,origin, 1.0f, SpriteEffects.None, 0f);
spriteBatch.End();
base.Draw(gameTime);
}
}
}
Do you have a github repo? I would like to help out but your wording is slightly confusing. You may have to update your collision to reflect changes in the X and Y axes seperately. I can try to replicate this and PM you my solution

Hooking a protected List in an Inner Class with an odd set of Parameters

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.

My solution to long press volume button

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, lambition​can 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.

Categories

Resources