Desarrollo FFB (DIY)

Montajes Personales : Cockpits, Pedales, Botoneras...

Moderador: XRStaff

Avatar de Usuario
willynovi
Piloto Histórico
Piloto Histórico
Mensajes: 1177
Registrado: 17 Mar 2009 01:00
Volante: 100% DIY, prox. con FFB
Ubicación: Argentina
Contactar:

Desarrollo FFB (DIY)

Mensaje por willynovi »

Estimados,
así como se logró el Display XR, la idea es ver si podemos desarrollar un volante con force feedback usando electronica que se consiga facil.

La idea es que vayamos aportando ideas de que es lo mejor para cada una de las partes del sistema.

Construcción Mecánica
Motor con reducción (varias opciones)
Placa para control de motor (Puente H)
Captura de datos (InternalsPlugin / X-Sim / Force Sender / YODA, etc)
Placa para salidad de datos (USB (HID, CDC, Custom Device) o RS232) creo RS232 tendriamos que descartarla, pero es una opcion bien viable. Aunque los que andan con la programacion de USB y la PC saben que la RS232 se emula con la CDC del USB.

Y cualquier otro tema que sea importante discutir.

Yo por el momento estoy en desarrollo de una placa para sacar datos de la PC para uso general, me estoy inclinando por un Custom Device.

Cualquier aporte será importante.
Avatar de Usuario
Geri26
Aprendiendo a trazar
Aprendiendo a trazar
Mensajes: 203
Registrado: 30 Dic 2008 01:00
Volante: Logitech DFP
Ubicación: Alcatraz

Re: Desarrollo FFB (DIY)

Mensaje por Geri26 »

Con un par de huevos, si señor. Seguro que de aqui sale algo muy pero que muy interesante!!

Aunque la idea es mas o menos facil no? es un motor con reduccion, que va para un sentido u otro, en mayor o menor fuerza, se necesitaria un sensor de posicion (con un pote, no?) y ala. Lo jodido es coordinar eso, pero la idea bàsica es esa no?


Lo he dicho en el post de la placa y lo vuelvo a decir en este, eres un fenomeno tio!!!

Saludos i GASSSSSss
Avatar de Usuario
crobol
Maestro al volante
Maestro al volante
Mensajes: 13867
Registrado: 28 Abr 2007 00:00
Volante: DFP
Ubicación: BCN
Contactar:

Re: Desarrollo FFB (DIY)

Mensaje por crobol »

Geri26 escribió:Aunque la idea es mas o menos facil no?
No se si será fácil pero la clave creo que está en el software. Intentar crear un DLL que trabaje como los drivers de un volante comercial. Que sea capaz de captar los datos de FFB (si el juego/Sim soporta FFB) y los envié a una controladora USB que gestione los motores.

Los drivers de los Logitech, Thustmaster, etc detectan los datos de FFB que genera un Sim sin tener que dar soporte exclusivo a cada uno de ellos. Al G25 le da igual que sea rFactor, LFS o el Toca, los detecta igual. Entonces ¿De donde lo detecta, del DirectX?
Yo creo que si, sin poder afirmarlo. Los 2 únicos juegos/Sim que tengo en mi PC creo que no trabajan con DirectX (RigsOfRods y IL2) no tienen soporte FFB. No se si es una hipótesis muy valida... :blush:
Avatar de Usuario
Geri26
Aprendiendo a trazar
Aprendiendo a trazar
Mensajes: 203
Registrado: 30 Dic 2008 01:00
Volante: Logitech DFP
Ubicación: Alcatraz

Re: Desarrollo FFB (DIY)

Mensaje por Geri26 »

Pues ahí esta crobol, como todos cometemos pequeñas (o grandes! 8O ) ilegalidades, se podria hechar un ojo a los drivers del logitech (alguien que entienda), y tener una minima idea. Hombre, me imagino que facil no sera, ni mucho menos, pero algo se podra hacer, por la parte del hardware no creo que haya complicaciones, no debe ser mas que un motor, una correa dentada (para evitar ruido, pero que sea dentada, ya que sino al pegar volantazos... mal) y con el mismo pote del volante (para saber la situacion del volante), ya se podria hacer algo bueno. Luego la placa conroladora... ya sera algo mas chungo, y el software, si se puede hechar una ojeada al de logitech, mucho mejor.

No es una cosa impossible, creo que es mas dificultoso el display con tantas entradas y tantas salidas, esto es un poco mas reducido.
A ver que opinan los expertos de esto!


Saludos i GASSSSSSSSs
Avatar de Usuario
labombarda
Espectador
Espectador
Mensajes: 28
Registrado: 25 Ene 2008 01:00
Volante: Logitech MOMO Racing
Ubicación: Rosario, Santa Fe, Argentina
Contactar:

Re: Desarrollo FFB (DIY)

Mensaje por labombarda »

Excelente amigos, excelente... sólo esto me faltaba para decidirme a fabricar mi volante.
Avatar de Usuario
jimiTES
Colaborador Rallys
Colaborador Rallys
Mensajes: 826
Registrado: 24 Oct 2007 00:00
Volante: G25
Ubicación: Cadiz

Re: Desarrollo FFB (DIY)

Mensaje por jimiTES »

crobol escribió:
Geri26 escribió:Aunque la idea es mas o menos facil no?
No se si será fácil pero la clave creo que está en el software. Intentar crear un DLL que trabaje como los drivers de un volante comercial. Que sea capaz de captar los datos de FFB (si el juego/Sim soporta FFB) y los envié a una controladora USB que gestione los motores.

