
مقدمة
بدأ الأمر كله بحقيقة أنني وجدت بالصدفة قائمة ببرامج البيرة المنزلية (البرامج التي طورتها جهود المستخدمين للأجهزة غير المخصصة لتشغيل برنامج المستخدم) لـ Nintendo DS ورأيت سطرًا مثيرًا للاهتمام للغاية فيه ، وهو: "تشغيل تطبيق Pstros NDS - MIDP على الجهاز جافا CLDC المترجمة ل NDS. "
نظرًا لكوني من كبار المعجبين بجافا و Nintendo DS ، فقد قررت معرفة نوع الوحش هذا ، وإذا أمكن ، حاول كتابة طلبي لهذا JVM. أولئك الذين يرغبون في طلب القط.
Pstros NDS
بعد تنزيل الأرشيف المحفوظ من الموقع ، بدأت في البحث عنه. بعد قراءة الملف التمهيدي ، اتضح أن Pstros NDS هو منفذ KVM (جهاز Java الافتراضي الذي طورته شركة صن مايكروسيستمز) لشركة Nintendo DS. على النحو التالي من المقالات على الإنترنت (
المادة 1 ،
المادة 2 ) ، تم تصميم آلة جافا هذه للأجهزة الصغيرة ذات كمية محدودة من ذاكرة الوصول العشوائي ، وتنتمي إلى مجموعة فرعية من منصات Java - J2ME.
J2ME العمارة
يحتوي J2ME على بنية نمطية تكون فيها التكوينات والتوصيفات هي العناصر الأساسية.
التهيئة هي أحد المواصفات التي تصف الأدوات المتاحة للتطوير لعائلة معينة من الأجهزة المحمولة (مجموعة من ميزات لغة Java وميزات وقدرات الجهاز الظاهري والحد الأدنى من المكتبات المدعومة).
يعمل ملف التعريف على توسيع واستكمال وظائف التكوين لجهاز محمول معين. يجعل من الممكن العمل مع شاشة عرض جرافيك ، وظائف اتصال ، أجهزة طرفية محددة (في حالتنا ، هذه شاشة لمس).
فيما يلي مخطط العمارة J2ME:

إطلاق البيرة
لا يمكنك فقط تشغيل برنامج Nintendo غير معتمد على وحدة التحكم. لحل هذه المشكلة ، تم إنشاء خراطيش فلاش خاصة (في الواقع ، على الأرجح تم إنشاؤها لإطلاق نسخ مقرصنة من الألعاب ، وكان البيرة منتجًا ثانويًا ، ولكن القصة لا تتعلق بذلك).
هناك العديد من خيارات خرطوشة الفلاش بأسعار معقولة على AliExpress. بنفسي ، أمرت R4i ثنائي النواة. استخدامه بسيط للغاية: فقط قم بفك ضغط الأرشيف الخاص في جذر microSD ، وحمل ملفًا هناك باستخدام جهاز Java بتنسيق jvm ، وأدخل خرطوشة فلاش في وحدة التحكم ويمكنك استخدامه.

أول إطلاق KVM
هناك عدة أمثلة لبرامج java في أرشيف Pstros NDS. لتشغيل هذه البرامج ، تحتاج إلى وضعها في أي مكان على خرطوشة فلاش microSD. بعد بدء تشغيل kvm.nds ، ستتمكن من تحديد الملفات على نظام الملفات:

بعد تحديد الملف Hello.class ، سنرى ما يلي:

عدد قليل من التطبيقات عينة:


منافس
إن توصيل جهاز Nintendo DS مباشرة بجهاز الكمبيوتر أمر مستحيل ، حسب علمي. التمسك باستمرار microSD من الكمبيوتر إلى الجهاز والعودة لرؤية النتيجة ، وقتا طويلا. لذلك ، لاختبار إطلاق التطبيق ، سوف نستخدم محاكي
DeSmuME الشهير.
هناك بعض الميزات في إطلاق تطبيقات البيرة المحلية لـ DeSmuME. بقدر ما أفهم السؤال ، هذا ينبع من مشكلة العمل مع نظام الملفات على خرطوشة فلاش.
لتفاعل تطبيقات البيرة المحلية مع نظام الملفات ، تمت كتابة مكتبة libfat. ومع ذلك ، هناك عدد كبير من خراطيش الفلاش لنينتندو دي إس ، وجميعهم يستخدمون أوامر القراءة / الكتابة الخاصة بملف معين. يتعذر على مكتبة libfat التعرف على هذه الأوامر وإرسال رسالة خطأ إلى تطبيق homebrew. لتجنب ذلك ، تم اختراع تقنية تسمى DLDI (واجهة الجهاز المرتبطة ديناميكيًا). تعمل كطبقة بين تطبيق البيرة المحلية وخرطوشة الفلاش ، وتحول أوامر القراءة / الكتابة المحددة إلى أوامر يمكن فهمها في مكتبات libfat.
عند محاولة بدء تشغيل DeSmuME kvm.nds ، نحصل على الخطأ التالي:

تشير الأسئلة المتداولة الخاصة بالمحاكي إلى أنه سيتم تطبيق تصحيح DLDI تلقائيًا ، ولكن للوصول الصحيح إلى الملفات ، يجب عليك تحديد جهاز بطاقة فلاش MPCF في فتحة GBA ، كما هو موضح في الشكل أدناه:

بعد ذلك ، يبدأ JVM بشكل طبيعي.
إعداد بيئة التطوير
عند دراسة الأرشيف باستخدام jvm ، لاحظت ملف _rebuild.bat. محتوياته معروضة أدناه:
المحتوى _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\*.* .\
من هذا ، يصبح من الواضح كيفية إنشاء تطبيقات لـ jvm ونوع البيئة التي نحتاجها. على موقع أوراكل ، يحتوي الأرشيف على إصدارات wtk و jdk التي نحتاجها. قم بتثبيتها وفقًا للمسارات المحددة في ملف الخفافيش (أو قم بتحرير المسارات في ملف الخفافيش) ويمكنك البدء في التطوير.
تطوير التطبيق
حسب طبيعة عملي ، عملت كثيرًا مع المكتبة لإنشاء واجهة المستخدم الرسومية Swing. أحب هذه المكتبة ، فعلى سبيل المثال ، قررت أن أكتب تنفيذها. قررت تطوير على أساس "الصندوق الأسود" ، أي معرفة كيف ينبغي أن ننظر إلى الخارج ، لا تنظر في كيفية ترتيبها في الداخل. أولاً ، نظرًا لأن المكتبة التي خططت لها ستكون لها وظائف أقل بكثير (حيث أقوم بتطويرها لأغراض الترفيه) ، وربما لن تكون هناك حاجة إلى العديد من الحلول المستخدمة في Swing. وثانيا ، الخروج بالتنفيذ الخاص بك هو أكثر إثارة للاهتمام.
كما ترون من البرنامج النصي للبناء ، سيكون عليك تطويره تحت java 1.1.
بالنسبة للمتطلبات ، أولاً وقبل كل شيء ، أردت أن يدعم مستخدم المكتبة رمز Swing النموذجي لاستدعاء نموذج الحوار:
MyDialogForm myDialogForm = new MyDialogForm(this, true); myDialogForm.setVisible(true); if (myDialogForm.getAnsewer()) {
أي في هذه الحالة ، يتم عرض نموذج الحوار وحتى يتم إغلاقه ، لن يتجاوز التنفيذ setVisible (صواب). في الوقت نفسه ، بالنسبة للمكونات الأخرى الموجودة في النموذج المُسمى ، يجب أن تستمر معالجة إجراءات المستخدم الخاصة بهم.
يتم عرض الإصدار الأول من مخطط تشغيل المكتبة في الشكل أدناه:

كما ترون من الرسم التخطيطي ، يتم تنفيذ كل إجراء مستخدم في سلسلة رسائل منفصلة. من خلال هذا التطبيق ، تم استيفاء متطلبات العمل مع نماذج الحوار ، ومع ذلك ، هناك مشكلة في حقيقة أن المستخدم في معالجاته يمكن أن يعمل في وقت واحد مع نفس البيانات من اثنين من سلاسل المواضيع (على سبيل المثال ، من خلال النقر السريع على زرين). وهذا يخلق إزعاجًا إضافيًا مرتبطًا بالحاجة إلى حماية الوصول إلى هذه البيانات للمستخدم.
نحن نفترض أن جميع الأشكال تفاعلية ، أي عند إظهار نموذج واحد ، من المستحيل العمل مع أشكال أخرى. في هذه الحالة ، هذا افتراض كافٍ ، لأن شاشات Nintendo DS ليست كبيرة ، وعرض عدة أشكال في وقت واحد غير مريح بكل بساطة.
في هذه الحالة ، يأخذ مخطط تشغيل المكتبة النموذج التالي:

أي ينشئ كل نموذج التدفق الخاص به لمعالجة إجراءات تطبيق المستخدم. إذا تم استدعاء نموذج جديد كنتيجة لمعالجة إجراء ما ، فإن مؤشر الترابط الذي يطلق عليه ينتظر إغلاق النموذج ، وفي هذا الوقت يتم إنشاء مؤشر ترابط جديد لمعالجة إجراءات المستخدم.
فيما يلي رمز مثال للعمل مع المكتبة:
مثال العمل 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();
كما هو الحال في Swing ، يتم وصف تخطيط النماذج ومعالجات إجراءات المستخدم لأول مرة ، ثم يتم نقل التحكم إلى المكتبة ، التي تبدأ السياق وتعرض النقرات على الشاشة التي تعمل باللمس.
مشكلة أخرى واجهتها هي لوحة المفاتيح. لسوء الحظ ، لم أجد طريقة لاستدعاء لوحة المفاتيح الجاهزة على الشاشة لنظام التشغيل. لذلك ، كان علي أن أقوم بتنفيذ عملي بشكل مبسط للغاية. نتيجة عملها موضحة أدناه:

كمكونات في الوقت الحالي ، قمت بتطبيق Label و TextField و Button فقط. على سبيل المثال ، أعتقد بما فيه الكفاية. يظهر الشكل الموضح أعلاه في الشكل:

يمكن الاطلاع على شفرة المصدر الكاملة
هنا .
إطلاق على جهاز حقيقي
انسخ ملفات * .class التي تم الحصول عليها نتيجة للتجميع إلى خرطوشة فلاش ، وقم بتشغيل kvm.nds وحدد ExampleJNDSWindowsManager.class فيه.
يتم تقديم نتيجة التطبيق في الفيديو التالي:
استنتاج
في الختام ، أود أن أشكر منشئي Nintendo DS ، ومطوري منفذ JVM لـ Nintendo DS ، ومنشئي خراطيش الفلاش على الفرصة لتطوير أجهزتهم المفضلة ، وكذلك زوجتي للمساعدة في تصوير مقاطع الفيديو وتحرير هذه المقالة.
شكرا لكم جميعا على اهتمامكم!