image

Buenas,

hoy estaba por comenzar a trabajar en un flamante proyecto de ASP.Net MVC en mi Visual Studio 2010 sobre Windows 8, cuando me encontré con lo siguiente:

image

---------------------------
Microsoft Visual Studio
---------------------------
ASP.NET 4.0 has not been registered on the Web server. You need to manually configure your Web server for ASP.NET 4.0 in order for your site to run correctly.
---------------------------
OK   Help  
---------------------------

Chan! de nuevo Windows 8 haciendo de las suyas, pero claro en realidad fui yo que probando unos scripts eliminé unas features de Windows. Así que desde la opción “Turn Windows features on or off”, simplemente elegimos las que son necesarias para ASP.Net 3.5 y ASP.Net 4.5 y listo!

image

si es que, estos días arreglo una cosa y rompo 2 !!!

Saludos @ Home

El Bruno

image image image

image

Buenas,

pues una de las buenas noticias del día:

El SDK de Kinect 1.5 y el developer Toolkit han sido liberados.

En este caso la descarga se separa en estos dos componentes donde ya no es necesario instalar el SDK con todos los samples, sino que si somos developers, pues tendremos nuestro propio set de herramientas.

Ahora que ya podemos comprar Kinect en varios países (incluido España), nos encontramos con que a la lista se añaden otros 15 países. Pero en realidad lo que más nos importa son las new features que se incluyen en esta versión. Vamos con las más importantes

  • Kinect Studio. Una herramienta que te permite grabar y reproducir una secuencia de acciones frente al sensor. Fundamental para evitar tener que pararte y realizar una prueba unitaria humana cada vez que cambias algo en una aplicación.
  • La Guía de desarrollo de aplicaciones para aplicaciones con Kinect. Imprescindibles 70 páginas con muchos detalles a tener en cuenta para desarrollos con Kinect.
  • Face Tracking, capacidades de reconocimiento facial. Ojo, esto no es identificar rostros, sino identificar los puntos de un rostro. Con un poco de trabajo podremos reconocer sonrisas, sorpresas, sustos, etc.
  • Detección de puntos de skeleton en personas sentadas. Esto es asombroso, la capacidad de detectar los joints superiores de un skeleton pero en personas sentadas, realmente abre otro abanico de posibilidades de aplicaciones.
  • La cámara ahora soporta una resolución de 640 x 480 a 30FPS, con mejoras en ambientes con poca luz.
  • Cool! Joint orientation !! no solo tenemos la posición de un Joint, sino que además tenemos la capacidad de ver la “orientación” del mismo.
  • Nuevos lenguajes para el reconocimiento de voz: Francés, Español, Italiano y Japonés.

Bueno ahora toca probar aquellas cosas a las que no teníamos acceso sin las betas del SDK y a postear detalles sobre el mismo Risa

Fuente: http://blogs.msdn.com/b/kinectforwindows/archive/2012/05/21/kinect-for-windows-runtime-and-sdk-version-1-5-released.aspx

Saludos @ Home

El Bruno

image image image
Publicado 21/5/2012 19:53 por El Bruno | con no comments
Archivado en: ,

image

Buenas,

en primer lugar vamos con la respuesta a la pregunta:

SI. Es posible trabajar en un mismo proyecto con Visual Studio 2010 y Visual Studio 11.

Ahora un poco más de detalles basados en la experiencia de este último medio año. Con la llegada de Visual Studio 11, de nuevo vemos en el manual que hay “project compatibility” entre proyectos de Visual Studio 2010 y Visual Studio 11. A esta historia la conocemos de VS2005, VS2008 y VS2010; y sabemos que no es tan simple.

Cuando se migraba un proyecto a VS2010 se actualizaba el archivo de proyecto (.csproj) y si trabajabas con informes de Crystal Reports, o proyectos de setup, pues por lo general tenías uno o más problemas para que puedan convivir fácilmente VS2005 y VS2010.

Visual Studio 11 toma un enfoque diferente y promete no cambiar los archivos de proyecto. Pero teniendo en cuenta varios cambios que tenemos en Visual Studio 11, más vale que veamos que escenarios soporta.