Los drivers de los Logitech, Thustmaster, etc detectan los datos de FFB que genera un Sim sin tener que dar soporte exclusivo a cada uno de ellos. Al G25 le da igual que sea rFactor, LFS o el Toca, los detecta igual. Entonces ¿De donde lo detecta, del DirectX?
Yo creo que si, sin poder afirmarlo. Los 2 únicos juegos/Sim que tengo en mi PC creo que no trabajan con DirectX (RigsOfRods y IL2) no tienen soporte FFB. No se si es una hipótesis muy valida... :blush:
Yo tambien creo que el FFB es un efecto DirectX. Habra que investigar.

Willy, cuenta conmigo para lo que buenamente pueda aportar con mis escasos conocimientos.
Avatar de Usuario
Nye
Primera conducción sin ayudas
Primera conducción sin ayudas
Mensajes: 398
Registrado: 16 Dic 2008 01:00
Volante: G25
Ubicación: Sabadell
Contactar:

Re: Desarrollo FFB (DIY)

Mensaje por Nye »

Uff

Como ya le comenté a Crobol, le estuve dando un vistazo por encima al tema y no encontré de que forma 'estandar' suministran los juegos los datos del FFB.
Chafardeando por el DirectX ( en concreto el DirectInput ) encontré la forma de mandar datos a un controlador. Conseguí hacer reaccionar a mi G25 a voluntad. Pero eso no es lo que hace falta precisamente....

Otro problema añadido para mi es la falta de soporte de DirectX 9 o 10 en el Visual Studio 6. A lo máximo que se llega a programar es con el SDK del DirectX 8. Tampoco creo que eso fuera un problema insalvable porque el DirectX es compatible hacia atras. Pero ahi queda.

Ahora mismo no puedo comprometerme a nada. Tengo un monton de cosas por hacer y sería desviar la atención hacia algo que de momento no tengo como prioritario. De todas formas intentaré seguir el hilo por si puedo echaros un cable en lo que se presente.

Saludos
Avatar de Usuario
crobol
Maestro al volante
Maestro al volante
Mensajes: 13867
Registrado: 28 Abr 2007 00:00
Volante: DFP
Ubicación: BCN
Contactar:

Re: Desarrollo FFB (DIY)

Mensaje por crobol »

Gracias Nye.

En mi opinión, la intencion de este hilo no es tanto la de lograr un producto finalizado (el caso del Display) como la de aportar luz a un tema del que no se encuentran muchas referencias en los foros de DIY.

Yo de electrónica e informática ni flowers, pero investigaré en los foros de X-sim a ver si hay algo. Cuando RSC estaba abierta seguía a diario el hilo de LeoBodnar sobre ese tema aunque a parte de enseñar vídeos de sus avances con el servo el tipo no soltaba prenda. EN algún sitio tengo esos vídeos e imágenes, si los encuentro los adjunto.
Avatar de Usuario
willynovi
Piloto Histórico
Piloto Histórico
Mensajes: 1177
Registrado: 17 Mar 2009 01:00
Volante: 100% DIY, prox. con FFB
Ubicación: Argentina
Contactar:

Re: Desarrollo FFB (DIY)

Mensaje por willynovi »

Nye, gracias por tus aportes, de la forma que puedas esta mas que bien.
Crobol, yo tb tengo esos videos de LB, no sabia que en RSC el posteaba, cuando me meti en esto RSC ya estaba caido, habra que esperar a ver que hay por alli.

Los muchachos de X-Sim trabajan todo con DirectX con un soft (creo es el YODA) que de alguna forma pincha los datos y luego los extraen por un puerto serie o USB.
Aunque tengo entendido que con la version X-Sim2 lo have todo este.

Explico un poco lo que yo tengo pensado:
Teniendo los datos de la fisica de las suspensiones y la fuera en el brazo de direccion, mas las fuerzas sobre las ruedas, todos datos que arroja el InternalsPlugin, se puede armar un modelo matematico para determinar la fuerza resultante en el volante. En esto estoy laburando un poco ya para modelizar el sistema.

DirectX trabajaria mas o menos así, pero la salida es un efecto sobre el motor directamente. En esto laburaba Leo Bodnar con la placa PID (seria un HID pero con feedback)

Comentario:
Como saben, no tengo un volante con FFB comercial, hace unos dias probé un MOMO en la casa de un amigo y no me gusto para nada los efectos que tira el volante, ni de casualidad coinsiden con la realidad. Esta bien que la idea sea tener la sensacion en el volante de todo lo que le pasa al auto, pero me parecio demasiado.
Mi intencion es en una primera instancia darle al volante solo los efectos de la direccion, es decir, los realcionados con la interaccion de las ruedas con el terreno.

Hace un ratito consegui compilar el Plugin, asi que pronto voy a estar sacando datos a mi placa para mostrarlos en un LCD y mover un motor. Hace un tiempo arme unos puente H para un robot sumo de 3kg, asi que tendrian que andar, creo son hasta 3 amperes. Con unos buenos disipadores andarian joya.

He chusmiado la pagina de X-Sim, incluso soy miembro, pero participo poco.
Un loco anduvo viendo de copiarse el SimWheel de FREX, yo le tire unos datos, pero creo no avanzo mucho. Otros proyectos de volantes no vi. Casi todos son de plataformas 2DOF, 3DOF y mas. Ahi hay info sobre placas y esas cosas, un poco por todos lados, asi que con paciencia.

