پروژه آردوینو
Kevin Ye
دانشگاه تنسی ناکسویل، Hye2@vols.utk.edu
Gregory Rouleau
دانشگاه تنسی ناکسویل، Grouleau@vols.utk.edu
Alan Person
دانشگاه تنسی، ناکسویل، aperson1@vols.utk.edu
Jabril Muhammad
دانشگاه تنسی، ناکسویل، jmuhamm1@vols.utk.edu
پروژه آردوینو: تاریخ اتمام 16/29/11
تیم 6
Alan Person- سرپرست گروه
Jabril Muhammad
Gregory Rouleau
Kevin Ye
مشتری: Michael Thomason
جدول محتوا
چکیده ی اجرایی 3
مقدمه 4
نیازمندی ها 5
گزارش تغییرات 6
فرآیند طراحی 6
مولفه های طراحی 6
پرسشهایی که نیازمند پاسخ هستند 6
راه حل های جایگزین 7
راه حلِ انتخاب شده 8
تاییدیه نسبت به فازهای پیشین 10
ارزیابیِ نیازمندی های برآورده شده 10
نتایجِ پروژه 11
نکاتِ آموخته شده 11
مشکلاتِ تیم 11
تغییراتِ آتی 13
مشارکت های تیم 13
موافقتنامه ی تیم 14
موافقت نامه ی مشتری 15
چکیده ی اجرایی
محیط یکپارچه ی توسعه ی نرم افزار (IDE) آردوینو، یک اپلیکیشنِ متن باز و چند پلتفرمی است، که برای کدنویسیِ میکروکنترلرها مورد استفاده قرار میگیرد. اساسا این اپلیکیشن با دارا بودنِ برخی مشخصه های حیاتی، که تسهیل کننده ی عملکردهایی نظیرِ بررسیِ سینتکس (نحو)، کامپایل-و-بارگزاری میباشند، در پی آن است تا تجربه ی این نوع از کدنویسی را لذت بخش تر نماید. با این حال، IDEفاقد برخی مشخصه هایی است، که از دید کاربران مهم تلقی میشوند، همین امر منجر به آن میشود که کاربردهایی خاص، نظیرِ برنامه نویسیِ اسمبلی، کاملا مبهم باشند.
هدفِ این پروژه آن است که با افزودنِ مجموعه ای خاص از مشخصه هایِ ناموجود، کاراییِ آردوینو IDE را گسترش دهد، افزودنِ این مشخصه ها برای برنامه نویسانِ ARM اسمبلی، سودمند واقع خواهد شد. افزون بر این، دانشجویانِ رشته ی علومِ کامپیوتر (COSC)130و سازماندهیِ کامپیوتر در دانشگاهِ تنسی، در صورتِ استفاده ی درست از مشخصه های جدید، بیشترین بهره را کسب خواهند نمود. برنامه نویسیِ ARM، چندان لذت بخش نبوده، و یادگیریِ آن نیز آسان نمی باشد. و از آنجاییکه دانشجویانِ COSC 130ملزم به یادگیریِ این مهارت می باشند، پروژه ی آردوینو میبایست کابردهای اسمبلی در درونِ آردوینو IDE را به تجربه ای بسیار سادهتر و سازگارتر تبدیل نماید.
اصلی ترین نیازمندیهایِ پروژه ی آردوینو شامل سازگاریِ چند پلتفرمی، مشخصه های متناسب با اسمبلی و تغییراتِ رابطِ کاربر میباشد، که این موارد، تواناییِ کامپایل، ایجاد، لینک و فیلتر نمودنِ فایلهای اسمبلی را نیز دربرمیگیرد. کاربران میتوانند یک فایلِ sketch (پروژه ی آردوینو که در یک فایلِ .inoذخیره میشود) را استخراج نموده و فایلِ .s متناظر با آن را به جهتِ ویرایش، اجرا و یا نمایشِ کلی، ذخیره کرده و یا اسمبل نمایند. با اینحال چنانچه کاربر تمایل داشته باشد تا برنامه ای را در ARM اسمبلیِ محض ایجاد کند، میتواند فایل خود را در محیط دلخواه ایجاد کرده و برنامه ی حاصل شده را در زمانِ کامپایل، لینک نماید. فیلتر نمودنِ فایلِ اسمبلیِ استخراج شده، برای کاربرانِ مربوطه و کاربرانِ دارای کدِ کابریِ سطحِ بالا نیز قابل دسترس خواهد بود، این قابلیت برای آن دسته از دانشجویانی سودمند است که کدهای اسمبلیِِ تابعیِ را آموزش می بینند.
IDE توسعه یافته در چندین پلتفرمِ مختلف مورد بررسی قرار گرفته است تا از صحتِ کاراییِ آن بر روی سیستمعامل های متفاوت اطمینان حاصل گردد. پلتفرمهای بررسی شده عبارتند از: Windows، Mac OS X، Ubuntu، Fedora، و Red Hat. نتایج حاصل شده بیانگر آن است که مشخصه های جدید در تناسب با نیازمندی های تعیین شده، به درستی عمل میکنند، گرچه با توجه به ماهیتِ پیچیده ی آردوینو IDE، در رابطه با مدیریتِ پروژههای کامپایل، اِعمالِ برخی اصلاحات در پیادهسازیِ اصلی، میتواند نتایج بهتری را نیز در پی داشته باشد.
در طولِ انجامِ پروژه، تیمِ طراحی با برخی مشکلات مواجه بود. اصلیترینِ این مشکلات به موضوعِ پیادهسازیِ پایه هایِ آردوینو IDE مربوط میشد، با این حال برخی مشکلات نیز نشات گرفته از نیازمندیهایی بود که عملا در چارچوبِ این پروژه جای نمیگرفت. علی رغمِ مسائلِ اجتناب ناپذیرِ مربوط به پروژه های گروهی، تیمِ ما نهایتا توانست، برای تمامیِ نیازمندیهای اساسی راه حلی پیدا کرده و پروژه را تکمیل نماید.
گرچه این پروژه به اتمام رسیده است، اما در رابطه با مشخصه های IDE، فضا برای اصلاح و بهسازی همچنان وجود دارد. از اصلاحاتِ بالقوه میتوان به افزودنِ هایلایتِ assembly syntax، تابعِ debug، و یک تابعِ فیلترِ دقیق تر (برای هر چه کمتر نمودنِ اسمبلیِ خارجی)، اشاره نمود.
مقدمه
پلتفرمِ الکترونیکی و متن بازِ آردوینو، در میانِ اساتید، دانشجویان و علاقه مندان به DIY و نظایر آن، پرطرفدار است. از نظر سخت افزاری، آردوینو مجموعه ای از میکروکنترلرهایی است که در حال حاضر شامل ARM، AVR و معماری های X86 میباشد. این بردها ارزان بوده و نرم افزار توسعه یافته ی آنها نیز از نوعِ متن باز است. زبانِ برنامه نویسیِ آردوینو از C++ برگرفته شده، که در نتیجه برای بسیاری از کابران شناخته شده است.
مشخصه های ارائه شده در آردوینو، بخش هایی جدایی ناپذیر از برنامه ی آموزشیِ دانشجویانِ رشته های COSC 130 و سازماندهیِ کامپیوتر در دانشگاهِ تنسی می باشند. دانشجویانِ رشته ی سازماندهیِ کامپیوتر بسیاری از کارهای خود را با c++ و اسمبلی به انجام رسانده و برای اجرای برنامه های خود بر روی میکروکنترلر Arduino Due ، از محیطِ یکپارچه ی توسعه ی نرم افزار آردوینو بهره میگیرند. همچنین برای آموزش اپلیکیشنهای کاربردیِ مربوط به ARM assembly، و چگونگیِ برنامه نویسیِِ عاملیت در سطحِ سخت افزار (نظیر خوانش دیجیتال و آنالوگ)، از بردها استفاده میشود.
نظر به اینکه آردوینو IDE، کار با فایلهای اسمبلی را پشتیبانی نمیکند، دانشجویان برای انجامِ کارهای مرتبط با اسمبلی، کد اسمبلیِ خود را در ASM wrapper که توسط GCC ارائه میشود، wrap مینمایند. این روند مولفهی جدیدی به عملیاتِ debug اضافه کرده، و از سویی دیگر، کدهایی ناموزون حاصل میشود. افزون بر این، به دلیل عدم استفاده از اسمبلیِ محض، دانشجویان تجربه ی کاملی از کدنویسی اسمبلی را کسب نمیکنند. C++، در میان دانشجویان و محیطِ اسمبلی ای که با آن کار میکنند، سطحی از انتزاع را پدید می آورد، که منجر به سردرگمیِ هر چه بیشترِ دانشجویان میشود.
پروژه ی آردوینو در پی آن است تا یک پشتیبانیِ بومی از فایلهای اسمبلی را فراهم آورد. از اهدافِ پروژه آن است که به دانشجویان این اجازه را بدهد تا اسمبلی را به درون یک sketch، import نموده و یا اسمبلی را از آن استخراج نمایند. Sketch درواقع کدی است که بر روی بردِ آردوینو آپلود شده و اجرا میگردد. به جهتِ فراهم سازیِ قابلیتِ استفاده، این مشخصه ها در واسط گرافیکیِ کاربرِ (GUI) مربوط به آردوینو IDE قرار خواهند گرفت.
قابلیت های جدیدِ IDE، طریقه ی تعاملِ دانشجویان با اسمبلی در COSC 130 را ارتقا خواهد داد. این دانشجویان خواهند توانست تا با اسمبلیِ بومی، به حکمِ بخشی یکپارچه شده از کدنویسی هایشان که دربرگیرنده ی Arduino Due board می باشد، کارکنند. پروژه ی آردوینو در تلاش است تا تجربهای را برای دانشجویانِ رشته ی سازماندهیِ کامپیوتر فراهم آورد، که بیشتر شامل اسمبلی بوده و از پیچیدگی کمتری برخوردار باشد، از طرفی، لایه های دیگری از انتزاع نیز مورد نیاز نباشد.
نیازمندی ها
یکی از گام های نخستین در ایجاد و طرح ریزیِ پروژه ی آردوینو، استقرارِ نیازمندی هایی بود که توسط مشتری و برای پروژه تعیین گردید. بعد از ساعت ها طرح ریزی و مباحثه، تیم نهایتا نیازمندی های لیست شده در زیر را جهتِ برآوردهسازیِ ویژگیهای درخواست شده توسط مشتری، ارائه داد.
1. پلتفرم
1.1 مشخصه های افزوده شده بایستی در Fedora 23 و نسخه های بعدیِ آن کارایی داشته باشند.
1.2 مشخصه های افزوده شده بایستی در Red Hat Enterprise Linux 7 و نسخه های بعدیِ آن کارایی داشته باشند.
1.3 مشخصه های افزوده شده بایستی در Ubuntu 15 و نسخه های بعدیِ آن کارایی داشته باشند.
1.4 مشخصه های افزوده شده بایستی در Mac OS X version 10.10 و نسخه های بعدیِ آن کارایی داشته باشند.
1.5 مشخصه های افزوده شده بایستی در Windows 7 و نسخه های بعدیِ آن کارایی داشته باشند.
2. قابلیتِ عملکرد
2.1 IDEبایستی قابلیتِ پشتیبانی از فایلِ ASM را دارا باشد.
2.1.1 IDE بایستی قادر به export نمودنِ پروژه به زبان اسمبلی باشد.
2.1.1.1 IDE در زمانِ کامپایل، بایستی قادر به export نمودنِ خودکار به زبانِ اسمبلی باشد.
2.1.2 IDE بایستی قادر به فیلتر نمودنِ اسمبلیِ export شده و تبدیل آن به دستورالعملها باشد.
2.1.3 IDE بایستی قادر به لینک نمودنِ فایلهای اسمبلی باشد.
2.1.4 IDE بایستی شاملِ یک الگویِ کدِ اسمبلی باشد.
3. نماهای ظاهری
3.1 رابط بایستی دارای گزینه ای جهتِ export نمودنِ فایلِ .s باشد.
3.1.1 رابط بایستی دارای گزینه ای جهتِ exportنمودنِ خودکارِ فایلِ .sباشد.
3.1.2 کاربر بایستی قادر به آن باشد که پوشه ای را برای ذخیرهی فایله ای export شده انتخاب نماید.
3.2 رابط بایستی دارای گزینه ای برای import نمودنِ فایلِ .s باشد.
4. اهدافِ ثانویه (در صورت وجودِ زمانِ کافی)
4.1 IDEبایستی مشخصه ای جهتِ پشتیبانی از debugging را دارا باشد.
4.1.1 IDE بایستی با یک debug adapter سخت افزاری، سازگار باشد.
4.1.2 IDE بایستی دارای یک تابعِ debug باشد.
4.1.2.1 تابعِ debug بایستی قابلِ درج در کدِ sketch باشد.
4.1.2.2 تابعِ debug بایستی قادر به استخراجِ محتوای register باشد.
4.1.2.3 تابعِ debug بایستی امکانِ تغییرِ محتوای register را فراهم آورد.
گزارش تغییرات
اهدافِ ثانویه در بخش نیازمندیِ 4 ، از لیستِ نیازمندی های پروژه ی اصلی، حذف گردید. هزینه ی مالی، جهتِ پیگیریِ نیازمندی های مربوط به debugging از توانِ مالیِ پروژه فراتر بوده و در نتیجه طی مذاکراتِ متعاقب با مشتری، توافق گردید که پیگیریِ موضوعِ debugging خارج از محدوده ی این پروژه میباشد.
فرآیندِ طراحی
مولفه های طراحی
اصلی ترین نیازمندیها برای پروژه به 4 مولفه تقسیم گردید که عبارتند از: مشخصه ی export، مشخصه ی import، تغییرِ GUI، و تستِ پروژه. وسعت عملکردِ این مولفه ها به قدری است که کارِ موازی بر روی پروژه را امکانپذیر می سازد. مانند بسیاری از پروژه ها، اکثریت زمانِ صرف شده، بر روی قابلیت عملکرد و debugging متمرکز خواهد بود. از آغاز کار بر روی پروژه، تیم این ایده را مدنظر قرار داد که، نیازمندیهای خُرد را به گونهای با یکدیگر جفت نماییم که، دوباره کاری ها به حداقل ممکن کاهش یابد. بدین ترتیب، مولفه های طراحی را به گونه ای تفکیک نمودیم که، مشخصه ی export با فیلتر نمودنِ کدِ اسمبلی، مشخصه ی import با الگوی اسمبلی، و تغییرِ GUIهمزمان با تستِ پروژه انجام گیرد.
پرسشهایی که نیازمند پاسخ هستند
در مراحل اولیه ی توسعه ی نرم افزار، پرسش های بدون پاسخی در رابطه با چگونگیِ پیاده سازیِ مشخصه های Import و export وجود داشت. نیازمندی ها دربرگیرندهی اصلاحِ دستوراتِ کامپایلرِ فعلی بود، که در کامپایلِ sketch مورد استفاده قرار میگرفت؛ از آنجاییکه Arduino IDE از کامپایلری استفاده میکند که توسط شخص ثالث تولید شده است. اطمینانی وجود نداشت که بتوان پیاده سازیِ مشخصه های اصلی را به گونهای به انجام رساند که در نتیجه ی آن، نیازی به اصلاحِ کامپایلرِ IDE وجود نداشته باشد. خوشبختانه برای مشخصه های import و export، نهایتا توانستیم نسخههای اولیه ای را بیابیم که با وجودِ برآورده نمودنِ نیازمندیها، نیازی به اصلاحِ کامپایلر نبود.
در رابطه با اهدافِ ثانویهی پروژه، تیم اطمینان نداشت که آیا همزمان با پیادهسازیِ مشخصه های فراهم کنندهی GDB-style debugging، امکانِ استفاده از بردِ آردوینو وجود خواهد داشت یا خیر. چراکه بردهای آردوینو فاقدِ مولفه های مورد نیاز برای دستکاریِ بلادرنگِ متغیرها یا debugging از نوعِ breakpoint و step میباشند، و حتی مهم تر از آن، عدم وجودِ حافظهای پایدار، و الزام به کامپایلِ مجدد و بارگزاری، ایجادِ هر گونه تغییراتی را ناممکن میساخت. وجودِ همین مسئله، فراهم سازیِ قابلیتِ debugging را محدود می نمود، چراکه برقراری این مشخصه درواقع به معنای آن بود که، اصلاحِ ثَباتهای خاص در حینِ اجرا و بر روی میکروکنترلر آردوینو به سادگی امکانپذیر نبوده و بایستی از سخت افزارهای دیگری نیز استفاده شود. در هوشمندانه ترین راه حل، تحقیقات نشان داد که debug نمودنِ بردِ آردوینو، به هر طریق نیازمندِ یک آداپتور ARM JTAG خواهد بود، و حتی برای فعالسازیِ خودِ debugging نیز، ترکیبی از سخت افزار و نرم افزارِ اضافی مورد نیاز می باشد. در صورتِ استفاده از سخت افزارِ دیگر، هزین هی سخت افزارِ مورد نیاز به نسبتِ بودجه ی فراهم شده برای پروژه بسیار بالا می بود، و از سویی دیگر، در مقایسه با مزایای دریافتی از پروژه، دانشجویان می بایست هزینه ی بسیار بالاتری را متقبل میشدند. بنابراین طبق توافق انجام گرفته با مشتری (همچنین با دپارتمان EECS در UT)، تصمیم نهایی این بود که فراهم سازیِ قابلیتِ debugging امکانپذیر نبوده و از نیازمندیهای پروژه قابل حذف میباشد.
راه حل های جایگزین
جهت برآورده کردنِ نیازمندیهای پروژه چندین راه حل مدنظر قرار گرفت. راه ِحل جایگزین در رابطه با مشخصه ی export، استفاده از رونوشت های کاملِdisassembly بود. راه حلِ جایگزین برای مشخصه ی filtering، این بود که برای استخراِجِ محتوایی خاص از فایل اسمبلی، از یک shell script استفاده شود. و جهتِ دستیابی به مشخصه ی import، راهِ حلِ جایگزین دربرگیرندهی این پروسه بود که کدها در درونِ فایلِ sketchمعادلسازی شده و به وسیله ی ASM wrapper، wrapشوند.
اصلی ترین هدف، کامپایلِ Arduino sketch code به اسمبلی میباشد، که به روشهای مختلفی میتوان آن را به انجام رساند. اولین راهِ حلِ ممکن، این بود که sketch را با آردوینو کامپایلرِ موجود، کامپایل نموده و با استفاده از ARM disassembler، رونوشتِ اسمبلیِ مورد نظر را ایجاد کنیم. اما استفاده از disassembler معایبی را نیز به همراه دارد، برای نمونه، خوانشِ کدِ خروجیِ به دست آمده دشوار خواهد بود، چراکه در طولِ پروسه ی disassemblyبخشی از اطلاعات، نظیرِ متغیرها و کامنتها گم میشود. راهِ حلِ دوم افزودنِ کامپایلر دیگری است که قابلیت های مورد نظر را دارا میباشد. شاید این راه ِحل، گزینه ی مناسب تری باشد، اما یافتنِ کامپایلری که بتواند مشخصه های خواسته شده را بر روی تمامی پلتفرم های مورد نظر ارائه دهد، دشوار بوده، و از سویی دیگر، استفاده از کامپایلرِ اضافه مشکلاتِ مربوط به لایسنس را به همراه دارد که مقوله ی توزیعِ مجدد را نیز محدود میسازد.
دومین هدف اصلی، حصولِ اطمینان از این امر است که اسمبلیِ تولید شده، به گونه ای فیلتر شود که تنها حاویِ اسمبلی های متناظر با کدِ کاربر باشد. Arduino Due از میکروکنترلرِ ARMاستفاده میکند که فاقد سیستم عامل است، این بدان معناست که هر sketch حجمی بسیار بالا خواهد داشت، چراکه کلِ سیستم عاملِ مربوط به اسمبلی را نیز بایستی با خود به همراه داشته باشد. در نگاه اول، چنین راهِ حلی آسان به نظر میرسد، اما مشکل اصلی از تفاوتهای موجود در فایلهای اسمبلیِ export شده، بروز خواهد کرد. برای مثال، نامِ توابعِ sketch در زمانِ export شدن به اسمبلی، نگهداری نشده و از دست خواهد رفت. افزون بر این، در هر بار export، ترتیبِ ِ ظهورِ توابع نیز یکسان نخواهد بود. این بدان معناست که چنانچه sketch اِ کاربر، حاویِ توابعی چندگانه باشد، این توابع در فایلِ اسمبلیِ متناظر، تنها از طریقِ بررسیِ کد اسمبلی قابل تشخیص خواهند بود. در رابطه با sketch های ساده تر، یک shell script اِ ساده، که محتوایِ فایلِ اسمبلی را (که دربرگیرندهی نامِ توابعِ مورد نیاز، setup و loop میباشد) استخراج میکند، میتواند کارآمد باشد، اما این راهکار در مورد sketch هایی که دارای توابعی به غیر از توابعِ مورد نیاز هستند، کاراییِ لازم را نخواهد داشت.
سومین هدفِ اصلیِ پروژه آن است که قابلیتِ لینک نمودنِ بومی، در فایلهای اسمبلی را برای دانشجویان میسر سازیم. در حال حاضر جهتِ کدنویسی در اسمبلی، دانشجویان بایستی هر دستور را با استفاده از ASM wrapper اِ ارائه شده توسط GCC، wrap نمایند. استفاده از wrapper برای دستوراتِ اسمبلی، قابلیتِ عملکرد را تنها به زیرمجموع های از دستوراتِ اسمبلی محدود کرده و مانع از برنامه نویسی میشود. معادلسازیِ فایلهای اسمبلی در ASM wrapperراهحلی جزئی برای این مشکل است؛ با این وجود، چنین راه حلی تنها طولِ حیاتِ فایل را افزایش داده و تاثیری بر روی گسترش قابلیت عملکرد نخواهد داشت. با وجودِ قابلیتِ لینک بومیِ فایل اسمبلی، نیاز به wrap نمودنِ دستورات حذف گردیده، و متعاقبا قابلیتِ خوانش و بهره وری بالاتر خواهد رفت. چنین وضعیتی بازخورد بهتری را نیز پدید میآورد چراکه به جای انجامِ کار از طریقِ یک لایه ی انتزاعی، دانشجویان میتوانند ارتباط مستقیمی بین ورودی و خروجی ایجاد نمایند.
پر واضح است که راه حل های جایگزینِ ذکر شده در بالا، تنها راه حل هایی جزئی برای مسائل موجود میباشند. شاید این راه حل ها، کارآمد باشند، اما استفاده از آنها مسلما ساده انگارانه بوده و پیاده سازیِ تمامی مشخصههای مورد نظر نیز نمیتواند به سبکی انعطافپذیر صورت گیرد. با اینحال، چنانچه در حینِ مبادرت به اجرای دیگر راهکارها، با مشکلات عدیدهای روبرو شویم، این راهحلها نقشه ی پشتیبانِ مناسبی برای پروژه خواهند بود.
راهِ حلِ انتخاب شده
راه حلِ انتخاب شده به میزان زیادی بر روی قابلیتهای زنجیره ی ابزار خودِ آردوینو تمرکز دارد. استفاده از زنجیره ی ابزار آردوینو بسیار کارآمدتر از ابزارهای کاملا جدید میباشد، و از سویی دیگر، زمانیکه پروژه در میانِ دانشجویانِ رشتهی سازماندهیِ کامپیوتر در دانشگاه تنسی توزیع میشود، مشکلاتِ ناشی از لایسنس نیز به حداقل خواهد رسید. زنجیرهی ابزارِ پایه، راه حل های ساده و بومی را برای مشکلاتِ پیش رو در پروژه ارائه میدهد، یافتنِ راه حل هایی متناسب با نیازمندی ها، تنها مستلزم کشفِ قابلیتِ عملکردِ زنجیرهی ابزار و اجرای مهندسیِ معکوس بر روی آنها خواهد بود. و قابلیتهای export به اسمبلی، فیلتر نمودنِ خروجی، import و link نمودنِ فایلهای اسمبلی، با ابزارهای موجود در آردوینو کاملا قابل انجام است.
مشخصه ی export، sketch اِ کاربر را (.ino.cpp) به اسمبلی (.s) کامپایل میکند. اصلی ترین مولفه های مربوط به قابلیتِ export اِ اسمبلی شامل این موارد میباشد: نمونه سازیِ دستورِ کامپایل، پیاده سازیِ یک فراخوانیِ دستورِ execute در جاوا، هماهنگ سازیِ flagهای کامپایل با متغیرها، و سپس انجامِ بروزرسانی جهتِ استفاده از متغیرها به جای پرچمهای اختصاصی. برای توسعهی طرحاولیهی دستور کامپایل که هدف از آن، کامپایل نمودنِ sketch به اسمبلی میباشد؛ تیم دستوراتِ کامپایلِ Arduino IDE موجود را مورد بررسی قرار داد، اینها دستوراتی بودند که برای کامپایلِ کدِ کاربر به کدهای قابل اجرا بر روی بردهای آردوینو مورد استفاده قرار میگرفتند. گام بعدی برای پیاده سازیِ قابلیتِ export، افزودنِ فرمانِ کامپایلِ مربوط به گام قبلی به درونِ IDE بود. این روند حداقل میزانِ قابلیتِ export اِ پروژه به اسمبلی را برای IDEفراهم کرد. بعد از افزودن قابلیتِ کامپایل به IDE، برخی از flag های کامپایل با متغیرهای استفاده شده در IDE هماهنگسازی شد. در نتیجه میزان انعطافپذیری و قدرتِ قابلیتهای اضافه شده افزایش یافت. برای یافتنِ متغیرهای قابلِ استفاده، میزان بیشتری از مهندسی معکوس بر روی IDE ، مورد نیاز بود، تا مشخص شود که در زمانِ کامپایلِ کد به کدِ قابل اجرا، flag ها دقیقا در کجا قرار دارند. گام نهایی، بروزرسانیِ کدِ جاوا بود، تا در پی آن، به جای flag های اختصاصی، متغیرها مورد استفاده قرار گیرند. پروسه ی دستیابی به حداقلِ مشخصه ی export، منجر به پیاده سازیِ مشخصه ی filterنیز میگردد. چراکه نتیجه ی حاصل از export اِ کدِ sketch اِ کاربر، به نوعی اسمبلیِ محض از همان کدِ کاربر است. تقریبا 90 درصد از اسمبلیِ مغایر با کد کاربر کاهش می یابد، چرا که موارد مغایر در حینِ export کنار گذاشته میشوند. با این حال خروجیِ به دست آمده به طورِ کامل یک اسمبلیِ محض به شمار نمی رود، چراکه هنوز هم حاویِ برخی خروجیِهای نامرتبط نظیر header و fotter اِ اسمبلی میباشد، اما اسمبلیِ به دست آمده به اندازهای پالایش یافته است که میتوان از دانشجویان خواست که آن میزانِ ناچیز از خروجیِ نامرتبط را نادیده بگیرند.
ایده ی موجود در ورایِ مشخصه ی import آن است که فارغ از نوعِ منبع، کابران بتوانند فایل های اسمبلی را جهتِ به اجرا درآوردن، لینک و یا کامپایل نمایند. برای آنکه این قابلیتِ عملکرد بتواند، نیازمندی های طراحی را برآورده سازد، مشخصه ی importبایستی بتواند فایلِ اسمبلی با پسوند .s را دریافت کرده، و تمامیِ گام های استانداردِ مربوط به کامپایل را بر روی آن پیاده کند؛ تا نهایتا کدی قابل اجرا بر روی میکروکنترلر Arduino Due ایجاد شود. چنین پروسه ای شامل مولفه های زیر خواهد بود: کامپایلِ فایل اسمبلی، آن هم به همراه سیستم عاملِ مرتبط با کتابخانه های Arduino، ایجاد یک نقشه ی اسمبلی، ایجاد یک فایل با پسوند .elf، و ایجادِ کتابخانه ی باینریِ قابل اجرا. هر یک از این مولفه ها، دربرگیرنده ی فرمانهای سیستمیِ مجزا اما مرتبط با یکدیگر هستند. برای آنکه مشخصه ی نهاییِ import بتواند نیازمندی های موجود را برآورده سازد، از گامهای ذکر شده در بخشِ قبلی پیروی شد. متناسب با فرمانهای موجود در shell script های اختصاصی و اصلی، هر فرمان به عنوانِ یک فرمانِ عمومیِ جاوا پیاده سازی شد. پیادهسازیِ یک به یک این مولفه ها در IDE، نهایتا موجب شد تا حداقل نیازمندیهای مربوط به مشخصه ی import برآورده گردد.
بعد از آنکه یک فایل اسمبلی به یک باینریِ قابل اجرا کامپایل شد، کاربر بایستی بتواند، کد اجرایی را بر روی یک بردِ Arduino Due آپلود نماید. البته قبل از آپلودِ کد، لازم است که برد پاکسازی شود. IDE خود میتواند عملیات های پاکسازی، نوشتنِ کدِ اجرایی و تایید داده بر روی برد را مدیریت کند، که همین امر منجر به ساده تر شدنِ تجربهی کاربر از این عملیات ها میشود. برای پیاده سازیِ عملیاتِ آپلودِ کد اجرایی، IDE اِ موجود را مورد بررسی قرار دادیم تا پیاده سازیِ فعلی را جهتِ بکارگیری، تعیین نماییم.
بعد از دستیابی به قابلیتِ عملکردِ import، و با استفاده از الگویِ اسمبلی، کاربر میتواند برنامه نویسیِ خود را به زبان اسمبلی به انجام برساند. الگوهای پایه ی اسمبلی را میتوان با export نمودنِ یک sketch اِ خالی یا یک sketch اِ موجود، به صورتِ اسمبلی، ایجاد کرد. از آنجاییکه عملیاتِ فیلتر بدونِ نقص نمی باشد، تعدادی اسمبلیِ مرتبط با سیستم عامل نیز در هر الگو ایجاد میگردد. گرچه فیلتر به قدری این اسمبلی های نامرتبط را کاهش میدهد که کاربران در بخشی خاص از فایل، نهایتا به برنامه هدایت میشوند. فایلِ حاصل شده از ویرایشِ کاربر، با استفاده از سه فرمانِ بعدی، (که در بخش قبلی مورد بحث قرار گرفت)، کامپایل شده و اجرا میگردد، این سه فرمان شاملِ ایجادِ فایلِ .map، ایجاد فایلِ .elf و نهایتا ایجادِ فایلِ .bin اِ قابل اجرا میباشد.
در رابطه با توسعه ی GUI، افزودنِ گزینه های بیشتر به جعبه ابزارِ موجود، بهترین روش برای ارائه ی مشخصه های بیشتر به کاربر میباشد. تصمیم گرفتیم که در مورد مشخصه های قابل دسترسِ جدید در منوها، کارآمدتر عمل نماییم، چرا که این مشخصه ها تنها برای اهدافِ آموزشی و debuggingمورد استفاده قرار خواهد گرفت. در نتیجه هر مشخصه ی مرتبط با ترجیحات، به منوی preferences انتقال داده شد. تغییر در رابطِ کاربر یکی از راحتترین مشخصه ها در توسعهی پروژه به شمار میآمد. در صورتیکه افزونه های جدید طبق انتظار عمل میکردند، مشخصه ی مورد نظر، تکمیل شده و در تناسب با نیازمندی ها، کارآمد تلقی میشد. دکمه ی مربوط به مشخصه های import و export در منوی sketch قرار گرفت. گرچه میانبری به این دکمه ها نیز طراحی شده است، تا در هر بار نیاز به اجرای این مشخصه ها، لازم نباشد که کاربر به منوی sketch مراجعه کند. یک checkbox نیز اضافه شده است، تا برای مثال، در صورتِ ترجیحِ کاربر در هر بار عملِ verify، sketch به طور خودکار به اسمبلی، exportگردد.
تاییدیه نسبت به فازهای پیشین
طیِ پروسه ی طراحی، تیم به طور مرتب پیشرفت فعلی را نسبت به فازهایِ پیشینِ طراحی مورد مقایسه قرار میداد، تا بدین ترتیب اطمینان حاصل شود که در راستای برآورده نمودنِ نیازمندی های پروژه پیش میرویم. با شروع از راه حل های احتمالی، تحلیل میکردیم که در تناسب با نیازمندیهای پروژه، چه دستاوردهایی مورد نیاز است. بدین ترتیب به محضِ یافتنِ راه حل های مربوط به پیاده سازیِ هر نیازمندی، تیم به فازِ پیاده سازیِ آن راه ِحل پیش میرفت. نسخه های اولیه ی هر راه حل، طبقِ رهنمودهای راهِ حلِ انتخاب شده، ایجاد میشد، و زمانیکه تمامِ نیازمندیهای مربوط به مشخصه ی مورد نظر برآورده گردید، پیاده سازیِ آن نسخه ی اولیه بر روی Arduino IDE انجام میگرفت. بعد از آنکه تمامیِ نسخه های اولیه از هر راهِ حل، به صورتِ مشخصه ها، پیاده سازی شدند، نوبت به تستِ این مشخصه ها رسید تا اطمینان حاصل گردد که هر مشخصه طبقِ نسخه ی اولیه ی راهِ حل عمل مینماید. بعد از حصولِ اطمینان از اینکه پیاده سازیهای انجام شده، نتایجی متناسب با نسخه های اولیه ی راهِ حل را ایجاد می نمایند، تیم با اطمینان میتوانست اعلام کند که هر مشخصه ی طراحی شده، نیازمندی های اصلیِ مربوط به خود را برآورده میسازد.
ارزیابیِ نیازمندیهای برآورده شده
برای حصولِ اطمینان از اینکه تمامِ نیازمندیهایِ پروژه برآورده شده است، تیم مشخصه های پیاده سازی شده ی جدید را مورد بررسی و آزمایش قرار داد تا نتایجِ به دست آمده را با نیازمندیهای مربوطه مورد مقایسه قرار دهد. تکمیلِ بودن یا نبودنِ اکثرِ نیازمندیهای این پروژه، به دلیلِ ماهیتِ مشخصه های درخواستی، به سادگی قابل ارزیابی بود. در هر فاز از توسعه ی پروژه، موضوعِ اینکه مشخصه ی پیاده سازی شده، نیازمندیِ مورد نظر را برآورده میکند یا خیر، به سادگی قابل بررسی بود، چراکه مشخصه ی مورد نظر، یا طبق انتظار عمل میکرد و یا با شکست مواجه میشد. الگوی اسمبلی، تنها مشخصه ای بود که ارزیابیِ موفقیت یا عدم موفقیتِ آن به این صورت قابل بررسی نبود، قابلیتِ عملکردِ الگو، به کاربری بستگی دارد که آن را ویرایش میکند. بنابراین، برای ارزیابیِ قابلیتِ عملکردِ این مشخصه، میبایست روش دیگری پیدا میکردیم که این روش نوشتنِ اسمبلی به صورتِ دستی بود. این مشخصه در صورتی میتوانست موفقیت آمیز تلقی شود که، بتوانیم با شروع از الگو، اسمبلی را بنویسیم، آن را به اسمبلیِ قابلِ اجرا لینک کنیم، و سپس با موفقیت بر روی بردِ Arduino Dueاجرا نماییم.
نتایجِ پروژه
ماهیتِ مستقلِ مشخصه ها، و تفکیکِ اینکه هر مشخصه، عملیاتِ مورد انتظار را به انجام میرساند یا خیر، موجب میشد تا بتوان نتایجِ پروژه را به دو حالتِ موفق یا ناموفق مورد بررسی قرار داد. مشخصه ی export موفق بود، چراکه این مشخصه با موفقیت توانست فایلِ اسمبلی را کامپایل و ایجاد کند، به گونهای که فایلِ اسمبلیِ ایجاد شده تنها حاویِ کدِ sketch اِ کاربر بود. این بدان معناست که اکثریتِ کدهای مربوط به سیستم عامل از کدهای اصلی، فیلتر و حذف گردیده و در نتیجه کدهای نامرتبط در فایلِ تولید شده توسط مشخصه ی export، وجود نداشتند. این بررسی نمایانگر این نیز میباشد که filter اِ اسمبلیِ export شده نیز مطابقِ انتظار عمل میکند، چراکه بعد از فیلتر، 90 درصد کاهش در طولِ کد را شاهد هستیم. مشخصه ی import به کاربر این اجازه را میدهد تا صرفنظر از نوعِ منبع، فایلهای اسمبلی را کامپایل کرده و لینک نماید. این مشخصه قادر است یک فایلِ اسمبلی را دریافت کرده و تمامیِ گام های استانداردِ کامپایل را بر روی آن به انجام برساند، و نهایتا فایلی قابلِ اجرا بر روی میکروکنترلرِ آردوینو تولید نماید. افزون بر این، فایل اجراییِ ایجاد شده توسطِ مشخصه ی import، را میتوان از IDE برداشته و بر روی بردِ Arduino Due آپلود کرد، که در اینصورت قابل اجرا خواهد بود. نتایجِ تستِ GUI نشان داد که قابلیتِ اضافه شده به Arduino IDE با استفاده از مولفه های GUI یِ جدید، به درستی عمل میکند. در هر بار شروعِ مجددِ IDE، ترجیحاتِ اعمال شده، قابلِ تغییر، ذخیره و بارگزاریِ مجدد میباشند. دکمه های مربوط به compile to assembly و export to assembly، عملکردهای متناظر را به درستی فراخوانی میکنند. هر یک از مشخصه های جدید را میتوان به طور مجزا و یا هماهنگ با یکدیگر مورد استفاده قرار داد و بدین ترتیب نیازمندی های پروژه به صورت یکجا برآورده میشود.
نکاتِ آموخته شده
مشکلاتِ تیم
در طولِ مدت زمانِ انجامِ پروژه، تیم با مشکلاتِ عدیدهای مواجه شد، مشکلِ اول نیازمندیِ موجود برای مرتبسازیِ صدها فایل، آن هم در کمترین زمانِ ممکن بود. یک ویرایشگر کدِ منبعِ قوی، در فراهم سازیِ امکانِ مرتبسازی و جستجو در میانِ این فایلها، تاثیر بسزایی دارد، استفاده از چنین ویرایشگری (برای مثال: ویرایشگرِ Sublime Text) بر روی VIM و shell commands منجر به صرفه جویی در مدت زمانِ انجامِ کار میشود. مشکلِ بعدی، روشی بود که Arduino IDE از طریقِ آن اقدام به کامپایلِ Sketch ها مینمود. کامپایلری که IDE در عملیاتِ تک گامیِ خود (Arduino Builder[1])، برای کامپایلِ sketch ها مورد استفاده قرار میدهد، از یک منبعِ خارجی است، که در نتیجه، نیازمندی های مربوط به هکِ کامپایلر را الزامی میکند. استفاده از یک کامپایلرِ خارجی، بدین معناست که استفاده از پرچم های کامپایل، برای کاربردهایی که IDE اساسا به آن منظور طراحی نشده است، دشوار خواهد بود. از اینرو، پیادهسازیِ مشخصه های مورد نیاز، از همان ابتدا از نظرِ کارایی و قدرتِ عملکردِ این مشخصه ها محدود میشد. برخی نیازمندیهای پروژه، یکی دیگر از این مشکلات بود، علی الخصوص مسئله ی مربوط به debugging ، که نهایتا مشخص شد که انجامپذیریِ آن غیر ممکن است. گرچه فراهمسازیِ امکانِ debugging برای Arduino IDE و بردِ Due بسیار سودمند واقع میشد، اما هزینه ی لازم برای انجامِ این کار از هر نظر، بسیار فراتر از بودجه ی تعیین شده برای پروژه بود.
در حینِ پیادهسازیِ مشخصهی import مشکلِ دیگری بروز کرد که، دلیلِ آن دکمه ی Erase اِ موجود بر روی بردِ Arduino Dueبود. آپلودِ فایلِ اسمبلیِ کامپایل شده، یکی از مراحلِ اصلی، در پروسه ی import به شمار میآید، اما برای انجامِ آن، کاربر ابتدا باید دکمهی Erase موجود بر روی میکروکنترلر را فشار میداد. گرچه این مشکل نهایتا برطرف شد، اما پروسه ی حلِ این مشکل، مستلزمِ انجامِ مهندسیِ معکوس بر روی سورس کدهای IDE، و حتی تحلیل نمودنِ عملیاتِ call stack بود، تا از طریقِ آن تشخیص دهیم که IDE، عملیاتِ erase را در کجا و چگونه فراخوانی مینماید.
یک مشکلِ کوچک اما تکنیکیِ دیگری که تیم با آن مواجه بود، [2]Git نام داشت. ظاهرا هیچ یک از اعضایِ تیم، از مزایایِ جادوییِ Git باخبر نبود. گاهی اوقات، حذفِ تصادفیِ تعداد بالایی از فایلها، مشکل ساز میشد، گرچه این مشکلات به سرعت برطرف میگردید اما، مدیریتِ توسعهی موازیِ پروژه، آن هم بر روی یک انبارِ کدِ دوردست، مشکلاتی را با خود به همراه داشت، فقدانِ ارتباط و همگام سازی، گاهی منجر به آن میشد که، کار یکی از اعضای تیم بر روی کار فردی دیگر، نوشته شود، راهکارِ موجود برای این مشکل، تقسیمبندیِ بیشترِ کارهای تیمی، علی الخصوص بخشبندیِ قسمتهایی از کد بود که تیم در حالِ کار بر روی آنها بود. در آینده، جهتِ آموزشِ چگونگیِ کار با نرمافزارهای کنترلِ ورژن مانند Git، احتمالا یک یا چند کلاسِ توجیهی را برای دانشجویان برگزار نماییم، و طی آن توضیح دهیم که مشکلاتی نظیر مواردی که تیمِ ما با آن روبرو شد را، چگونه میتوان برطرف کرد.
در زمانِ بررسیِ مشکلاتِ کارِ تیمی، مشخص میشود که، شروعِ پروژه در سریعترین زمانِ ممکن، بهترین راهکار برای پروژه های بزرگ میباشد. با وجود اینکه تیمِ ما، مراحل کار بر روی پروژه را برای یک نیمسالِ تحصیلی زمانبندی نمود، اما در اواخر ترم، زمانِ قابل دسترس برای کار بر روی پروژه به کمترین میزانِ ممکن کاهش یافت. تعداد گزارشاتِ پروژه چه از نظر طولِ گزارش و چه از نظرِ تعداد دفعاتِ آن، افزایش یافت؛ نیاز به ذکر نیست که حجمِ تکالیفِ مربوط به دروسِ دیگر نیز، بخش دیگری از مشکل بود. در برخی موارد حتی نیاز بود که به طور موقت کار بر روی پروژه را تعطیل نماییم، تا بتوانیم به تکالیف مربوط به دروسِ دیگر رسیدگی کنیم. با این وجود، از آنجاییکه که چنین شرایطی از قبل قابل پیشبینی نیستند، میتوان گفت که تیم در رابطه با مدیریتِ محدودیتهای زمانی، نمیتوانست بهتر از این عمل نماید.
یکی از بزرگترین مشکلاتِ تیم، توزیعِ کار در میانِ اعضای آن بود. بسته به وضعیتِ توزیعِ نیازمندیهای پروژه، حجمِ کاریِ برخی از اعضای تیم به مراتب بیشتر از دیگر اعضایِ آن بود. چنین مشکلی برخاسته از پیشفرض های نادرستی است، که در زمانِ پیشبینیِ میزانِ سختیِ پیاده سازیِ نیازمندیهای پروژه، انجام میگیرد. آسانترین راه حل برای این مشکل، افزایشِ ارتباطاتِ میانِ اعضایِ تیم و مدیریتِ بهتر در رابطه با زمانبندیِ انجامِ کار است.
مشکلِ دیگر، از دست دادن برخی از اعضای تیم بود. در طولِ تعطیلاتِ تابستانی، یکی از اعضای تیم به نام Austin McEver تیم را ترک نمود، گرچه این رخداد دور از انتظار نبود، چراکه Austin اطلاعرسانیِ لازم را در زمانِ مناسب آن انجام داده بود. اما در طولِ هفتهی اولِ ترمِ پاییز، یکی دیگر از اعضای تیم به نام Ajmeria Dushyant، تیم را ترک کرد، اما اینبار به دلیل عدم اطلاع رسانی، تیم از قبل انتظارِ چنین رخدادی را نداشت. با اینحال، خوشبختانه حجمِ باقیمانده از کارِ پروژه، برای یک تیم 4 نفره، همچنان قابل انجام بود.
تغییراتِ آتی
بعد از کار بر روی Arduino IDE آن هم به مدتِ یک نیمسالِ تحصیلی، تیم انتظار دارد که در آینده برخی تغییرات را، در رابطه با پیادهسازیِ IDE شاهد باشد. برای مثال، Arduino IDE، آن طور که باید نمیتواند syntax را برای assembly، هایلایت نماید، البته دلیل آن این است که Arduino IDE به طورِ بومی از اسمبلی پشتیبانی نمیکند. با اینحال، هایلایتِ syntax قابلیتِ خوانشِ کد را بالا برده و عملیات debugging را سادهتر میکند. نیازمندی هایی که تحتِ عنوانِ اهدافِ ثانویه لیست شده بود نیز یکی دیگر از این تغییرات است، در زمانِ کارِ مستقیم با اسمبلی، قابلیتهای مربوط به عملیاتِ debug میتواند بسیار کارآمد باشد. از سویی دیگر، میتواند مزایایِ ابزارهایِ معمولِ debug، مانند GDB را در اختیار کاربر قرار دهد. این عملیات امکانِ دسترسیِ بلادرنگ به ثَباتهای میکروکنترلرِ Arduino را فراهم میآورد، که در پی آن میتوان محتوای ثبات را مشاهده کرده و یا تغییر داد. تغییرِ دیگری که میتواند مزایایِ مشابهی را به همراه داشته باشد، استفاده از یک debug adapter اِ سختافزاری است، در اینصورت میتوان از قابلیتِ debug اِ توکار بهره گرفت و مشخصه های پردازندهی ARM Cortex-M3 یِ مربوط به Arduino Due را ردیابی کرد. طبقِ تجربیاتِ ما، در صورتِ پیاده سازیِ قابلیتِ debugging بر روی IDE، بهتر آن است که همین پیادهسازی، به عنوان یک پروژهی مجزا در نظر گرفته شود، چراکه هم از نظرِ وسعتِ تحقیقاتِ مورد نیاز و هم دشواریِ پروژه، این پیاده سازی به خودیِ خود یک پروژه ی بزرگ تلقی میشود.
از سویی دیگر، IDE میتواند از مزایایِ یک فیلترینگِ اسمبلی مناسب تر نیز بهره مند گردد. حذفِ هر چه بیشترِ اسمبلیهای اضافیِ تولید شده توسطِ کدِ کاربر، تجربهی بهتری را برای دانشجویان فراهم میآورد. از سویی دیگر، مجزا نمودنِ قابلیتِ فیلتر، و تبدیلِ آن به یک مشخصهی مستقل، کاراییِ آن را به مراتب افزایش خواهد داد. پیادهسازیِ مربوط به الگویِ اسمبلی، در صورتِ استفاده از روشی برای تقسیمِ آن به الگوهایِ اسمبلیِ کوچکتر، میتواند بهبود یابد. به این ترتیب که، فایلِ chunk میتواند حاویِ عملیاتِ loop در اسمبلی باشد، که بعدا توسط کابر مورد ویرایش قرار گرفته و حاویِ دستوراتِ اسمبلیِ کاربر خواهد بود. بعد از آن، فایلِ ویرایش شده با دیگر فایلهای chunk اِ اسمبلی، ترکیب گردیده و یک فایلِ اسمبلیِ معتبر را ایجاد مینماید. چنین روندی موجبِ صرفه جویی در نوشتنِ کد اسمبلی خواهد شد، چراکه کاربر دیگر نیازی نخواهد داشت که زمانِ بسیاری را صرفِ جستجوی الگوهای اسمبلی کرده و مکانِ مناسب را برای درج کدها پیدا کند.
سپاسگزارم
Alan Parson
مترجم:اميرحسين صادق دقيقي