Por ejemplo, he creado una solución con 17 proyectos representativos de lo que encontramos casi “out of the box” en Visual Studio 2010. Desde proyectos de ASP.Net MVC 2 hasta extensiones de Office. He incluido, solo a modo de ejemplo un proyecto para Windows Phone, aunque sé que Visual Studio 11 no lo abrirá.

image

Ahora bien, cuando abrimos esta solución con Visual Studio 11, lo primero que vemos es que el tipo de proyecto de Visual Studio Installer está deprecado. Esto no es novedad, ya que lo sabíamos desde hace un tiempo, pero a tenerlo en cuenta.

image

Otro error, pero esta de vez de configuración:

image

Hay que tocar un poco las tripas de Visual Studio 11 para que funcione con una versión anterior de SQL Express.

Pero después de un segundo de migración ya tenemos listo el proyecto en Visual Studio 11

image

Ahora bien, si estabas trabajando con proyectos de ASP.Net MVC 2.0, no te quedará otra más que actualizarte a la ultima versión. Los proyectos de ASP.Net MVC 2.0 no se soportar y te sugieren amablemente que los actualices a la versión ASP.Net MVC 3.

AspNetMvc2WebApplication1_Net4\AspNetMvc2WebApplication1_Net4.csproj: The project file 'E:\srcElBruno\Tests\ProjectCompatibility\TestForVs11\AspNetMvc2WebApplication1_Net4\AspNetMvc2WebApplication1_Net4.csproj' cannot be opened. There is a missing project subtype. Subtype: '{F85E285D-A4E0-4152-9332-AB1D724D3325}' is unsupported by this installation. http://go.microsoft.com/fwlink/?prd=12395&pver=11&sbp=ProjectTypeDeprecated&plcid=0x409&clcid=0x409&ar=MSDN&sar=ProjectCompatibility&o1={F85E285D-A4E0-4152-9332-AB1D724D3325}

Obviamente, los proyectos de Windows Phone no están soportados todavía en Visual Studio 11.

PhoneApp1_Net4\PhoneApp1_Net4.csproj: The project file 'E:\srcElBruno\Tests\ProjectCompatibility\TestForVs11\PhoneApp1_Net4\PhoneApp1_Net4.csproj' cannot be opened. There is a missing project subtype. Subtype: '{C089C8C0-30E0-4E22-80C0-CE093F111A43}' is unsupported by this installation. http://go.microsoft.com/fwlink/?prd=12395&pver=11&sbp=ProjectTypeDeprecated&plcid=0x409&clcid=0x409&ar=MSDN&sar=ProjectCompatibility&o1={C089C8C0-30E0-4E22-80C0-CE093F111A43}

Ahora bien, el panel del Solution Explorer nos deja muy en claro, qué tipos de proyectos están soportados, cuales no se pudieron cargar y cuales son incompatibles.

image

Si intentamos compilar los proyectos, veremos que los mismos compilan correctamente. Pero ahora viene la prueba de fuego:

¿podrá Visual Studio 2010 abrir la nueva solución y compilar los proyectos modificados?

Y la respuesta es …. NO !!! Lo primero que vemos es el asistente para conversiones y curiosamente apunta al proyecto de ASP.Net MVC 2.

image

La pregunta en este momento, estimado lector, es ¿cómo demonios se modifica este archivo si el crack de Visual Studio 11 me ha dicho que no lo puede cargar?. Pues si, lo modifica y mucho al archivo csproj, y es por esto que en este punto Visual Studio 2010 entiende que tiene que actualizarlo.

Así que si lo actualizas con VS2010, pues ya no hay más problemas, salvo que quieras trabajar en modo mixto en tu equipo con VS2010 y VS11.

Así que los puntos finales a tener en cuenta son los siguientes:

  • Hasta el día de hoy Visual Studio 11 no se puede utilizar para desarrollar para Windows Phone.
  • Con desarrollos para AZURE, Visual Studio 11 todavía no soporta un upgrade limpio desde VS2010, pero ese es motivo de un post completo
  • No hay soporte para proyectos de Visual Studio Installer en VS11
  • Cuidado con los proyectos de ASP.Net MVC 2.0 si piensas trabajar con Visual Studio 11