Si hay alguien que investigue si se puede hacer algo con X-Sim o DirectX, seria buenisimo.

Saludos
Avatar de Usuario
Nye
Primera conducción sin ayudas
Primera conducción sin ayudas
Mensajes: 398
Registrado: 16 Dic 2008 01:00
Volante: G25
Ubicación: Sabadell
Contactar:

Re: Desarrollo FFB (DIY)

Mensaje por Nye »

El problema de utilizar exclusivamente los datos que te ofrece el InternalsPlugin del rFactor, es la falta de 'estandarización' del proyecto.
Aunque el rFactor sea el juego principal de alguien, supongo que si tiene un volante lo utilizará para todos los sims y no solo en el rFactor.
Seguramente con los datos de suspensiónes, ruedas,... se consiguiera un Force Feedback cojonudo, pero tiene ese inconveniente.
Creo que la via mas adecuada para todo proyecto es la universal.

Yo tambien soy miembro de x-sim. A ver si tengo algo de tiempo para chafardear :)
Avatar de Usuario
willynovi
Piloto Histórico
Piloto Histórico
Mensajes: 1177
Registrado: 17 Mar 2009 01:00
Volante: 100% DIY, prox. con FFB
Ubicación: Argentina
Contactar:

Re: Desarrollo FFB (DIY)

Mensaje por willynovi »

bueno, hace un ratito estuve chusmiando algo en X-Simulator y esta es la cuestion:

YODA: software dedicado para extraer los efectos desde el DirectX. Es un Force FeedBack Scanner. Los datos luego deben tomarse desde el Force Sender.

FORCE SENDER: es el gestor de los efectos mediante la telemetria del simulador particular. Puede tomar del YODA o en el caso de Simuladores que disponen de plugins dedicados no es necesario pasar por el YODA. En el caso del rFactor, el InternalsPlugin.dll se reemplaza por uno especifico para el Force Sender, pero en escencia es lo mismo. Actualmente estan pensados para movimientos de plataforma, por lo que estan disponibles los efectos de posicion global y aceleraciones en los sentidos X Y Z. No veo que hagan algo con los datos de la suspension y el brazo de direccion.

FORCE PROFILER: es una aplicacion dedicada para el control fisico de los actuadores.

Para el rFactor: http://www.x-simulator.de/main/en/force ... actor.html
Para el GTR2: http://www.x-simulator.de/main/en/force ... gtr-2.html
Para el IL2: http://www.x-simulator.de/main/en/force ... movik.html

En definitiva, se pasa por el bendito plugin o los efectos de DirectX. Las dos opciones parecen igual de viables. En un post del foro de X-Sim se recomienda no usar YODA en los simuladores que tengan plugin que extraen telemetria.

Por ahora voy a seguir con los efectos del plugin.
En caso de ser así, pienso que habria que compilar un plugin especifico que pueda usarse con el DisplayXR y el FFB, es decir que mande ciertos datos al Display y otros al FFB. Habria que probar de tener dos plugin paralelos, pero no se como será el tema del uso del microprocesador y nos reste fotogramas por segundo.
Avatar de Usuario
crobol
Maestro al volante
Maestro al volante
Mensajes: 13867
Registrado: 28 Abr 2007 00:00
Volante: DFP
Ubicación: BCN
Contactar:

Re: Desarrollo FFB (DIY)

Mensaje por crobol »

willynovi escribió:Habria que probar de tener dos plugin paralelos, pero no se como será el tema del uso del microprocesador y nos reste fotogramas por segundo.
En rF se pueden llegar a usar varios pluggins sin problema (Motec, Spotter, RealFeel) El problema vendría mas por la carga de trabajo de la CPU. Para el caso de las plataformas móviles y con ordenadores medianos, en X-sim recomiendan usar un 2º PC modesto para gestionar los actuadores.

No se si servirá de algo pero los DLL del Realfeel y del LeoFFB quizas den algunas pistas. Imagino que se podrán abrir y analizar... :?

Estoy con Nye en que lo ideal seria una solucion global independiente de la plataforma, pero claro ¿Como imitar el comportamiento de los drivers de un Logitech? :sorry:
Avatar de Usuario
alvaro_pasto
Maestro al volante
Maestro al volante
Mensajes: 5082
Registrado: 04 Sep 2006 00:00
Volante: Logitech G27
Frex Shift+
Ubicación: La Coruña
Contactar:

Re: Desarrollo FFB (DIY)

Mensaje por alvaro_pasto »

crobol escribió:No se si servirá de algo pero los DLL del Realfeel y del LeoFFB quizas den algunas pistas. Imagino que se podrán abrir y analizar... :?
Casi no he trabajado con DLL's, pero al ser un elemento compilado en teoria no se puede abrir y ver el código fuente.
Alvaro Vazquez
#15 Top-Racing
Avatar de Usuario
willynovi
Piloto Histórico
Piloto Histórico
Mensajes: 1177
Registrado: 17 Mar 2009 01:00
Volante: 100% DIY, prox. con FFB
Ubicación: Argentina
Contactar:

Re: Desarrollo FFB (DIY)

Mensaje por willynovi »

de una DLL ya compilada solo se puede conocer que funciones tiene y que variables toma o devuelve cada una, pero el source lo veo poco probable.

