[#TFService] Algunas novedades de ultimo momento

image

Buenas,

de la mano del gran Brian Harry ya podemos hacer públicas algunas de las new features incorporadas al otro TFS > Team Foundation Service (me sigue pareciendo un poco desafortunada la elección del nombre).

  • Por un lado tenemos una interfaz mucho más “touch friendly”, es decir que si quieres controlar el TaskBoard o el product BackLog desde un dispositivo táctil es mucho más simple. Si como yo lo que quieres hacer son aplicaciones de control con Kinect, pues también se simplifica mucho el trabajo.
  • Basta de selección del provider de seguridad cuando solo hay LiveId. Un formulario menos y mucha más gente feliz.
  • Filtros en algunas partes importantes y … poco más.
  • Ahh y un nuevo look&feel mucho mas metro Risa

image

 

Fuente: http://blogs.msdn.com/b/bharry/archive/2012/04/30/tfspreview-update.aspx

Saludos @ Home

El Bruno

image image image

[#VIDEO] Magia con Kinect (augmented reallity)

image

Buenas,

después de un par de horas de jugar a Kinect Star Wars con Valentino, me duelen partes del cuerpo que no conocía. Así que en esta semana que es un poco de retorno a ALM, pues empiezo por un video que no tiene absolutamente nada que ver con ALM, pero que es impresionante en lo que se refiere a despliegue de medios.

Link: http://youtu.be/C4pHP-pgwlI

Lo más interesante del video, es que es una tecnología que la mayoría de nosotros podríamos implementar y crear en nuestra propia casa. Yo ya he estado “jugando” con un poco de realidad aumentada con Kinect y la verdad es que si bien hace falta conocer un poco de como funcionan las imágenes en general, no es tan complicado.

Esto hace unos años era una locura de solo pensarlo, pero ahora gracias a Kinect y al Kinect SDK, pues lo tenemos más fácil. Impresionante, ¿no?

 

Saludos @ Home

El Bruno

image image image

[#KINECTSDK] Kinect Missile Launcher (V): Video y codigo fuente

image

Buenas.

Primero vamos con los links de la serie

    1. Identificando el dispositivo HID
    2. Moviendo el lanza misiles
    3. Otra forma de averiguar los valores para trabajar con el lanza misiles con C#
    4. Controlando el lanza misiles con Kinect
    5. Video y código fuente de ejemplo

Y ahora un video de 30 segundos donde muestro un pequeño ejemplo de la aplicación en funcionamiento.

Link : http://youtu.be/ATxtYes6pBQ

Un detalle, el misil sale con una potencia que ni en HALO, con lo que los pocos frames de la cámara de Kinect no lo pueden capturar en su vuelo. Otro detalle es que como puse el lanza misiles delante del Kinect para poder grabar el video, la captura del skeleton va un poco así así, con lo que puede hacer unos raros.

Y para terminar, el código fuente de la aplicación se puede descargar desde https://skydrive.live.com/redir.aspx?cid=bef06dffdb192125&resid=BEF06DFFDB192125!4275&parid=BEF06DFFDB192125!1932&authkey=!AOhNmp_md8XLYbo

 

 

Saludos @ Home

El Bruno

image image image

[#KINECTSDK] Kinect Missile Launcher (IV): Controlando el lanza misiles con Kinect

image

Buenas,

hoy ya vamos a crear una aplicación que nos permita controlar el lanza misiles utilizando gestos de Kinect. Para esto he pensado en los siguientes controles

  • La mano derecha controla la dirección del lanza misiles. Puede ir a la derecha, a la izquierda, arriba o abajo.
  • La mano izquierda controla el disparo del misil, la forma de disparar es levantar la mano encima de la cabeza.
  • Si ambos manos están por debajo de la cintura se detienen los movimientos del lanza misiles

Con esta base, y aprovechando los controles visuales de “Microsoft.Samples.Kinect.WpfViewers” he creado una aplicación WPF con el siguiente código en la ventana principal

   1: using System.Linq;

   2: using System.Windows;

   3: using Microsoft.Kinect;

   4:  

   5: namespace ElBruno.Rocket.Ui

   6: {

   7:     public partial class MainWindow

   8:     {

   9:         private KinectSensor _sensor;

  10:         private Rocket _rocket;

  11:         public MainWindow()

  12:         {

  13:             InitializeComponent();

  14:             Loaded += MainWindowLoaded;

  15:         }

  16:  

  17:         private void MainWindowLoaded(object sender, RoutedEventArgs e)

  18:         {

  19:             InitRocket();

  20:             InitKinectSensor();

  21:         }

  22:  

  23:         private void InitRocket()

  24:         {

  25:             _rocket = new Rocket(@"vid_0a81", @"pid_ff01");

  26:             _rocket.Connect();

  27:         }

  28:  

  29:         private void InitKinectSensor()

  30:         {

  31:             // validate

  32:             if (KinectSensor.KinectSensors.Count == 0) return;

  33:  

  34:             // init Kinect

  35:             var parameters = new TransformSmoothParameters

  36:                                  {

  37:                                      Smoothing = 0.75f,

  38:                                      Correction = 0.1f,

  39:                                      Prediction = 0.0f,

  40:                                      JitterRadius = 0.05f,

  41:                                      MaxDeviationRadius = 0.08f

  42:                                  };

  43:  

  44:             _sensor = KinectSensor.KinectSensors[0];

  45:             _sensor.ColorStream.Enable(ColorImageFormat.RgbResolution640x480Fps30);

  46:             _sensor.DepthStream.Enable(DepthImageFormat.Resolution320x240Fps30);

  47:             _sensor.SkeletonStream.Enable(parameters);

  48:             _sensor.Start();

  49:             colorViewer.Kinect = _sensor;

  50:             skeletonViewer.Kinect = _sensor;

  51:             _sensor.SkeletonFrameReady += SensorSkeletonFrameReady;

  52:         }

  53:  

  54:         private void SensorSkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e)

  55:         {

  56:             Skeleton[] skeletons = null;

  57:             using (var frame = e.OpenSkeletonFrame())

  58:             {

  59:                 if (frame != null)

  60:                 {

  61:                     skeletons = new Skeleton[frame.SkeletonArrayLength];

  62:                     frame.CopySkeletonDataTo(skeletons);

  63:                 }

  64:             }

  65:  

  66:             if (skeletons == null) return;

  67:  

  68:             foreach (var kinectRocketGestures in (

  69:                 from skeleton in skeletons

  70:                 where skeleton.TrackingState == SkeletonTrackingState.Tracked

  71:                 let headJoint = skeleton.Joints[JointType.Head]

  72:                 where headJoint.TrackingState != JointTrackingState.NotTracked

  73:                 select skeleton).Select(skeleton => new KinectRocketGestures(skeleton, _rocket)))

  74:             {

  75:                 var gesture = kinectRocketGestures.ValidateGestures();

  76:                 textBlockInformation.Text = gesture;

  77:             }

  78:         }

  79:     }

  80: }

Es importante tener en cuenta que esta ventana no posee casi nada de lógica interesante, solo inicia los sensores del Kinect y del lanza misiles y luego se suscribe a las notificaciones de actualización de skeleton.
En esta notificación (línea 54), se valida que el tracking del skeleton sea correcto y luego utilizamos una clase KinectRocketGestures que es la que hace un poco la magia entre Kinect y el lanza misiles.
El código de esta clase es el siguiente
   1: using Microsoft.Kinect;

   2:  

   3: namespace ElBruno.Rocket.Ui

   4: {

   5:     class KinectRocketGestures

   6:     {

   7:         private readonly Skeleton _skeleton;

   8:         private readonly Rocket _rocket;

   9:  

  10:         public KinectRocketGestures(Skeleton skeleton, Rocket rocket)

  11:         {

  12:             _skeleton = skeleton;

  13:             _rocket = rocket;

  14:         }

  15:  

  16:         public string ValidateGestures()

  17:         {

  18:             var gesture = @"Not defined";

  19:             // STOP

  20:             // Right hand and Left hand hanging at the side

  21:             if (_skeleton.Joints[JointType.HandRight].Position.Y < _skeleton.Joints[JointType.HipCenter].Position.Y &&

  22:                 _skeleton.Joints[JointType.HandLeft].Position.Y < _skeleton.Joints[JointType.HipCenter].Position.Y)

  23:             {

  24:                 _rocket.StopAll();

  25:                 _rocket.StopFiring();

  26:                 _rocket.StopMovements();

  27:                 gesture = @"STOP";

  28:                 return gesture;

  29:             }

  30:  

  31:             // FIRE

  32:             if (_skeleton.Joints[JointType.HandLeft].Position.Y > _skeleton.Joints[JointType.Head].Position.Y)

  33:             {

  34:                 gesture = @"FIRE";

  35:                 _rocket.FireOnce();

  36:             }

  37:  

  38:             // MOVE RIGHT OR LEFT

  39:             // Right hand in front of right shoulder

  40:             // Right hand below shoulder height but above hip height

  41:             if (

  42:                 (_skeleton.Joints[JointType.HandRight].Position.Z < _skeleton.Joints[JointType.ElbowRight].Position.Z &&

  43:                 _skeleton.Joints[JointType.HandLeft].Position.Y < _skeleton.Joints[JointType.HipCenter].Position.Y)

  44:                 &&

  45:                 (_skeleton.Joints[JointType.HandRight].Position.Y < _skeleton.Joints[JointType.Head].Position.Y &&

  46:                 _skeleton.Joints[JointType.HandRight].Position.Y > _skeleton.Joints[JointType.HipCenter].Position.Y)

  47:                 )

  48:             {

  49:                 // Right hand right of right shoulder

  50:                 if (_skeleton.Joints[JointType.HandRight].Position.X > _skeleton.Joints[JointType.ShoulderRight].Position.X)

  51:                 {

  52:                     gesture = @"MOVE RIGHT";

  53:                     _rocket.MoveRight();

  54:                 }

  55:                 // Right hand left of left Shoulder

  56:                 if (_skeleton.Joints[JointType.HandRight].Position.X < _skeleton.Joints[JointType.ShoulderLeft].Position.X)

  57:                 {

  58:                     gesture = @"MOVE LEFT";

  59:                     _rocket.MoveLeft();

  60:                 }

  61:             }

  62:  

  63:             // MOVE UP OR DOWN

  64:             // Right hand in front of body with Left hand hanging at the side

  65:             // Right hand between shoulders

  66:             if (

  67:                 (_skeleton.Joints[JointType.HandRight].Position.Z < _skeleton.Joints[JointType.ShoulderCenter].Position.Z &&

  68:                 _skeleton.Joints[JointType.HandLeft].Position.Y < _skeleton.Joints[JointType.HipCenter].Position.Y)

  69:                 &&

  70:                 (_skeleton.Joints[JointType.HandRight].Position.X < _skeleton.Joints[JointType.ShoulderRight].Position.X &&

  71:                 _skeleton.Joints[JointType.HandRight].Position.X > _skeleton.Joints[JointType.ShoulderLeft].Position.X)

  72:                 )

  73:             {

  74:                 // Right hand above the shoulders

  75:                 if (_skeleton.Joints[JointType.HandRight].Position.Y > _skeleton.Joints[JointType.ShoulderCenter].Position.Y)

  76:                 {

  77:                     gesture = @"MOVE UP";

  78:                     _rocket.MoveUp();

  79:                 }

  80:                 // Right hand below the chest/gut

  81:                 if (_skeleton.Joints[JointType.HandRight].Position.Y < _skeleton.Joints[JointType.Spine].Position.Y)

  82:                 {

  83:                     gesture = @"MOVE DOWN";

  84:                     _rocket.MoveDown();

  85:                 }

  86:                 return gesture;

  87:             }

  88:         }

  89:     }

  90: }

 

Y listo! Un poco de validación de posiciones de la mano derecha y la mano izquierda y ya tenemos el control del lanza misiles utilizando Kinect.

Ahora me voy rápido al evento de MadridDotNet y en el próximo post pongo un video y el código de ejemplo de la aplicación.

Saludos @ La Finca

El Bruno

image image image

[#KINECTSDK] Kinect Missile Launcher (III): Otra forma de averiguar los valores para trabajar con el lanza misiles con C#

image

Buenas,

como he recibido varias preguntas relacionadas sobre cómo interpretar el buffer de entrada y salida de los dispositivos USB, voy a dejar una forma fácil de realizarlo.

Personalmente, yo utilizo la técnica del prueba y error; pero claro, esto te trae bastantes problemas de cabeza y lo mejor es trabajar con algún lenguaje de bajo nivel (C# sucks!).

Así que si eres amigo de las abstracciones, USB Monitor puede serte de gran ayuda. Este software te permite monitorizar los flujos de datos que se envían en los hubs USB. Dicho de otra forma podrás ver uno a uno los bytes que pasan por cada puerto USB.

En mi caso particular, y con la versión completa instalada, he configurado la misma para que capture toda la información que pasa por el segundo dispositivo HID. Ya me he dado cuenta de que el primero es el mouse.

image

Así que una vez definido el dispositivo que queremos atacar, lo siguiente es comenzar con la grabación de datos. En mi caso particular, no he aplicado ningún filtro.

He lanzado la aplicación de control del lanza misiles que viene con el mismo y he lanzado un misil. Esta es la traza que me deja el log

   1: 000238: Class-Specific Request Sent (DOWN), 24.04.2012 23:33:07.320 +22.500

   2: Request Type:Set Report (Data Field)

   3: Report Type:Output

   4: ReportID:0x0

   5: Parsed Report:

   6: Report Name:Unknown

   7: Unknown[-128..127]/[0..255]: 64

   8:  

   9: 000239: Class-Specific Data (UP), 24.04.2012 23:33:07.320 +0.0

  10: Request Type:Set Report (Data Field)

  11:  

  12: 000240: Report Arrived (UP), 24.04.2012 23:33:07.335 +0.015

  13: Report Name:Unknown

  14: Unknown[-128..127]/[0..255]: 0

  15:  

  16: 000241: Report Arrived (DOWN), 24.04.2012 23:33:07.335 +0.0

  17: Report Name:Unknown

  18: Unknown[-128..127]/[0..255]: 0

  19:  

  20: 000242: Class-Specific Request Sent (DOWN), 24.04.2012 23:33:07.335 +0.0

  21: Request Type:Set Report (Data Field)

  22: Report Type:Output

  23: ReportID:0x0

  24: Parsed Report:

  25: Report Name:Unknown

  26: Unknown[-128..127]/[0..255]: 16

  27:  

  28: 000243: Class-Specific Data (UP), 24.04.2012 23:33:07.335 +0.0

  29: Request Type:Set Report (Data Field)

  30:  

  31: 000244: Class-Specific Request Sent (DOWN), 24.04.2012 23:33:07.850 +0.514

  32: Request Type:Set Report (Data Field)

  33: Report Type:Output

  34: ReportID:0x0

  35: Parsed Report:

  36: Report Name:Unknown

  37: Unknown[-128..127]/[0..255]: 64

  38:  

  39: 000245: Class-Specific Data (UP), 24.04.2012 23:33:07.850 +0.0

  40: Request Type:Set Report (Data Field)

  41:  

  42: 000246: Report Arrived (UP), 24.04.2012 23:33:07.866 +0.015

  43: Report Name:Unknown

  44: Unknown[-128..127]/[0..255]: 16

  45:  

  46: 000247: Report Arrived (DOWN), 24.04.2012 23:33:07.866 +0.0

  47: Report Name:Unknown

  48: Unknown[-128..127]/[0..255]: 16

  49:  

  50: 000248: Class-Specific Request Sent (DOWN), 24.04.2012 23:33:07.953 +0.086

  51: Request Type:Set Report (Data Field)

  52: Report Type:Output

  53: ReportID:0x0

  54: Parsed Report:

  55: Report Name:Unknown

  56: Unknown[-128..127]/[0..255]: 64

  57:  

  58: 000249: Class-Specific Data (UP), 24.04.2012 23:33:08.007 +0.053

  59: Request Type:Set Report (Data Field)

  60:  

  61: 000250: Report Arrived (UP), 24.04.2012 23:33:08.026 +0.019

  62: Report Name:Unknown

  63: Unknown[-128..127]/[0..255]: 16

  64:  

  65: 000251: Report Arrived (DOWN), 24.04.2012 23:33:08.026 +0.0

  66: Report Name:Unknown

  67: Unknown[-128..127]/[0..255]: 16

  68:  

  69: 000252: Class-Specific Request Sent (DOWN), 24.04.2012 23:33:14.565 +6.539

  70: Request Type:Set Report (Data Field)

  71: Report Type:Output

  72: ReportID:0x0

  73: Parsed Report:

  74: Report Name:Unknown

  75: Unknown[-128..127]/[0..255]: 32

  76:  

  77: 000253: Class-Specific Data (UP), 24.04.2012 23:33:14.565 +0.0

  78: Request Type:Set Report (Data Field)

  79:  

  80: 000254: Class-Specific Request Sent (DOWN), 24.04.2012 23:37:05.977 +231.412

  81: Request Type:Set Report (Data Field)

  82: Report Type:Output

  83: ReportID:0x0

  84: Parsed Report:

  85: Report Name:Unknown

  86: Unknown[-128..127]/[0..255]: 64

  87:  

  88: 000255: Class-Specific Data (UP), 24.04.2012 23:37:05.977 +0.0

  89: Request Type:Set Report (Data Field)

  90:  

  91: 000256: Report Arrived (UP), 24.04.2012 23:37:05.977 +0.0

  92: Report Name:Unknown

  93: Unknown[-128..127]/[0..255]: 0

  94:  

  95: 000257: Report Arrived (DOWN), 24.04.2012 23:37:05.977 +0.0

  96: Report Name:Unknown

  97: Unknown[-128..127]/[0..255]: 0

  98:  

  99: 000258: Class-Specific Request Sent (DOWN), 24.04.2012 23:37:06.040 +0.062

 100: Request Type:Set Report (Data Field)

 101: Report Type:Output

 102: ReportID:0x0

 103: Parsed Report:

 104: Report Name:Unknown

 105: Unknown[-128..127]/[0..255]: 16

 106:  

 107: 000259: Class-Specific Data (UP), 24.04.2012 23:37:06.040 +0.0

 108: Request Type:Set Report (Data Field)

 109:  

 110: 000260: Class-Specific Request Sent (DOWN), 24.04.2012 23:37:06.102 +0.062

 111: Request Type:Set Report (Data Field)

 112: Report Type:Output

 113: ReportID:0x0

 114: Parsed Report:

 115: Report Name:Unknown

 116: Unknown[-128..127]/[0..255]: 64

 117:  

 118: 000261: Class-Specific Data (UP), 24.04.2012 23:37:06.196 +0.093

 119: Request Type:Set Report (Data Field)

 120:  

 121: 000262: Report Arrived (UP), 24.04.2012 23:37:06.211 +0.015

 122: Report Name:Unknown

 123: Unknown[-128..127]/[0..255]: 16

 124:  

 125: 000263: Report Arrived (DOWN), 24.04.2012 23:37:06.211 +0.0

 126: Report Name:Unknown

 127: Unknown[-128..127]/[0..255]: 16

 128:  

 129: 000264: Class-Specific Request Sent (DOWN), 24.04.2012 23:37:06.258 +0.046

 130: Request Type:Set Report (Data Field)

 131: Report Type:Output

 132: ReportID:0x0

 133: Parsed Report:

 134: Report Name:Unknown

 135: Unknown[-128..127]/[0..255]: 64

 136:  

 137: 000265: Class-Specific Data (UP), 24.04.2012 23:37:06.367 +0.109

 138: Request Type:Set Report (Data Field)

 139:  

 140: 000266: Report Arrived (UP), 24.04.2012 23:37:06.367 +0.0

 141: Report Name:Unknown

 142: Unknown[-128..127]/[0..255]: 16

 143:  

 144: 000267: Report Arrived (DOWN), 24.04.2012 23:37:06.367 +0.0

 145: Report Name:Unknown

 146: Unknown[-128..127]/[0..255]: 16

 147:  

 148: 000268: Class-Specific Request Sent (DOWN), 24.04.2012 23:37:06.430 +0.062

 149: Request Type:Set Report (Data Field)

 150: Report Type:Output

 151: ReportID:0x0

 152: Parsed Report:

 153: Report Name:Unknown

 154: Unknown[-128..127]/[0..255]: 32

 155:  

 156: 000269: Class-Specific Data (UP), 24.04.2012 23:37:06.523 +0.093

 157: Request Type:Set Report (Data Field)

Si analizamos los paquetes enviados (CS Request Sent) podremos ver la siguiente secuencia

  • 64
  • 16
  • 64
  • 64
  • 32

Además tenemos la diferencia de tiempo entre cada llamada. Yo para mi prueba la he redondeado a 50 milisegundos y he creado una aplicación de ejemplo son el siguiente código:

   1: using System;

   2: using System.Threading;

   3: using USBHIDDRIVER;

   4:  

   5: namespace HidUsbDriverConsoleTest

   6: {

   7:     internal class Program

   8:     {

   9:         private static void Main(string[] args)

  10:         {

  11:             var usb = new USBInterface(@"vid_0a81", @"pid_ff01");

  12:             usb.Connect();

  13:             WriteData(usb, 64);

  14:             WriteData(usb, 16);

  15:             WriteData(usb, 64);

  16:             WriteData(usb, 64);

  17:             WriteData(usb, 32);

  18:             Console.ReadLine();

  19:         }

  20:         private static void WriteData(USBInterface usb, byte secondByteValue)

  21:         {

  22:             var command = new byte[] { 0, 2 };

  23:             command[1] = secondByteValue;

  24:             usb.UsbDevice.writeDataSimple(command);

  25:             Thread.Sleep(50);

  26:         }

  27:     }

  28: }

Como se puede ver, las líneas 13 a la 17 simulan esta secuencia y al momento de interactuar con el lanza misiles USB, pues hacen lo mismo que la aplicación original.

Más simple es imposible Risa

 

Descarga: http://www.hhdsoftware.com/usb-monitor

Saludos @ Home

El Bruno

image image image

[#KINECTSDK] Kinect Missile Launcher (II): Moviendo el lanza misiles

image

Buenas.

En el post de ayer explicaba como trabajar con un dispositivo HID. Hoy veremos como trabajar con el mismo, enviando información al device.

Lo primero que tenemos que hacer es decidir que biblioteca utilizaremos para trabajar con un dispositivo HID. En mi caso utilizaré una que funciona bastante bien, creada por Florian Leitner-Fischer, y que se puede descargar desde aquí.

En el post del link anterior, Florian explica las bases necesarias sobre como funciona su creación. En este post haremos lo siguiente:

  • Conectarnos al dispositivo
  • Validar la conexión
  • Enviar un mensaje para mover el lanza misiles USB

Para esto seguimos los siguientes pasos

1. Crear una aplicación de Consola

2. Agregar una referencia a la biblioteca USBHIDDRIVER

image

3. Cambiamos la configuración para que la aplicación sea X86, en lugar de AnyCPU

4. Ya tenemos lista nuestra aplicación

Lo siguiente es determinar el VendorId y el ProductId de nuestra aplicación. Si bien lo vimos en el post anterior, las siguientes líneas de código nos muestran todos los dispositivos HID que tengamos conectados

   1: var getAllDevices = new USBHIDDRIVER.USBInterface("_");

   2: getAllDevices.Connect();

   3: var devices = getAllDevices.getDeviceList();

   4: foreach (var device in devices)

   5: {

   6:     Console.WriteLine("device: " + device);

   7: }

Cuando ejecutamos la aplicación, vemos este output en la consola de Windows

device: \?hid#vid_413c&pid_3012#7&39484631&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}

device: \?hid#vid_0a81&pid_ff01#7&b08aa68&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}

Asumiendo que nuestro dispositivo es el segundo, los valores quedarían así:

  • VendorId = vid_0a81
  • ProductId = pid_ff01

Si queremos por ejemplo mover el lanzamisiles hacia abajo, tenemos que pasar un array de bytes con 2 elementos, Zero y dos. El código quedaría de la siguiente forma:

   1: var usb = new USBHIDDRIVER.USBInterface(@"vid_0a81", @"pid_ff01");

   2: usb.Connect();

   3: var startCMD = new byte[2] {0, 2};

   4: // move down

   5: usb.UsbDevice.writeDataSimple(startCMD);

Ahora bien, si te has bajado la biblioteca de Florian, verás que la funcion writeDataSimple() no existe. Esto es porque Florian agrega un proceso de doble validación para enviar siempre arrays “limpios” a los dispositivos USB.

Yo soy una persona que vive al límite y como no le tengo miedo al BSOD, cree la siguiente función para enviar mensajes al dispositivo.

   1: public bool writeDataSimple(byte[] bDataToWrite)

   2: {

   3:     var success = false;

   4:     if (getConnectionState())

   5:     {

   6:         try

   7:         {

   8:             var myOutputReport = new OutputReport();

   9:             success = myOutputReport.Write(bDataToWrite, myUSB.HidHandle);

  10:         }

  11:         catch (AccessViolationException ex)

  12:         {

  13:             success = false;

  14:         }

  15:     }

  16:     return success;

  17: }

La función anterior evita validaciones sobre el buffer a enviar al dispositivo y le envía directamente el array de bytes. En bastantes ocasiones esto nos puede retornar un false o lanzar una excepción no manejada, pero si ya sabemos que el lanza misiles funciona con un buffer de 2 bytes, pues lo tenemos más fácil.

Ahora bien, para conocer esta información he vuelto a utilizar la herramienta SimpleHIDWrite. La misma cuando se selecciona un dispositivo nos muestra la cantidad de elementos que tiene que tener el array de entrada.

image

En mi caso, y sabiendo que eran 2 los bytes a poner en el buffer de escritura, pues comencé a probar con el método de prueba/error y llegué a los siguientes valores:

  • 00, 00. Stop
  • 00, 01. Down
  • 00, 02. Up
  • 00, 04. Giro anti horario
  • 00, 08. Giro horario
  • 00, 10. Dispara misiles

Con estos datos ya tengo casi todo para comenzar. Pero claro, en el camino me encuentro con que en CodePlex hay un proyecto que ya me da interacción con el lanza misiles, con el WiiMote, etc. Pero claro, no funciona a la primera y no tengo lugar para escribir el porqué. Pero tienen una implementación de una clase Rocket, que la verdad es que está muy bien.

Así que he reemplazado el componente que se utiliza para la conexión con el HID, he hecho un poco de refactoring y me ha quedado una clase con la siguiente estructura.

image

Ahora solo queda un poco de trabajo con KinectSDK y listo !!!

 

Referencias:

 

 

Saludos @ Home

El Bruno

image image image

[#KINECTSDK] Kinect Missile Launcher (I): Identificando el dispositivo HID

image

Buenas

Hace 2 semanas que estamos jugando con el Valentino al Kinect Star Wars y tengo que admitir que mi enano juega mucho mejor que yo. Hoy mientras estábamos ordenando un poco mis juguetes, encontramos mi lanzamisiles USB y claro, el Valentino me pidió que lo probáramos.

Una vez que hube instalado el software se lo di al Valentino y claro, cuando tuve que acercarse y utilizar el teclado y el mouse se quedó un poco de palo.

image

Después de meses de jugar con un iPad, una tableta con Windows 8 y con el Kinect, esto del teclado y el mouse no le gusta nada.

Así que como buen padre que soy, me puse manos a la obra para poder controlar el lanza misiles con el Kinect.

Al tema lo encaré con bastante optimismo, porque ya hace un par de años había creado una extensión para Team Build que lanzaba un misil cuando una build fallaba, al programador que “rompió la build”.

Antes de comenzar tenía una pregunta en mente que tal vez me tiraba el proyecto abajo:

Windows 8 habrá cambiado la forma de detectar dispositivos HID?

Por suerte, no. Esto es importante porque por lo general estos dispositivos no tienen SDK, ni nada por el estilo. Windows los reconoce de la misma forma en la que se reconoce un teclado o un mouse, y a partir de allí hay que hacer un poco de ingeniería inversa para poder entender como funcionan los mismos.

Un detalle, si yo lo he podido entender es porque no es tan complicado. Siempre lo trato de explicar, haciendo una analogía con 2 buffers de datos, uno de entrada y otro de salida para el puerto USB. Cada vez que queremos que un dispositivo realice una acción específica, tenemos que conocer el set de bytes que tenemos que “enviar”. De la misma forma, tenemos que aprender a interpretar los datos de entrada para “leer” la información que nos envía el dispositivo.

Antes de comenzar a “leer” y “enviar” información al dispositivo USB, tenemos que identificar el mismo. Esto Windows lo hace una forma simple, y nosotros como developers tenemos 2 opciones

1. Pasarnos 4 días interpretando información del registro de Windows

2. Utilizar una herramienta como HID Device Info para conocer los datos de nuestro dispositivo HID

Esta herramienta se puede descargar desde HID Page, un excelente sitio con mucha información para trabajar con HID desde .Net. La siguiente imagen muestra los datos de los dispositivos que tengo conectado a mi PC.

image

En el caso del Rocket Baby, los datos que debemos apuntar son:

  • Vendor Name
  • Product Name
  • VID
  • PID
  • Revision

Esto es importante porque luego la clase .Net que utilizamos para interactuar con el dispositivo utiliza estos datos para identificar el mismo.

Pues bien, me guardo el ejemplo de código integrado con el Kinect para el próximo post y me voy a controlar otras cosillas más con el Kinect Guiño

 

Referencias:

 

Saludos @ Home

El Bruno

image image image

[#VS11] CodeMaid: Excelente extensión con las 3 cosas que siempre te faltan

image

Buenas,

los que me conocen saben que soy un enemigo acérrimo del mouse. Ojo! eso no significa que sea un amigo de lo táctil, sino más bien que intento siempre trabajar con atajos de teclado.

Así fue que hace un par de días me instalé una extensión en Visual Studio llamada CodeMaid, pero no fue hasta ayer que tuve la oportunidad de utilizarla. En realidad, uno de los atajos de teclado de teclado “se pisó” con otro de los que utilizo y ahí me di cuenta de que tenía la extensión instalada.

Llevo 2 días y la verdad es que CodeMaid, me gusta. Me gusta porque es gratis, porque es de código abierto, porque apunta a cosas sencillas pero efectivas y porque funciona en las últimas 4 versiones de Visual Studio.

image

Por ejemplo, me ha llamado la atención lo bien que funciona la opción “Cleanup”. Esta acción se encarga de “limpiar” nuestro código buscando detalles como

  • sentencias using no utilizadas
  • elimina espacios en blanco no necesarios
  • elimina líneas en blanco consecutivas
  • etc.

Lo he ejecutado en un par de ficheros que sabía que tenían margen de mejora y lo ha hecho realmente bien.

Otra opción que me gusta es “Reorganize” una clase. Esta opción reorganiza el código de una clase basado en las especificaciones de StyleCop. Si luego ejecutamos el análisis de StyleCop, veremos que nos saca mucho trabajo de arriba.

Nota: Recuerda que en Avanade Spain, es altamente probable que te toque pasar una revisión con StyleCop como regla obligatoria para el estilo de código.

Finalmente, una acción que me parece genial. La capacidad de cambiar entre archivos relacionados. Lo más usual que solemos hacer cuando editamos WPF entre el XAML y el XAML.cs

image

Pues bien, solo remarcar esas 3 cosillas aunque sé que tiene más. CodeMaid ha merecido la pena para los 2 días de trabajo.

Mientras, volveré a activar ReSharper y trabajaré con el mismo que me da las mismas opciones Sonrisa y lo conozco bastante mejor.

Descarga: http://www.codemaid.net/

Saludos @ Home

El Bruno

image image image

[#TFSERVICE] Team Foundation Service Whitepaper released by ALM Rangers

image

Buenas,

hace unos días, nuestros amigos los ALM Rangers han liberado una guía extremadamente útil:

Team Foundation Service Preview

Practical experience from the ALM Rangers

Como su nombre lo indica, es una guía donde se recogen diferentes experiencias de trabajo con TFService por parte de los ALM Rangers.

Si todavía no los conoces, los ALM Ranger son un grupo de personas cuya especialidad es ALM pero “on the field”, es decir, no hablando a 10000kms de altura, sino más bien desde un punto de vista bastante práctico basado en la experiencia. Este grupo de trabajo está compuesto por personas de Microsoft, MVPs, partners, etc. Es un grupo bastante variado y donde hay bastantes opiniones encontradas, ya que las experiencias y requerimientos de trabajo de cada persona son diferentes entre sí.

  • Pues bien, en este whitepaper (still in beta), podemos encontrar diferentes temas como:
  • Qué es Team Foundation Service?
  • Diferentes formas de organizar un equipo de trabajo distribuido
  • Por qué TFService es un servicio pensado para organizaciones?
  • etc.

Vamos que hay de todo un poco, como en botica. Yo le he dado un vistazo inicial y efectivamente, hay de todo un poco. Lo bueno, es que lo que me sirve me lo guardo y lo demás, … pues bien como un perro tuerto, lo dejaré de lado Sonrisa

 

Saludos @ Home

El Bruno

image image image

[#WINDOWS8] HowTo: Habilitar Hyper-V en Windows8

image

Buenas,

si bien es cierto que Microsoft estaba siempre un paso (o dos) por detrás en lo referido a tecnología de virtualización, con Windows 8 han dado un gran cambio, y que creo que es para mejor:

Han decidido unificar la tecnología de virtualización en sistemas operativos de servidor y de cliente en Hyper-V.

Menudo golazo! Pues bien, ahora ya podemos comenzar a utilizar máquinas virtuales de 64 bits, sin tener que recurrir a VirtualBox, y por fin nos alejamos del innombrable VirtualPC.

La forma de habilitar el rol de Hyper-V es muy simple:

1. Presionamos Win-W para acceder a las búsquedas de Settings

2. Escribimos “features”

3. En el formulario de features de Windows, seleccionamos “Hyper-V”

image

4. Esperamos que se instalen las features.

5. Reiniciamos un par de veces (16 segundos de reloj!!!)

6. Ahora ya podemos lanzar Hyper-V. Para esto presionamos la tecla de Windows, escribimos “Hyper”, y tendremos acceso a “Hyper-V Manager”

image

A partir de aquí las opciones de Hyper-V para Windows 8 son bastante similares a otros productos, gestión de discos, de máquinas virtuales, etc.

Sin embargo es una gran plataforma para poder trabajar con máquinas virtuales que por suerte ya es parte del Sistema Operativo Risa

 

Saludos @ Home

El Bruno

image image image