Lo bueno de todo este jardín, es que luego realmente el trabajo es “side by side” entre ambos Visual Studios sin complicaciones, algo que antes entre VS2005 y VS2010 por ejemplo no era tan fácil.

Saludos @ Home

El Bruno

image image image

image

Buenas,

estas semanas nos hemos estado pegando con el desarrollo de una aplicación para Windows 8. Como yo andaba flojo de estado físico; me he entrenado como Rocky en Siberia con 30 minutos de CodeKatas por día, los videos del Build (que a decir verdad no me han servido mucho) y otras técnicas de mi entrenados personal que no me permite difundir.

Pero como la base de todos los desarrollos sigue siendo

- 20% código

- 80% comprender la plataforma sobre la que trabajas

me he encontrado con este excelente recurso que me ha dado horas y horas de lectura de código:

WinRT XAML Toolkit

Mi proceso de aprendizaje era similar al siguiente:

1, elegir una problemática a solucionar (para la app que creamos hay bastantes en el backlog)

2. ver la forma de solucionarlo sobre WinRT

3. investigar como funcionan los componentes de WinRT que están por debajo para la solución que hemos implementado

4. un poco de TDD

5. volver al paso 1

6. refactorizar el código y el proceso de trabajo

 

Es por eso que este conjunto de clases, controles, etc. me ha venido muy bien, ya que cumplen con reglas básicas como clases con nombres coherentes, código limpio (bueno casi todo, etc.), en algunas partes se utiliza var (lo siento @J0rgeSerran0 @_PedroHurtado @eiximenis, menuda han montado ehh??), etc.

Si estas por empezar con Windows 8 y METRO, pues te recomiendo que revises algunas de las implementaciones que han hecho, ya que realmente están muy bien.

Proyecto: http://winrtxamltoolkit.codeplex.com/

Source: http://winrtxamltoolkit.codeplex.com/SourceControl/changeset/changes/13755

 

Saludos @ Home

El Bruno

image image image

image

Buenas,

hoy toca poner un ejemplo de código bastante simple, pero que puede traerte un par de dolores de cabeza si no sabes por donde empezar. La idea es simple:

Incluir un archivo XML en una aplicación METRO y des serializar el mismo para trabajar en una aplicación.

Esto que parece tan simple, se complica un poco en METRO ya que los tan namespaces tan populares como System.IO y otros con los que estamos acostumbrados a trabajar ya no están disponibles.

Si a eso le sumamos, que la mayoría de las acciones son en modo asíncrono, pues la programación cambia bastante. Pero claro, Visual Studio 11 llega a nuestro rescate con las nuevas sentencias ASYNC y AWAIT que realmente nos ayudan a programar en modo asíncrono.

Vamos por partes, en el proyecto de ejemplo tenemos una clase sample data con 2 propiedades definidas como el siguiente ejemplo:

   1: namespace Application1
   2: {
   3:     public class SampleData
   4:     {
   5:         public string Id { get; set; }
   6:         public string Name { get; set; }
   7:     }
   8: }

Luego incluimos un archivo XML dentro de una carpeta XML, con la siguiente información dentro del mismo

   1: <?xml version="1.0"?>
   2: <ArrayOfSampleData 
   3:    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
   4:    xmlns:xsd="http://www.w3.org/2001/XMLSchema">
   5:   <SampleData>
   6:     <Id>El</Id>
   7:     <Name>Bruno</Name>
   8:   </SampleData>
   9: </ArrayOfSampleData>

Así a simple vista, podemos ver que este XML es una serialización de un Array de elementos de tipo SampleData.

Luego queda la parte interesante, que es leer de este archivo. El siguiente código muestra un ejemplo donde la función LoadSampleData() retorna una colección de elementos del tipo SampleData leyendo un archivo llamado “data.xml” de un directorio de la aplicación llamado “XML“.

   1: private async void BtnGetClick(object sender, RoutedEventArgs e)
   2: {
   3:     var collection = LoadSampleData();
   4:     await collection;
   5:     var item = collection.Result[0];
   6:     txtId.Text = item.Id;
   7:     txtName.Text = item.Name;
   8: }
   9:  
  10: public async Task<ObservableCollection<SampleData>> LoadSampleData()
  11: {
  12:     var storageFolder = await Package.Current.InstalledLocation.GetFolderAsync("XML");
  13:     var sampleDataItems = await LoadFromXmlFile<ObservableCollection<SampleData>>("data.xml", storageFolder);
  14:     return sampleDataItems;
  15: }