De todas formas, la DLL del RealFeelPlugin lo que haces es filtrar los efectos que no deberian sentirse en el volante y ampificar los que si, al menos eso entendí. Tampoco hay mucha info oficial de que es lo que hace. Solo que es una mejora al FFB para hacerlo mas real.
Avatar de Usuario
crobol
Maestro al volante
Maestro al volante
Mensajes: 13867
Registrado: 28 Abr 2007 00:00
Volante: DFP
Ubicación: BCN
Contactar:

Re: Desarrollo FFB (DIY)

Mensaje por crobol »

Alguno info encontrada en una sencilla busqueda en Google.

Video del Proto de LeoBodnar usando un Servo.

Antigua placa FFB de LeoB (Proyecto abandonado) :llorar:
[img]http://img5.imageshack.us/img5/5928/22884417.th.jpg[/img]
Un foro donde pretenden construirse un FFB para helicopteros :: http://www.mycockpit.org/forums/showthread.php?t=12459
Donde hacen un comentario curioso.ç

Código: Seleccionar todo

I use a small app called "RTC"that was originally made for race car sims that don't have FFB coded in the sim. It gives an FFb stick (or wheel) a good center spring feel and a steady thumping at any freq. that you choose.
chimpin
Primera conducción sin ayudas
Primera conducción sin ayudas
Mensajes: 388
Registrado: 04 Sep 2007 00:00
Volante: Logitech G25
Ubicación: Galiza
Contactar:

Re: Desarrollo FFB (DIY)

Mensaje por chimpin »

Como se hizo con el display XR seguro que se puede hacer esto y ademas habiendo por aki cracks como nye, pololo...
Avatar de Usuario
crobol
Maestro al volante
Maestro al volante
Mensajes: 13867
Registrado: 28 Abr 2007 00:00
Volante: DFP
Ubicación: BCN
Contactar:

Re: Desarrollo FFB (DIY)

Mensaje por crobol »

No es una tarea fácil esta del FFB y no podemos pretender que estos cracks vuelvan a dedicarse en ""cuerpo y alma"" como hicieron con el Display. La intención es aportar ideas no que desarrollen un proyecto completo.
Avatar de Usuario
crobol
Maestro al volante
Maestro al volante
Mensajes: 13867
Registrado: 28 Abr 2007 00:00
Volante: DFP
Ubicación: BCN
Contactar:

Re: Desarrollo FFB (DIY)

Mensaje por crobol »

Como RSC volvió, dejó aquí el hilo de LeoBodnar y su proyecto FFB.
Como pasa el tiempo, ya tiene un año ese hilo y desde entonces no han habido muchas novedades, independientemente que RSC estuviera KO desde Febrero.

http://forum.racesimcentral.com/showthread.php?t=317778
Avatar de Usuario
guiller94
Piloto de Prototipos
Piloto de Prototipos
Mensajes: 903
Registrado: 18 Feb 2009 01:00
Volante: T500RS+ TH8RS + F1 wheel
Ubicación: Valladolid
Contactar:

Re: Desarrollo FFB (DIY)

Mensaje por guiller94 »

¿willy as visto esto http://www.google.com/patents?id=mlk-AA ... _1#PPA8,M1?
son esquemas electricos de ffb
Avatar de Usuario
guiller94
Piloto de Prototipos
Piloto de Prototipos
Mensajes: 903
Registrado: 18 Feb 2009 01:00
Volante: T500RS+ TH8RS + F1 wheel
Ubicación: Valladolid
Contactar:

Re: Desarrollo FFB (DIY)

Mensaje por guiller94 »

http://www.mikesflightdeck.com/Download ... hapter.pdf
esto es el esquema electrico para los tacometros para los que sepan que nos enseñen :consuelo: y para ti willy para que te le puedas hacer.
Avatar de Usuario
Nye
Primera conducción sin ayudas
Primera conducción sin ayudas
Mensajes: 398
Registrado: 16 Dic 2008 01:00
Volante: G25
Ubicación: Sabadell
Contactar:

Re: Desarrollo FFB (DIY)

Mensaje por Nye »

guiller94 escribió:http://www.mikesflightdeck.com/Download ... hapter.pdf
esto es el esquema electrico para los tacometros para los que sepan que nos enseñen :consuelo: y para ti willy para que te le puedas hacer.
Madre mia.... eso es una Biblia de instrumentación!
Bajado y guardado a buen recaudo. Está de muerte. Gracias por el link :chao:

Pero solo está el capitulo de ejemplo. Sabes si se pueden conseguir los demas?
Avatar de Usuario
guiller94
Piloto de Prototipos
Piloto de Prototipos
Mensajes: 903
Registrado: 18 Feb 2009 01:00
Volante: T500RS+ TH8RS + F1 wheel
Ubicación: Valladolid
Contactar:

Re: Desarrollo FFB (DIY)

Mensaje por guiller94 »

