
Introduccion
Todo comenzó con el hecho de que accidentalmente encontré una lista de programas homebrew (programas desarrollados por los esfuerzos de los usuarios para dispositivos no destinados a ejecutar software de usuario) para Nintendo DS y vi una línea muy interesante en ella, a saber: "Pstros NDS - Ejecución de implementación MIDP en la máquina Java CLDC compilada para NDS ".
Siendo un gran fanático de Java y Nintendo DS, decidí averiguar qué tipo de bestia es esta y, si es posible, tratar de escribir mi aplicación para esta JVM. Aquellos que estén interesados en pedir un gato.
Pstros nds
Después de descargar el preciado archivo del sitio, comencé a investigarlo. Después de leer el archivo Léame, resultó que Pstros NDS es un puerto KVM (máquina virtual Java desarrollada por Sun Microsystems) para Nintendo DS. Como se desprende de los artículos en Internet (
artículo 1 ,
artículo 2 ), esta máquina Java está diseñada para dispositivos pequeños con una cantidad limitada de RAM y pertenece a un subconjunto de plataformas Java: J2ME.
Arquitectura J2ME
J2ME tiene una arquitectura modular en la que las configuraciones y los perfiles son los elementos centrales.
Una configuración es una especificación que describe las herramientas disponibles para el desarrollo de una familia específica de dispositivos móviles (un conjunto de características de lenguaje Java, características y capacidades de máquina virtual, bibliotecas mínimas compatibles).
El perfil amplía y complementa las funciones de configuración para un dispositivo móvil específico. Permite trabajar con una pantalla gráfica, funciones de comunicación, periféricos específicos (en nuestro caso, esta es una pantalla táctil).
El diagrama de arquitectura J2ME se presenta a continuación:

Lanzar homebrew
No puedes simplemente ejecutar el software no certificado de Nintendo en la consola. Para resolver este problema, se crearon cartuchos flash especiales (de hecho, lo más probable es que se crearon para lanzar copias piratas de juegos, y homebrew era un subproducto, pero la historia no se trata de eso).
Hay muchas opciones de cartuchos flash a precios asequibles en AliExpress. Para mí, pedí el R4i Dual Core. Usarlo es extremadamente simple: simplemente descomprima un archivo especial en la raíz microSD, cargue un archivo allí con una máquina Java en formato jvm, inserte un cartucho flash en la consola y podrá usarlo.

El primer lanzamiento de KVM
Hay varios ejemplos de programas java en el archivo Pstros NDS. Para ejecutar estos programas, debe colocarlos en cualquier lugar del cartucho flash microSD. Después de iniciar kvm.nds, podrá seleccionar archivos en el sistema de archivos:

Habiendo seleccionado el archivo Hello.class veremos lo siguiente:

Algunas aplicaciones de muestra más:


Emulador
Conectar una Nintendo DS directamente a una computadora es, hasta donde yo sé, imposible. Pegue constantemente la tarjeta microSD de la computadora al dispositivo y viceversa para ver el resultado, demasiado tiempo. Por lo tanto, para los lanzamientos de prueba de la aplicación, utilizaremos el popular emulador
DeSmuME .
Hay algunas características en el lanzamiento de aplicaciones homebrew para DeSmuME. Hasta donde entiendo la pregunta, esto se deriva del problema de trabajar con el sistema de archivos en un cartucho flash.
Para la interacción de las aplicaciones homebrew con el sistema de archivos, se escribió la biblioteca libfat. Sin embargo, hay una gran cantidad de cartuchos flash para Nintendo DS, y todos usan comandos específicos de lectura / escritura de archivos. La biblioteca libfat no puede reconocer estos comandos y envía un mensaje de error a la aplicación homebrew. Para evitar esto, se inventó una tecnología llamada DLDI (interfaz de dispositivo vinculado dinámicamente). Actúa como una capa entre la aplicación homebrew y el cartucho flash, convirtiendo comandos específicos de lectura / escritura en comandos que son entendibles para las bibliotecas libfat.
Al intentar iniciar DeSmuME kvm.nds, obtenemos el siguiente error:

Las preguntas frecuentes para el emulador indican que el parche DLDI se aplicará automáticamente, pero para el acceso correcto a los archivos, debe especificar el dispositivo de tarjeta flash MPCF en la ranura GBA, como se muestra en la figura a continuación:

Después de eso, la JVM comienza normalmente.
Configurar el entorno de desarrollo
Al estudiar el archivo con jvm, noté el archivo _rebuild.bat. Sus contenidos se presentan a continuación:
Contenido _rebuild.batSET WTKDIR=c:/wtk22 SET CP=%WTKDIR%/lib/cldcapi10.jar;%WTKDIR%/lib/midpapi20.jar;./classes.zip del .\output\*.* /Q "c:/program files/java/jdk1.5.0_06/bin/javac.exe" -source 1.3 -target 1.1 -bootclasspath %CP% ./src/*.java %WTKDIR%/bin/preverify -classpath %CP% ./src del .\src\*.class /Q copy output\*.* .\
A partir de esto, queda claro cómo construir aplicaciones para jvm y qué tipo de entorno necesitamos. En el sitio web de Oracle, el archivo contiene las versiones de wtk y jdk que necesitamos. Instálelos según las rutas especificadas en el archivo bat (o edite las rutas en el archivo bat) y puede comenzar el desarrollo.
Desarrollo de aplicaciones
Por la naturaleza de mi trabajo, trabajé mucho con la biblioteca para crear la GUI de Swing. Me gusta esta biblioteca, así que, por ejemplo, decidí escribir su propia implementación. Decidí desarrollar sobre la base de la "caja negra", es decir Sabiendo cómo debería verse afuera, no mire cómo está organizado adentro. En primer lugar, porque la biblioteca que planeé tendrá una funcionalidad significativamente menor (ya que la desarrollo con fines de entretenimiento) y, probablemente, muchas de las soluciones utilizadas en Swing simplemente no serán necesarias para mí. En segundo lugar, crear su propia implementación es mucho más interesante.
Como puede ver en el script de compilación, deberá desarrollarlo en Java 1.1.
En cuanto a los requisitos, en primer lugar, quería que el usuario de la biblioteca admitiera el código Swing típico para invocar el formulario de diálogo:
MyDialogForm myDialogForm = new MyDialogForm(this, true); myDialogForm.setVisible(true); if (myDialogForm.getAnsewer()) {
Es decir en este caso, se muestra el formulario de diálogo y hasta que se cierre, la ejecución no irá más allá de setVisible (verdadero). Al mismo tiempo, para otros componentes que están en el formulario llamado, el procesamiento de sus acciones de usuario debe continuar.
La primera versión del esquema de operación de la biblioteca se presenta en la figura a continuación:

Como puede ver en el diagrama, cada acción del usuario se realiza en un hilo separado. Con esta implementación, se cumple el requisito de trabajar con formularios de diálogo, sin embargo, existe un problema con el hecho de que el usuario en sus controladores puede trabajar simultáneamente con los mismos datos de dos hilos (por ejemplo, presionando rápidamente dos botones). Esto crea inconvenientes adicionales asociados con la necesidad de proteger el acceso a dichos datos para el usuario.
Suponemos que todas las formas son interactivas, es decir cuando se muestra una forma, es imposible trabajar con otras formas. En este caso, esta es una suposición adecuada, ya que las pantallas de Nintendo DS no son grandes, y mostrar varias formas a la vez es simplemente inconveniente.
En este caso, el esquema de operación de la biblioteca toma la siguiente forma:

Es decir Cada formulario crea su propio flujo de procesamiento de acciones de aplicación de usuario. Si se llama a un nuevo formulario como resultado del procesamiento de una acción, entonces el hilo que lo llamó espera a que se cierre el formulario, y en este momento se crea un nuevo hilo para procesar las acciones del usuario.
A continuación se presenta un código de ejemplo para trabajar con la biblioteca:
Ejemplo de trabajo JNDSComponentsForm jNDSComponentsForm = new JNDSComponentsForm(); jNDSComponentsForm.setTitle("Main form"); final JNDSLabel jndsLabel = new JNDSLabel("Simple label", 20, 30); jNDSComponentsForm.addComponent(jndsLabel); JNDSTextField jndsTextField = new JNDSTextField("Hello world", 20, 58, 150); jNDSComponentsForm.addComponent(jndsTextField); JNDSButton jndsButtonDialogForm = new JNDSButton("Show dialog form", 20, 90); JNDSAction jndsActionImplDialogForm = new JNDSAction() { public void action() { final JNDSDialogForm jndsDialogForm = new JNDSDialogForm(); jndsDialogForm.setTitle("Dialog form"); JNDSButton jndsButtonClose = new JNDSButton("Close", 10, 130); jndsButtonClose.setClickAction(new JNDSAction() { public void action() { jndsDialogForm.setVisible(false); } }); jndsDialogForm.addComponent(jndsButtonClose); JNDSLabel jndsLabelDialogForm = new JNDSLabel("This is Dialog Form!", 70, 80); jndsDialogForm.addComponent(jndsLabelDialogForm); jndsDialogForm.setVisible(true); } }; jndsButtonDialogForm.setClickAction(jndsActionImplDialogForm); jNDSComponentsForm.addComponent(jndsButtonDialogForm); jNDSComponentsForm.setVisible(true); JNDSWindowsManager.instance().run();
Al igual que en Swing, primero se describe el diseño de los formularios y los manejadores de acciones del usuario, y luego el control se transfiere a la biblioteca, que inicializa el contexto y procesa y hace clic en la pantalla táctil.
Otro problema que encontré es el teclado. Desafortunadamente, no encontré una manera de llamar al teclado en pantalla ya preparado del sistema operativo. Por lo tanto, tuve que hacer mi propia implementación, muy simplificada. El resultado de su trabajo se presenta a continuación:

Como componentes en este momento, solo implementé Label, TextField y Button. Por ejemplo, pienso lo suficiente; La apariencia del formulario descrito anteriormente se muestra en la figura:

El código fuente completo se puede encontrar
aquí .
Lanzamiento en un dispositivo real
Copiamos los archivos * .class obtenidos como resultado de la compilación en el cartucho flash, ejecutamos kvm.nds y seleccionamos ExampleJNDSWindowsManager.class en él.
El resultado de la aplicación se presenta en el siguiente video:
Conclusión
En conclusión, me gustaría agradecer a los creadores de Nintendo DS, a los desarrolladores del puerto JVM para Nintendo DS, a los creadores de cartuchos flash por la oportunidad de desarrollar su hardware favorito, así como a mi esposa por la ayuda para grabar videos y editar este artículo.
¡Gracias a todos por su atención!