Un par de detalles a tener en cuenta es que la función LoadSampleData() está definida con un prefijo async, que denota que la misma se puede ejecutar de modo asíncrono. Esto es posible ya que la lectura del directorio de trabajo (línea 12) se realiza en modo asíncrono.

En este punto merecen un especial detalle las sentencias donde para la ejecución de la función asíncrona se utiliza await. La forma más simple de definir a await es pensar en que con esta sentencia podremos llamar a funciones asíncronas y cuando se terminen las mismas, await retornará al flujo de trabajo indicado.

Ahora vamos a la parte interesante que es la desserialización del archivo XML. Para esto utilizamos la función LoadFromXmlFile que internamente, una vez que ha leido el contenido del archivo, des serializa el mismo en memoria (líneas 3 a 6). El siguiente código muestra un ejemplo de este funcionamiento:

   1: public static async Task<T> LoadFromXmlFile<T>(string fileName, StorageFolder folder = null)
   2: {
   3:     var xmlString = await ReadFromFile(fileName, folder);
   4:     var ms = new MemoryStream(UTF8Encoding.UTF8.GetBytes(xmlString));
   5:     var ser = new XmlSerializer(typeof(T));
   6:     T result = (T)ser.Deserialize(ms);
   7:     return result;
   8: }
   9:  
  10: public static async Task<string> ReadFromFile(string fileName, StorageFolder folder = null)
  11: {
  12:     folder = folder ?? ApplicationData.Current.LocalFolder;
  13:     var file = await folder.GetFileAsync(fileName);
  14:     using (var accessStream = await file.OpenAsync(FileAccessMode.Read))
  15:     {
  16:         using (var inStream = accessStream.GetInputStreamAt(0))
  17:         {
  18:             using (var reader = new DataReader(inStream))
  19:             {
  20:                 await reader.LoadAsync((uint)accessStream.Size);
  21:                 var data = reader.ReadString((uint)accessStream.Size);
  22:                 reader.DetachStream();
  23:                 return data;
  24:             }
  25:         }
  26:     }
  27: }
 

Voy a intentar separar el código del pedazo de POC que estoy construyendo y después de un poco de refactoring subiré un ejemplo más completo.

 

Saludos @ Home

El Bruno

image image image

 image

Buenas,

no soy un desarrollador de aplicaciones de Windows Phone, para eso están los cracks (@RafaSermed o @JosueYeray por ejemplo), pero desde que tengo Windows 8 instalado como plataforma principal de trabajo, pues echaba en cara poder terminar de dar unos toques a una aplicación de WP.

Ahora que tenemos el Windows Phone SDK 7.1.1 Update que ya nos permite instalar las herramientas de desarrollo de WP sobre Windows 8, pues pensé que tenía todo solucionado. Pero … zas! la primera en la cara, al momento de querer compilar el proyecto, pues me doy cuenta de que ando falto de XNA.

image

Así que ignorante de mí, pienso que instalando Microsoft XNA Game Studio 4.0 solucionaría mis problemas, pero claro

intentar instalar XNA en Windows 8 es igual de fácil que rascarse la espalda con la rodilla

Así que toca leer un poco los logs de instalación, y después de un rato me doy cuenta de que el problema de fondo parece que está relacionado con un producto que no conocía hasta el día de hoy: Game for Windows Client.

Y claro, el problema es el siguiente:

  • El instalador de Windows Phone intenta instalar una versión de XNA, aunque no puede
  • En realidad no puede, porque el instalador de XNA intenta instalar una versión de Game for Windows Client y Windows 8 dice NOT IN MY WATCH !!!

Así que de a poco y con cariño, los pasos para lograr que todo funcione son los siguientes:

Eso sí, la tarde interesante de Logs que me he dado hoy no me la quita nadie Risa

 

Descargas:

 

Saludos @ Home

El Bruno

image image image

image

Buenas,

hoy me encontraba mirando/actualizando un poco de código viejuno donde utilizaba NUnit como framework para mis pruebas unitarias y claro, como ahora estamos utilizando 100% Visual Studio 11 para el desarrollo, pues me decidí a utilizar el plugin para NUnit.