emm esto me lo dijo willy y buscando en esta web lo encontre
el enlace que me dio willy: http://www.mikesflightdeck.com/diy_airc ... uments.htm
el enlace de la pagina principal: http://www.mikesflightdeck.com/instrument_panel_1.htm
y tambien te aconsejaria mirar todo lo que te sale en esa web,aunque no entiendo mucho tiene pinta de valer mucho la informacion,y aqui http://www.betainnovations.com/support/ ... evice.html tambien ve los archivos escritos en formato adobe que algo viene sobre el tema y en dormato zip alguna descarga, y aqui podras investigar algo mas si buscar un poco http://www.betainnovations.com/support/ ... pport.html haber si con esto sabeis los grandes hacerlo y nos lo contais como se hace :consuelo: o nos lo vendeis :evil:.
salu2
Avatar de Usuario
willynovi
Piloto Histórico
Piloto Histórico
Mensajes: 1177
Registrado: 17 Mar 2009 01:00
Volante: 100% DIY, prox. con FFB
Ubicación: Argentina
Contactar:

Re: Desarrollo FFB (DIY)

Mensaje por willynovi »

estos dias estuve de mudanza, asi que medio perdido, ademas todvia no tengo internet en casa, asi que a esperar, cuando arme el taller nuevamente me pongo a laburar a full. aunque primero tengo que terminar la pedalera asi puedo competir en los proximos torneos. Esa es la prioridad.

Los link ya los habia visto, es que he visto tantas cosas relacionadas al FFB que todo parece igual y diferente a la ves, jejeje.

Que bueno lo de RaceSimCentral, yo por allá en diciembre me hice miembro y estuve chusmiando algo y alcance a postear un par de mensajes a un chango que se estaba haciendo un volante de F1 en madera, pero creo la intencion es hacerlo en fibra de carbono, tengo entendido esta esperando le lleguen los materiales. Estos gringos algunos son unos capos, es que con presusupuesto se puede hacer cualquier cosa.

Lo del hilo de LeoBodnar lo habia visto, pero no larga mucha piola, igual algo saque sobre el control, es que leyendo lo que hacen los demas como que me surgen algunas ideas.
Avatar de Usuario
jimiTES
Colaborador Rallys
Colaborador Rallys
Mensajes: 826
Registrado: 24 Oct 2007 00:00
Volante: G25
Ubicación: Cadiz

Re: Desarrollo FFB (DIY)

Mensaje por jimiTES »

http://forum.racesimcentral.com/showthread.php?t=335933

En este hilo de RSC un chaval comenta que quiere desarrollar un Tacometro que se mueva a traves de motores de FFB, para ello dice que esta estudiando programacion en DirectX.

Su argumento para atribuirle coherencia al proyecto es el uso "modificado" que se hace el efecto FFB en programas como FFShifter.

No es una mala via de investigacion el analizar estos programas, ¿verdad?

Para los trasteadores avanzados, la sdk de directX:

http://www.microsoft.com/downloads/deta ... IY6g%3d%3d
Avatar de Usuario
jimiTES
Colaborador Rallys
Colaborador Rallys
Mensajes: 826
Registrado: 24 Oct 2007 00:00
Volante: G25
Ubicación: Cadiz

Re: Desarrollo FFB (DIY)

Mensaje por jimiTES »

Os confirmo que este paquete incluye un ejemplo en c++ que aplica una fuerza constante a un dispositivo FFB.
-----------------------------------------------------------
// File: FFConst.cpp
//
// Desc: Demonstrates an application which sets a force feedback constant force
// determined by the user.
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
#define STRICT
#define DIRECTINPUT_VERSION 0x0800

#include <tchar.h>
#include <windows.h>
#include <windowsx.h>
#include <commctrl.h>
#include <basetsd.h>
#include <mmsystem.h>
#include <dinput.h>
#include <math.h>
#pragma warning( disable : 4996 ) // disable deprecated warning
#include <strsafe.h>
#pragma warning( default : 4996 )
#include "resource.h"
#if defined(DEBUG) | defined(_DEBUG)
#include <crtdbg.h>
#endif





//-----------------------------------------------------------------------------
// Function prototypes
//-----------------------------------------------------------------------------
INT_PTR CALLBACK MainDlgProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam );
BOOL CALLBACK EnumFFDevicesCallback( const DIDEVICEINSTANCE* pInst, VOID* pContext );
BOOL CALLBACK EnumAxesCallback( const DIDEVICEOBJECTINSTANCE* pdidoi, VOID* pContext );
HRESULT InitDirectInput( HWND hDlg );
VOID FreeDirectInput();
VOID OnPaint( HWND hDlg );
HRESULT OnMouseMove( HWND hDlg, INT x, INT y, UINT keyFlags );
VOID OnLeftButtonDown( HWND hDlg, INT x, INT y, UINT keyFlags );
VOID OnLeftButtonUp( HWND hDlg, INT x, INT y, UINT keyFlags );
INT CoordToForce( INT x );
HRESULT SetDeviceForcesXY();




//-----------------------------------------------------------------------------
// Defines, constants, and global variables
//-----------------------------------------------------------------------------
#define SAFE_DELETE(p) { if(p) { delete (p); (p)=NULL; } }
#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }

#define FEEDBACK_WINDOW_X 20
#define FEEDBACK_WINDOW_Y 60
#define FEEDBACK_WINDOW_WIDTH 200

LPDIRECTINPUT8 g_pDI = NULL;
LPDIRECTINPUTDEVICE8 g_pDevice = NULL;
LPDIRECTINPUTEFFECT g_pEffect = NULL;
BOOL g_bActive = TRUE;
DWORD g_dwNumForceFeedbackAxis = 0;
INT g_nXForce;
INT g_nYForce;
DWORD g_dwLastEffectSet; // Time of the previous force feedback effect set