Lo bueno de VS11 es que permite utilizar diferentes plugins para pruebas unitarias (algo de lo que ya hablé aquí), pero fue mejor mi sorpresa cuando me encontré con una nueva versión del adaptador para NUnit.

Como en la página del PlugIn de Visual Studio Gallery no hay mucha información al respecto, pues me apunto los siguientes enlaces para ver las novedades, porque entre otras cosas ver que no hay ningún Bug activo me alegra como developer Risa

Saludos

 

Saludos @ Home

El Bruno

image image image

image

Buenas,

hoy toca compartir una experiencia de las que te pasan los viernes. Casi al final del desarrollo de una aplicación METRO (a que mola no?), y haciendo un par de pruebas en entornos no portátiles, tablets, touch, en el momento de probar algunas configuraciones en el emulador me encuentro con el siguiente error:

image

Nota: si te estás preguntando porqué tuve que utilizar el emulador de Windows 8, te animo a que intentes mover de landscape a portrait un HP Touch de 5 kilos.

Pues bien, el emulador no se puede lanzar si tienes activado el Microsoft Speech y en caso de que necesites ambos, te puedes llevar un buen disgusto.

Pero claro, es viernes mejor rebuscar entre frases alentadoras de viernes y salir adelante con un

Los problemas nunca se acaban, pero las soluciones tampoco.

La solución más objetiva consiste en convertirse al creacionismo e intentar crear una extensión para el emulador que soporte dispositivo de audio. La opción más realista, es probar la aplicación en el emulador sin las features de audio y acordarse de la madre de Sinofsky (o como se escriba el nombre del jefazo de W8).

Eso sí, con cualquiera de las 2 opciones ya podremos tener la aplicación en funcionamiento con todas las features que necesitamos.

image

Saludos @ Home

El Bruno

image image image
Publicado 11/5/2012 18:47 por El Bruno | con no comments

image

Buenas,

si se te ha vencido el trial del EAP de ReSharper 7 para Visual Studio 11 y cuando abres Visual Studio te encuentras con

image

Verás que el link que propone para actualizar a una nueva versión no funciona. Así que lo mejor es desinstalar Resharper 7 a mano desde “add and remove programs”

image

Y una vez desinstalado, vamos nuevamente al listado de compilaciones nocturnas de ReSharper 7 que se puede acceder desde http://confluence.jetbrains.net/display/ReSharper/ReSharper+7+EAP+for+VS11+Beta, descargamos la versión que nos ponga más felices y listo a instalar nuevamente Risa

En 10 minutos ya tenemos la ayuda de ReSharper embebida dentro del IDE.

 

Saludos @ Home

El Bruno

image image image

image

Buenas,

y es que lo de VS11 Beta era un poco intolerable. Un poco más soso y era como masticar cartón mojado. Ahora parece que para el próximo RC tendremos un carnaval de colores que nos ayudará a pensar seriamente si tanto trabajar con azules remarcados no nos quemará la vista.

En el post del equipo de producto de Visual Studio están todos los ejemplos, pero algunos no me terminan de gustar.

Por ejemplo, el definir un color de fondo más claro que el gris actual y marcar los elementos seleccionados en Azul, es muy Metro, pero no sé si para un IDE esa idea es correcta.

image

image

Ni hablar si encima comenzamos a utilizar colores como indicadores de estado o de progreso. La película Rio será una peli en blanco y negro al lado del nuevo Visual Studio.

image

Eso sí, hay algunas cosas interesantes como los nuevos colores del Solution Explorer o una barra de herramientas más amigable

image

image

Aunque, después de un par de meses me terminé acostumbrando al nuevo IDE y entiendo que con este haré lo mismo.

Eso sí, en mi próxima vida quiero ser experto en experiencia de usuario Risa

 

Fuente: http://blogs.msdn.com/b/visualstudio/archive/2012/05/08/visual-studio-11-user-interface-updates-coming-in-rc.aspx

Saludos @ Home

El Bruno

image image image
Publicado 8/5/2012 22:10 por El Bruno | con no comments
Archivado en:

image

Buenas,

me lo apunto para no olvidarme:

Test Scribe. esa extensión que te permite generar documentación a partir de información de Microsoft Test Manager, ahora soporta trabajar con Visual Studio 11.

image

Por cierto y por si no lo sabías, la herramienta es creada y soportada por el equipo de QA de Visual Studio Risa

Descarga: http://visualstudiogallery.msdn.microsoft.com/85b8215f-263f-4d1f-822b-307de339af38

Saludos @ Home

El Bruno

image image image

ALM 03

Buenas,

hoy le pego un empujón y termino el post que entre tanto AVE, viaje y showrooms de Innovación, no tengo mucho tiempo.

Hace un par de días Juan Quijano (@jc_quijano) y Álvaro Roca publicaron una serie de artículos donde comentaban los pros y contras de seguir el camino “de Programador a Manager”.

Yo os voy a comentar mi opinión personal, donde hoy no soy un Programador al 100% pero tampoco soy una persona que se dedica al Management en la forma que lo conocemos. Lo primero que me ha llamado la atención en los comentarios de ambos posts es LA COMPLETA REPUGNANCIA que demuestra más de un programador por cambiar a una posición de Management, y claro, estoy un 99,9999% seguro que esto es porque han tenido malas experiencias con jefes de equipo (desde ahora no más managers) que no saben hacer su trabajo.

En mi caso en particular, me he pasado años programando. No soy de esos que comentan que a los 4 años ya programaban en una Commodore 64 y desde allí tiran líneas, sino que descubrí a la informática más de grande y me apasionó desde el primer día. Me pasé años aprendiendo a programar y creo que lo que más me llamó la atención es que en este mundillo, siempre tenemos que estar aprendiendo constantemente.

Cuando estaba en mi primer trabajo tuve la suerte de participar en la creación de un producto que comenzó a comercializarse a nivel internacional y claro, lo que comenzó siendo un equipo de 3 personas, comenzó a crecer hasta que no me alcanzaban los dedos de una mano para contar el equipo. En ese punto, lo que había sido años de autoformación sobre nuevas tecnologías, programación, etc.; tuvo que convertirse en comenzar a aprender sobre elementos para garantizar que el trabajo que hacíamos todos como equipo era coherente, que todos entendíamos hacia donde queríamos llegar, etc.

En esa misma época llegué a España y como coincidía con el lanzamiento de Visual Studio 2005, pues empecé a leer libros que iban más allá de las técnicas de programación. Conocí AGILE, descubrí el negocio detrás de CMMI, pero principalmente comprendí que salvo proyectos concretos, en mi carrera profesional iba a tener que trabajar mucho en equipo. Es por este motivo que comencé a intentar mejorar la calidad de los entregables de mi equipo, intenté que todo el mundo sea mejor que yo (Germán me enseñó que la calidad de un equipo se mide por el peor de sus integrantes), etc.

Por el camino, me cayeron un par de premios MVPs, donde en los últimos años han sido de la categoría MVP ALM. Básicamente es reconocer y aprender como utilizar correctamente las herramientas de Visual Studio ALM para trabajar en equipo.

Así que bien, no soy un “manager de esos” que comentan en los posts de Juan Quijano y Álvaro Roca, pero si me considero una de las personas que intenta llevar adelante un equipo hasta obtener un cliente satisfecho y un equipo productivo. ¿Parece una incoherencia , no?

 

Por cierto, hace 2 días me encontré frente a un problema lógico que me costó casi una noche de construir. Como me di cuenta de que estoy “medio oxidado” me he puesto como objetivo hacer 30 minutos de Code Kata diariamente durante el mes de mayo.

¿A cuántos jefes de proyecto / gestores / managers conoces que hagan este tipo de cosas?

 

Referencias:

Saludos @ Home

El Bruno

image image image
Publicado 6/5/2012 17:24 por El Bruno | 5 comment(s)
Archivado en: ,

image

Buenas.

Si yo fuese un ratón o mouse estaría bastante cabreado / enfadado / enojado o como se diga en tu tierra. Resulta que ahora llega un dispositivo de más o menos €100 llamado Microsoft Kinect que apunta a reemplazarme y destronarme en el mundo de los ordenadores. Pero claro, el cabreo / enfado / enojo ya comienza hace un tiempo, cuando unos tíos de una empresa con una manzanita, reinventan un teléfono móvil un poco grande, le ponen de nombre iPad y todo el mundo se acostumbra a