//-----------------------------------------------------------------------------
// Name: WinMain()
// Desc: Entry point for the application. Since we use a simple dialog for
// user interaction we don't need to pump messages.
//-----------------------------------------------------------------------------
INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR, INT )
{
// Enable run-time memory check for debug builds.
#if defined(DEBUG) | defined(_DEBUG)
_CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
#endif

InitCommonControls();

// Display the main dialog box.
DialogBox( hInst, MAKEINTRESOURCE( IDD_FORCE_FEEDBACK ), NULL, MainDlgProc );

return 0;
}




//-----------------------------------------------------------------------------
// Name: MainDlgProc
// Desc: Handles dialog messages
//-----------------------------------------------------------------------------
INT_PTR CALLBACK MainDlgProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam )
{
switch( msg )
{
case WM_INITDIALOG:
if( FAILED( InitDirectInput( hDlg ) ) )
{
MessageBox( NULL, _T( "Error Initializing DirectInput " )
_T( "The sample will now exit." ),
_T( "FFConst" ), MB_ICONERROR | MB_OK );
EndDialog( hDlg, 0 );
}

// Init the time of the last force feedback effect
g_dwLastEffectSet = timeGetTime();
break;

case WM_MOUSEMOVE:
if( FAILED( OnMouseMove( hDlg, GET_X_LPARAM( lParam ), GET_Y_LPARAM( lParam ), ( UINT )wParam ) ) )
{
MessageBox( NULL, _T( "Error setting effect parameters. " )
_T( "The sample will now exit." ),
_T( "FFConst" ), MB_ICONERROR | MB_OK );
EndDialog( hDlg, 0 );
}
break;

case WM_LBUTTONDOWN:
OnLeftButtonDown( hDlg, GET_X_LPARAM( lParam ), GET_Y_LPARAM( lParam ), ( UINT )wParam );
break;

case WM_LBUTTONUP:
OnLeftButtonUp( hDlg, GET_X_LPARAM( lParam ), GET_Y_LPARAM( lParam ), ( UINT )wParam );
break;

case WM_PAINT:
OnPaint( hDlg );
break;

case WM_ACTIVATE:
if( WA_INACTIVE != wParam && g_pDevice )
{
// Make sure the device is acquired, if we are gaining focus.
g_pDevice->Acquire();

if( g_pEffect )
g_pEffect->Start( 1, 0 ); // Start the effect
}
break;

case WM_COMMAND:
switch( LOWORD( wParam ) )
{
case IDCANCEL:
EndDialog( hDlg, 0 );
break;

default:
return FALSE; // Message not handled
}
break;

case WM_DESTROY:
// Cleanup everything
KillTimer( hDlg, 0 );
FreeDirectInput();
break;

default:
return FALSE; // Message not handled
}

return TRUE; // Message handled
}




//-----------------------------------------------------------------------------
// Name: InitDirectInput()
// Desc: Initialize the DirectInput variables.
//-----------------------------------------------------------------------------
HRESULT InitDirectInput( HWND hDlg )
{
DIPROPDWORD dipdw;
HRESULT hr;

// Register with the DirectInput subsystem and get a pointer
// to a IDirectInput interface we can use.
if( FAILED( hr = DirectInput8Create( GetModuleHandle( NULL ), DIRECTINPUT_VERSION,
IID_IDirectInput8, ( VOID** )&g_pDI, NULL ) ) )
{
return hr;
}

// Look for a force feedback device we can use
if( FAILED( hr = g_pDI->EnumDevices( DI8DEVCLASS_GAMECTRL,
EnumFFDevicesCallback, NULL,
DIEDFL_ATTACHEDONLY | DIEDFL_FORCEFEEDBACK ) ) )
{
return hr;
}

if( NULL == g_pDevice )
{
MessageBox( NULL, _T( "Force feedback device not found. " )
_T( "The sample will now exit." ),
_T( "FFConst" ), MB_ICONERROR | MB_OK );
EndDialog( hDlg, 0 );
return S_OK;
}

// Set the data format to "simple joystick" - a predefined data format. A
// data format specifies which controls on a device we are interested in,
// and how they should be reported.
//
// This tells DirectInput that we will be passing a DIJOYSTATE structure to
// IDirectInputDevice8::GetDeviceState(). Even though we won't actually do
// it in this sample. But setting the data format is important so that the
// DIJOFS_* values work properly.
if( FAILED( hr = g_pDevice->SetDataFormat( &c_dfDIJoystick ) ) )
return hr;

// Set the cooperative level to let DInput know how this device should
// interact with the system and with other DInput applications.
// Exclusive access is required in order to perform force feedback.
if( FAILED( hr = g_pDevice->SetCooperativeLevel( hDlg,
DISCL_EXCLUSIVE |
DISCL_FOREGROUND ) ) )
{
return hr;
}

// Since we will be playing force feedback effects, we should disable the
// auto-centering spring.
dipdw.diph.dwSize = sizeof( DIPROPDWORD );
dipdw.diph.dwHeaderSize = sizeof( DIPROPHEADER );
dipdw.diph.dwObj = 0;
dipdw.diph.dwHow = DIPH_DEVICE;
dipdw.dwData = FALSE;

if( FAILED( hr = g_pDevice->SetProperty( DIPROP_AUTOCENTER, &dipdw.diph ) ) )
return hr;

// Enumerate and count the axes of the joystick
if( FAILED( hr = g_pDevice->EnumObjects( EnumAxesCallback,
( VOID* )&g_dwNumForceFeedbackAxis, DIDFT_AXIS ) ) )
return hr;

// This simple sample only supports one or two axis joysticks
if( g_dwNumForceFeedbackAxis > 2 )
g_dwNumForceFeedbackAxis = 2;

// This application needs only one effect: Applying raw forces.
DWORD rgdwAxes[2] = { DIJOFS_X, DIJOFS_Y };
LONG rglDirection[2] = { 0, 0 };
DICONSTANTFORCE cf = { 0 };

DIEFFECT eff;
ZeroMemory( &eff, sizeof( eff ) );
eff.dwSize = sizeof( DIEFFECT );
eff.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS;
eff.dwDuration = INFINITE;
eff.dwSamplePeriod = 0;
eff.dwGain = DI_FFNOMINALMAX;
eff.dwTriggerButton = DIEB_NOTRIGGER;
eff.dwTriggerRepeatInterval = 0;
eff.cAxes = g_dwNumForceFeedbackAxis;
eff.rgdwAxes = rgdwAxes;
eff.rglDirection = rglDirection;
eff.lpEnvelope = 0;
eff.cbTypeSpecificParams = sizeof( DICONSTANTFORCE );
eff.lpvTypeSpecificParams = &cf;
eff.dwStartDelay = 0;

// Create the prepared effect
if( FAILED( hr = g_pDevice->CreateEffect( GUID_ConstantForce,
&eff, &g_pEffect, NULL ) ) )
{
return hr;
}

if( NULL == g_pEffect )
return E_FAIL;

return S_OK;
}




//-----------------------------------------------------------------------------
// Name: EnumAxesCallback()
// Desc: Callback function for enumerating the axes on a joystick and counting
// each force feedback enabled axis
//-----------------------------------------------------------------------------
BOOL CALLBACK EnumAxesCallback( const DIDEVICEOBJECTINSTANCE* pdidoi,
VOID* pContext )
{
DWORD* pdwNumForceFeedbackAxis = ( DWORD* )pContext;

if( ( pdidoi->dwFlags & DIDOI_FFACTUATOR ) != 0 )
( *pdwNumForceFeedbackAxis )++;

return DIENUM_CONTINUE;
}




//-----------------------------------------------------------------------------
// Name: EnumFFDevicesCallback()
// Desc: Called once for each enumerated force feedback device. If we find
// one, create a device interface on it so we can play with it.
//-----------------------------------------------------------------------------
BOOL CALLBACK EnumFFDevicesCallback( const DIDEVICEINSTANCE* pInst,
VOID* pContext )
{
LPDIRECTINPUTDEVICE8 pDevice;
HRESULT hr;

// Obtain an interface to the enumerated force feedback device.
hr = g_pDI->CreateDevice( pInst->guidInstance, &pDevice, NULL );

// If it failed, then we can't use this device for some
// bizarre reason. (Maybe the user unplugged it while we
// were in the middle of enumerating it.) So continue enumerating
if( FAILED( hr ) )
return DIENUM_CONTINUE;

// We successfully created an IDirectInputDevice8. So stop looking
// for another one.
g_pDevice = pDevice;

return DIENUM_STOP;
}




//-----------------------------------------------------------------------------
// Name: FreeDirectInput()
// Desc: Initialize the DirectInput variables.
//-----------------------------------------------------------------------------
VOID FreeDirectInput()
{
// Unacquire the device one last time just in case
// the app tried to exit while the device is still acquired.
if( g_pDevice )
g_pDevice->Unacquire();

// Release any DirectInput objects.
SAFE_RELEASE( g_pEffect );
SAFE_RELEASE( g_pDevice );
SAFE_RELEASE( g_pDI );
}




//-----------------------------------------------------------------------------
// Name: OnPaint()
// Desc: Handles the WM_PAINT window message
//-----------------------------------------------------------------------------
VOID OnPaint( HWND hDlg )
{
PAINTSTRUCT ps;
HDC hDC;
HPEN hpenOld;
HPEN hpenBlack;
HBRUSH hbrOld;
HBRUSH hbrBlack;
INT x;
INT y;

hDC = BeginPaint( hDlg, &ps );
if( NULL == hDC )
return;

// Everything is scaled to the size of the window.
hpenBlack = GetStockPen( BLACK_PEN );
hpenOld = SelectPen( hDC, hpenBlack );

// Draw force feedback bounding rect
MoveToEx( hDC, FEEDBACK_WINDOW_X, FEEDBACK_WINDOW_Y, NULL );

LineTo( hDC, FEEDBACK_WINDOW_X,
FEEDBACK_WINDOW_Y + FEEDBACK_WINDOW_WIDTH );
LineTo( hDC, FEEDBACK_WINDOW_X + FEEDBACK_WINDOW_WIDTH,
FEEDBACK_WINDOW_Y + FEEDBACK_WINDOW_WIDTH );
LineTo( hDC, FEEDBACK_WINDOW_X + FEEDBACK_WINDOW_WIDTH,
FEEDBACK_WINDOW_Y );
LineTo( hDC, FEEDBACK_WINDOW_X,
FEEDBACK_WINDOW_Y );

// Calculate center of feedback window for center marker
x = FEEDBACK_WINDOW_X + FEEDBACK_WINDOW_WIDTH / 2;
y = FEEDBACK_WINDOW_Y + FEEDBACK_WINDOW_WIDTH / 2;

// Draw center marker
MoveToEx( hDC, x, y - 10, NULL );
LineTo( hDC, x, y + 10 + 1 );
MoveToEx( hDC, x - 10, y, NULL );
LineTo( hDC, x + 10 + 1, y );

hbrBlack = GetStockBrush( BLACK_BRUSH );
hbrOld = SelectBrush( hDC, hbrBlack );

x = MulDiv( FEEDBACK_WINDOW_WIDTH,
g_nXForce + DI_FFNOMINALMAX,
2 * DI_FFNOMINALMAX );

y = MulDiv( FEEDBACK_WINDOW_WIDTH,
g_nYForce + DI_FFNOMINALMAX,
2 * DI_FFNOMINALMAX );

x += FEEDBACK_WINDOW_X;
y += FEEDBACK_WINDOW_Y;

Ellipse( hDC, x - 5, y - 5, x + 6, y + 6 );

SelectBrush( hDC, hbrOld );
SelectPen( hDC, hpenOld );

EndPaint( hDlg, &ps );
}