Tocar y arrastrar en lugar de mover y clicar

Pues por eso, si fuese un ratón estaría muy cabreado. Pero como dice el gran Groucho Marx

Es mejor permanecer callado y parecer tonto que hablar y despejar las dudas definitivamente.

Es por eso que el ratón sigue calladito acompañado a más de uno y creo que tardará bastante tiempo para que nos abandone definitivamente.

Especialmente cuando hay muchas personas que, al momento de crear una nueva interfaz de usuario, lo que intentan es reemplazar el ratón, por ejemplo con gestos y acciones de Kinect. Estos proyectos están orientados y destinados al fracaso en un 99,99% de los casos.

La clave de estos casos está en la palabra “crear”. Lo que debemos hacer es dejar en paz al ratón, agradecerle los servicios prestados y comenzar a pensar cuáles son las formas más efectivas de trabajo con los nuevos sensores que poseemos.

Ahora la interacción entre dispositivos cada vez más móviles, superficies táctiles, detectores de gestos como Kinect, pico proyectores, etc.; hace que podamos pensar en nuevos escenarios para aplicaciones que realmente pueden ser grandiosos o desastrosos.

Alguno se preguntará, ¿le ha afectado el poco sueño al Bruno o qué le pasa que escribe esto?, es muy simple. Como algunos se han dado cuenta que me gusta jugar con Kinect y con este tipo de dispositivos, muchas veces me llegan preguntas del tipo

  • ¿Cómo puedo hacer para reemplazar el ratón con Kinect?
  • No se cómo hacer un doble clic con Kinect, cuando intento reemplazar al ratón.

Y si bien es cierto que intento responder todo lo que me preguntan, para esas preguntas la respuesta será este post. Donde no respondo nada en concreto pero … bueno ya sabes.

Yo por suerte, no solo tengo la oportunidad de “jugar” con estos dispositivos sino que además son parte de mi trabajo en Avanade, con lo que puedo ver las buenas y malas experiencias en el mundo de las NUI (término molón para describir formas naturales de trabajo frente a dispositivos electrónicos). Muchas personas no se dan cuenta que Kinect, por ejemplo, necesita un espacio considerable para ser efectivo, o que en un dispositivo táctil pues la sensibilidad del touch no es la misma que un ratón.

Finalmente, un dato a tener en cuenta:

Durante el año 2008 la cantidad de dispositivos conectados a internet superó a la cantidad de personas en la tierra. Para el año 2020 se espera que haya más de 50 billones de dispositivos conectados a internet. (Fuente)

Esto qué significa?, que además de tener un Mustang 100% conectado a internet, ahora tendremos que interactuar con muchos tipos de dispositivos nuevos y claro, nuestro amigo el mouse no estará allí para ayudarnos y tampoco es cuestión de que emulemos el funcionamiento del mouse en todas partes.

Así que, yo no guardaré mi mouse ya mismo, pero ya comenzaré a ver de que forma puedo trabajar en diferentes espacios sin un mouse … luego veré que dispositivo me brinda la mejor ayuda en ese escenario Risa

Por cierto

1. Como el Lego me ha quedado chico,  espera a ver lo que estoy haciendo con mi RX8, un Kinect, una tableta con Windows 8, etc. 230CV en manos de una porción de código C#. Mi chica está un poco asustada pero el Valentino súper feliz de poder jugar con el coche desde una tableta … Risa

.2 El ratonazo cabreado / enfadado / enojado lo saqué de http://abstract.desktopnexus.com/get/134212?t=08tt07vgrel6eo8knisme46jh34fa00c9fcba2b

Saludos @ Home

El Bruno

image image image

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
Publicado 30/4/2012 23:37 por El Bruno | con no comments

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
Publicado 28/4/2012 20:55 por El Bruno | con no comments
Archivado en: ,,

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

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

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
Publicado 24/4/2012 23:51 por El Bruno | con no comments

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

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
Publicado 22/4/2012 21:07 por El Bruno | con no comments
Más artículos Página siguiente >