//-----------------------------------------------------------------------------
// Name: OnMouseMove()
// Desc: If the mouse button is down, then change the direction of
// the force to match the new location.
//-----------------------------------------------------------------------------
HRESULT OnMouseMove( HWND hDlg, INT x, INT y, UINT keyFlags )
{
HRESULT hr;
DWORD dwCurrentTime;

if( NULL == g_pEffect )
return S_OK;

if( keyFlags & MK_LBUTTON )
{
dwCurrentTime = timeGetTime();

if( dwCurrentTime - g_dwLastEffectSet < 100 )
{
// Don't allow setting effect more often than
// 100ms since every time an effect is set, the
// device will jerk.
//
// Note: This is not neccessary, and is specific to this sample
return S_OK;
}

g_dwLastEffectSet = dwCurrentTime;

x -= FEEDBACK_WINDOW_X;
y -= FEEDBACK_WINDOW_Y;

g_nXForce = CoordToForce( x );
g_nYForce = CoordToForce( y );

InvalidateRect( hDlg, 0, TRUE );
UpdateWindow( hDlg );

if( FAILED( hr = SetDeviceForcesXY() ) )
return hr;
}

return S_OK;
}




//-----------------------------------------------------------------------------
// Name: OnLeftButtonDown()
// Desc: Capture the mouse so we can follow it, and start updating the
// force information.
//-----------------------------------------------------------------------------
VOID OnLeftButtonDown( HWND hDlg, INT x, INT y, UINT keyFlags )
{
SetCapture( hDlg );
OnMouseMove( hDlg, x, y, MK_LBUTTON );
}




//-----------------------------------------------------------------------------
// Name: OnLeftButtonUp()
// Desc: Stop capturing the mouse when the button goes up.
//-----------------------------------------------------------------------------
VOID OnLeftButtonUp( HWND hDlg, INT x, INT y, UINT keyFlags )
{
ReleaseCapture();
}




//-----------------------------------------------------------------------------
// Name: CoordToForce()
// Desc: Convert a coordinate 0 <= nCoord <= FEEDBACK_WINDOW_WIDTH
// to a force value in the range -DI_FFNOMINALMAX to +DI_FFNOMINALMAX.
//-----------------------------------------------------------------------------
INT CoordToForce( INT nCoord )
{
INT nForce = MulDiv( nCoord, 2 * DI_FFNOMINALMAX, FEEDBACK_WINDOW_WIDTH )
- DI_FFNOMINALMAX;

// Keep force within bounds
if( nForce < -DI_FFNOMINALMAX )
nForce = -DI_FFNOMINALMAX;

if( nForce > +DI_FFNOMINALMAX )
nForce = +DI_FFNOMINALMAX;

return nForce;
}




//-----------------------------------------------------------------------------
// Name: SetDeviceForcesXY()
// Desc: Apply the X and Y forces to the effect we prepared.
//-----------------------------------------------------------------------------
HRESULT SetDeviceForcesXY()
{
// Modifying an effect is basically the same as creating a new one, except
// you need only specify the parameters you are modifying
LONG rglDirection[2] = { 0, 0 };

DICONSTANTFORCE cf;

if( g_dwNumForceFeedbackAxis == 1 )
{
// If only one force feedback axis, then apply only one direction and
// keep the direction at zero
cf.lMagnitude = g_nXForce;
rglDirection[0] = 0;
}
else
{
// If two force feedback axis, then apply magnitude from both directions
rglDirection[0] = g_nXForce;
rglDirection[1] = g_nYForce;
cf.lMagnitude = ( DWORD )sqrt( ( double )g_nXForce * ( double )g_nXForce +
( double )g_nYForce * ( double )g_nYForce );
}

DIEFFECT eff;
ZeroMemory( &eff, sizeof( eff ) );
eff.dwSize = sizeof( DIEFFECT );
eff.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS;
eff.cAxes = g_dwNumForceFeedbackAxis;
eff.rglDirection = rglDirection;
eff.lpEnvelope = 0;
eff.cbTypeSpecificParams = sizeof( DICONSTANTFORCE );
eff.lpvTypeSpecificParams = &cf;
eff.dwStartDelay = 0;

// Now set the new parameters and start the effect immediately.
return g_pEffect->SetParameters( &eff, DIEP_DIRECTION |
DIEP_TYPESPECIFICPARAMS |
DIEP_START );
}
Responder