مشکلی با عکسهای آرشیویام پیش آمده که بد نیست بنویسم برای خود آیندهام و رهگذران عزیز.
من عکسهایی که با گوشیهای مختلف گرفتهام را به کمک Syncthing با کامپیوترم سینک میکنم. در حال حاضر یکسالی میشود که روی یک Rock64 فسقلی Libreelec ریختهام و یک هارد پنجترابایتی هم برای سینک به درگاه USB 3 آن متصل کردهام (که ممکن است دیر یا زود به خاطر روشن و خاموش شدن متعدد عمرش را بدهد به شما). سینکتینگ روی راک است و فایلها سنک میشود روی آن هارددیسک. حالا مشکلی که پیش امده این است که من گوشی جدیدی خریدهام و تمام فایلها را روی آن به شکل ترکیبی! (دستی و سینکتینگ) کپی کردم. حالا تاریخ آخرین تغییر فایلها به هم ریخته است و وقتی در برنامهی گالری گوشی عکسها را باز میکنم تاریخها اشتباه است. این تغییر نه تنها باعث میشود که سورت کردن تصاویر براحتی امکانپذیر نباشد بلکه برنامههایی که از روی عکسها کلیپهای کوچک میسازند به اشتباه میافتند. تصور بکنید در حال تماشای عکسهای سالهای گذشته هستیم و به کمک توالی تاریخ عکسها در حال بازسازی گذر ایام در ذهنمان که به یکباره عکسی نامربوط ظاهر میشود که دلپذیر نیست.
خلاصه برای حل این مشکل طبق معمول با یک مقدمه دست به دامن خط فرمان میشویم.
خبر خوش اینکه در نام همهی عکسها روز عکاسی در فرمت سادهی ISO8601 آمده است. یعنی از چپ به راست اولی تاریخ چهار رقمی و بعد ماه دو رقمی و بعد روز دو رقمی (حالا دیگری هم دارد که از بحث ما خارج است). در برخی فایلها اولی چیز ثابتی آمده و بعد تاریخ که مشکلی نیست. از این گذشته عکسها حاوی اطلاعات Exif هستند که تاریخ اصلی عکاسی در آن ثبت شده است. پس در بدترین حالت میتوانیم تاریخ را از روی نام فایلها بازسازی کنیم.
داشتن تاریخ یک رویداد در نام فایل به قدری کاربردی است که افزودن تاریخ به فرمتISO8601 به ابتدای نام تمام فایلها به یک عادت دائمی برای من تبدیل شده است. معمولا وقتی قصد کپی گرفتن از یک فایل دارم از دستور زیر استفاده میکنم:
$ copy myfile.jpg $(date -I)_myfile.jpg
یا بدون خط تیره در نام فایل:
$ copy myfile.jpg $(date +%+4Y%m%d)_myfile.jpg
حسن این فرمت اینست که نام فایل ابتدا با سال و سپس با ماه و روز شروع میشود که کار سورت کردن فایلها را خیلی ساده میکند.
ایدهی فعلی من برای رفع این ایراد اینست که متادیتای فایلهایمان را به کمک اطلاعات اگزیف (یا در نبود آن با کمک نام فایل) اصلاح کنیم و بگذاریم که سینکتینگ فایلها را دوباره سینک کند. پیش از آن بیایید نگاهی بکنیم به این متادیتا.
مهم است که بدانیم متادیتا (داده در مورد داده) چیست و کجا ذخیره میشود. تاریخ ساخت و تغییر و دسترسی و مانند اینها در حالت عادی داخل فایل ذخیره نمیشوند و هر فایلسیستم و سیستمعامل آن را جداگانه ذخیره میکند. فایلسیستم ما در این مورد ext4 و سیستم عامل هم ما مبتنی بر لینوکس است. من اطلاعی در مورد ویندوز ندارم اما در سیستمعاملهای مشابه یونیکس متادیتای فایل در ساختاری بنام inode ذخیره میشود (از جایی که مکاوس هم از خانوادهی یونیکس است آنجا هم باید این موارد صادق باشد). به کمک فرمان ls -i
میتوانیم inode یکتای مختص هر فایل را ببینیم. inode اطلاعات مختلفی از جمله حق دسترسیها و همچنین چندین تاریخ (timestamp) مختلف را در خود ذخیره میکند. برای مشکلی که ما اینجا با آن روبرو هستیم ctime یا همان creation_time
و mtime یا همان modification_time
مهم است. اولی تاریخ ساخت و دومی تاریخ آخرین تغییر فایل است. atime یا همان access_time
هم وجود دارد که تاریخ آخرین دسترسی یا خوانده شدن محتوای فایل است. در مستندات کرنل لینوکس برای ext4 جزئیات پیادهسازی inode در لینوکس آمده است.
نکتهی جالبی که در مستندات یاد شده آمده است اینست که متغیری که برای ذخیرهی برخی از این تاریخها استفاده شده چهار بایت (سی و دو بیت) است. نحوهی رایج ذخیرهی timestamp یا لحظهی خاص در امتداد محور زمان یک عدد است که تعداد ثانیههای سپری شده از بامداد روز اول ژانویهی سال ۱۹۷۰ به وقت گرینویچ در خود ذخیره میکند. منتها در سال ۲۰۳۸ تعداد این ثانیهها دیگر در چهار بایت جا نمیشود و به اصطلاح overflow یا سرریز میکند. برای رفع این مشکل تمهیداتی اندیشیده شده است که شرح آن در مستندات ذکر شده آمده است.
به کمک دو دستور ls و stat میتوانیم برخی از اطلاعات inode را ببینیم. مثلا بیایید خروجی زیر را برای یکی از عکسهای خراب من ببینیم:
mx@playground[21250]:/home/mx/Sync/Everything/DCIM/Camera
$ stat 20190928_200752.jpg
stat 20190928_200752.jpg
File: 20190928_200752.jpg
Size: 1828942 Blocks: 3576 IO Block: 4096 regular file
Device: 253,0 Inode: 15409043 Links: 1
Access: (0664/-rw-rw-r--) Uid: ( 1100/ mx) Gid: ( 985/ users)
Access: 2024-03-01 10:48:49.262525490 +0100
Modify: 2021-10-27 23:04:21.000000000 +0200
Change: 2022-05-14 12:07:15.297708323 +0200
Birth: 2021-11-08 10:43:23.375113903 +0100
mx@playground[21249]:/home/mx/Sync/Everything/DCIM/Camera
$ ls -l !$
ls -l 20190928_200752.jpg
-rw-rw-r-- 1 mx users 1828942 Oct 27 2021 20190928_200752.jpg
از مقایسهی خروجی stat با ls پیداست که ls تاریخ آخرین تغییر را در خروجیاش نمایش میدهد (که ۲۷ اکتبر ۲۰۲۱ است).
همانطور که از مقایسهی نام فایل با خروجی دستوارت بالا پیداست ایرادی که برای عکسهای ما پیش آمده اینست که به طریقی این متاداده حین کپی فایلها از یک کامپیوتر (لینوکس) به دیگری (لینوکس) و در نهایت موبایل تغییر کرده است (اندروید هم لینوکس است البته در مورد گوشی سامسونگم از نوع فایلسیستم مطمئن نیستم). مثلا عکسی که سال ۲۰۱۹ گرفته شده است تغییر کرده است به سال ۲۰۲۱ یا ۲۰۲۳. با جستجو در فروم سینکتینگ متوجه شدم که سینکتینگ تاریخ آخرین تغییر را سینک میکند. بنابراین برنامه اصلاح تاریخ آخرین تغییر است. در حقیقت این مسئله به قدری رایج است که برنامههای cp و scp و rsync و غیره فلگی برای حفظ متادیتای فایل مرجع دارند. مثلا در مورد cp نگاهی به man cp
به ما میگوید که -p
(حرف اول preserve) باعث حفظ تاریخها و حقدسترسیهای فایل مرجع میشود.
برگردیم سروقت مشکل اصلی. از جایی که متادادههای inode عکسهای ما خراب شده باید تاریخ را یا از نام فایل بگیریم یا از خود فایل. بسته به نوع فایل ممکن است اطلاعاتی اضافه بر دادهی خام نیز داخل آن ذخیره شده باشد که میشود نوع دوم متاداده. در مورد عکسها (و اصوات ضبط شده در قالب WAV) این قضیه صادق است و برخی انواع فایل مانند JPG و TIF و WAV و PNG و WEBP میتوانند متاداده با قالب Exif در خود ذخیره کنند (ممکن است انواع دیگری هم باشد که من از آن بی اطلاعم).
برای دیدن متادیتای اگزیف از برنامهای قدیمی به نام exiftool کمک میگیریم (که به زبان پرل توسط فیل هاروی نوشته شده است). مثلا به کمک دستور زیر میتوان تمام تاریخهای ذخیره شده در یک فایل سالم را دید:
$ exiftool -time:all -s 20190307_144822.jpg
FileModifyDate : 2019:03:07 14:48:22+01:00
FileAccessDate : 2024:02:28 08:25:22+01:00
FileInodeChangeDate : 2024:02:28 08:25:21+01:00
ModifyDate : 2019:03:07 14:48:22
DateTimeOriginal : 2019:03:07 14:48:22
CreateDate : 2019:03:07 14:48:22
SubSecTime : 0611
SubSecTimeOriginal : 0611
SubSecTimeDigitized : 0611
TimeStamp : 2019:03:07 14:48:22.654+01:00
SubSecCreateDate : 2019:03:07 14:48:22.0611
SubSecDateTimeOriginal : 2019:03:07 14:48:22.0611
SubSecModifyDate : 2019:03:07 14:48:22.0611
میبینیم که «تگ»های مختلفی در اطلاعات اگزیف وجود دارد (ممکن است exiftool اطلاعات inode را هم به خروجی اضافه کرده باشد). اگر نام فایل را با تاریخهای ذخیره شده مقایسه کنیم هم میبینیم که تاریخها درست هستند (بجز تاریخ آخرین دسترسی و تاریخ آخرین تغییر inode). مثال دیگری از یک فایل خراب (دقت کنید که متادیتای کمتری دارد):
$ exiftool -time:all -s 20190928_200752.jpg
FileModifyDate : 2021:10:27 23:04:21+02:00
FileAccessDate : 2024:01:21 23:56:30+01:00
FileInodeChangeDate : 2022:05:14 12:07:15+02:00
ModifyDate : 2019:09:28 20:07:52
DateTimeOriginal : 2019:09:28 20:07:52
CreateDate : 2019:09:28 20:07:52
TimeStamp : 2019:09:28 20:07:52.812+02:00
در این مورد مقایسه نام فایل با FileModifyDate نشان میدهد تاریخ آخرین تغییر غلط است (من این فایلها را از زمان عکاسی ویرایش نکردهام البته شاید سهوا کپی کرده باشم). از جایی که با بررسی فایلهای مختلف متوجه شدم مقدار CreateDate صحیح است بیایید به کمک آن اطلاعات inode عکسهایمان را تصحیح کنیم.
برای بیرون کشیدن CreateDate از فرمت زیر کمک میگیریم:
$ exiftool -CreateDate -S -d %Y%m%d%H%M.%S -ext jpg 20190307_144822.jpg
CreateDate: 201903071448.22
علت فرمت کردن خروجی اینست که ما میخواهیم در گامهای بعدی آن را به خورد touch بدهیم و این فرمتی است که touch قبول میکند. man exiftool
را ببینید.
روش کار به کمک دستوارت سادهی یونیکس و همچنین Bash خیلی ساده است:
هر چهار مرحلهی بالا به هم به کمک |
به هم وصل شده است. به |
میگویند «پایپ» یا «لوله». یعنی ما دستورات مختلف (پراسسهای مختلف) را به یک لوله به هم وصل میکنیم (لولهکشی میکنیم!). کار این لوله وصل کردن خروجی استاندارد هر دستور به ورودی استاندارد دستور بعدی است. لوله اختراع Douglas McIlroy یونیکسکار ۹۲ سالهی آمریکایی است و یکی از معجزات یونیکس به شمار میرود. جالب است بدانید او در ۹۲ سالگی هنوز هم در میلینگ لیست TUHS فعال است.
برای لیست کردن فایلها در یک حلقه از حلقهی for که در Bash فراهم است کمک میگیریم. کافیست به man bash
نگاهی بکنیم و چند صفحه پایین برویم تا برسیم به Compound Commands و کمی پایینتر نحوهی نوشتن for را پیدا میکنیم:
for name [ [ in [ word ... ] ] ; ] do list ; done
The list of words following in is expanded, generating a list of items. The variable name is set to each ele‐
ment of this list in turn, and list is executed each time. If the in word is omitted, the for command exe‐
cutes list once for each positional parameter that is set (see PARAMETERS below). The return status is the
exit status of the last command that executes. If the expansion of the items following in results in an empty
list, no commands are executed, and the return status is 0.
در بدنهی یک حلقهی for میشود به آن مقدار یا لغتی که در آن لحظه به آن رسیدهام با بکارگیری $name
دسترسی داشت. name
مقداری است اختیاری که ما انتخاب میکنیم. باید دقت داشته باشیم که از دید for هر آنچه در برابرش ظاهر میشود چیزی جز یک کلمه نیست. مثلا اگر خروجی دستور ls را به آن بدهیم و نام فایلهای ما خط فاصله داشته باشد for آنها را چند لغت جدا از هم خواهد دید. این نکتهی بسیار مهمی است و برای رفع آن همواره باید متغیرها را درون گیومه قرار داد. بیایید اول یک لیست ساده بنویسیم:
$ for i in $(ls *.jpg | head -n3); do echo "$i"; done
20190307_144822.jpg
20190307_144826.jpg
20190313_172658.jpg
این دستور عکسهای ما را لیست میکند. ما فقط نام فایل را echo کردیم (دستوری که هر آنچه به آن بدهید در خروجی استاندارد خودش مینویسد). نام متغیر را i
انتخاب کردهایم. علاوه بر آن بجای word مقدار $(ls *.jpg | head)
گذاشتهایم. Bash هر چیزی که درون $()
بگذاریم همیشه به عنوان یک فرمان اجرا میکند و با خروجی آن جایگزین میکند. ما دستور ls *.jpg | head -n3
داخل آن گذاشتهایم. ls که فایلهای منتهی به .jpg
را لیست میکند و خروجی آن را به کمک لوله میدهد به head
که دستور سادهایست که فقط چند خط اول را نگه میدارد (چون فایلها زیاد است و برای مثال ما همین کافی بود). جلوتر هم طبق مستندات for دستوری که میخواهیم برای هر «لغت» اجرا شود آوردهایم که چیزی جز echo "$i"
نیست. برای فهم بهتر در نظر بگیرید که دستور بالا دقیقا معادل دستور پایین است:
$ for in in 20190307_144822.jpg 20190307_144826.jpg 20190313_172658.jpg; do echo $i; done
20190322_200524.jpg
20190322_200524.jpg
20190322_200524.jpg
با این مقدمه در مورد for حالا دستور exiftool را در دل آن جای میدهیم:
$ for i in $(ls *.jpg | head -n3); do exiftool -CreateDate -S -d %Y%m%d%H%M.%S -ext jpg "$i"; done
CreateDate: 201903071448.22
CreateDate: 201903071448.26
CreateDate: 201903131726.58
به همین ترتیب ادامه میدهیم و اینبار خروجی را میبریم تا فقط تاریخ فرمت شده باقی بماند:
$ for i in $(ls *.jpg | head -n3); do exiftool -CreateDate -S -d %Y%m%d%H%M.%S -ext jpg "$i" | cut -d ' ' -f 2; done
201903071448.22
201903071448.26
201903131726.58
میبینید که دوباره خروجی یک دستور را لوله کردهایم در ورودی دستور بعدی، اینجا دستور cut
. این دستور هر خط ورودیاش را به کمک یک جداکننده (اینجا خط فاصله) قیچی میکند و آنها را به چند ستون تبدیل میکند که بعد ما میتوانیم یک ستون خاص را با پارامتر -f
انتخاب کنیم. حالا نام هر فایل و تاریخ صحیح را داریم، ماند اصلاح فایلها.
برای اصلاح فایل از دستور touch
استفاده میکنیم. man touch
به ما میگوید که touch
میتوان تاریخ همین لحظه یا یک تاریخ دلخواه را در inode یک فایل بنویسد. تاریخ فرمتشده مطابق خواست touch
را که قبلا ساختیم و نام فایل را هم که در متغیر i
داریم. منتها از جایی که ما میخواهیم فایلهای مختلفی را با تاریخهای مختلف اصلاح کنیم باید دستور touch را برای تکتک آنها جداگانه اجرا کنیم. به همین منظور از دستور xargs
کمک میگیریم. xargs برای هر خط که در ورودی استانداردش نوشته بشود یکبار دستوری که به آن در خط فرمان دادهایم اجرا میکند.
حالا فقط میماند اجرای دستور نهایی. منتها برای تست اول یکبار همه را echo
میکنیم:
$ for i in $(ls *.jpg | head -n3); do exiftool -CreateDate -S -d %Y%m%d%H%M.%S -ext jpg "$i" | cut -d ' ' -f 2 | xargs echo touc
h "$i" -t; done
touch 20190307_144822.jpg -t 201903071448.22
touch 20190307_144826.jpg -t 201903071448.26
touch 20190313_172658.jpg -t 201903131726.58
این خروجی دستور نهایی است. که خوب به نظر میرسد. فقط کافیست head -n3
را به همراه echo
ی قبل از xargs
حذف کنیم و آن را دوباره اجرا کنیم:
$ for i in $(ls *.jpg); do exiftool -CreateDate -S -d %Y%m%d%H%M.%S -ext jpg "$i" | cut -d ' ' -f 2 | xargs touch "$i" -t; done
و تمام.
در این مقالهی کوتاه نگاهی کردیم به متادیتای فایلها در یونیکس و نیز متادیتای اگزیف موجود در عکسها و به کمک مقادیر صحیح تگ CreateDate اگزیف تاریخ آخرین تغییر فایلهایمان را اصلاح کردیم تا برنامههای گالری عکس بتوانند عکسها را با توالی صحیح نمایش بدهند.
]]>پس از وقفهای یکساله که شاید در آینده دربارهاش بنویسم برمیگردیم سروقت نوشتن. اینبار قصد دارم چالش Advent of Code را به خوانندگان عزیر معرفی کنم.
در عموم کشورهای مسیحی به ایامی که مؤمنین خود را برای جشن تولد مسیح آماده میکنند Advent گفته میشود. این ایام معمولا سه هفته اول ماه دسامبر است تا روز اول کریسمس (۲۵ دسامبر در آلمان). مثلا در کشور آلمان در این ایام بازارچههای سال نو برپا هستند (که همگی حداکثر یکی دو روز قبل از کریسمس تعطیل میکنند) و برنامههای مختلف سرگرمکننده برای کودکان و بزرگسالان در سراسر کشور برپاست. رایج است که در این کشورها مردم به شکلهای مختلف به استقبال کریسمس میروند. یکی از رایجترین اقلامی که در این ایام بویژه برای کودکان خریداری میشود یک تقویم ادونت است. یک تقویم ادونت بیست و پنج خانه دارد، یکی برای هر روز. معمولا این تقویمها برای هر روز یک خانه دارند که میتوان درب آن را باز کرد و داخل آن معمولا تصویر یا متن یا یک جایزه قرار دارد.
برنامهنویس خوشقریحهای بنام Eric Wastl از سال ۲۰۱۵ هر ساله در این ایام چالشی بنام Advent of Code منتشر میکند. این چالش از روز اول دسامبر شروع میشود و ۲۵ روز ادامه دارد. در بامداد هر روز او یک سوال روی سایت چالش منتشر میکند که دو بخش دارد. با حل هر بخش میتوان یک ستاره دریافت کرد و در پایان ۲۵ روز حداکثر ۵۰ ستاره جمعآوری کرد.
هر چالش دو بخش دارد. یک بخش اول و اصلی که سادهتر است و یک بخش دوم. بخش دوم معمولا ادامهی همان بخش اول است و میتوان از راهحل بخش اول در حل بخشی از آن استفاده کرد یا کلا همان بخش اول است اما ورودی بزرگتری دارد و نکتهدار است. برای گرفتن هر ستاره کافیست که پاسخ صحیح را در کادر مربوطه وارد کرد و نیازی به ارسال کد نیست. از جایی که ورودیها برای هر کاربر میتواند متفاوت باشد باید در سایت چالش ثبتنام کرد. دسترسی به سوالات سالهای گذشته نیز روز وبسایت چالش امکانپذیر است.
ساختار چالشها شبیه مسابقات ICPC است (زمان ما میگفتیم ACM). به این صورت که یک ورودی تست و یک خروجی تست به همراه یک ورودی اصلی برای هر قسمت ارائه میشود. گاهی قسمت دوم هم از همان ورودی قسمت اول استفاده میکند و ورودی جدیدی ندارد. برنامهنویس فقط کافیست که جواب صحیح را وارد کند و نیازی به سابمیت کردن کدی که نوشته است نیست. اصلا هم مهم نیست که به چه زبانی مسئلهها را حل میکنیم. در ضمن نیازی به حل تمام مسائل نیست. اگر سوالی وقتگیر یا مشکل بود میتوان رفت سروقت بعدی و از ستارهی سوال سخت صرفنظر کرد.
من سال گذشته تا روز ۱۹ را حل کردم. البته در روز ۱۹ گیر کردم و دیگر نتوانستم پیشروی کنم! البته سعی کرده بودم حتما هر روز را حل کنم تا بروم روز بعدی که توصیه میکنم شما اینکار را نکنید و اگر سوالی خیلی سخت بود بروید سروقت بعدی. در ضمن سعی کرده بودم که همه را با زبان برنامهنویسی Go بنویسم که آنهم کمی وقت گرفت ولی در مجموع خوب بود. پیشنهاد من اینست که در هر برنامهای که مینویسید یک ساختار یکسان را رعایت کنید:
۱. ورودی را از فایل بخوانید (فایلها را با یک ساختار خوب ذخیره کنید مثلا dayXinput و dayXtestinput).
۲. فایل را پارس کنید و در یک ساختار دادهی درست ذخیره کنید. مثلا اگر گراف است در یک ساختار گراف درست با جستجو و حذف و اضافه ذخیره کنید.
۳. چالش را برای ورودی تستی حل کنید.
۴. چالش را برای ورودی اصلی حل کنید.
برای حل مسائل الگوریتمی اگر میتوانید حتما دو کتاب را دم دست داشته باشید. هر دو کتاب رفرنسهای بسیار معتبر و شناختهشدهای هستند.
اگر به سایت چالش دقت کنید همانجا تعدادی گروه معمولا انگلیسی زبان برای پشتیبانی لیست شده. فعالترین آنها سابردیت خود چالش است. آنها اگر مثلا دنبال 2022 day 5 بگردید پستهای مربوط به آن را پیدا میکنید. در ضمن میتوانید از سایدبار بخوانید که چطور سوال بپرسید. چون پستها انواع مختلفی دارند، مثلا بعضی افراد هر سال برای راهحلهایشان جلوههای بصری تولید میکنند و با بقیه به اشتراک میگذارند. در پستهای خاصی هم جوابهایشان را منتشر و مقایسه میکنند. حتما سایدبار را بخوانید که بتوانید جواب درست بگیرید.
جدای از کامیونیتی انگلیسی زبان هم میتوانید اینجا بپرسید (که طول میکشد منتشر بشود) یا ایمیل بزنید و یا روی اتاق ماتریکس یا آیآرسی بپرسید یا روش بهتری پیدا کنید یا یکی بسازید.
بیش از این رودهدرازی نمیکنم. این شما و این هم چالش ادونت آو کد سال ۲۰۲۳!
موفق باشید.
]]>در این نوشته به طور خلاصه با کَنباس CAN bus1 آشنا میشویم و یاد میگیریم چطور با آن کار کنیم. طبق معمول ابزارهای بکار رفته همه آزاد هستند.
کنباس یک باس یا گذرگاه دادهی بسیار ساده و مقاوم و ارزان است که برای سادهسازی سیمکشی درون خودروها و ارتباط اجزاء مختلف با کنترلرها و کامپیوترهای خودرو در سال ۱۹۸۶ توسط شرکت بوش آلمان به خودروسازان جهان معرفی شده است. مستندات فنی نسخهی ۲ آن به سال ۱۹۹۱ را میتوانید در این آدرس بخوانید. بعدها در سال ۱۹۹۳ مشخصات فنی کنباس به استاندارد ایزو شمارهی ۱۱۸۹۸ تبدیل شد.
بدون وجود یک باس، میبایست درون خودرو کیلومترها سیم برای اتصال اجزاء مختلف به کنترلرها بکار رود. علاوه بر این بدون یک باس نمیتوان از سیمها برای مقاصد مختلف استفاده کرد. مثلا تصور کنید چراغ ترمز یک خودرو خراب شده است، اما چراغ خطر اضافی عقب خودرو سالم است. کامپیوتر خودرو میتواند خرابی را تشخیص بدهد و از چراغ خطر اضافی عقب بجای چراغ ترمز استفاده کند. بدون یک باس امکان اینکار وجود ندارد. علت اینکه به چنین گذرگاهی «باس» میگویند اینست که شبیه یک اتوبوس عمل میکند. یعنی دادههای قطعات مختلف همگی میتوانند سوار این اتوبوس بشوند و از یک ایستگاه به ایستگاه دیگری بروند.
یک کنباس حداقل به دو نود (عضو) برای کار نیاز دارد. همهی اعضا با یک زوج سیم پیچ و تاب خورده به یکدیگر متصل میشوند. یکی از این سیمها CAN High و دیگری CAN Low نام دارد. هر دو انتهای این سیمها باید با یک مقاومت ۱۲۰ اهمی به هم بسته بشوند. تصویر زیر از ویکیپدیا به خوبی این معماری را نمایش میدهد.
By EE JRW - Own work, CC BY-SA 4.0, https://commons.wikimedia.org/w/index.php?curid=38256600
هر یک از نودهای برای اتصال به کنباس به یک مدار ساده احتیاج خواهد داشت. این مدار معمولا حاوی سه جزء است. یکی ترنسیور2 و دیگری کنترلر3 و آخری هم میکروکنترلر (پردازندهی میزبان) نام دارد. زوج سیمهای باس تنها به ترنسیور وصل میشود و ترنسیور به نوبه خود به کنترلر. ترنسیور قطعهی بسیار سادهایست. کارش اینست که ولتاژهای الکتریکی CAN Low و CAN High را به سطوح منطقی صفر و یک قابل فهم برای کنترلر تبدیل بکند. از سوی دیگر کنترلر قطعهی مهمی است و کارش پیادهسازی قرارداد ارتباطی است که در مستندات فنی کنباس قید شده است. کنترلر است که تصمیم میگیرد چه زمانی با باس صحبت بکند و اینکه چگونه پیام را ارسال بکند و چه زمانی تنها گوش بکند و چه زمانی کاملا خاموش باشد.
دست آخر هم هر نود باید برای ارسال و دریافت پیام روی باس با کنترلر خودش صحبت بکند. این کار را میکروکنترلر انجام میدهد. جایی که کاربر معمولا برنامهاش را باید بنویسد و فلش و اجرا کند. میکروکنترلر معمولا از یک طرف به سنسورها یا پمپها و مانند این متصل است و از سوی دیگر به کنترلر. مثلا در مثال چراغ خطر بالا میکروکنترلر از یک سو به چراغ خطر وصل خواهد بود و از سوی دیگر به کنترلر. به این ترتیب او میتواند هم وضعیت چراغ خطر را پیوسته از طریق باس به کامپیوتر خودرو ارسال بکند و از سوی دیگر فرامین کامپیوتر خودرو را دریافت و مثلا کاربری چراغ خطر را تغییر بدهد. امروزه میکروکنترلرهای زیادی حاوی کن کنترلر درونی هستند (اما فاقد ترنسیور مثل برخی پردازندههای سری ESP32).
تصویر زیر از ویکیپدیا معماری یک نود را به خوبی نمایش میدهد.
EE JRW, CC BY-SA 4.0 https://creativecommons.org/licenses/by-sa/4.0, via Wikimedia Commons
مشخصاتی که در سال ۱۹۹۱ از طرف بوش برای کنباس منتشر شده است حاوی دو بخش A و B است. پیادهسازیهایی که طبق بخش A ساخته شدهاند به CAN2.0A و آنهایی که سازگار با بخش B طراحی شدهاند به نام CAN2.0B (نسخهی توسعهیافته) شناخته میشوند. هر دو با هم سازگار هستند و میتوانند در آن واحد در باس مشارکت کنند. تنها تفاوت آنها در طول شناسهی پیامهاست. در کنباس نودهای باس به یکدیگر پیام (یک فریم) ارسال میکنند. هر نود باید پیامهایش را با یک شناسهی یکتا ارسال بکند. هر پیام هم به نوبه خود حاوی شناسهی نود فرستنده و یک بدنه است. شناسه میتواند طبق CAN2.0A و ۱۱ بیت یا طبق CAN2.0B و ۲۹ بیت باشد. کنباس محدودیتی تئوریک برای تعداد نودهای حاضر در باس تعریف نمیکند. تمام نودهای حاضر در باس تمام پیامها را دریافت میکنند حتی نود فرستنده. تصویر زیر ساختار یک فریم یازده بیتی را نمایش میدهد.
Fröstel (S.G.), CC0, via Wikimedia Commons
کن چهار نوع فریم تعریف میکند: داده و ریموت و خطا و اوورلود. مهمترین نوع فریم داده است که نودها با آن داده ارسال میکنند. هر فریم داده میتواند صفر تا ۶۴ بیت (۸ بایت) داده داشته باشد. نودها نیز نیازی به تنظیمات مرکزی ندارند. هر نود به محض اتصال میتواند در باس مشارکت بکند. کنترلر وظیفهی ارسال و دریافت پیامها را طبق مشخصات فنی کنباس بر عهده میگیرد. مثلا ارسال فریم خطا هنگام دریافت فریم ناقص یا سکوت کامل هنگام دریافت خطا بیش از حد مجاز یا خاموش کردن کامل نود (bus-off) در برخورد با خطاهای غیر قابل اصلاح و چشمپوشی.
علاوه بر نسخهیای که در بالا معرفی کردیم نسخههای سطح بالاتری از کن هم توسط بوش و دیگران ساخته شده است که برای کاربردهای پیچیدهتر به کار میروند. از میان آنها میتوان به CAN-FD توسط بوش و CANopen اشاره کرد. ویژگی مشترک اغلب آنها اینست که از کنباس به عنوان پایینترین لایهی ارتباطی استفاده میکنند.
از جایی که کن بسیار ساده و مقاوم و ارزان است، نه تنها در خودروها بلکه به شکل گستردهای در صنایع مختلف راه پیدا کرده است. اگر به مشخصات تجهیزات صنعتی نگاهی بیندازید حتما کن را در میان پروتکلهای ارتباطی آنها پیدا خواهید کرد. قطعاتی مثل لامپهای هشدار چند رنگ رایج در انبارهایی که لیفتراک یا ربات برای حمل و نقل استفاده میکنند تا رباتهای خودکار موجود در خط تولید یا شارژرهای بیسیم صنعتی و بسیاری دیگر همگی از کن برای ارتباط استفاده میکنند.
از طرفی کن برخلاف پروتکل اترنت (شبکههای کامپوتری) شکل فیزیکی پورت اتصال کابل به نود را محدود نمیکند. تا آنجا که به کن مربوط است فقط کافیست دو سیم برای اتصال وجود داشته باشد. اینکه چگونه نودها به یکدیگر متصل میشوند برای کن مهم نیست. از این رو در بازار روشهای مختلفی رایج شده است. محبوبترین و ارزانترین پورت اتصالی ترمینال پیچی است:
Phoenix Contact https://www.phoenixcontact.com/
پورت بعدی که گران است ولی در محصولات صنعتی رایج است انواع اتصالات گرد از سری محصولات شرکت فونیکس کانتکت است. هر تولیدکنندهای تصمیم میگیرد که چه متصلکنندهای برایش مناسبتر است و اینکه کدام پینها باید برای CAN High و CAN Low بکار برود. این جزئیات هم در دیتاشیت تولید کننده منتشر میشود. شکل زیر تعدادی متصلکننده را نشان میدهد:
Phoenix Contact https://www.phoenixcontact.com/
آخرین پورت رایجی که نام میبریم OBD II نام دارد که در خودروها بکار میرود. البته این پورت فقط برای کن نیست بلکه کاربرد اصلی آن استاندارد کردن نحوه دسترسی به اطلاعات فنی خودرو بوده است. چرا که خودروسازان مانند بسیاری شرکتهای دیگر علاقهی شدیدی به انحصاری کردن خدماتشان دارند. بنابراین هر یک برای دسترسی به اطلاعات کامپیوتر خودرو که برای تعمیر و نگهداری خودرو لازم است پروتکلهای انحصاری خودشان را بکار میبردند و به تعمیرگاههای مستقل امکان دسترسی نمیدادند (مگر مثلا با اخذ مجوز و خرید دستگاههای لازم از خودشان). ODB II پاسخ قانونگذاران در آمریکا و اروپا به این وضع بود. از سال ۱۹۹۶ در آمریکا و از سال ۲۰۰۱ در اروپا خودروسازان مجبورند یک پورت ODB II با شکل فیزیکی و پیامهای تعریف شده در استاندارد در خودرو تعبیه کنند. از این طریق تعمیرکاران مستقل و حتی مصرفکنندگان میتوانند به اطلاعات پایهی خودرو دسترسی پیدا کنند بدون اینکه تولید کننده بتواند مانع آنها بشود و درخواست وجه بکند. این پورت طبق استاندارد باید در فاصلهی ۶۱ سانتیمتری فرمان باشد. اگر به زیر فرمان خودروهای ساخت خارج نگاهی بیندازید حتما این پورت را پیدا میکنید:
By M.M.Minderhoud - Own work, Female OBD-II connector on a car, CC BY-SA 4.0, vie Wikimedia Commons
طبق استاندارد دو پین شمارهی ۶ و ۱۴ برای کن در نظر گرفته شده است که به رنگ سبز در تصویر زیر مشخص است:
*Xoneca - Own work, CC0, via Wikimedia Commons *
در بازار گیرندههای مختلفی وجود دارند که میتوان به این پورت وصل کرد و اطلاعات خودرو و پیامهای خطا را خواند و پاک کرد و برخی تنظیمات خودرو را تغییر داد. من یک گیرندهی بلوتوث کوچک دارم که بعد از اتصال به ماشین و بلوتوث یک گوشی میتوان به کمک یک به اطلاعات خودرو دست یافت. تمام این کارها را هم میتوان مستقیما با اتصال دو سیم به پینهای کن انجام داد که از حوصلهی این مقاله خارج است.
آداپتور OBD II بلوتوث من
آداپتور OBD II بلوتوث من
در ادامه شرح میدهم که چطور میتوان روی لینوکس با کن کار کرد. همانطور که در ابتدا دیدیم نودها میتوانند با کنباس ارتباط برقرار کنند و پیام دریافت و ارسال بکنند. دستگاه لینوکسی ما هم باید به باس وصل و تبدیل به یک نود بشود تا بتوانیم پیامها را دریافت و ارسال بکنیم. برای اینکار در درجه اول نیاز به سختافزار کن داریم. در بازار آداپتورهای کن به USB فراوانی وجود دارد که معمولا مبتنی به تراشههای ارزان میکروچیپ هستند. مثل ترنسیور MCP2551 و کنترلر MCP2515. من دو نمونه آداپتور از سایت canable.io تهیه کردهام که در زیر میبینید:
CANable Pro & CANable
تفاوت مهم نسخهی بزرگتر با نسخه کوچکتر در ایزولاسیون است که از لپتاپ من در صورت اتصالی یا مانند اینها حفاظت میکند. به جز این هر دو شبیه هستند، در یک سو پورت میکرو یواسبی است که با یک کابل به کامپیوتر وصل میشود و در صوی دیگر ترمینال پیجی برای سیمهای CAN High و CAN Low و در صورت نیاز گراوند قرار گرفته. یک جامپر هم روی هر یک تعبیه شده که مقاومت ۱۲۰ اهمی را فعال و غیرفعال میکند. در مورد نحوهی بکارگیری گراوند من نمیتوانم راهنمایی مفیدی بکنم چرا که از حوزهی تخصص من خارج است. یک مهندس الکترونیک میتواند اهمیت آن را بهتر شرح بدهد فقط اضافه کنم که اتصال اشتباه گراوند/زمین میتواند منجر خرابی باس بشود و گیرنده هیچ پیامی دریافت نمیکند و معمولا نیازی به اتصال آن نیست.
دو روش رایج برای کار با کن در لینوکس عبارت است از slcan و socketcan. هر دو درایور در تنهی اصلی کرنل قرار دارند و بنابراین بدون نصب هیچ گونه نرمافزار اضافی در دسترس قرار دارد. هرچند پیش از استفاده باید مطمئن شد که ماژولهای مورد نظر لود شدهاند:
$ sudo modprobe can
$ sudo modprobe slcan #for slcan
در ادامه من فقط به شرح کار با socketcan میپردازم.
سوکتکن از Berkly sockets استفاده میکند که همان سوکت یونیکس است که کل اینترنت روی آن بنا شده است. یعنی مثل رابط شبکه رفتار میکند. این به معنای اینست که تمام ابزارهای رایج لینوکس مانند دستور ip میتوانند با آداپتور کن ارتباط برقرار کنند. برای این منظور یک رابط نرمافزاری CAN-to-USB هم نیاز است. آداپتورهایی که من دارم از درایور slcan و gs_usb (هردو به لینوکس اضافه شدهاند) پشتیبانی میکنند. من نسخهای بنام CandleLight را فلش کردهام که به کمک آن آداپتور من بیواسطه توسط کرنل به عنوان یک سختافزار شبکه مبتنی بر SocketCAN شناخته میشود. ناگفته پیداست که اینکه یک سختافزار چگونه خود را به سیستم عامل معرفی کند وابسته به firmware ایست که روی آن فلش شده است.
با اتصال آداپتور به کامپیوترم کرنل براحتی آن را تشخیص میدهد:
$ sudo dmesg -w
[21050.404363] usb 3-2.2: new full-speed USB device number 11 using xhci_hcd
[21050.509412] usb 3-2.2: New USB device found, idVendor=1d50, idProduct=606f, bcdDevice= 0.00
[21050.509421] usb 3-2.2: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[21050.509424] usb 3-2.2: Product: canable gs_usb
[21050.509426] usb 3-2.2: Manufacturer: canable.io
[21050.509428] usb 3-2.2: SerialNumber: 00238008574D430820333735
[21050.510049] gs_usb 3-2.2:1.0: Configuring for 1 interfaces
شش خط اول از درایور یواسبی است و خط آخر از درایور gs_usb که اینترفیس را ایجاد میکند. با دستور ip میتوانیم سختافزارهای واقعی و مجازی شبکه شناخته شده توسط کرنل لینوکس را ببینیم:
$ ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: enp4s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP mode DEFAULT group default qlen 1000
link/ether 04:92:26:da:0a:6b brd ff:ff:ff:ff:ff:ff
3: can0: <NOARP,ECHO> mtu 16 qdisc noop state DOWN mode DEFAULT group default qlen 10
link/can
اولی دیوایس لوپبک است که لینوکس میتواند به کمک آن با خودش روی یک شبکه مجازی حرف بزند. دومی کارت اترنت من است و سومی آداپتور کن ماست.
قبل از اینکه ببینیم چطور میشود پیام از کنباس بخوانیم و به آن ارسال کنیم بیایید یک باس واقعی بسازیم.
برای اینکار من هر دو آداپتورم را بکار میگیرم. جامپرهای ۱۲۰ اهم را در هر دو سو فعال میکنم و با دو کابل CAN High را به CAN High و CAN Low را به CAN Low وصل میکنم:
ساخت کن باس با دو آداپتور کن به یواسبی
به نحوهی اتصال سیمها توجه کنید (جامپرهای مقاومت هم بسته است ولی در عکس پیدا نیست)
حالا هر دو آنها را به دو پورت یواسبی متصل میکنم:
$ sudo dmesg -w
[24221.741438] usb 3-2.1: new full-speed USB device number 19 using xhci_hcd
[24221.842849] usb 3-2.1: New USB device found, idVendor=1d50, idProduct=606f, bcdDevice= 0.00
[24221.842857] usb 3-2.1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[24221.842860] usb 3-2.1: Product: canable gs_usb
[24221.842863] usb 3-2.1: Manufacturer: canable.io
[24221.842865] usb 3-2.1: SerialNumber: 00238008574D430820333735
[24221.843491] gs_usb 3-2.1:1.0: Configuring for 1 interfaces
[24224.554745] usb 3-2.2: new full-speed USB device number 20 using xhci_hcd
[24224.659402] usb 3-2.2: New USB device found, idVendor=1d50, idProduct=606f, bcdDevice= 0.00
[24224.659407] usb 3-2.2: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[24224.659408] usb 3-2.2: Product: canable gs_usb
[24224.659410] usb 3-2.2: Manufacturer: canable.io
[24224.659410] usb 3-2.2: SerialNumber: 00330023574D430820333735
[24224.659961] gs_usb 3-2.2:1.0: Configuring for 1 interfaces
هر دو آداپتور به لیست سختافزارهای شبکه اضافه شده:
$ ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: enp4s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP mode DEFAULT group default qlen 1000
link/ether 04:92:26:da:0a:6b brd ff:ff:ff:ff:ff:ff
3: can0: <NOARP,ECHO> mtu 16 qdisc noop state DOWN mode DEFAULT group default qlen 10
link/can
4: can1: <NOARP,ECHO> mtu 16 qdisc noop state DOWN mode DEFAULT group default qlen 10
link/can
برای اینکه از یک اینترفیس سوکتکن بتوان استفاده کرد باید آن را تنظیم کرد و بالا آورد. فعلا هر دو قطعه پایین هستند (DOWN). با دستور ip آنها را بالا میآوریم:
$ sudo ip link set can0 up type can bitrate 500000
$ sudo ip link set can1 up type can bitrate 500000
$ ip link
...
3: can0: <NOARP,UP,LOWER_UP,ECHO> mtu 16 qdisc pfifo_fast state UP mode DEFAULT group default qlen 10
link/can
4: can1: <NOARP,UP,LOWER_UP,ECHO> mtu 16 qdisc pfifo_fast state UP mode DEFAULT group default qlen 10
link/can
میبینیم که هر دو UP شدهاند. از جایی که هر کنباس یک bitrate یکسان دارد باید مقدار آن را هنگام بالا آوردن آداپتور بدهیم. من پانصد کیلوبیت را انتخاب کردم که رقم رایجی است. اگر فلگ -statistics
را به دستور ip بدهیم اطلاعات بیشتری میبینیم:
$ ip -statistics link show can0
3: can0: <NOARP,UP,LOWER_UP,ECHO> mtu 16 qdisc pfifo_fast state UP mode DEFAULT group default qlen 10
link/can
RX: bytes packets errors dropped missed mcast
0 0 0 0 0 0
TX: bytes packets errors dropped carrier collsns
0 0 0 0 0 0
حالا شبکهی ما آماده است و میتوانیم برویم سروقت ارسال و دریافت پیام. برای اینکار به ابزارهای موجود در can-utils نیاز خواهیم داشت. پروژهی can-utils حاوی ابزارهای userspace برای SocketCAN است. این پروژه در برخی دیستروها پکیج شده است و در سایرین باید زحمت نصب آن را کشید که از حوصلهی این مقاله خارج است. ما از دو ابزار موجود در این پروژه استفاده میکنیم: candump و cansend. اولی برای خواندن پیامهای باس و دیگری برای ارسال پیام روی باس. دو ابزار دیگر هم که برای تمرین خوب است یکی cangen است که پیامهای رندوم میسازد و به باس ارسال میکند و دیگری canplayer که میتواند پیامهای ضبط شده با candump را دوباره ارسال کند.
حالا که نرمافزار لازم را هم داریم لحظهی امتحان نهایی فرا رسیده است! بیایید پیامی از نود صفر به باس ارسال کنیم و آن را در نود شمارهی یک بخوانیم. اول در یک ترمینال candump را باز میکنیم و در ترمینال دیگر cansend را اجرا میکنیم:
$ candump can1
can1 1FF [0]
...
$ cansend can0 1FF#
در اسکرینکست کوتاه زیر میتوانید پروسه را ببینید. مقدار قبل از # آدرس فریم یا CAN ID است و مقدار بعد از # داده است (که من خالی گذاشتم، تا هشت کاراکتر HEX میتوان داده پاس داد یعنی FFFFFFFF). توجه کنید که من یکبار با فرمت کوتاه و یکبار دیگر با فرمت بلند CAN ID دلبخواهی میسازم و فریم را ارسال میکنم.
در زیر هم استفاده از cangen برای ساخت فریمهای تصادفی را میتوانید ببینید. باز هم توجه کنید که یکبار فریمها را با فرمت کوتاه (CAN2.0A) و یکبار با فرمت بلند (توسعهیافته CAN2.0B) ارسال میکنم.
ابزارهای موجود در پروژهی can-utils بسیار ساده و سریع و مفید هستند. یکی از قابلیتهای مجبوب من ضبط پیامهای یک باس به کمک candump (candump -l
) و پخش آن با canplayer (cat dump.log | canplyer can0=can0
) روی یک باس مجازی هنگام برنامهنویسی یا بررسی یک مشکل است. اما شاید بپرسید مگر بدون آداپتور هم میشود کنباس را امتحان کرد؟ در جهان نرمافزار آزاد پاسخ اغلب این پرسشها «آری» است! (بد نیست بدانید که شرکتهای تولیدکننده دستگاههای صنعتی اغلب برای بررسی اشکال یک Logger (دستگاهی مشابه آداپتور که پیامها را روی یک کارت حافظه ضبط میکند) به مشتری ارسال میکنند تا پیامها را ضبط کند و فایل آن را برای بررسی توسط مهندسان ارسال کند.)
برای امتحان کنباس و پخش لاگ فایلهای ضبط شده بدون دسترسی به یک آداپتور میتوان از ماژول vcan لینوکس استفاده کرد. ابتدا باید از لود بودن ماژول vcan مطمئن شد و بعد به کمک دستور ip میتوان یک اینترفیس مجازی از نوع vcan ساخت:
$ sudo modprobe vcan
$ sudo ip link add type vcan
در اسکرینکست مختصر زیر یک اینترفیس مجازی کن میسازم و آن را فعال میکنم و پیامهای رندوم روی آن ارسال میکنم.
آخرین موضوعی که به طور خلاصه به آن میپردازیم پارس کردن پیامهاست. ابزارهای پروژهی can-utils تنها با فریمهای خام کار میکنند. برای دیکد کردن این اطلاعات به ابزارهای سطح بالاتری نیاز است. آنچه در صنایع و دنیای برنامهنویسی توکار رایج است ذخیرهی فرمت دادهها و ماتریس پیامهای ارسالی و نیز آدرسهای آنها در فایلهایی با فرمتهای مختلف از جمله DBC است. (فرمت KCD یک فرمت آزاد است که استفاده نکردهام). استاندارد خاصی در این حوزه وجود ندارد و به طور سنتی تولیدکنندههای آداپتورها هر یک طبق وزن خودشان در دنیای صنعت فرمتهای خودشان را ساختهاند که اغلب هم انحصاری هستند. از جایی که کمتر تولیدکنندهای ابزارهای آزاد منتشر میکند پروژههای مختلفی برای دیکد کردن لاگفایلها و نیز فایلها تعریف فرمت فریمها بوجود آمده است. دوپروژهی خوبی که در این حوزه از آن بسیار بهره بردهام یکی python-can و دیگری cantools است. اولی میتواند با آداپتورهای مختلف ارتباط برقرار کند و دومی هم امکان دیکد کردن دادهها با استفاده از فرمت DBC و دیگر فرمتها فراهم میکند. یکی از ویژگیهای جالب پروژهی cantools آن امکان دیکد کردن زندهی پیامهای ارسالی روی باس است که هنگام بررسی و رفع اشکال توسط تیمهای پشتیبانی یا برنامهنویسان بسیار مفید است. من در اینجا به تکرار آنچه روی سایت پروژه آمده است نمیپردازم چرا که مثالهای مختلف روی ریپازیتوری cantools به تفصیل شرح داده شده است.
]]>به درخواست عرفان راهنمای ویدیویی کوچکی در مورد کار با فونت فورج ساختم که میتوانید در ادامه تماشا کنید. از این گذشته تغییرات بسیاری در فونت نقطه دادهام که در آخرین نسخه بتا میتوانید به آن دسترسی داشته باشید. علاوه بر اینها در وبسایت هم فونت نقطه را اضافه کردهام که آن را هم میتوانید دانلود کنید.
شرح ویدیوها هم به این گونه است که به کمک فونتفورج یک فونت ساده حاوی دو کاراکتر «الف» و «ب» میسازیم و آن را در سیستم عامل اضافه میکنم و در برنامهی لیبرهآفیس برای تایپ کلمات «بابا» و «مادر» بکار میگیریم.
متاسفانه فرصتی برای ادیت نداشتم و ویدیوها خام هستند. ویدیو اول معرفی است تا جایی که دوستی زنگ زد و مجبور شدم کار را متوقف کنم. ویدیو دوم ادامه ماجرا تا انتهاست. به دلیلی نامعلوم هم در ضبط صدا یک تاخیر ۷۰۰ میلیثانیهای وجود دارد که زحمت بکشید موقع پخش خودتان اصلاح کنید.
ویدیوی اول حاوی معرفی و مقدمات
این هم ویدیوی دوم تا انتهای مطلب
آپدیت: شرمنده به جهت کمتجربگی سمت راست مانیتور در کادر نیفتاده. خوشبختانه اصل ماجرا قابل استفاده است بجز لیبرهافیس که در انتها در پنجره دیده نمیشه که خروج را اسکرینشات گرفتم در زیر قابل دیدن است.
زنده باشید
]]>طی هفته گذشته تقریبا شبانهروز از بیخ و بن مشغول ساختن یک پیکسلفونت جدید و آزاد فارسی بودهام. امروز اصل کار تقریبا تمام شده است. نام این قلم را «نقطه» گذاشتهام.
نقطه به اصطلاح یک پیکسلفونت است. یعنی تمام «گلیفهای» درون فونت از اجزائی شبیه به پیکسل ساخته شدهاند و بنابراین روی صفحههای نمایش قدیمی یا «رترو» بویژه برای بازیهای دوبعدی برای کنسولها به خوبی نمایش داده میشود.
معمولا جواب این پرسش این است: «چرا که نه؟» ولی شرح میدهم. مدتها پیش میخواستم یک صفحهی خطای ۴۰۴ رترو برای وبسایتم بسازم و مدتی پیش هم حین ساختن یک بازی کوچک دوبعدی به جستجوی یک قلم رترو آزاد فارسی برآمدم. اصلا چیزی پیدا نکردم چه برسد به یک فونت آزاد. بنابراین تصمیم گرفتم یکی بسازم.
ایدهی کلیام این بود که مثل حروفچینی و تایپوگرافی سنتی ایرانی یک نقطه را بع عنوان مبدا انتخاب کنم و تمام گلیفها را از روی آن و با کنار هم قرار دادن مربعها بسازم. هرچند حین ساخت پی بردم به دلیل استفاده زیاد از منحنی در الفبای عربی و نیز اتصال گیلفها از هر دو طرف این کار بسیار سخت است. بویژه هنگامی که اعراب وارد معادله میشود، چرا که طراحی آنها با مربع مرجع من به طول ۶۴ نقطه یک چالش جدی است. فعلا برای طراحی اعراب از یک مربع کوچکتر به طول ۳۲ نقطه استفاده کردهام.
با مطالعهی کتاب تایپوگرافی آقای فرشید مثقالی سعی کردم اصولی را در طراحیام رعایت کنم. بویژه استفاده از کرسیهای مشخص برای دندانهها و نقطهها و اعراب و مانند آن. از طرفی در طراحی گلیفها هم تصمیماتی گرفته و سعی کردم در طراحی تمام گلیفها آنها را به صورت یکپارچه راعایت کنم:
۱. ارتفاع تمام گلیفها معمولا حداکثر ۷ بلاک است (هر بلاک ۶۴×۶۴ نقطه است)
۲. هر گلیف آغازی یک بلاک خالی سمت راست دارد
۳. هیچ گلیف میانی بلاک خالی دست راست ندارد
۴. هیچ گلیف بلاک خالی سمت چپ ندارد
۵. هر گلیف میانی موظف است به مقدار کافی از سمت چپ جا رزرو کند (بخاطر قانون ۲)
یادآوری کنم که هر حرف به چهار حالت نیاز دارد: آغازی و میانی و پایانی و منزوی. یعنی چهار گلیف برای هر حرف که جمعا میشود ۱۳۳ گلیف فقط برای حروف الفبا بدون احتساب ارقام و نشانهها.
برای ساخت نقطه از برنامهی FontForge استفاده کردم. از جایی که میدانستم صابر راستیکردار تعداد زیادی قلم با آن طراحی کرده است متقاعد شدم که حتما کار من را هم راه میاندازد! راهنمای صابر را هم برای شروع خواندم که سودمند بود بویژه شرح رفرنسها. برای فهم طرز کار فونتفورج مرتب از کتاب فونتفورج بهره گرفتم که بسیار سودمند بود. همچنین از یک فونت کنسول آزاد ایده گرفتم. همینطور به کرات از مستندات فونتفورج برای فهم عملکرد برنامه و دیالوگهای مختلف آن استفاده کردم. در طراحی هم به وفور از رفرنسها استفاده کردهام تا از تکرار مکررات پرهیز کنم.
بیشتر گلیفهای لازم برای نمایش صحیح نوشتار فارسی و تا حدودی عربی و برخی از گلیفهای اسکی را از میان چهار بلاک یونیکد زیر پیادهسازی کردهام:
Arabic (0600–06FF)
Arabic Presentation Forms-A (FB50–FDFF)
Arabic Presentation Forms-B (FE70–FEFF)
Basic Latin (ASCII) - letters missing
توجه کنید که در حال حاضر نقطه همچنان نیاز به بهینهسازی دارد و در وضعیت بتا است. اشکالاتی وجود دارد که باید برطرف کنم بویژه در اعراب و قرارگیری نقطهها ولی برای استفاده اولیه مناسب است و در بازی کوچکی که دارم میسازم از آن استفاده کردهام. سعی میکنم حروف لاتین را هم به آن اضافه کنم.
سورس نقطه را روی سورسهات منتشر کردهام. سورس تنها یک فایل است بنام noqte.sfd
که میتوانید با سورسفورج باز کنید. فایل ttf نقطه هم از ریپازیتوری قابل دانلود است. اگر سورسفورس را نصب دارید (روی لینوکس و مانند آن) کافیست دستور make
را در فولدر نقطه وارید کنید تا فایل noqte.ttf
ساخته شود. روی لینوکس میتوانید این فایل را در پوشهی ~/.fonts
کپی کنید و بعد با دستور fc-cache -v
کش سیستم را بروز کنید. بعد از آن باید بتوانید آن را در برنامهها ببینید و بکار ببرید. نقطه تحت مجوز آزاد OFL منتشر شده است.
این هم عیدی امسال من به شما.
آپدیت ۲۱ فروردین: افزودن پانگرام با فونت نقطه (جملهای که دربردگیرندهی همهی حروف باشد)
از زمانی که تصمیم به سادهسازی گرفتهام چند ابزار خیلی به کارم آمده است. یکی از آنها GNU Make است که در ادامه شرح میدهم.
کم و بیش طبق شرح وبسایت خودش:
GNU Make ابزاری است که تولید خروجیهای اجرایی و غیراجرایی از سورسهای یک برنامه را کنترل میکند.
اگر سورس برنامهای را دانلود و کامپایل کرده باشید احتمالا به دستوراتی مانند make
و make install
برخورد کردهاید. لازمهی کار کردن این دستورات هم وجود فایلی بنام Makefile
در فولدر مربوطه است.
در حقیقت Make ابزار ساده ایست که میتواند دستوراتی که ما تعریف میکنیم اجرا کند. ما به هر گروه از دستورات یک نام اختصاص میدهیم و Make آنها را اجرا میکند و از خودش چیزی ندارد، حتی دستور install
فقط یک نام سنتی است و باید توسط برنامهساز تعریف شود.
برای استفاده از Make باید تعدادی «قانون» یا Rule داخل فایلی بنام Makefile نوشت. دقت کنید که تورفتگیهای داخل این فایل حتما باید با TAB باشد. ساختار این فایل اینگونه است:
# Rule No 1
target: dependencies ...
commands
...
هر قانون Make از سه بخش تشکیل شده است:
هر Makefile هم میتواند تعداد دلخواهی قانون داشته باشد. وقتی در کامندلاین دستور make
را وارد میکنیم اولین قانون داخل فایل اجرا میشود، فارغ از نام target. از طرفی هم میتوان اسم یک قانون را وارد کرد مثلا make install
، یعنی اجرای قانون install
.
فرض کنید یک فایل C بنام dorood.c
را میخواهیم کامپایل کنیم:
#include <stdio.h>
int main (int argc, char* argv[]) {
puts("Hello World!");
return 0;
}
میتوانیم Makefile زیر را برای برنامهمان بنویسیم:
dorood: dorood.c
gcc -o dorood dorood.c
حالا اگر در کامندلاین make
یا make dorood
وارد کنیم این دستورات اجرا میشوند:
$ make
gcc -o dorood dorood.c
اما اگر دوباره make
وارد کنیم:
$ make
make: 'dorood' is up to date.
چه اتفاقی افتاد؟ Make از کجا فهمید که دستور اجرا شده؟ روش کار ساده است. بار اول فایل خروجی بنام dorood
وجود نداشت پس Make دستور را اجرا کرد. بار دوم اما این فایل ساخته شده بود بنابراین نیازی به اجرای دوبارهی دستور نبود.
حالا بگذارید فایل dorood.c
را تغییر بدهیم و دوباره Make را اجرا کنیم. من اینکار را با تغییر آخرین زمان تغییر این فایل به کمک دستور touch
انجام میدهم:
$ touch dorood.c
$ make
gcc -o dorood dorood.c
اینبار چه شد؟ Make تاریخ آخرین تغییر خروجی را با ورودیها مقایسه میکند. اگر خروجی جدیدتر باشد یعنی همه چیز روبراه است. اگر خروجی قدیمیتر از هر یک از وابستگیها باشد یعنی باید دوباره ساخته شود. به این ترتیب Make در وقت کامپایل صرفهجویی میکند.
همه دستورات هم نیاز نیست مروبط به کامپایل باشند. ما میتوانیم قوانین “phony” داشته باشیم، یعنی «الکی». بیایید یک قانون clean
اضافه کنیم:
.PHONY: clean
dorood: dorood.c
gcc -o dorood dorood.c
clean:
rm dorood
دستورات «الکی» لزومی ندارد سورسکد بخوانند و خروجی بسازند. یعنی Make دنبال فایل ورودی و خروجی برای آنها نمیگردد و اگر دستور بدهیم همیشه اجرا میشوند. مثلا برای پاک کردن خروجیها دستور زیر کافیست:
$ make clean
rm dorood
قوانین Make را میتوان به یکدیگر زنجیر کرد. مثلا فرض کنید ما میخواهیم فایل بالا را در دو مرحله تولید کنیم. اول سورس را کامپیال میکنیم به object file و بعد آن را لینک میکنیم و خروجی اجرایی را میسازیم. برای این منظور یک قانون جدید نیاز داریم:
.PHONY: clean
dorood: dorood.o
gcc -o dorood dorood.o
dorood.o: dorood.c
gcc -c dorood.c
clean:
rm dorood dorood.o
و حالا اجرا:
$ make clean
rm dorood dorood.o
$ make
gcc -c dorood.c
gcc -o dorood dorood.o
به صورت سنتی Make برای کامپایل سورسکد استفاده شده است، هرچند من از Make در هر پروژه برای تجمیع دستورات پراکندهای استفاده میکنم که معمولا باید در هیستوری ترمینالم به دنبال آنها بگردم. مثلا بیایید نگاهی به Makefile ساخت وبسایتم بیندازیم:
DBPATH=mehdix.db
all: build
.PHONY: init serve publish clean
init: init_db
bundle config set path vendor/bundle
bundle install
pip install -r scripts/requirements.txt
build: comments
bundle exec jekyll build
comments:
@echo rebuilding alef comments
python scripts/rebuild_comments.py
serve: build
bundle exec jekyll serve
publish: build
rsync -vr _site/* mehdix.ir:/var/www/mehdix.ir/
clean:
rm -rf _site
rm -rf **/.jekyll-cache
init_db: scripts/schema.sql
sqlite3 ${DBPATH} < scripts/schema.sql
مجال شرح این دستورات نیست، ولی تمام اینها را در دوران پیش از Make در حافظهی ترمینالم جستجو میکردم و گاهی فراموش میکردم. حالا در ابتدای ساخت هر پروژه همواره یک Makefile میسازم که مثل یک اسفنج عمل میکند و تمام دستورات ریز و درشتی که به آن پروژه مربوط است را به تدریج به خودش جذب میکند.
امیدورام مفید فایده شده باشد.
]]>یادتان باشد روز اول خرداد ۱۴۰۰ غزل خداحافظی نتلیفای را خواندیم. از آن روز کامنتدونی تعطیل بود. حالا کامنتدونی با قدرت تمام به صحنه برگشته!
با انتقال وبسایت از سرورهای دیگران به سرور خودم بخش نیمه خودکار و نیمه داینامیک وبسایتم یعنی کامنتدونی از کار افتاد چرا که پیش از این از سرویسهای سرویسدهندهی قبلی برای ثبت فرم HTML کامنت و بیلد سایت استفاده کرده بودم. حالا این بخش را خودم نوشتهام و دوباره راهانداختهام که جلوتر شرح میدهم.
برای راهاندازی نسخهی جدید یک اسکریپت سادهی CGI با Bash نوشتهام و آنرا به کمک وب سرور nginx برای اجرا آماده کردهام. CGI یک روش نسبتا قدیمی اما ساده برای تولید خروجی توسط برنامههای موجود روی سرور است.
یک سرور وب وقتی یک درخواست HTTP دریافت میکند نگاه میکند که آیا آن آدرس یک فایل مثلا index.html
است یا اینکه باید توسط یک برنامه تولید بشود. اگر درخواست برای یک فایل باشد، وب سرور آن فایل را از دیسک میخواند و به براوزر ما تحویل میدهد. براوزر هم آن را نمایش میدهد. تمام صفحات این وبسایت فایلهایی روی هارددیسک سرور من هستند و مستقیما خوانده شده و به درخواستکننده تحویل داده میشود.
اما اگر درخواست برای یک فایل نباشد و یک درخواست داینامیک باشد، وب سرور درخواست را یک پراسس دیگر ارجاع میکند و پاسخ آن پراسس را در نهایت به براوزر ما تحویل میدهد. این وبسایت تنها یک عدد آدرس داینامیک دارد که آنهم به عنوان آدرس فرم HTML کامنتدونی تنظیم شده است. (اگر Ctrl + U را بگیرید میتوانید در سورس وبسایت فرم را ببینید.)
برای ارتباط بین سرور وب و پراسسهای دیگر (مثل پایتون یا PHP و مانند اینها) که به درخواستهای داینامیک رسیدگی میکنند پروتکلهای مختلفی وجود دارد. CGI یکی از این پروتکلهاست.
اما CGI چگونه کار میکند؟ برای فهم روش کار باید بدانیم ورودی و خروجیهای یک پراسس در لینوکس و سیستمهای یونیکسی چگونه است. وقتی سیستم عامل یک پراسس میسازد برای آن سه نوع ورودی و خروجی تعریف میکند. برنامه میتواند از ورودی بخواند و در خروجیها بنویسد. به ترتیب زیر:
مثلا وقتی ما در یک ترمینال مشغول کار با شل هستیم (مثلا Bash یا Zsh) و فرامین مختلف را اجرا میکنیم، ترمینال میتواند در ورودی استاندارد ابزارهای مختلف بنویسید و یا خروجیهای آنها را بخواند. مثلا دستور سادهی ls
که لیستی از یک مسیری در سیستم فایل کامپیوتر به ما نشان میدهد چطور کار میکند؟ ترمینال فرمان را اجرا میکند و ls
هم نتیجه را در خروجی استاندارد مینویسد و ترمینال این خروجی استاندارد را روی صفحه چاپ میکند. اگر خطایی تولید شود ترمینال همین کار را برای خروجی خطا انجام میدهد. برای استفاده موثر از ترمینال باید این مفاهیم و نحوهی کنترل آنها را بلد بود. مثلا به کمک اوپراتور کنترلی |
میتوان در شل لولهکشی کرد! یعنی استاندارد یا خطای یک دستور را به ورودی بعدی وصل کرد و الی آخر. بحث مفصلی است که از حوصلهی این مقاله خارج است.
حالا CGI هم از همین موضوع استفاده میکند. یعنی ما سرور را طوری تنظیم میکنیم که درخواستهایی که به آدرس خاصی ارسال میشود را تحویل بدهد به اسکریپ/برنامهی ما و خروجی استاندارد برنامهی ما را به عنوان نتیجه به بازدیدکننده تحویل بدهد.
اگر درخواست HTTP POST باشد، سرور وب پارامترهای فرم ما را یا به عبارتی همان Query String را در ورودی استاندارد برنامه مینویسد و برنامه باید آن را از آنها بردارد و پردازش بکند. این بسته به هر زبان فرق میکند. اگر درخواست HTTP GET باشد، سرور وب Query String را در یک متغیر محیطی بنام QUERY_STRING مینویسد و برنامه میتواند آن را بخواند و استفاده کند. سایر اطلاعات نیز در متغیرهای محیطی (Environment Variables) نوشته میشوند و برنامه میتواند از آنها استفاده کند. مثلا اگر شما برای این مقاله دیدگاهی بنویسید در خروجی آدرس IP خودتان و نیز USER_AGENT
ارسالی از مرورگرتان را خواهید دید (جواب معما را در فرم غلط بدهید و فرم را سابمیت کنید خودتان میبینید). هر دو اینها از متغیرهای محیطی ارسالی از سرور وب خوانده میشوند که آن هم به نوبهی خود از درخواست شبکهای که به دست آن رسیده است استخراج میشود.
با nginx نمیشود مستقیم یک اسکریپت را اجرا کرد بلکه باید از FastCGI استفاده کرد. علت هم اینست که در CGI اولیه سرور وب میبایست برای هر درخواست وب یک پراسس بسازد و بعد از اجرا آن را نابود کند. این کار هزینهبر است و منابع سرور را هدر میدهد هر چند برای سایتهایی با ترافیک پایین این موضوع اهمیت چندانی ندارد (مگر اینکه به سایت حمله بشود). با FastCGI تعدادی پراسس در پشت صحنه همیشه گوش به زنگ میایستند و وقتی درخواستی آمد یکی از آنها فورا به آن رسیدگی میکند. اما از جایی که من یک اسکرپیت Bash نوشتهام خبری از این قرطیبازیها نیست! برای اینکه اسکریپتهایی مثل اسکرپیت ما را بشود با nginx اجرا کرد برنامهنویسی چیزی نوشته بنام fcgiwrap که به nginx امکان اجرای اسکریپتهای مستقل را میدهد.
تنظیم بلاک cgi در nginx روی سرور اوبونتو خیلی ساده است و زیر آمده است:
location /cgi-bin/ {
gzip off;
fastcgi_pass unix:/run/fcgiwrap.socket;
include /etc/nginx/fastcgi_params;
fastcgi_param ALEF_DB "آدرس فایل بانک داده";
fastcgi_param ALEF_PUZZLE "جواب معما";
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
این بلاک به nginx میگوید که درخواستهایی که زیر آدرس /cgi_bin/
قرار میگیرند را بدهد به سوکت fcgiwrap. دو متغیر محیطی اضافه هم من به آن دادهام که یکی جواب معما است و دیگری آدرس بانک داده. بله یک بانک داده هم داریم…
بالاخره دادهها را باید جایی نوشت. یا در سرور دیگری یا در سرور خودت. اسکریپت ما برای ثبت دیدگاهها از پایگاه دادهی بسیار ساده اما قدرتمند sqlite3 استفاده میکند. این پایگاه داده از فرط سادگی نیازی به runtime ندارد. یعنی نیازی نیست که برنامهای در حال اجرا باشد تا بتوان از آن استفاده کرد. تا حجم عظیمی داده را هم میتواند در خودش ذخیره کند. مادامی که ما به محدودیتهایش احترام بگذاریم، یعنی سعی نکنیم همزمان از چند جای مختلف در پایگاه داده چیزی بنویسیم. البته اسکریپت ما هنوز جلوی اینکار را نمیگیرد (انصافا احتمالش خیلی کم است). با اضافه کردن یک Lock مثلا Semaphore یا حتی یک فایل موقتی میشود آن مشکل را رفع کرد. میگذاریمش برای بعد.
ما یک جدول ساده لازم داریم که میسازیم و همزمان به خورد برنامهی sqlite3 میدهیم (همه اینها در Makefile هست):
cat <<EOF | sqlite3 "$ALEF_DB"
CREATE TABLE IF NOT EXISTS comments (
-- A unique ID for each comment
id INTEGER PRIMARY KEY AUTOINCREMENT,
-- ISO8601 strings with UTC/zulu timezone, try date --iso-8601=seconds --utc
time TEXT NOT NULL,
-- Comment author's name
name TEXT NOT NULL,
-- Comment author's email
email TEXT NOT NULL,
-- The page where the comment belongs to
page_id TEXT NOT NULL,
-- The ID of a parent comment
reply_to TEXT,
-- Some URL
website TEXT,
-- Whether this is a spam (wrong puzzle answer)
spam INTEGER NOT NULL,
-- The body of the comment
message TEXT NOT NULL
);
EOF
به این روش خوراندن یک متن چند خطی به یک برنامه میگویند heredocs. (از طریق ورودی استاندارد! بعله!) همانطور که میبینید تعدادی فیلد داریم که برای ثبت یک دیدگاه ضروری است.
اگر به اسکریپت submit هم نظری بیفکنیم میبینیم که کارهای زیر را در Bash انجام میدهد:
&
از هم جدا شدهاند)این اسکریپت نکات زیادی دارد که هر کدام مقالهای برای خودش میطلبد. فقط بگویم که هرچه echo
میکنیم در خروجی استاندارد نوشته میشود و درنهایت به کاربر ارسال میشود و آنچه echo
شده اما یک >&2
در آخر خط دارد در خروجی خطا نوشته میشود و به بازدیدکننده ارسال نمیشود (بلکه در لاگهای سرور نوشته میشود که بنده میروم میخوانم :)).
این اسکرپیت کاستی زیاد دارد. مثلا چک نمیکند که پیام تکراری است یا اسپم را بررسی نمیکند (بجز اینکه جواب معما درست باشد) و حتی ممکن است نقطه ضعف امنیتی داشته باشد. هرچند کاربر اجرا کنندهی این اسکریپت روی سرور به همین منظور کاربر محدودی است. ولی کار را انجام میدهد.
خلاصه با این مقدمهی طولانی خواستم بگویم که کامنتدونی برگشته است و از نظرات شما استقبال میکند! من بخش نظرات وبسایت را محلی برای تعامل جمیع خوانندگان و خودم در نظرم میگیرم نه محلی برای دیالوگ فقط بین نویسنده و خواننده. بنابراین اگر جوابی برای سوال دیگری داشتید بنویسید و از سوال هم نهراسید!
]]>من یک گوشی گلکسی ۸ سامسونگ دارم که از ژانویه ۲۰۲۰ آپدیت نشده است و حداقل برای رفع باگهای امنیتی که در این فاصله ترمیم شدهاند وقت خانهتکانیاش رسیده است. در ادامه آن را بروز و روت میکنیم و F-Droid و برنامههای بانکی و سایر چیزهای مفید و آزاد را هم روی آن نصب میکنیم.
علت آپدیت نبودن اینست که گوشی من روت است و بنابراین آپدیتهای OTA را دریافت نمیکند. البته آپدیت خاصی هم دیگر براش وجود ندارد چرا که آخرین آپدیت حاوی پچ امنیتی سامسونگ برایش در آوریل ۲۰۲۱ بوده است که به همان نسخه ارتقا میدهیم. در این مقاله گوشی را آپدیت و دوباره روت میکنم. بعد هم تنظیمات معمول شامل سینک را هم انجام میدهم و اپها را هم معرفی و شرح میدهم.
فقط بخاطر داشته باشید که همهی این پیچیدگیها که در ادامه خواهیم دید به خاطر سیستمی است که میخواهد به کمک قفلهای سختافزاری و Secure Boot و غیره دستهای کاربر را ببندد و قدرت را در دست تولیدکنندههای غولپیکری مثل سامسونگ و گوگل و مانند اینها نگاه دارد. به همین خاطر من از پروژههای آزادی مانند PinePhone حمایت میکنم و در آینده سویچ میکنم (امروز هم سالهاست که از دیگر از سرویسهای سامسونگ و گوگل و مانند آنها استفاده نمیکنم و اکثر نیازهام با F-Droid و Syncthing و Decsync برآورده میشود).
هشدار: در ادامه معمولا اطلاعات روی گوشی کامل پاک میشود.
در طول مقاله از برنامههای اوپن سورس و آزاد مختلفی استفاده میکنیم که شرح خواهم داد. سیستم عامل هم آرچ لینوکس است و شل هم bash. پیش از هرچیز باید Android Debug Bridge یا همان adb را نصب داشت که من پیشتر نصب کردهام. adb devices
هم باید گوشی را وقتی با کابل USB به دستگاه وصل است نشان بدهد. برای اینکار باید USB Debugging در تنظیمات برنامنویس یا Developer Options گوشی فعال باشد. خود Developer Option هم وقتی ظاهر میشود که در تنظیمات اندروید روی Build Number چند بار پشت سر هم کلیک کنید. بعد از اینکار و بعد با اتصال کابل USB و اجرای adb یک پنجره روی گوشی ظاهر میشود و میپرسد که آیا به این کامپیوتر اعتماد میکنیم یا نه. با اعتماد به کامپیوتر میتوانیم ادامه بدهیم. (در اسکرینشاتها میتوانید این مراحل را ببینید، زبان گوشی آلمانی است ولی به نظرم واضح است که منظور چیست.)
تا حالا کسی را دیدهاید که افسوس بخورد چرا از عکسها و پیغامهایش بکآپ گرفته است؟ من که ندیدهام. اما برعکسش را زیاد دیدهام. پس اول به هر روشی که بلد هستید اطلاعات ارزشمند خود را از گوشی بیرون بکشید. من برنامههای مهم را جداگانه و بعد اسدی کارت را با adb روی کامپیوترم کپی کردم.
به چند روش میشود بکآپ گرفت، یکی به کمک adb است:
$ adb pull sdcard
به کمک adb همچنین میتوان اپها و دادههایشان را کپی کرد البته بجز اپهایی که نمیخواهند دادههایشان بکآپ گرفته شود (مثل سیگنال). برخی اپها هم حتی اگر با روت از آنها بزور بکاپ گرفته شود و روی یک گوشی جدید بازگردانده بشود باز هم کار نخواهند کرد، چرا که کلیدهای سری آنها درون سیپییو نگهداری میشود و قابل بکآپ گرفت نیست (باز هم مثل سیگنال).
$ for APP in $(adb shell pm list packages -3 -f); do adb pull $( echo ${APP} | sed "s/^package://" | sed "s/base.apk=/base.apk /").apk; done این دستور اول لیست پکیجها را از گوشی میگیرد و بعد یکی یکی آنها را داخل یک حلقه دانلود میکند.
میشود یکجا هم بکآپ گرفت و بعد اکسپورت کرد:
$ adb backup -f backup.adb -all -apk -nosystem
$ dd if=backup.adb bs=24 skip=1 | zlib-flate -uncompress | tar xf -
ظاهرا بکآپ کلی adb فرمت خاصی دارد که به طریق بالا میتوان آن را باز کرد. جزئیاتش زیاد مهم نیست. مهم اینست که از این طریق بسیاری برنامهها بکآپ گرفته نمیشوند و باید برنامههای مهم را یا از خود برنامه یا از طریق اپهای دیگر بکآپ گرفت. شرح بیشتر در این جیست گیتهاب.
من از oandbackupx استفاده کردم و برنامهها را روی کارتحافظه بکآپ گرفتم.
به کمک اپ Smart Switch سامسونگ هم میتوان از بسیاری چیزها مخصوصا تنظیمات دسکتاپ و هیستوری تماسها و این قبیل چیزها روی کارت حافظه بکآپ گرفت. روی اکانت سامسونگ هم میشود که من با این اپ استفاده نکردم. کافیست یک کارت حافظه اضافی یا یک فلشدیسک به گوشی وصل بکنید و در صفحهی اصلی برنامه عکس کارتحافظه را لمس کنید. ادامهی کار آسان است. برنامه به من خطای نبود حافظهی کافی میداد که دسته آخر معلوم شد بخاطر کارتحافظه بود که بعد از فرمت کردن آن مشکل رفع شد.
من با برنامهی oandbackupx به کمک روت از همهی اپها و دادههایشان بکآپ گرفته بودم. متاسفانه نتیجه بدردبخور نبود. از طرفی پسورد بکآپ را ظاهرا فراموش کرده بودم (یه اصلا برنامه درست کار نکرد) و از طرف دیگر برنامه با تعداد بالای اپها مشکل جدی دارد. رابط کاربری هم ضعیف است، مثلا من به اشتباه اپهای سیستم را بازگردانی کردم که منجر به خراب شدن تنظیمات و بلوتوث گوشی شد و برنامه هم هیچ هشداری نداد (مجبور شدم پارتیشن سیستم را مجددا فلش بکنم). توصیه میکنم به این برنامه تکیه نکنید یا حتما بکآپ را تست بکنید.
از برخی اپهای مهم هم میتوان جدا جدا نسخهی پشتیبان تهیه کرد. برای مثال:
ناگفته پیداست که باید بکآپ را از گوشی به یک حافظهی جانبی منتقل کرد (مثلا به کمک Syncthing) و آن را امتحان کرد.
بکآپی که تست نشده است همانند بکآپی است که اصلا وجود ندارد.
با پشت سر گذاشتن مقدمات میرویم سروقت آپدیت.
آخرین آپدیت سامسونگ برای گوشی من را میتوان در اینترنت پیدا کرد ولی از همه بهتر دانلود مستقیم از سرورهای آپدیت خود سامسونگ است. برای اینکار از ابزار خوب samloader استفاده میکنیم.
برای استفاده از samloader باید مدل گوشی و کد CSC منطقهی دلخواهمان را بدانیم. مدل رسمی گوشی من SM-G950F است. سامسونگ این گوشی را با دو چیپ مختلف تولید و عرضه کرده است: Snapdragon و Exynos. گوشی من Exynos است. کد CSC یعنی Country Specific Code. من کد آلمان را پیدا کردم که DBT است. در گوشی بخش تنظیمات نرمافزاری هم کد CSC گوشی قابل رؤیت است.
بعد از پیدا کردن اینها میتوانیم چک کنیم چه آپدیتهایی برای این گوشی و این منطقه وجود دارد:
$ samloader -m SM-G950F -r DBT checkupdate
G950FXXUCDUD1/G950FOXMCDUD1/G950FXXUCDUD1/G950FXXUCDUD1
و حالا دانلود:
$ samloader -m SM-G950F -r DBT download -v 'G950FXXUCDUD1/G950FOXMCDUD1/G950FXXUCDUD1/G950FXXUCDUD1' -O .
و بعد باز کردن قفل:
$ samloader -m SM-G950F -r DBT decrypt -v 'G950FXXUCDUD1/G950FOXMCDUD1/G950FXXUCDUD1/G950FXXUCDUD1' -i SM-G950F_1_20210407122336_qro5zx59p1_fac.zip.enc4 -o SM-G950F_1_20210407122336_qro5zx59p1_fac.zip
و در نهایت بازکردن فایل زیپ:
$ unzip SM-G950F_1_20210407122336_qro5zx59p1_fac.zip
$ ls
SM-G950F_1_20210407122336_qro5zx59p1_fac.zip.enc4
AP_G950FXXUCDUD1_CL21427293_QB39365966_REV00_user_low_ship_meta_OS9.tar.md5
BL_G950FXXUCDUD1_CL21427293_QB39365966_REV00_user_low_ship.tar.md5
CP_G950FXXUCDUD1_CP18734711_CL21427293_QB39365966_REV00_user_low_ship.tar.md5
CSC_OXM_G950FOXMCDUD1_CL21427293_QB39365966_REV00_user_low_ship.tar.md5
HOME_CSC_OXM_G950FOXMCDUD1_CL21427293_QB39365966_REV00_user_low_ship.tar.md5
SM-G950F_1_20210407122336_qro5zx59p1_fac.zip
این فایلهایی پارتیشنهای مختلفی هستند که ما در ادامه روی گوشی فلش میکنیم. البته بد نیست بدانیم که میشود این فایلها را باز کرد و محتوای آنها را تغییر داد که البته در این مورد امتحان نکردهام (ممکن است بوت نشود).
گوشی را با کابل USB به کامپیوتر متصل میکنیم و میرویم سروقت فلش.
برای اینکه بتوان یک گوشی اندرویدی را فلش کرد باید قفل bootloader را باز کرد. برای اینکار باید از منوی تنظیمات برنامهنویس گزینه OEM Unlocking را فعال کرد. در برخی گوشیها این گزینه وجود ندارد که باید در اینترنت گشت فهمید چرا.
در مورد گوشی گلکسی ۸ برایم جالب بود که این گزینه وقتی گوشی را برای اولین بار روشن میکنید غیرفعال است تا زمانی که به وایفای وصل بشویم که بعد از اتصال با سرور سامسونگ و احتمالا بررسی اینکه گوشی به صورت آنلاک فروخته شده است باز میشود. این واقعا جای تاسف است که یک گوشی که در زمان خودش گرانقیمت محسوب میشد هنوز هم در چنگال تولیدکننده است و نشان از اهمیت پروژههایی مثل Pinephone دارد که در تلاشند یک گوشی با سختافزار و نرمافزار آزاد در اختیار ما بگذارند (دقیقا به همین خاطر و برای پشتیبانی از پروژههای Pine64 مدتهاتس که یک گوشی Pinephone سفارش دادهام که اگر اجل امانم دهد دربارهاش مینویسم).
برای فلش کردن گوشیهای اندرویدی اغلب از برنامهی Odin استفاده میشود. این برنامه آزاد و همگانی نیست بلکه از سامسونگ نشت کرده است. من برای فلش کردن از ابزار آزاد Heimdall استفاده میکنم که برای گوشیهای گلکسی نوشته شده است. این برنامه نسخهی گرافیکی هم دارد ولی برای کار ما فقط نسخهی ترمینال کفایت میکند. (نسخهی گرافیکی heimdall-frontend نام دارد و به فایل pit که پایینتر دانلود خواهیم کرد برای فلش کردن نیاز دارد.)
در مرحلهی بعدی باید گوشی را وارد Download Mode کرد. توضیح مختصر اینکه گوشیهای اندرویدی دو وضعیت Recovery و Fastboot دارند. Recovery مثل یک سیستم عامل کوچک است (یک پارتیشن مجزا هم برای خودش دارد) که میتوان از آن برای بک آپ گرفتن و نصب آپدیت و آپگرید و نصب ROM یا فرمت پارتیشنها و این قبیل کارها استفاده کرده. Fastboot هم برای ظاهرا برای فلش کردن مستقیم پارتیشنها و حتی تغییر پارتیشنبندی است. اما گوشیهای سامسونگ بجای Fastboot چیزی به نام Download mode دارند که برای فلش کردن گوشی است. به چند طریق میتوان وارد دانلود مود شد. اگر گوشی قبلا برای adb تنظیم شده (شرح آن پیشتر رفت) میتوان فرمان زیر را بکار برد:
$ adb reboot download
راه دیگر هم روشن کردن گوشی است با فشار همزان کلیدهای Volume Down + Bixby + Power. ممکن است موقع شروع گوشی برای ورود تاییدیه بخواهد که فشردن کلید Volume Up است.
حالا که مقدمات را پشت سر گذاشتیم و از سیر تا پیاز گوشی هم بکآپ گرفتهایم (آن درد کشیدهها میفهمند چرا!) وقت فلش کردن است. اول چک میکنیم که گوشی در دسترس است یا نه:
$ heimdall detect
Device detected
برای اطمینان از جدول پارتیشنهای گوشی هم یک بکاپ میگیرم، یکبار به صورت باینری و یکبار متنی:
$ heimdall download-pit --output sm-g950f.pit --no-reboot
Heimdall v1.4.2
Copyright (c) 2010-2017 Benjamin Dobell, Glass Echidna
http://www.glassechidna.com.au/
This software is provided free of charge. Copying and redistribution is
encouraged.
If you appreciate this software and you would like to support future
development please consider donating:
http://www.glassechidna.com.au/donate/
Initialising connection...
Detecting device...
Claiming interface...
Setting up interface...
Initialising protocol...
Protocol initialisation successful.
Beginning session...
Some devices may take up to 2 minutes to respond.
Please be patient!
Session begun.
Downloading device's PIT file...
PIT file download successful.
Ending session...
Releasing device interface...
$ heimdall print-pit --no-reboot > sm-g950f_text.pit
حسن بکاپ دوم (متنی) اینست که داخل آن میشود اسم پارتیشنها و نام معمول فایل آنها را که برای فلش با heimdall لازم است پیدا کرد.
بستهای که قبلا دانلود کردیم حاوی تعدادی ایمیج است شامل: AP و BL و CP و CSC_OXM و HOME_CSC_OXM. فرق CSC_OXM و HOME_CSC_OXM هم در این است که دومی را اگر فلش کنیم اندروید بعد از نصب فایلهای داخل کارت حافظهی داخلیاش را پاک نمیکند. در جایی هم خواندم که آنها که پسوند OXM دارند Multi-CSC خوانده میشوند و کد کشور را از سیمکارت میگیرند.
برای فلش کردن با Heimdall بر خلاف Odin باید همهی این فایلها را باز کرد و پارتیشنها را یک به یک فلش کرد. پس ما فایلهای بالا را به همراه HOME_CSC_OXM به یک فولدر جدید کپی و باز میکنیم:
$ for i in $(ls *.tar.md5); do tar xvf "$i"; done
$ for i in $(ls *.lz4); do unlz4 "$i"; done
$ rm *.tar.md5 *.lz4
$ ls
meta-data cm.bin modem.bin modem_debug.bin param.bin sboot.bin up_param.bin boot.img cache.img recovery.img system.img userdata.img
حالا که فایلها را داریم وقت فلش کردن است. اسم پارتیشنها را از فایل sm-g950f_text.pit
استخراج میکنیم و فرمان زیر را اجرا میکنیم:
$ heimdall flash --CM cm.bin --PARAM param.bin --UP_PARAM up_param.bin --BOOT boot.img --CACHE cache.img --SYSTEM system.img --USERDATA userdata.img
میشد فرمان زیر را هم اجرا کرد ولی من نخواستم همهی پارتیشنها را جایگزین کنم تا از مشکلات احتمالی جلوگیری کنم. تصمیم گرفتم اگر فرمان قبلی کار نکرد همه را فلش کنم که البته مشکلی پیش نیامد.
$ heimdall flash --CM cm.bin --RADIO modem.bin --CP_DEBUG modem_debug.bin --PARAM param.bin --BOOTLOADER sboot.bin --UP_PARAM up_param.bin --BOOT boot.img --CACHE cache.img --RECOVERY recovery.img --SYSTEM system.img --USERDATA userdata.img
گوشی را ریبوت کردم و خوشبختانه بی درسر بود شد. البته اول وارد ریکاوری شد که ریستارت کردم. انتظار داشتم که کارت حافظهی داخلی پاک نشده باشد که شده بود. بهرحال آپدیت درست انجام شد.
پینوشت برای این بخش: البته که عشق آسان نمود اول ولی افتاد مشکلها! بعد از فلش متوجه شدم که سایز کارتحافظه از ۶۴ به ۱۶ کاهش پیدا کرده که احتمالا به خاطر اشتباه بودن سایز ایمیج HOME_CSC_OXM بود. با فلش ایمیج داخل CSC_OXM این مشکل رفع شد. مشکلات دیگری هم در میانهی کار پیشآمد که باعث شد LineageOS روی گوشی بریزم که خیلی خوب کار کرد و برخلاف سیستم سامسونگ هیچ چیز بیهودهای داخلش وجود ندارد (سامسونگ برنامههای خودش و گوگل و فیسبوک و خیلیهای دیگر را پیشفرض نصب میکند که برای من فقط زحمت حذف آنها باقی میماند). ولی فعلا آمادگی سویچ به یک محیط کاملا جدید را نداشتم چرا که با گرافیک گلکسی (One UI 1.0) فعلی خیلی راحتم و کارم راه میافتد. بنابراین با همان سامسونگ ادامه میدهیم (من همیشه اپهای اضافه را غیرفعال میکنم یا با برنامههای روت کاملا حذف میکنم).
تا اینجا گوشی آپدیت شده و در حال تنظیمات کارخانه است. از جایی که همه چیز ریست شده است دوباره تنظمات برنامهنویس را که پیشتر دیدیم فعال میکنیم و بعد هم USB Debugging را و ورود به دانلود مود و درنهایت میرویسم سروقت روت کردن گوشی.
من گوشی را روت میکنم تا بتوانم نرمافزارهای زورکی سامسونگ و گوگل و مانند اینها را از رام گوشی حذف کنم. علاوه بر این میخواهم برنامهی AdAway را نصب کنم تا درخواستهایی که به دامینهای تبلیغاتی و ترکینگ و مانند اینها ارسال میشود از بیخ بلاک شوند. اینکار فقط با روت امکانپذیر است. از طرفی با روت گوشی نرمافزارهای بانکی از کار میافتند که در ادامه شرح میدهیم چطور آنها را دوباره فعال کنیم. هرچند بخاطر داشته باشید که روت گوشی کار خطرناکی است. هر برنامهای که دسترسی روت داشته باشد میتواند همهی سیستم را تغییر بدهد. گوشی من گارانتی ندارد و من هم از برنامههای روت استفادهی چندانی جز آنچه گفتم نمیکنم و به برنامههای رندوم و ناشناخته هم هیچگونه دسترسی چه روت و غیر روت نمیدهم. (اصلا نصبشان نمیکنم!) بنابراین با مسئولیت خودتان ادامه بدهید . و البته به خاطر داشته باشید که با کمک امکانات سختافزاری تعبیه شده در چیپ گوشی هر برنامهای که اراده بکند میتوان به کمک سرویسهای گوگل از روت بودن گوشی مطلع بشود. منتها این را باید گوگل فعال بکند که تا به امروز اینکار را نکرده.
هر برنامهای که دسترسی روت داشته باشد میتواند همهی سیستم را تغییر بدهد.
برای روت گوشی نیاز است ریکاوری سامسونگ را با TWRP جایگزین کنیم چرا که ریکاوری پیشفرض سامسونگ کار بدرد ما نمیخورد. اول باید ریکاوری مناسب گوشی را پیدا کرد. من از سایت twrp.me و بخش مخصوص گلکسی ۸ ریکاوری مخصوص گلکسی ۸ را دریافت کردم (این سایت متاسفانه پر از تبلیغات است، نصب ublock را فراموش نکنید). البته میشود ریکاوری را بیلد کنیم که کار پرزحمت اما مطمئنتری است. فکر میکنم بدون ریکاوری هم میشود به کمک adb در مود دانلود کرنل را عوض کرد و گوشی را روت کرد اما درست و حسابی امتحانش نکردهام. در آنصورت اصلا نیازی به TWRP نخواهد بود.
نرمافزار پیشفرض سامسونگ اگر تشخیص بدهد که ریکاوری دیگری بجز سامسونگ نصب شده است آن را حذف میکند و ریکاوری خودش را جایگزین میکند. (بالا گفتم که این پدرسوختهبازیها مال سیستمهای بستهای مثل این گوشی است که امیدوارم در آینده از شر آنها خلاص بشویم.) به همین خاطر نصب ریکاوری کمی دردسرساز است. با Heimdall باید ریکاوری را نصب کنیم ولی موقع ریبوت باید فورا کلیدهای Volume Up + Bixby + Power را همزمان فشار دهیم تا ریکاوری لود شود در غیر اینصورت بعد از سیستم آن را حذف میکند:
$ adb reboot download
$ heimdall flash --no-reboot --RECOVERY ~/Downloads/twrp-3.5.2_9-0-dreamlte.img
Heimdall v1.4.2
Copyright (c) 2010-2017 Benjamin Dobell, Glass Echidna
http://www.glassechidna.com.au/
This software is provided free of charge. Copying and redistribution is
encouraged.
If you appreciate this software and you would like to support future
development please consider donating:
http://www.glassechidna.com.au/donate/
Initialising connection...
Detecting device...
Claiming interface...
Setting up interface...
Initialising protocol...
Protocol initialisation successful.
Beginning session...
Some devices may take up to 2 minutes to respond.
Please be patient!
Session begun.
Downloading device's PIT file...
PIT file download successful.
Uploading RECOVERY
100%
RECOVERY upload successful
Ending session...
Releasing device interface...
بعد از ریبوت مجدد به ریکاوری باید به TWRP اجازهی تغییر سیستم را بدهیم تا جلوی حذف شدن خودش به دست سامسونگ را بگیرد. البته به همین سادگی نیست. (بار اول خودش میپرسد که اینکار را بکند یا نه) TWRP میتواند جلوی حذف شدن خودش را بگیرد اما برخی گوشیها مثل این گوشی از dm-verify استفاده میکنند که یک قابلیت از کرنل لینوکس است برای کشف دستکاری و تغییر در فایلسیستم. سامسونگ و دوستان از این فیچر برای کشف تغییر در پارتیشنهای پیشفرض سیستم و حذف ریکاوری و مانند اینها استفاده میکنند، بله بر علیه ما کاربران! بنابراین ما مجبوریم بر علیه این ضدفیچر هم یک هک دیگر بکار ببریم و این کنترل را از کار بیندازیم. به این منظور باید یک پچ را دانلود و همزمان که به طور موقتی در ریکاوری هستیم آن را نصب کنیم. من پچ Disable_Dm-Verity_ForceEncrypt را دانلود کردم (این لینک یک کپی است) کد آن را خواندم، چیز خطرناکی داخلش ندیدم. کافیست محتوای ریپازیتوری را زیپ کنیم (ساختار فایلها مطابق یک بستهی قابل فلش کردن اندرویدی است، بیشتر نمیدانم) و روی گوشی کپی کنیم. میشود از داخل ریپازیتوری فایل را کپی کرد:
$ adb push Disable_Dm-Verity_ForceEncrypt_quota_11.02.2020.zip /sdcard/
اسم فایل مهم است. اسکریپت درون این بسته از روی اسم فایل میفهمد چه چیزهایی را غیرفعال کند. بعد از کپی کافی است از منوی Install ریکاوری فایل را انتخاب و اعمال و بعد ریبوت کنیم.
پسنوشت: من بار اول که وارد ریکاوری شدم به TWRP اجازه دادم پارتیشن سیستم من را تغییر بدهد تا جلوی حذف خودش را بگیرد. بدون اپلای پچ بالا ریبوت کردم و گوشی داخل boot-loop گرفتار شد. با اپلای پچ مشکل رفع شد.
حالا بالاخره میرویم سروقت روت کردن.
برای روت گوشی ما از Magisk استفاده میکنیم که ایمج بوت گوشی را پچ میکند و بدون تغییر پارتیشن سیستم دسترسی روت برایمان فراهم میکند و امکان کور کردن اپها را میدهد تا از روت شدن گوشی مطلع نشوند. ماژولهای مختلفی هم دارد برای اعمال تغییرات خاص روی گوشی که برای روت نیازی به آنها نیست.
آخرین نسخه را از روی گیتهاب مجیسک میگیریم (هنگام نوشتن v23.0) و روی گوشی مثل قبل کپی میکنیم (یا در حالت ریکاوری با adb push Magisk-v23.0.apk /sdcard/
). حالا کافیست وارد ریکاوری بشویم و این فایل را نصب کنیم (بله همین فایل با پسوند apk را). همانند قبل در بخش Install ریکاوری فایل را انتخاب و اعمال میکنیم و بعد ریبوت.
بعد از ریبوت از داخل گوشی هم همین فایل را دوباره نصب میکنیم تا اپ MagiskManager به گوشی اضافه شود. داخل آن میتوانیم وضعیت روت را بررسی کنیم و MagiskHide را فعال کنیم یا ماژولهای مختلف را به گوشی اضافه کنیم. من بیش از این آن را شرح نمیدهم که از حوصلهی این نوشته خارج میشود. اطلاعات بیشتر و کلی عکس روی سایت magiskmanager.
تا اینجا گوشی را روت کردیم اما این برای استفاده از برنامههای بانکی و مانند اینها کافی نیست (مثلا اپ موبیلت بانک سامان). این قبیل برنامهها از API مخصوص امنیت در اندروید بنام SafetyNet API استفاده میکنند که به برنامه میگوید که آیا گوشی دستکاری شده است یا نه. در حال حاضر به کمک مجیسک میشود اندروید را فریب داد چرا که این فیچر نرمافزاری است. هرچند به محض اینکه گوگل اراده بکند میتواند از قابلیتهای امنیتی موجود در پردازندههای موجود آرم استفاده کند و به کمک سختافزار این موضوع را کنترل کند که در آن صورت هنوز راهی برای فرار از این موضوع پیدا نشده است. معنایش اینست که اگر گوشی از سختافزار برای کنترل روت استفاده کند راهی برای فریب برنامههایی که از این API استفاده کنند وجود ندارد. بعضی برنامهها هم چک میکنند که آیا مجیسک روی گوشی وجود دارد یا نه (باز هم موبیلت) که البته با تغییر نام پکیج مجیسک از داخل خود اپ این مشکل حل میشود.
در گذشته با نصب مجیسک این تستها هم پاس میشد ولی اینبار Basic Attestation و ctsProfile پاس نشدند (اسمی که اپ مجیسک برای این کنترلها بکار میبرد). با مقداری تحقیق متوجه شدم که به کمک MagiskHidePropsConf مشکل حل میشود (این هم یک کپی است). البته اگر SafetyNet Test داخل اپ مجیسک پاس شد نیازی به اینکار نیست. به هرحال روش کار اینطور است:
su
و اجازهی روت موقتی به ترموکسprops
با اجرای این مراحل SafetyNet Test هم پاس شد.
این گوشی یک دگمهی خوب اما بیمصرف دارد که فقط تبلیغات سامسونگ را باز میکند. من دوست دارم وقتی این دگمه را میفشارم از صفحه یک اسکرینشات گرفته شود. این کار هم فقط با روت امکانپذیر است. از روی کامپیوتر یا داخل ترموکس:
$ adb shell
$ su
# [mount] -o rw,remount /system
# cd /system/usr/keylayout
# # now replace WINK mit [SYSRQ]
# sed -i "s/WINK/SYSRQ/" Generic.kl
# reboot
اگر همه چیز درست پیش رفته باشد (که برای من نرفت!) یک گوشی گلکسی ۸ روت با اندروید ۹ داریم که خالی است. حالا کافیست بکآپ را بازگردانی بکنیم و اپها را دوباره نصب کنیم. البته احتمالا اگر آن بالا پارتیشن userdata را فلش نمیکردیم و اپلای کردن پچ dm-verify هم فراموش نشده بود دادهها حذف نمیشدند. (پارتیشن userdata حاولی اپها و اطلاعات کاربر است، اپهای سیستم روی پارتیشن system هستند.)
پسنوشت: در ابتدای مقاله گفتم که بازگردانی دادهها و نصب اپهای بانکی را هم انجام میدهیم اما سخن به درازا کشید و به آنجا نرسیدیم. اجل امان دهد در مطلبی دیگر :)
]]>در این پست شرح میدهم چطور به همراه شایگان یک کامپیوتر فسقلی با صفحه لمسی و بلندگوی توکار در ابعاد بسیار کوچک ساختیم تا آن را به دوستش هدیه بدهد. از جایی که این مقاله بسیار طولانی است، جایی را بخوانید که بدرد کارتان میخورد.
ماجرا از آنجا شروع شد که شایگان با من برای ساخت و سرهم کردن یک کامپیوتر کوچک و نسبتا ارزان مبتنی بر رزبریپای تماس گرفت. ایدهاش این بود که این کامپیوتر به محض روشن شدن تصویر گیف آلبوم صوتی مورد علاقه دوستش را، در حالی که همزمان تعدادی ترانه از آن آلبوم را پخش میکند، به صورت تمامصفحه نمایش بدهد. بله، باید یک کامپیوتر میساختیم! برای اینکار به دو چیز احتیاج داشتیم: سختافزار و نرمافزار. چالش اصلی انتخاب و تهیه و ساخت و مونتاژ قطعات اصلی بود. پس اول میپردازیم به سختافزار.
کاور آلبوم رنگی
همچنان که در اینترنت در جستجوی ایدههای مشابه بودیم به پروژهای به نام تاینی مک یعنی «مک فسقلی» از اوستاکاری بنام «cgenco» رسیدیم و تصمیم گرفتیم آن را الگو قرار دهیم. cgenco یک رزبریپای زیرو و یک صفحهی نمایش لمسی را برای ساخت یک کامپیوتر مکینتاش کوچک بکار برده است. او برای اینکار یک بدنهی عالی با نهایت ظرافت و توجه به جزئیات طراحی کرده است. او در نهایت یک شبیهساز مکینتاش هم روی رزبریپای زیرو نصب میکند و به یک مکینتاش کوچک میرسد. برای پخش صدا هم از یک اسپیکر خارجی بلوتوث استفاده میکند. ما سختافزار او را الگو قرار دادیم و تغییراتی در آن ایجاد کردیم. از جمله افزودن مدار فیلتر صوتی و یک جک ۳.۵ میلیمتری صوتی و یک پیج کم و زیاد کردن صدا و یک جفت اسپیکر توکار. با این اوصاف کامپیوتر کوچک ما چند بخش کوچک و ارزان لازم داشت:
ما تصمیم گرفتیم که از رزبریپای برای بورد اصلی استفاده کنیم چون کامیونیتی بزرگی دارد و پیدا کردن اطلاعات و نمونهها و قطعات لازم سادهتر است. شرکت سازندهی رزبریپای مدلهای مختلفی از کامپیوترهای تکبورد با امکانات مختلف تولید میکند. از جایی که همهی این کامپیوترها میتوانند آنچه ما میخواهیم انجام بدهند ما کوچکترین و ارزانترین عضو خانواده یعنی رزبریپای زیرو را انتخاب کردیم. صفحهی نمایش را از چین سفارش دادیم و یک جفت اسپیکر هم دوست و همکارم فدریکو، وقتی داشتیم راجع به نحوهی کار فیلترهای صوتی صحبت میکردیم در اختیارم گذاشت. کارت حافظه خودم داشتم. مدار فیلتر صوتی را ساختم و بدنه را هم با چاپگر سه بعدی چاپ کردم. جزئیات را در ادامه شرح میدهم که قصه طولانی است.
وقتی نوجوان بودم خیلی دوست داشتم که یک کامپیوتر کوچک داشته باشم و آنرا جایی در خانه روی دیوار نصب کنم و همیشه روشن بگذارم و بتوانم از آن به عنوان یک ایستگاه کنترل از راه دور استفاده کنم. آنزمان اما کامپیوترها بزرگ و حجیم و پرمصرف بودند و امکان اتصال آنها به سیستمهای برقی دیگر وجود نداشت یا خیلی گران بود. مثلا تصور کنید که میخواهیم یک لامپ را با کامپیوتر روشن و خاموش کنیم. چطور میتوانستم آن را به یک کامپیوتر وصل کنم؟ نمیدانم. شاید از طریقی میشد ولی امکانش برای من نوجوان وجود نداشت، آنهم با جیبهای خالی.
حتی امروز هم اینکار با کامپیوترهای خانگی معمولی سخت است. این کامپیوترها پورتهای USB و شبکه و گرافیک دارند و حتی دیگر از پورتهای سریال برای دستگاههای قدیمی خبری نیست. این کامپیوترها برای سرگرمی و کارهای رایج خانگی و اداری ساخته شدهاند. برق مصرفی آنها هم بیش از آنست که شبانه روز روشن بمانند یا شاید سر و صدای فن کامپیوتر مانع روشن گذاشتن آن بشود.
اما امروزه مدلهای متنوعی از کامپیوترهای کوچک در بازار یافت میشود. کامپیوترهایی کممصرف که توی کف دست جا میشوند و فن هم نیاز ندارند. اغلب این کامپیوترهای کوچک مبتنی بر پردازندههای خانواده ARM هستند نه اینتل. مهمترین ویژگی این معماری کم مصرف بودن آن است. این هم به معنی خود یعنی خنک بودن و عدم نیاز به فن. از طرفی معمولا CPU با یک یا چند هستهی ARM به همراه رم و چندین ورودی/خروجی و حافظهی دائمی معمولا در یک پکیج بنام System on Chip (SoC) بستهبندی میشود و در این کامپیوترهای کوچک بکار میرود. این کامپیوترها را Single Board Computer (SBC) مینامند، یعنی کامپیوتر تکبورده. مشهورترین SBC هم رزبریپای است.
اما مهمترین چیزی که یک SBC بویژه رزبریپای را از یک کامپیوتر معمولی متمایز میکند، در کنار کممصرف و کوچک بودن، وجود GPIO است. GPIO مخفف General Purpose Input/Output است. یعنی ورودی/خروجی چند منظوره. به زبان ساده روی هر رزبریپای حدود چهل پین کنار هم چیده شدهاند که قابل برنامهریزی هستند. این پینها را میتوان به ابزارهای جانبی وصل کرد و رفتار آنها را در یک برنامه کنترل کرد. یک ابزار جانبی میتواند به سادگی یک مقاومت و یک LED باشد که مستقیما با برق ۵ یا ۳ ولت از پینها تغذیه میشود (که از داخل برنامه قابل فعال/غیرفعال شدن هستند) یا به پیچیدگی یک صفحهی نمایش لمسی. از این گذشته ابزارهای جانبی که معمولا Hardware Attached on Top یا HAT نامیده میشوند از پروتکلهای مختلفی مانند SPI یا I²C برای اتصال به رزبریپای میتوانند استفاده کنند. در سایت pinout.xyz میتوان چیدمان پینهای بوردهای مختلف رزبریپای و کاربردهای هر پین را مشاهده کرد.
تصویر یک رزبریپای زیرو از سایت رزبریپای
رزبریپای زیرو سادهترین عضو خانواده رزبری است. تنها دارای یک پورت micro USB و یک پورت mini HDMI است. دومین پورت میکرو یواسبی برای تغذیه بورد است و هیچ کاربرد دیگری ندارد. این بورد ۵۱۲ مگابایت RAM دارد و فاقد حافظهی دائمی است. درگاه SD Card نقش حافظهی دائمی را بازی میکند. آخرین درگاه موجود روی این بورد مخصوص دوربین است. این بورد در دو مدل عرضه میشود، یکی بدون وایفای و بلوتوث و دیگری با هردوی آنها. ما برای پروژهمان نیاز جدی به وایفای و بلوتوث نداشتیم ولی از جایی که داشتن وایفای هم کار من را راحت میکرد و هم کامپیوتر فسقلی ما را به اینترنت وصل میکرد تصمیم گرفتیم از این نسخه استفاده کنیم. توجه کنید که رزبریپای زیرو خروجی ۳.۵ میلیمتری برای جک صوتی و نیز هیچ نوع صفحه نمایش ندارد. ما برای این پروژه به هر دوی آنها نیاز داریم و در ادامه شرح میدهم که چطور آنها را اضافه کردیم. البته پیش از وصل کردن صفحهی نمایش چهل پین به بورد لحیم کردم، چرا که ما بخاطر صرفهجویی بوردی سفارش دادیم که پینها از پیش به آن لحیم نشده بودند (فقط حفرههایی برای اتصال آنها روی بورد قرار داشت).
ما عینا همان صفحهی نمایشی را که cgenco انتخاب کرده بود از سایت علیاکسپرس سفارش دادیم که دو سه هفته بعد به دست من رسید. همانطور که پیشتر در مورد پینها توضیح دادم، این صفحه نمایش هم مستقیم به پینهای GPIO متصل میشود. من از یک کابل چهل سیمه استفاده کردم تا زیرو را به صفحهی نمایش متصل کنم.
صفحهی نمایش که با کابل ۴۰ سیمه به زیرو متصل شده است
برخلاف خروجیهای ویژهی مانیتورها مانند HDMI، برای آنکه چیزی روی این صفحهی نمایش ببینیم باید سیستم عامل را تنظیم کنیم. صرف وصل کردن آن به پینها هیچ اتفاقی نمیافتد. خوشبختانه مدتهاست که کرنل لینوکس از معماری آرم پشتیبانی میکند و سیستم عامل دبیان و نسخهی رزبریپای آن امکان تنظیم سیستم عامل برای استفاده از پینها را فراهم میکند. در بخش نرمافزار شرح میدهم که چطور اینکار را کردیم.
نصب سختافزار صفحهی نمایش در کل کار نسبتا سادهای بود بنابراین میرویم سروقت بخش بعدی.
برای پخش موزیک از کامپیوترمان باید یک جفت اسپیکر به رزبریپای زیرو اضافه میکردیم. تصور خام اولیهی من این بود که میتواتم به سادگی یک جفت اسپیکر کوچک را مستقیما به پینهای رزبریهای متصل کنم. ولی به سرعت پی به اشتباهم بردم. رزبریپای زیرو بر خلاف اعضای قویتر خانواده مثل رزبریپای ۳ و ۴ فاقد خروجی ۳.۵ میلیمتری جک صوتی است. بنابراین اتصال یک هدفن یا یک اسپیکر خارجی دارای آمپلیفایر منتفی است. هرچند آنچه از نظر پنهان است یک مدار کوچک فیلتر صداست که آن هم در رزبریپای زیرو وجود ندارد. برای اینکه بتوان یک هدفن یا اسپیکر را به رزبریپای زیرو اضافه کردن باید ابتدا این مدار را ساخت.
رزبریپای زیرو فاقد فیلتر صدا و خروجی ۳.۵ میلیمتری جک صوتی است.
یک هدفن یا اسپیکر یا یک آمپلیفایر (تقویت کننده صدا) نیاز به یک سیگنال آنالوگ ورودی دارد نه یک سیگنال دیجیتال. مثلا یک فایل mp3 حاوی تخمینی دیجیتال/گسسته از یک سیگنال آنالوگ/پیوسته است و کیفیت آن هم بسته به دقت نمونهگیری (sampling rate) آن است. از طرفی رزبریپای زیرو تبدیل کنندهی دیجیتال به آنالوگ (Digital to Analog Converter - DAC) ندارد. پس نمیتواند خروجی مناسب برای اسپیکر تولید کند. یک پین GPIO رزبریپای میتواند در یک لحظه یک منطقی (۳.۳. ولت) یا صفر منطقی (صفر ولت) باشد و نه چیزی بین این دو (البته همه پینها GPIO نیستند). با مقداری جستجو و مطالعه یادگرفتم که همه مدلهای رزبریپای برای تولید صدا از تکنیکی بنام Pulse Width Modulation (PWM) استفاده میکنند. به کمک این روش میتوان یک سیگنال آنالوگ را به کمک یک سیگنال دیجیتال شبیهسازی کرد. در این روش ولتاژ پینها با فرکانسی بالا بین صفر و ۳.۳ ولت سویچ میشود (بسته به نوع اپلیکیشن مورد نیاز، مثلا یک موتور یا یک آمپلیفایر). با کنترل مدت زمانی که هر پالس خروجی را روشن میکند (۳.۳ ولت) میتوان میزان جریان الکتریکی و مجموع توان منتقل شده به مصرف کننده (اینجا اسپیکر) را کنترل کرد. شرح عمیقتر این موضوع از منظر الکتریکی فعلا در حیطهی تخصص من نیست.
خوشبختانه کرنل لینوکس چیپ BCM2835 بکار رفته در رزبری را به خوبی ساپورت میکند و ما در نهایت کافیست کرنل را بدرستی تنظیم کنیم و مدار فیلتر را به رزبریپای زیرو اضافه کنیم. مدار فیلتر سادهای که در در سایر رزبریپایها بجز زیرو وجود دارد ترکیبی است از تعدادی خازن و مقاومت که حاوی یک Low Pass Filter و یک High Pass Filter است که فقط یک رنج فرکانس خاص را از خودش عبور میدهد و باقی را حذف میکند که حداقل باعث حذف نویز میشود. اگر فهم عمیقتری از فیلترها دارید در بخش نظرات بنویسید که مفید فایده بشود. ما این مدار را میسازیم و به کامپیوترمان اضافه میکنیم.
فیلتر صوتی محصولات رزبری بجز زیرو. سمت راست خروجی ۳.۵ میلیمتری است و سمت چپ دو ورودی PWM. ما از دیودها سمت راست پایین صرف نظر کردیم.
مدار این فیلتر خیلی ساده است. اگر به تصویر بالا دقت کنید دو بخش بالا و پایین عینا مثل هم هستند. حتی یکی از آنها کافی است اما خروجی احتمالا مونو و تک کاناله خواهد شد. من هر دو را اضافه کردم. برای هر بازوی مدار به قطعات زیر احتیاح است:
من بیشتر این قطعات را در خانه داشتم بجز خازن ۳۳ نانو فارادی که تعدادی تهیه کردم. تصویر زیر مداری را نشان میدهد که ساختم.
اولین تلاش من برای ساخت فیلتر صوتی
مدارهای ساده را اول روی Breadboard میسازند. بردبورد از دو بخش کلا مجزای بالا و پایین تشکیل شده. هر طرف هم به نوبه خود به دو بخش تقسیم شده. در امتداد لبهی کناری بورد تمام حفرههای آبی به هم وصل هستند و همهی حفرههای قرمز هم همینطور. یکی برای منفی است و دیگری برای اتصال مثبت. حفرههای درونی برد برد که با پنج حرف a b c d e مشخص شدهاند پنج تا پنج تا به صورت عمودی به هم وصل هستند.
ورودی این فیلتر را به پینهای PWM متصل کردم (شرح در بخش نرمافزار) و خروجی آن را به یک هدفن. بدون مشکل کار کرد صدا هم خوب بود (البته من خوره صدا نیستم!). هرچند با اتصال آن به اسپیکرهای ۳ واتی که از فدریکو گرفتم متوجه شدم که صدا بینهایت ضعیف است و باید گوشت را به اسپیکرها بچسبانی تا بتوانی به زحمت چیزی بشنوی. وقت اضافه کردن یک آمپلیفایر رسیده بود!
بعد از مقداری مطالعه در اینترنت و صحبت با همکارم که متخصص الکترونیک است فهمیدم که برای اینکه سیمهای یک اسپیکر را مستقیم به خروجی فیلتر وصل کنم نیاز به یک آمپلیفایر (تقویتکننده) دارم چرا که توان خروجی فیلتر برای تغذیهی اسپیکر سه واتی من کافی نبود (تصور کنید که اگر اسپیکر بزرگتری با توان بالاتر داشتم احتمالا اصلا چیزی نمیشنیدم). اینجا لازم است اضافه کنم که بیشتر اسپیکرهایی که ما دور و برمان داریم و به کامپیوتر و موبایل متصل میکنم یک مدار آمپلیفایر داخل خودشان دارند. هدفنها به خاطر کوچکیشان و توان پایین نیازی به آمپلیفایر ندارند بنابرین میتوانیم آنها را مستقیما به خروجی ۳.۵ میلیمتری وصل کنیم.
حالا دو انتخاب در پیش رو داشتیم: فقط به هدفن اکتفا کنیم یا یک آمپلیفایر هم بسازیم. خوب، جواب را خودتان حد بزنید :)
با توضیحات فدریکو و مطالعه مقالات دیگرانی که فیلتر صوتی ساخته بودند فهمیدم که میتوان حتی با یک ترانزیستور یک مدار تقویتکنندهی ساده ساخت. کافیست یکسوی آنرا به خروجی ۳.۳ یا ۵ ولت (از رزبری) متصل کرد و سوی دیگر را به خروجی فیلتر صوتی با مقداری جزئیات بیشتر. ولی در این مرحله آنقدر کار باقی مانده بود که تصمیم گرفتم یک مدار نقلی آمپلی فایر بخرم و به فیلتر اضافه کنم. با مقداری جستجو یک آمپلیفایر یک دلاری پیدا کردم بنام PAM8403 (در ایران هم به قیمت ناچیزی پیدا میشود).
آمپلیفایر ارزان و کوچک PAM8403. سمت راست بالا ورودی مثبت و منفی از منبع تغذیه. سمت راست پایین ورودی چپ و راست از فیلتر صدا. سمت چپ بالا خروجی اسپیکر سمت راست. سمت چپ پایین خروجی اسپیکر سمت چپ. عکس از سایت electrodragon.com
با کمک این آمپلیفایر میتوان اسپیکرهای کوچک و متوسط را مستقیما پشتیبانی کرد. به خاطر بیاورید که بدون آمپلیفایر با مدار ما بیش از یک هدفن کوچک را به زحمت میتوان پشتیبانی کرد. روش کار هم ساده است. ما خروجی فیلتر صدا و منبع تغذیه را به آمپلیفایر وصل میکنیم و سپس خروجی آمپلیفایر را به اسپیکرهایمان متصل میکنیم. نکته مهم در مورد این آمپلیفایر اینست که نباید گراوند (زمین/قطب منفی) خروجی به اسپیکرها به هم متصل شود. این را وقتی متوجه شدم که قصد داشتم یک خروجی ۳.۵ میلیمتری به مدار اضافه کنم که گراوند چپ و راست در آن مشترک است. ابتدا این خروجی را به اشتباه بعد از آمپلیفایر قرار داده بودم و با اتصال کابل هدفن گراوند چپ و راست آمپلیفایر به هم وصل میشد و باعث میشد که تقویت کننده از کار بیفتد. البته این را اصلاح کردم. در دیزاین آخر آمپلیفایر بعد از خروجی ۳.۵ میلیمتری قرار گرفته و دو اسپیکر به طور مجزا به خروجیهای آن وصل شدهاند.
اضافه کردن یک جک ۳.۵ میلیمتری کاری مفرح بود. من نمیدانستم که جکهای ۳.۵ میلیمتری مثل یک کلید عمل میکنند. یعنی نحوهی نصب کردن آن مهم است. جکی که من اضافه کردم ۵ پین داشت. یک پین گراوند و دو پین ورودی صدا و دو پین خروجی صدا. در حالتی که هیچ فیشی به جک وصل نیست ورودیها به خروجیها وصل هستند و صدا میرود به طرف آمپلیفایر و بعد اسپیکرها. اما به محض اتصال فیش یک هدفن سویچ باز میشود و صدا میرود به هدفن و ورودی آمپلیفایر قطع میشود. به همین سادگی! هیچ تکنولوژی خاصی در کار نیست. یک کلید ساده. البته من در ابتدا جک ۳.۵ میلیمتری را هم به خروجی آمپلیفایر وصل کرده بودم که نه تنها مشکلآفرین بود (اتصال کوتاه آمپلیفایر) بلکه کلا اشتباه بود چرا که هدفن به آنهمه توان خروجی نیاز نداشت و صدا گوش کر کن میشد. که همانطور که پیشتر گفتم آنرا اصلاح کردم.
بعد از اضافه کردن جک صوتی متوجه شدم که جای یک ولوم صدا خالی است. در غیر اینصورت امکان کم و زیاد کردن صدا بدون نرمافزار ممکن نبود. پس دست به کار شدم و بعد از چند تست با مقاومتها یک پتانسیومتر یک مگااهمی سفارش دادم. البته تا رسیدن به ترکیب صحیح هنوز راه درازی باقی مانده بود!
پتانسیومترها را خیلی جاها دیدهاید. روی رادیوهای قدیمی برای کم و زیاد کرن صدا و روی تجهیزات صوتی یا گاهی برای کم و زیاد کردن نور لامپهها یا کم و زیاد کردن گرمکنندههای برقی و مانند اینها زیاد پیدا میشود. سادهترین کارش اینست که مثل یک مقاومت متغیر عمل میکند. البته بسته به نحوهی قرار دادن آن در مدار میتوان با آن ولتاژ متغیر هم بوجود آورد. اینجا ما از آن به عنوان مقاومت متغیر برای کم و زیاد کردن صدا استفاده میکنیم.
یک پتانسیومتر. عکس از ویکیپدیا
اولین اشتباه از سری اشتباهاتم انتخاب مقاومت بسیار بزرگ بود. بعد از نصب پتانسومتر متوجه شدم که به محض اینکه ذرهای پیچ صدا را میچرخانم صدا به سرعت قطع میشود. در حقیقت فقط وقتی میتوانستم چیزی بشنوم که مقاومت پتانسیومتر صفر یا نزدیک صفر بود. به سرعت یک پتانسومتر خطی دیگر با مقاومت ۱۰ کیلواهم سفارش دادم. هنوز روحم خبر نداشت که این هم کار نخواهد کرد.
مهمترین اشتباهم این بود که تصور کردم پتانسیومتر فقط یک مقاومت متغیر خطی است. یعنی مقاومت را با یک شیب خطی زیاد میکند و باعث افت جریان میشود و این برای یک مدار صوتی کفایت میکند. مثلا فکر میکردم اگر پیج صدا را ۴۵ درجه بچرخانم با ۲۵ درصد افزایش مقاومت، صدا هم ۲۵ درصد کم میشود و اگر ۱۸۰ درجه بچرخانم با ۵۰ درصد افزایش مقاومت، صدا هم ۵۰ درصد کم میشود. تنها بعد از نصب پتانسومتر بود که متوجه شدم اصلا اینطور نیست…
بعد از این کشف جالب بیشتر مطالعه کردم و فهمیدم که گوش انسان شدت صدا را به صورت خطی حس نمیکند بلکه آنرا به صورت لگاریتمی حس میکند. این [سوال روی استکاکسجنج] کمکم کرد تا موضوع را بفهمم. خلاصهاش اینست که شدت صدا به دسیبل محاسبه میشود و ده دسیبل افزایش یا کاهش شدت سیگنال صدا منجر به دو برابر یا نصف شدن سیگنالی میشود که گوش انسان حس میکند. این یعنی هرچند پات من مقامت را مثلا ۵۰ درصد زیاد میکرد ولی این باعث نصف شدن سیگنالی نمیشد که گوش انسان حس میکرد. اینجا بود که تفاومت پاتهای خطی و لگاریتمی را فهمیدم (مدتی هم طول کشید تا بفهمم اسم کوچک پتانسیومتر، «پات/pot» است).
یک پات خطی برای کم و زیاد کردن نور لامپ یا شدت چرخش یک پنکه مناسب است اما برای کم و زیاد کردن شدت صدا مناسب نیست. برای اپلیکیشنهای صوتی باید از پاتهای لگاریتمی استفاده کرد که مقاومت را نه به صورت خطی، بلکه به صورت لگاریتمی تغییر میدهند. یعنی نمودار تغییر خروجی خطی نیست بلکه منحنی است. بنابراین اگر پیچ صدای یک پات لگاریتمی را ۲۵ درصد بچرخانیم سیگنال صدا هم ۲۵ دسیبل تغییر میکند. همانطوری که ما انتظار آن را داریم. پس کافی بود که یک پات لگاریتمی سفارش بدهم. ولی به دلیل مسافرت دیگر فرصت سفارش پات دیگری نداشتم. در این مرحله حتما تصدیق میفرمایید که دیگر چارهای نبود جز ساخت یک پات لگاریمتی!!!
حالا که چند پات خطی روی دستم مانده بود و فرصت سفارش پات لگاریتمی هم نبود دوباره دست به دامن اینترنت شدم اینبار وبسایت یکی از بچههای قدیم را پیدا کردم. (از کجا میدانم بچهی قدیم است؟ خودتان وبسایت نویسندهی زندگی سحرآمیز پاتها را ببینید و قضاوت کنید! دود همچنان از کنده بلند میشود!) بهترین مقالهای که در این رابطه خواندم مقالهی زندگی سحرآمیز پاتها است. ظاهرا به دلایل مختلفی از جمله سرمایهداری و تلاش برای حداکثر کردن سود، شرکتها دیگر پتانسیومترهای لگاریتمی آنهم با مقاومتهای دلخواه و کلا هرچه کمتر مصرف شود را کمتر تولید میکنند یا دیگر اصلا تولید نمیکنند. ظاهرا نان توی تولید انبوه چیزی است که بیشتر مشتری دارد. اما این وسط هکرها و بچههای قدیم بیکار ننشستهاند و کشف کردهاند چطور مقاومت خطی را به لگاریتمی تبدیل کنند.
اگر جزئیات را دوست دارید بداند آن مقاله را به هر ضرب و زوری که میتوانید بخوانید. خیلی آموزنده بود. خلاصهاش این بود که باید هر سه پین پتانسیومتر را بکار میگرفتم. دقت کنید که پتانسیومتر معمولا سه پین دارد. البته پات من شش پین داشت. یکی برای اسپیکر چپ یکی هم برای اسپیکر راست. اما در حقیقت چیزی جز دو پات به هم چسبیده نیست. پس من همان سه پین را شرح میدهم.
وقتی از یک پات به صورت مقاومت خطی استفاده میشود فقط دو پین کفایت میکند. یک پین ورودی است و یک پین خروجی. پین سوم هم وصل نیست. اما برای تبدیل یک مقاومت خطی به لگاریتمی (یا بکار گرفتن پات به عنوان متغیر ولتاژ) باید هر سه را به کار گرفت. تغییر البته ساده بود. فقط کافی بود پین سوم به گراوند مدار وصل بشود و بین پین ورودی و خروجی هم یک مقاومت اضافه بشود. میزان این مقاومت را به کمک فرمولی که در مقاله بالا داده شده بود محاسبه کردم.
http://www.geofex.com/Article_Folders/potsecrets/potscret.htm
بنابراین فقط کافی بود که فرمول سادهی زیر را برای پات ده کیلوییام حل کنم:
Rt=Rpot/b b=1,2,3,4,5(max)
Rt=10K/5=2K
از جایی که من یک پات ده کیلویی داشتم فقط به دو کیلو مقاومت احتیاج بود. پس پین سوم هر طرف پتانسیومتر را به گراند وصل کردم و در هر سوی پات بین ورودی و خروجی یک مقاومت دو کیلویی اضافه کردم و مشکل حل شد.
پس از حل همهی چالشهای بالا من مدار فیلتر و پتانسیومتر استریو و جک ۳.۵ میلیمتری و اسپیکرها را در مدار زیر ادغام کردم. فایل دیزاین را میتوانید دانلود کنید و در ادیتور سایت circuit-diagram.org ایمپورت کنید.
مدار صوتی حاوی فیلتر و پتانسیومتر و جت ۳.۵ میلیمتری و اسپیکرها. طراحی به کمک www.circuit-diagram.org.
مدار صوتی کامل
یکی از مقاومتهای دو کیلویی بین پتانسومتر و آمپلیفایر، بالا سمت چپ، قابل دیدن است. دیگری زیر پات است و دیده نمیشود. توجه کنید از جایی که مقاومت بیست اهمی نداشتم، دو مقاومت ده اهمی را سری کردهام که در بخش چپ پایین عکس قابل مشاهده است. برای ورودیها و خروجیها هم تعدادی پین لحیم کردم که اتصال آنها را ساده کند.
تصویر بالا بورد صوتی با همهی ملحقات آن را نمایش میدهد. سیمکشیها و اتصالات زیر بورد قابل دیدن نیست. متاسفانه حین مسافرت تجهیزات کافی همراه نداشتم و هویه و سیم لحیم و سیمهای مسی که بکار بردم مناسب نبودند و سیمها به سختی لحیم شدند و خیلی مستحکم از آب درنیامد. از طرفی چون برای رفع مشکلات مختلف مجبور شدم سیمکشی را تغییر بدهم خروجی سیمکشی زیگ زاگ از آب درآمد که از نمایش آن صرف نظر میکنم (چسب کاغذی را برای فیکس کردن سیمها و جلوگیری از شکستن اتصالات بکار بردهام).
حالا وقت سر هم کردن همه قطعات سختافزاری بود: زیرو و بورد صدا و صفحهی نمایش. برای اتصال صفحهی نمایش فقط کافی بود کابل آن را به زیرو وصل کنم. اما از جایی که کابل صفحهی نمایش تمام پینها را میپوشاند، مجبور شدم پینهای PWM و گراند و پنج ولت تغذیه آمپلیفایر را از زیر به زیرو لحیم کنم. مهمترین چالشی که حین ادغام بورد صوتی و صفحهی نمایش نگران آن بودم این بود که صفحهی نمایش تمام پینهای GPIO را استفاده کند و دیگر پین آزاد برای PWM باقی نماند. خوشبختانه با مطالعهی مستندات صفحهی نمایش و فایل اکسل شرح پینهای آن متوجه شدم که تعدادی از پینها استفاده نشدهاند (هرچند اتصال کابل همه را میپوشاند). از سوی دیگر بخت با ما یار بود و PWM روی پینهای باقی مانده قابل فعالسازی بود. طبق مستندات رزبریپای هر پین تعدادی کاربری دارد، میتواند GPIO باشد یا مثلا PWM یا SPI و مانند اینها باشد. اینها را از طریق تنظیمات سیستم عامل قابل تغییر است که جلوتر اشاره خواهم کرد.
شاید بپرسید چرا کاربریهای مختلفی برای پینها در نظر گرفته شده است. علت اینست که چیپ بکار رفته در زیرو قابلیتهای بسیاری دارد که برای همهی آنها پین کافی وجود ندارد. چرا که اقتصادی نیست و جا هم روی بورد برای آنهمه پین وجود ندارد. بنابراین رایج است که با نرمافزار قابلیت دلخواه را فعال میکنند.
بعد از اتصال همه قطعات و تست پخش صدا و گیف مشکل جدیدی پیش آمد. به محض زیاد کردن صدا یا پخش تصاویر متحرک رزبریپای زیرو ریست میشد. ابتدا فکر کردم مشکل جایی در اتصالات بورد صدا و آمپلیفایر است (چون به محض متصل کردن آن دستگاه ریست میشد). اما مشکل جای دیگری بود: منبعتغذیه. رزبریپای زیرو را برای تغذیه ابتدا به پورت usb کامپیوتر وصل کرده بودم. در استاندارد USB ویژگیهای مکانیکی و الکتریکی این پورتها تعریف شده است منجمله ولتاژ و حداکثر جریان خروجی. در استاندارد USB برای USB 2.0 ولتاژ ۵ ولت و حداکثر جریان ۵۰۰ میلیآمپر تعریف شده است. برای USB 3.0 این مقدار ۵ ولت و حداکثر ۹۰۰ میلیآمپر تعریف شده است. از طرفی تولیدکنندگان همگی این استاندارد را رعایت نمیکنند، پس ممکن است یک کامپیوتر بتواند این را تامین کند و دیگر نتواند. من زیرو را به لپتاپ ۱۹۹ دلاری Pinebook Pro خودم متصل کرده بودم که با اتصال صفحهی نمایش و پخش صدا ریست میشد (بدون اینها مشکلی پیش نمیآمد). طبق مستندات رزبری در مورد منبع تغذیه جریان مصرفی زیرو در حالت عادی ۱۰۰ میلیآمپر است و منبع تغذیه باید تا ۱.۲ آمپر را بتواند تامین کند که بیش از توان خروجی پورتهای USB است. از طرفی اتصال صفحههی نمایش و اسپیکرها میزان جریان مصرفی را افزایش میدهد که با مراجعه به مشخصات هر قطعه قابل محاسبه است (من محاسبه نکردم). جریان مصرفی برابر خواهد بود با مجموع جریان مصرفی هر قطعه. بعد از استفاده از یک منبع تغذیهی USB با ۲ آمپر جریان مشکل حل شد (شارژر یک بلندگو را بکار بردم).
منبع تغذیهی رزبریپای زیرو باید بتواند حداقل ۱.۲ آمپر جریان را تامین بکند.
خلاصه با اطمینان از اینکه سختافزار ما کار میکند میرویم سروقت بدنه.
همانطور که در ابتدا اشاره کردم ما از بدنهای که قبلا طراحی شده استفاده کردیم. cgenco زحمت طراحی یک بدنه شبیه یک مکینتاش قدیمی را کشیده است که برای ما ایدهآل بود. من فایلهای stl برای چاپ سه بعدی آن را دانلود کردم و به کمک یک پرینتر سه بعدی پروسا Prusa I3 MK3S چاپ کردم. اما از روی کم تجربگی «ساپورت» مناسبی برای چاپ انتخاب نکرده بودم. یعنی موقع چاپ بخشهایی که زیرشان خالی است (مثل یک حفره) ممکن است خراب شود. برای ممانعت از اینکار باید از ساپورت استفاده کرد. در آنصورت چاپگر یک ساختار پوک که براحتی قابل حذف کردن است زیر و درون حفرهها چاپ میکند که مانع ریزش آنها حین چاپ میشود (مادهای که از نازل چاپگر خارج میشود داغ و نرم است و فرو میریزد).
دست راست: چاپ شده بدون ساپورت. دست چپ چاپ شده با ساپورت.
ما مجبور بودیم دو حفره برای پتانسیومتر و جت ۳.۵ میلیمتری در بدنه ایجاد کنیم. باید فایلهای سه بعدی را در یک برنامهی CAD اصلاح میکردیم و حفرههای لازم را در بنده ایجاد میکردیم و فایل تغییر یافته را پرینت میگرفتیم. متاسفانه از جایی که هنوز اینکار را بلند نیستم و فرصت یادگیری هم فراهم نشد به روش سنتی سیخ داغ مراجعه کردیم! و البته کار انجام شد.
اگه کار میکنه احمقانه نیست!
خلاصه با یک جسم داغ دو حفره در بدنه ایجاد کردیم و بعد از مقداری صافکاری و تمیزکاری بورد صدا کامل جا خورد. البته جک ۳.۵ میلیمتری کاملا با بدنه همسطح نشد، که باعث میشود برخی هدفنها که فیشهای ضخیمی دارند خوب جا نخورند. اضافه کنم که در بدنه جایی برای محکم کردن زیرو در نظر گرفته شده بود اما نه برای اسپیکرها و بورد صدا و خروجیهای آن. اما از جایی که فضا به مقدار کافی وجود داشت، جای نگرانی نبود. من بورد صدا را در دیوارهی پشتی محکم کردم و کنارههای آن را هم به کمک تفنگ حرارتی با مقداری پلاستیک مایع سفت کردم. پتانسیومتر هم یک مهره داشت که از بیرون بدنه روی آن پیچ میشد و آن را محکم در جای خودش نگاه میداشت. یک کلاه هم برای پات سفارش داده بودم که روی آن از بیرون نصب کردیم.
بدنهی اول به رنگ آبی را برای تست بکار بردیم.
بدنهی نمونهی اول (پروتوتایپ) در مقایسه با بدنهی اصلی.
بدنهی نمونهی اول (پروتوتایپ) در مقایسه با بدنهی اصلی.
حالا میرویم سر وقت اسپیکرها.
اسپیکرهای ما حداکثر سه وات توان دارند و مقاومت درونی هر یک از آنها چهار اهم است. متاسفانه فراموش کردم پیش از نصب از مشخصات فنی پرینت شده روی آنها عکس بگیرم و ممکن است این ارقام اشتباه باشد (طی فرآیند نصب برچسب مشخصات فنی اسپیکر از بین رفت). صدای اسپیکرها چندان بلند نیست و وقتی داخل بدنه قرار میگیرد کمتر هم میشود. اول میخواستیم تعدادی حفره هم برای اسپیکرها ایجاد کنیم (اینکار را روی بدنهی آبی امتحان کردیم)، اما از نظر ظاهری خوب درنیامد و از اینکار صرفنظر کردیم. برای هدف ما صدا به اندازهی کافی خوب بود. بنابراین اسپیکرها را به پینهای خروجی که روی بورد صدا در نظر گرفته بودم متصل کردم و آنها را داخل قاب روی دیوارهها چسباندم.
همه آنچه برای پخش صدا از اسپیکرها نیاز است: رزبریپای زیرو و بورد صدا و یک جفت اسپیکر. دقت کنید که در این تصویر سیمها از رو به پینهای زیرو متصل شدهاند در حالی که در قاب اصلی از زیر به آن لحیم شدهاند.
برای اسپیکرها هم جای خاصی داخل بدنه در نظر گرفته نشده بود اما خوشبختانه فضا به اندازهی کافی برای اسپیکرها وجود داشت.
جای کافی برای اسپیکرها وجود داشت.
بورد صدا و اسپیکرها داخل قاب اصلی. کابلهای بورد صدا از زیر به زیرو لحیم شدهاند چرا که کابل صفحههای نمایش همه فضای بیرونی را اشغال کرده است.
با نصب اسپیکرها دیگر میتوانستیم درب قاب را ببنیدیم.
سختافزار کامل مک فسقلی با سیستم عامل رزبری (دبیان با گرافیک xfce).
با پایان کار سختافزار حالا با اعتماد بنفس خیلی بیشتر میرویم سروقت چیزی که از آن خیلی بیشتر سردرمیآورم یعنی نرمافزار!
در مقایسه با ساختن کامپیوتر کوچکمان کار نرمافزاری زیادی نداریم. با اینحال موارد زیر را شرح میدهم:
در کامپیوترهای مبتنی بر چیپستهای شرکت اینتل (معماری x86) کامپیوتر با یک برنامهی کمکی در BIOS یا جدیدا UEFI بوت میشود. در کامپیوترهای مبتنی بر ARM بایوس یا UEFI وجود ندارد و بوت به گونهی دیگری و به نوعی سادهتر است. ما فقط نیاز است که سیستمعامل مناسبی را به درستی روی یک کارت حافظه فلش کنیم و آنرا در درگاه کارتخوان رزبریپای زیرو وارد کنیم و کامپیوتر را روشن کنیم. یعنی فرآیند نصب و بود خلاصه میشود به دانلود ایمیج مناسب کامپیوتر و فلش کردن آن روی یک کارت حافظه.
برای کامپیوتر فسقلیمان ما یک کارت حافظهی ۳۲ گیگاباتی استفاده کردیم (من در وسایلم داشتم). برای دانلود سیستم عامل و فلش کردن آن راههای زیادی هست اما سادهترین آن استفاده از [ایمیجساز رزبری ]است. ایمیجساز رزبری میتواند همزمان سیستم عامل مناسب را دانلود کند و آن را روی کارت حافظه بنویسد. من سیستم عامل دسکتاپ رزبری را انتخاب کردم که از همه سادهتر است و البته با حدود ۸ گیگابایت حجم، بزرگترین آنها.
ایمیجساز رزبری برای ویندوز و لینوکس و مک قابل دانلود است.
بعد از دانلود سیستم عامل و فلش کارت حافظه کافیست آن را در درگاه کارتخوان وارد کردن و زیرو را روشن کرد. شرح بدهم که هیچ یک از محصولات خانواده رزبری کلید روشن و خاموش ندارند و به محض اتصال کابل منبع تغذیه روشن میشوند و فرآیند بوت آغاز میشود. در مورد زیرو منبع تغذیه پورت میکرو usb است که باید به یک منبع تغذیهی مناسب (همانگونه که پیش از این شرح آن رفت) متصل بشود.
رزبریپای را به دو شیوه میتوان تنظیم کرد (تنظیمات صدا و HDMI و GPIO و SSH و پورت سریال و مانند اینها). یکی تغییر دو فایل موجود در پارتیشن بوت آن است: cmdline.txt و config.txt. این فایلها به ترتیب پارامترهای کرنل لینوکس و تنظیمات overlay رزبری هستند (دومی ممکن است بیش از این هم باشد، دقیق نمیدانم). این فایلها را میشود مستقیما با اتصال کارت حافظه به یک کامپیوتر تغییر داد بدون آنکه از رزبریپای استفاده کرد. ما هر دو اینها را تغییر خواهیم داد تا کارهای زیر را انجام بدهیم:
روش دیگر تنظیم رزبریپای رزبری استفاده از برنامهایست بنام raspi-config که از پیش روی سیستمعامل رزبری نصب است. ناگفته پیداست که برای استفاده از این برنامه باید به رزبریپای وصل شد که مستلزم دیدن خروجی (کنسول یا گرافیکی) و اتصال کیبورد و مانیتور با کابل mini hdmi و اتصال سریال یا شبکه است. اما آیا میشود بدون کیبورد و ماوس و اتصال شبکه و اتصال مونیتور یک رزبریپای را تنظیم کرد؟ بله میشود! با اتصال UART به اختصار آشنا شوید.
شاید گزاف نباشد اگر بگویم که در عالم کامپیوترهای کوچک و بوردهای الکترونیکی توکار UART محبوبترین روش اتصال و تبادل اطلاعات با یک دستگاه است. در این روش تنها به دو سیم احتیاج است و هیچ برنامه یا درایور خاصی نیاز نیست و در همهی سیستم عاملها هم فراهم است. UART یک کابل TX به معنای ترانسفر و یک کابل RX به معنای دریافت نیاز دارد. و نیز یک سیم سوم برای اتصال گراوند که بدون آن هم شاید کار کند. رزبریپای هم میان انبوه پینها UART هم دارد. کافیست سه پینهای ۸ (TX) و ۱۰ (RX) را به ترتیب به RX و TX یک دستگاه دیگر وصل کرد (TX یکی به RX دیگری وصل میشود و بلعکس). برای متصل کردن رزبریپای به لپتاپ لینوکسیام از یک تبدیل کنندهی سریال به USB استفاده کردم چون لپتاپم خروجی UART ندارد (شاید دارد و هنوز نمیدانم). البته این کار خیلی رایجی است.
اتصال به رزبری از طریق پورت سریال. در سمت راست تصویر میتواند تبدیلکننده USB-UART را که با سه سیم به پینهای رزبری متصل شده است را ببینید.
یک تبدیلکنندهی USB-UART. عکس از waveshare
برای اینکه بتوان خروجی کنسول لینوکس را به کمک UART روی کامپیوتر دید باید به غیر از اتصال صحیح کابلها (TX به RX و RX به TX) رزبریپای را هم تنظیم کرد. یکی برای فعال کردن UART و دیگری برای فعال کردن یا اطمینان از فعال بودن کنسول لینوکس (کنسول لینوکس همه آن چیزی است که کرنل در خروجی/مانیتور به صورت متنی نمایش میدهد که معمولا شامل یک خط فرمان هم میشود). هدف اینست که روی کامپیوترمان به این خط فرمان وصل بشویم و زیرو را کنترل و تنظیم کنیم و نیز آن را به شبکهی وایرلیس خانگی وصل بکنیم.
چیدمان پینهای رزبریپای زیرو و برخی از قابلیتهای هر پین. بالا سمت راست پینهای سریال را میبینید. عکس از سایت pinout.xyz
برای فعال کردن UART رزبریپای زیرو کافیست که فایل /boot/config.txt
را روی کارت حافظه ویرایش کنیم و مطمئن شویم خط زیر در آن وجود دارد:
enable_uart=1
از طرفی باید فایل /boot/cmdline.txt
شامل تنظیمات زیر باشد:
console=serial0,115200 console=tty1
با اطمینان از وجود این تنظیمات کافیست کارت حافظه را در زیرو قرار دهیم و آن را روشن کنیم. با این تغییرات خروجی کنسول لینوکس روی UART فراهم خواهد بود. برای دیدن آن (و گرفتن یک خط فرمان) کافیست از برنامهای مانند picocom برای اتصال به پورت سریال استفاده کنیم. البته تبدیل USB-to-UART ما باید وصل باشد. با فرض اینکه تبدیل با اتصال تبدیل، یک پورت سریال در آدرس /dev/ttyUSB0
باز شده است به آن وصل میشویم:
rock@rock:~$ sudo picocom -b 115200 /dev/ttyUSB0
ممکن است تبدیلکننده در آدرسی به جز این پدیدار بشود. اگر پیش از اتصال تبدیلکننده فرمان sudo dmesg -w
را در یک ترمینال باز کرده باشیم در خروجی لاگ کرنل خواهیم دید که تبدیلکننده در چه آدرسی در دسترس قرار میگیرد.
اگر همه چیز درست پیش رفته باشد از این مرحله به بعد ما یک خط فرمان خواهیم داشت که میتوانیم با نام کاربری pi و پسورد دیفالت raspberry در سیستم وارد شویم و کارمان را ادامه دهیم. اگر در این کار موفق نشدید وحشت نکنید. رزبریپای را با یک کابل mini hdmi به یک مانیتور وصل کنید و به کمک یک مبدل micro USB به USB A (معمول) یک کیبورد و ماوس به آن وصل کنید و کار را دنبال کنید.
من تنها حین راهاندازی اولیه و ساخت بورد صوتی از خروجی سریال استفاده کردم. چرا که به محض فعالسازی صفحهی نمایش پینهایی که برای سریال بکار رفته برای صفحهی نمایش نیاز است و بنابراین باید UART را غیرفعال میکردم:
enable_uart=0
برای نصب بستههای نرمافزاری لازم و نیز اتصال از طریق شبکه نیاز است زیرو را به شبکه خانگی و اینترنت متصل کنیم. از جایی که ما رزبریپای زیرو نسخه وایفای سفارش دادهایم میتوانیم آنرا به شبکه وایرلس خانگی متصل کنیم. برای اینکار از wpa_supplicant استفاده میکنیم. این ابزار از پیش روی سیستمعامل رزبری نصب است. مطابق مستندات رزبری کافیست فایل /etc/wpa_supplicant/wpa_supplicant.conf
را تغییر بدهیم و سرویس wpa_supplicant را فعال و کامپیوتر را ریبوت کنیم. به فایل بالا کد کشور و نام و پسورد وایفای خانگی را اضافه میکنیم:
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
country=IR
update_config=1
network={
ssid="<Name of your wireless LAN>"
psk="<Password for your wireless LAN>"
}
علت اضافه کردن کد کشور اینست که چیپ وایرلس فرکانس صحبح آن کشور را بکار بگیرد و در ارتباطات رادیویی دیگر اختلال ایجاد نکند. بعد سرویس را فعال و استارت کنید و بعد ریبوت:
$ sudo systemctl enable wpa_supplicant.service
$ sudo systemctl start wpa_supplicant.service
$ sudo reboot
بعد از ریبوت باید اتصال شبکه و اینترنت (اگر برقرار باشد) فراهم شده باشد. یک پینگ ساده معمولا برای بررسی این موضوع کافیست:
rock@rock:~$ ping 1.1
PING 1.1 (1.0.0.1) 56(84) bytes of data.
64 bytes from 1.0.0.1: icmp_seq=1 ttl=49 time=141 ms
64 bytes from 1.0.0.1: icmp_seq=2 ttl=49 time=145 ms
64 bytes from 1.0.0.1: icmp_seq=3 ttl=49 time=391 ms
^C
--- 1.1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2003ms
rtt min/avg/max/mdev = 140.939/225.884/391.216/116.922 ms
بد نیست اشاره کنم که با در نهایت پس از تنظیم صفحهی نمایش و صفحهی لمسی حتی بدون کیبورد و ماوس میشود از این کامپیوتر کوچک استفاده کرد و مثلا به وایفای خانگی متصل شد. فقط باید برای تایپ پسورد از صفحه کلید کوچک مجازی که از پیش روی سیستم عامل نصب است بکار گرفت. آن را میتوان از منوی برنامهها پیدا کرد.
حال با برقراری اتصال وایرلس و اینترنت میرویم سروقت بخش بعدی: فعالسازی ssh.
فعالسازی ssh اجازه میدهد که بدون اتصال مانیتور و کیبورد و بدون دسترسی به پورت سریال به کامپیوتر وصل شد و دستوراتی را اجرا کرد. برای فعالسازی آن روی رزبری دو راه وجود دارد. یکی قرار دادن یک فایل خالی به نام ssh در پارتیشن بوت کارت حافظه قبل از اولین بوت رزبری است، یعنی بلافاصله بعد از فلش کردن کارت حافظه. روش دوم به کمک خط فرمان است، یعنی یا باید از طریق کنسول یا با کیبورد و مانیتور به رزبری وصل شده باشیم:
$ sudo systemctl enable ssh
$ sudo systemctl start ssh
تمام این روشها [در بخش ssh مستندات رزبری] شرح داده شده است. از جایی که برای فعالسازی صفحهی نمایش باید UART را غیرفعال میکردم فعالسازی ssh ضروری بود. از اینجا به بعد تمام دستورات از طریق ssh انجام شده است. برای پیدا کردن آی پی رزبری هم کافیست در ترمینال دستور ip addr show
را وارد کنید یا در مودم آن را پیدا کنید.
مرحله بعدی نصب صفحهی نمایش است.
برای نصب صفحهی نمایش من راهنمای سازنده را دنبال کردم:
$ git clone https://github.com/tianyoujian/MZDPI.git
$ cd MZDPI/vga
$ sudo chmod +x mzdpi-vga-autoinstall-online
$ sudo ./mzdpi-vga-autoinstall-online
$ sudo reboot
اگر نصب به درستی انجام شود بجز اضافه شدن یک یا چند فایل جدید به پوشهی /boot/overlays
تنظیمات زیر به انتهای فایل config.txt اضافه خواهد شد:
#gpio=18=op,dh
gpio=7-8=a2
dtparam=spi=on
dtoverlay=ads7846,penirq=27,swapxy=1,xmin=200,xmax=3850,ymin=200,ymax=3850
display_rotate=3
dtoverlay=mzdpi
framebuffer_width=640
framebuffer_height=480
enable_dpi_lcd=1
display_default_lcd=1
dpi_group=2
dpi_mode=87
dpi_output_format=0x07f003
hdmi_timings=480 0 41 20 60 640 0 5 10 10 0 0 0 60 0 32000000 1
البته خط اول را من کامنت کردهام چرا که به گمانم اسکرین با PWM روی این پین کانفلیکت داشت و من کاربری دیگری برای این پین تعریف کرده بودم (PWM). درس حاشیهای اینست که اگر گزارش طویل را هنگام ساخت اندک اندک نوشته بودم الان بهتر بخاطر داشتم که چرا اینکار را کردهام!!
این دستورات هم کار محیرالعقولی انجام نمیدهد. اصل کارش اینست که Device Tree Overlay این صفحهی نمایش را دانلود و کامپایل و نصب میکند. نصب هم چیزی جز کپی کردن در مسیری در پارتیشن بوت و افزودن چند خط به فایل config.txt نیست.
وقتی ما یک وسیلهی USB به یک دستگاه وصل میکنیم آن وسیله طبق پروتکل USB با کامپیوتر صحبت میکند. اما وقتی یک وسیله به چند یا چندین پین رزبریپای متصل میکنیم چه اتفاقی میافتد؟ آنجا دیگر USB یا مانند آن در کار نیست، بلکه قطعات با پروتکلهایی مانند SPI و I²C یا UART با رزبریپای ارتباط برقرار میکنند. برای اینکه سیستم عامل این قطعات را بفهمد نیاز به چیزی شبیه به درایور است که آن سختافزار جانبی را تعریف کند و عملکردش را شرح بدهد. بواسطهی پیچیدگی SoCهای امروزی و نیز تنوع زیاد HATها، رزبریپای و کرنل لینوکس از Device Tree و overlayها برای فهمیدن سختافزارهای مختلف استفاده میکنند.
اما یک overlay چیست؟
کرنلهای رزبریپای و Firmware آن برای شرح سختافزار موجود در رزبریپای از Device Tree یا «درخت تجهیزات» استفاده میکنند. اگر با سیستمهای فایل یونیکسی آشنا باشید، میدانید که فایلسیستم از چشم کرنل مثل یک درخت است. ریشه روت است یعنی /
و «همه چیز فایل است». مثلا پیشتر برای وصل شدن به تبدیل کنندهی UART به USB با یک برنامه فایلی بنام /dev/ttyUSB0
را باز کردیم یا مثلا فایلهای کاربر در «خانهی» او قرار دارند مثلا /home/pi
. همین سبک در Device Tree بکار رفته و در بخشی مشترک مشخصات سیپییو و حافظهی موجود در دستگاه و جزئیات مشترک تعریف شده و سایر سختافزارهای دلبخواهی هر یک این درخت اصلی را توسعه میدهند و آن را با مشخصات خودشان بروز میکنند. به این بخشهای اضافی میگویند overlay.
برای فعالکردن overlayهای مختلف باید در فایل config.txt خطی مانند dtoverlay=… اضافه کرد. هر Device Tree Overlay هم میتواند تنظیماتی داشته باشد که با کلید dtparams=… در فایل کانفیگ اضافه میشود. اسکریپت بالا اینکار را برای صفحهی نمایش ما انجام میدهد. شرح بیشتر این موضوع از حوصلهی این مقاله خارج است.
بورد صدای ما هم به مانند صفحهی نمایش نیاز به تغییراتی در config.txt به شرح زیر دارد:
در این مورد البته کار سادهتر است. مورد اول و دوم را با هم در یک خط به config.txt اضافه میکنیم:
dtoverlay=pwm-2chan,pin=18,func=2,pin2=19,func2=2
این خط GPIO شماره ۱۸ و ۱۹ را برای PWM0 و PWM1 تنظیم میکند. برای اطلاعات بیشتر سورس pwm-2chan overlay را بخوانید.
به محض اضافه کردن این خط و حتی بدون تنظیمات صدای لینوکس میتوان مستقیما روی GPIO شماره ۱۸ و ۱۹ موزیک پخش کرد! البته فقط با برنامهی زیر که برای رزبریپای ساخته شده:
$ omxplayer <somemusic.mp3> --adev local
در ویدیوی زیر با پورت سریال به رزبری وصل میشوم و آهنگ بازی Hotline Miami را پخش میکنم.
اگر یک اسیلوسکوپ به این پینها وصل کنید جهشهای ولتاژ را خواهید دید. با وصل کردن مستقیم یک هدفن هم باید چیزی شبیه موزیک پخش شود اما مواظب گوش خودتان باشید چرا که ممکن است صدای زیاد ناگهانی به گوش صدمه بزند.
تنظیمات بالا هرچند برای پخش صدا با دستوری که گفتیم کفایت میکند اما اگر دسکتاپ را بوت کنید متوجه میشوید که هیچ برنامهای قادر به پخش صدا نخواهد بود و از دید لینوکس کارت صوتی وجود ندارد. برای این مشکل کافیست پارامتر زیر را به کرنل رزبریپای با ویرایش فایل cmdline.txt پاس بدهیم تا کرنل سختافزارهایی را شبیهسازی بکند که ALSA (مخفف Advanced Linux Sound Archiitecture) یک سختافزار صوتی ببیند و بتواند خروجی صدای برنامهها را به آن هدایت بکند:
snd_bcm2835.enable_compat_alsa=1
و ریبوت. کانفیگفایلهای نهایی را میتوانید با کلیک روی config.txt و cmdline.txt دانلود کنید. حالا بالاخره بعد از طی راهی طولانی میتوانیم برویم سروقت پخش موزیک و گیف.
حالا با در دست داشتن یک کامپیوتر معمولی که میتواند صدا و گرافیک پخش بکند کافیست به آن بگوییم هر بار که بوت میشود یک گیف را در حالت تمام صفحه پخش بکند و همزمان تعدادی موزیک به ترتیب از اسپیکرها پخش بشود. یعنی دو کار زیر:
اول میخواستم برای این کار برنامهای با پایتون بنویسم. اما دیدم با شل اسکریپت بسیار سادهتر است. از سویی میخواستم که بشود از کامپیوتر بدون این برنامه هم استفاده کرد. بنابراین روشی را انتخاب کردم که مانع استفاده عادی از کامپیوتر نشود. اسکریپت ما یک برنامه را در حالت تمام صفحه باز میکند که میتوان آن را با فشردن کلید ESC یا با لمس صفحه نمایش و لمس دگمهی ضربدر پنجره بست. از سوی دیگر پس از پخش همهی فایلهای صوتی خود به خود برنامه تمام شده و پنجره بسته خواهد شد.
ابتدا فایلهای لازم شامل گیف و ترکهای آلبوم صوتی را در پوشهی خانه/home روی کارت حافظه کپی کردم. من اینکار را با scp انجام دادم.سپس شل اسکریپت زیر را برای برنامه اصلی نوشتم:
#!/bin/bash
sleep 5
cd /home/pi/Rangi
IFS=$(echo -en "\n\b")
sxiv -bfa rangi.gif &
for i in $(ls *.mp3); do
omxplayer "$i" --adev local
done;
برنامه چه کار میکند؟ خط اول که به Shebang معروف است میگوید در صورتی که این فایل به صورت مستقیم اجرا شود کدام برنامه باید آن را هندل کند. بعد برنامه در صورت اجرا ۵ ثانیه به خواب میرود. اینکار برای این لازم بود تا اجازه دهد دسکتاپ رزبری کامل لود شود، در غیر اینصورت پنجره بعدی تمام صفحه نمیشد. بعد برنامه مسیر جاری خودش را به فولدری که حاوی فایلهای صوتی و تصویری است تغییر میدهد. خط بعدی که حاوی IFS به bash میگوید که برای جدا کردن خروجی دستوراتی مانند ls از newline استفاده کند. دیفالت space است.
خط بعدی به کمک برنامهی sxiv که مخفف Simple X Image Viewer است گیف را در حالت تمام صفحه باز میکند و آن را به بکگراند میفرستد. هر فرمانی که & در انتها داشته باشد میرود به بکگراند و اجرای آن ادامه پیدا میکند و شل میرود سروقت فرمان بعدی.
بعد یک لوپ ساده داریم. روی خروجی دستوری ls *.mp3
لوپ میزنیم (که با newline تفکیک خواهد شد) و به ازای هر خروجی با برنامهی omxplayer آن فایل را پخش میکنیم.
تنها لازم بود برنامهی sxiv را روی رزبری نصب کنم که با دستورات زیر انجام شد:
$ sudo apt update
$ sudp apt install sxiv
اسکریپت را هم قابل اجرا کردم که بتوان آن را مستقیم اجرا کرد:
$ chmod +x rangi.sh
سیستمعامل رزبری از دسکتاپ XFCE استفاده میکند. بنابراین من برای اجرای خودکار اسکریپت پس از هر بوت از قابلیت autostart در XFCE استفاده کردم. برای اینکار فایلی بنام rangi.desktop
با محتویات زیر ساختم و در مسیر /etc/xdg/autostart/
کپی کردم:
[Desktop Entry]
Name=Rangi
Exec=/home/pi/Rangi/rangi.sh
این باعث میشود که شل اسکریپت ما پس از هر بوت به دسکتاپ اجرا شود. و تمام.
در این مقاله شرح دادیم که چطور یک کامپیوتر کوچک ساختیم. کامپیوتری با صفحهای لمسی و دو اسپیکر توکار و نیز پیچ تنظیم بلندی صدا و یک خروجی ۳.۵ میلیمتری صوتی و یک بدنه چاپ شده توسط یک چاپگر سه بعدی. به تفصیل چگونگی ساخت یک بورد صوتی را شرح دادیم و مداری برای آن طراحی کردیم. و نیز نحوه اتصال از طریق پورت سریال و شبکه را نشان دادیم و Overlayهای لازم را راهاندازی کردیم.
ویدیوی زیر توسط شایگان ادیت شده که خروجی نهایی را نمایش میدهد.
مقالهای بود بسیار طولانی در مورد پروژهای طولانی! امیدوارم برای علاقهمندی مفید فایده بشود. زنده باشید.
]]>قبلا در مورد پروتکل چت اینترنتی بنام irc نوشتهام. اینبار در مورد znc (یک باونسر) و weechat و revolution irc مینویسم.
آیآرسی یک پروتکل قدیمی است که هنوز هم میان کاربران نرمافزار آزاد به خاطر سادگیاش محبوبیت دارد. بویژه از این جهت که در ترمینال یک سرور میتوانید برنامهی چت را باز کنید و از آن استفاده کنید. منتها سرور پیامها را فقط به کاربرانی که در لحظه به سرور متصل هستند ارسال میکند و به تازهواردین (یا کسانی که اتصالشان قطع و وصل شده است) پیامهای قبلی را ارسال نمیکند. برای رفع این مشکل قبلا از screen و irssi و نیز برای مدتی از thelounge استفاده میکردم. اما روش درست استفاده از یک «باونسر» آیآرسی است.
باونسر یک برنامه است که روی یک کامپیوتر همیشه روشن (مثلا یک رزبریپای در منزل) جا خوش کرده است و به نمایندگی از شما به اتاقهای مختلف وصل میشود و همانجا حاضر میماند و مکالمات را دریافت و ذخیره میکند. ما هم بجای وصل شدن به سرورهای اصلی به باونسر وصل میشویم که پیامهای قبلی را ذخیره کرده است. وصل شدن به یک باونسر مثل وصل شدن به یک سرور آیآرسی است.
متاسفانه آیآرسی در ترمینال به جهت ساپورت بسیار ضعیف کنسول لینوکس و نیز ترمینالهای موجود از حروف عربی کاربرد چندانی برای فارسینویسی ندارد. اما از جایی که معماری آیآرسی کلاینت سرور است (یعنی اتاقها روی یک سرور قرار دارد)، کلاینتهای متنوعی برای آن وجود دارد که کاربران از آن طریق به سرور و اتاقها وصل میشوند. و خوشبختانه کلاینتهای گرافیکی برای لینوکس و اندروید مشکلی با متن فارسی ندارند.
یکی از باونسرهای قدیمی و جاافتاده znc است. نصب این برنامه روی سرور اوبونتو کار تقریبا بیدردسری بود:
sudo apt install znc
sudo -u _znc znc --makeconf
دستور بالا برای تنظیم اولیهی znc است (اوبونتو از یوزر _znc
برای znc استفاده میکند). باید آدرس سرور مقصد و پورت و یک نام برای آن و نیز نیکنیم دلخواهمان را وارد کنیم. من مقادیر زیر را وارد کردم:
server name: libera
server: irc.libera.chat
server port: 6697
nick: mehdix
از شما یک پسورد هم خواسته میشود برای اتصال به سرور که وارد کنید. بعد از اینها باید بشود یونیت systemd مربوطه را استارت کرد که البته روی اوبونتوی ۲۰ استارت نشد. علت هم نقص در کانفیگ systemd بود که اوبونتو برای znc اضافه کرده است که اصلاح کردم (هرچقدر یک سیستم عامل برنامهها را کمتر دستکاری کند بهتر است):
# Edit /lib/systemd/system/znc.service
# Change this line:
ExecStart=/usr/bin/znc -f --datadir=/var/lib/znc/
# to:
ExecStart=/usr/bin/znc -f --datadir=/var/lib/znc/.znc/
کار بالا را میشود در یک خط هم انجام داد:
# sed 's/\/znc\//\/znc\/.znc\//' /lib/systemd/system/znc.service > /lib/systemd/system/znc.service
بعد از هر تغییر در فایلهای systemd باید آنرا ریلود کرد:
# systemd --daemon-reload
مطمئن شوید znc در حال اجرا نیست و سرویس systemd را فعال و استارت کنید:
$ sudo killall znc
$ sudo systemctl enable --now znc.service
مدتی پیش مالک جدید برزگترین سرور آیآرسی بنام Freenode سیاستهای جدیدی در پیش گرفت که منجر به ترک این شرکت توسط بخش بزرگی از کارمندان و راهاندازی Libera.Chat شد. فرینود هم اتاق هر کسی که اسم لیبرا چت آورد را بست. بخش مهمی از کامیونیتی هم به لیبراچت مهاجرت کرد.
برای اتصال به باونسر znc من سه برنامه را امتحان کردم که همگی بدون مشکل کار کردند: weechat و hexchat و revolution irc. از میان اینها weechat برای ترمینال است و hexchat برای ویندوز و لینوکس و revolution irc برای اندروید.
روی ویکی znc تنظیمات ویچت و نیز تنظیمات هگزچت دقیقا شرح داده شده، بنابراین از تکرار آن خودداری میکنم. روی اندروید من از برنامهی آزاد و خوب revolution irc استفاده کردم (نصب از F-Droid). اتصال به باونسر هم ساده بود، کافی بود آدرس سرور و پورت و نیک و پسوردی که در ابتدا انتخاب کرده بودم وارد کنم. این هم نتیجه:
به بهانهی این مقاله یک کانال آیآرسی روی لیبراچت برای خوانندگان این وبسایت ایجاد کردم. فقط کافی بود روی یکی از کلاینتهایی که بالاتر تنظیم کردهام دستور زیر را اجرا کنم:
/join #mehdix.ir
از جایی که این کانال وجود نداشت ساخته شد (البته من پیشتر آیدی مهدیکس را روی لیبرا رجیستر کرده بودم). من این کانال را همواره باز نگه خواهم داشت. خواستید آیآرسی تمرین کنید دریغ نکنید.
]]>همانطور که از نوشتههای اخیرم پیداست در حال کوچکسازی جعبهیابزار فنی و ذهنیام هستم. برای کشف چیزهایی که باید مرخص بشوند یک تکنیک ساده پیدا کردهام که شرح میدهم.
این تکنیک چیزی جز یک پرسش ساده نیست. آگاهانه ابزارهای مورد استفادهام را مورد پرسش قرار میدهم. مثلا از خودم میپرسم چرا من از zsh استفاده میکنم؟ اگر بتوانم به این پرسش پاسخ درخوری بدهم و دلیل قانعکنندهای داشته باشم آن ابزار سرجایش باقی میماند. اگر نتوانم به این پرسش پاسخ بدهم آن ابزار یا تکنولوژی را با یک چیز سادهتر جایگزین میکنم یا کلا کنار میگذارم.
مثلا در مثال zsh من نتوانستم به پرسش خودم جواب بدهم. پاسخهای جسته و گریختهای دادم ولی پاسخ قانعکنندهای نداشتم. فهمیدم که بلد نبودن کار با bash (که شل پیشفرض سیستم عاملهای من بوده است) مهمترین دلیلم بوده است. هر چیزی که گفتم با zsh میتوانم انجام بدهم دیدم که با bash هم میشود. البته zsh ویژگیهای مهمی دارد که فهمیدم من نه به درستی از آنها اطلاع دارم نه هرگز استفاده کردهام. یعنی نادانی از آنچه با ابزار سادهتر و پیشفرض مقدور بوده باعث شده که ابزار جدیدی به زندگیام اضافه کنم بدون آنکه هیچ کدام را به درستی فرا بگیرم و از مزایای آنها بهرهمند شوم. بنابراین zsh را بازنشست کردم و به bash برگشتم.
بعد از خودم پرسیدم که آیا من به bash احتیاج دارم؟ شاید sh (همان bourne shell) برای من کفایت کند؟ فعلا با هر دو کار میکنم و جرئت نکردم کامل سراغ sh بروم که بزرگترین مخرج مشترک شلهای رایج است. حسن این دو اینست که تقریبا جهانشمول هستند و روی توزیعهای مخلتف لینوکس و BSD و مک و مانند اینها یافت میشود. از سوی دیگر من از ایمیجهای Alpine به شدت استفاده میکنم که پیشفرض از bourne shell استفاده میکند و بنابراین میخواهم به نوشتن سادهترین شکلاسکریپت ممکن عادت بکنم و در همان محیط هم کار بکنم.
شل را مثال زدم چون شل محیط انجام کارهای روزمره و برنامهنویسی من است و من وقت زیادی در آن صرف میکنم. در حقیقت من دیگر از دسکتاپمنیجر استفاده نمیکنم (پنجرهای که از شما یوزرنیم و پسورد میپرسد و دسکتاپ را باز میکند). بلکه کامپیوترم مستقیم به یک ترمینال بوت میشود و خودم دسکتاب را لود میکنم:
$ exec sway
(دستور exec پراسس جاری(شل) را با پراسس جدید جایگزین میکند.)
یک عکس هم ضرر ندارد:
ممکن است بپرسید علت این حساسیت چیست؟ من روزانه حداقل ده ساعت با کامپیوتر کار میکنم. هر انتخاب اشتباهم در صدها و بلکه هزاران ساعت تکثیر میشود. هر ابزار جدید مشکلاتی با خودش به همراه میآورد. باید آنرا نصب کرد، فرا گرفت و از آن نگهداری کرد. ذهن ما را درگیر میکند. بنابراین از بکارگیری ابزار جدید بدون دلیل محکم خودداری میکنم و به جای آن سعی میکنم ابزارهای رایج یونیکس را بهتر یاد بگیرم. مثلا برای فراگیری شل اواخر این مقالهی مفصل را مطالعه کردم که فورا نتایجش را در طول هفته حس کردم (اسکریپتهای مختلف را فهمیدم، ضعفهایشان را دیدم و شروع کردم به نوشتن).
]]>بعد از سالها استفاده از نتلیفای بالاخره زمان مهاجرت فرا رسید، البته به سرور خودم.
دیروز اول دیدگاههای خوانندگان را از سرور نتلیفای استخراج کردم (اسکریپت بیلدم اینکار را انجام میدهد) و سایت را لوکال ساختم و در سرور خودم کپی کردم (با scp). سپس مشخصات سرویس DNS سرویسدهندهی سرور مجازیام را در nic.ir وارد کردم. (پیش از این از سرویس DNS رایگان نتلیفای استفاده کرده بودم.) روی صفحهی ادمین سرویسدهندهام هم آیپیهای سرور را به دامنه متصل کردم. بعد اول تنظیمات دامنه را از نتلیفای حذف کردم. تقریبا درجا سایت از کار افتاد. بعد خود سایت را از نتلیفای حذف کردم و بعد هم اکانتم را.
سایت همانطور که پیشبینی میکردم از کار افتاد. عجلهای نداشتم. تقریبا دو ساعتی طول کشید تا تغییرات از nic.ir به سایر بخشهای اینترنت برسد. التبه این را امروز به کمک یک سرویس کوچک دیگر (که قصد بازنشسته کردنش را دارم) متوجه شدم. این سرویس کوچک در فواصل زمانی مشخص سرور را پینگ میکند و اگر جوابی نیامد ایمیل میزند که سرور داون است. وقتی هم که برگشت بالا مدت داون بودن را گزارش میکند. من از وبسرور nginx استفاده میکنم. یک بلاک جدید برای سایت اضافه کردم:
server {
listen 80;
root /var/www/mehdix.ir;
index index.html;
server_name mehdix.ir;
location / {
try_files $uri $uri/ =404;
}
}
بعد از این هم با کمک certbot سرتیفیکیتهای لازم برای https را ساختم:
$ sudo certbot
و وبسرور را ریلود کردم:
$ sudo nginx -s reload
انتشار سایت هم میشود یک بیلد:
$ bundler exec jekyll build
و یک کپی:
$ scp -r _site mehdix.ir:/var/www/mehdix.ir;
حالا سایت روی سرور جدید است. همانطور که قبلا نوشتم تا اطلاع ثانوی کامنتدونی کار نمیکند. تا زمانی که آن را تعمیر کنم دو راه حل در نظر گرفتهام. یکی یک کانال ماتریکس است که ساختهام. فعلا که خالی است اما پرسشی داشتید آنجا در خدمتم. فعلا پشه پر نمیزند البته. اگر اسم ماتریکس (بجز فیلم آن!) تا بحال به گوشتان نخورده نگاهی به آن بیندازید. ماتریکس یک پروتکل فدراتیو برای ارتباط امن سرتاسری است (End-to-End or e2e). یعنی سرور مرکزی ندارد و هرکس میتواند از یک سرور با سرورهای دیگر حرف بزند. اتاق مهدیکس که ساختهام روی سرور شرکت المنت سازندهی ماتریکس است. در تعریف ماتریکس هم بگویم که کل رویداد امسال FOSDEM به صورت آنلاین روی ماتریکس برگزار شد، به همراه ویدیو و صوت و چت و اموجی و مانند اینها.
راه دیگر گفتگو هم ایمیل است. اواخر بیش از همیشه به میلینگلیستهای علاقه پیدا کردهام و در اندک اندک در تعداد بیشتری عضو میشوم. برای سایت مهدیکس هم یک میلینگلیست ساختهم که در آن به روی همهی شما باز است، البته اگر توان پنچهدرانداختن با کلایننتهای میل قراضه و وبمیلهای ضد راست به چپ در شما هست! اینباکس عمومی سایت مهدیکس دات آیآر در این آدرس در خدمت شماست. عضویت برای عموم آزاد است. پیامها به صورت استاندارد روی سورسهات قابل مشاهده خواهند بود. ایمیل فقط میتواند متن باشد (html ریجکت میشود، با دلایل خوب). سایت متن راست به چپ را به درستی نماش میدهد (حمل بر خودپرستی نشود خودم تعمیرش کردهام). امتحان بکنید شاید سبب خیری شد.
شاید کنجکاو باشید که مزایای اینکار چیست؟ عرض میکنم. اول اینکه من از تغییرات ناگهانی در شرکت سرویسدهنده که دست برقضا میلیونها دلار هم سرمایه از سرمایهگذاران دریافت کرده و متعاقبا باید منافع آنها را تامین بکند رها هستم. فردا ایمیل نمیاید که داریم در سرویس مفتی را میبندیم بیا سایتت را ببند یا فلان و بهمان. دیگر اینکه لازم نیست یاد بگیرم نتلیفای چطور کار میکند. شاید بگویید خوب حالا مجبوری یاد بگیری nginx و کامنتدونی جدیدت و یا سایر ابزارها چطور کار میکنند. در جواب بگویم که ایرادی ندارد. ترجیح من اینست که کار با فناوری و ابزار کمتر و بنیادیتر را یادبگیرم که تا دهها سال بکارم بیاید. دیگر اینکه حالا میتوانم سایت را نه تنها روی http بلکه مثلا با gemini هم سرو بکنم. یا لاگهای وبسرورم را خودم بخوانم یا کامنتدونی خودم را هاست بکنم. منی که سرم برای این کارها درد میکند خوب برایم همین بهتر است.
خلاصه به این ترتیب پایان یک دوران رقم خورد و دورهی جدیدی برای من شروع شد. دورهای خلوتتر از گذشته اما عمیقتر.
]]>سال ۲۰۱۹ ریچارد استالمن بنانگذار بنیاد نرمافزار آزاد و emacs و GNU بعد از انتقادات عمومی نسبت به رفتارش و نظراتش بویژه در مورد ارتباط بزرگسالان با نوجوانان از سمتش در FSF و MIT کناره گرفت. دو هفته پیش او بازگشتش را به FSF اعلام کرد که یک بحث عمومی را برانگیخته است. در این مقاله به این موضوع میپردازم.
توجه: پیش از شروع بنویسم که قصد من شرح کامل داستان و عکسالعمل آنچه در آمریکا گذشته است نیست. من تا آنجا که این موضوع به جامعهی نرمافزار آزاد میتواند مربوط باشد به این موضوع توجه میکنم و بیش از آن برایم مهم نیست.
در آن سال یک مقاله در مورد جفری اپستاین در شرح ارتباط جنسی یکی از دخترانی که او از آنها بهرهبرداری جنسی میکرد با ماروین مینسکی، یکی از اساتید دانشگاه MIT و از همکاران (یا دوستان) استالمن، منتشر شد.
پس از این مقاله و انتقادات به کمک مالی اپستاین به MIT و کمپینهایی در این رابطه پای استالمن با یک مقاله در انتقاد از رفتار و نظرات استالمن در مورد زنان در دانشگاه MIT و FSF به ماجرا باز شد. در این مقاله نویسنده با نقل قول از ایمیل استالمن او را به عدم رواداری و تبعیض و سوءرفتار نسبت به سایر زنان در حوزهی تکنولوژی متهم میکند، چرا که او در میلینگ لیست دانشگاه به جملهبندی و کلمات یک کمپین علیه مینسکی و اپستاین انتقاد کرده بود.
با وجود انتقاداتی که به محتوای این مقالات شد، بویژه این مقالهی مفصل این ماجرا ادامه پیدا کرد و افراد و شرکتهای مختلف به نفع یا بر علیه استالمن موضعگیری کردند و در نهایت او از سمتهایش کناره گرفت و ماجرا فروکش کرد. تا اینکه دو هفته پیش پس از رویداد اینترنتی Libreplanet 2021 او به طور ناگهانی اعلام کرد که به هیئت مدیرهی FSF بازگشته است، اینبار نه به عنوان مدیر بلکه به عنوان یک عضو.
به فاصلهی یک روز یک نامهی اینترنتی بر علیه استالمن با امضای افراد و شرکتهای مختلف منتشر شد که با خطاب کردن او به عنوان «زنستیز» و «معلولستیز» و «ترنسهراس» درخواست کردهاند نه تنها استالمن از سمتش در FSF و GNU و هرنوع سمت مدیریتی کنار گذاشته شود، بلکه تمام اعضای هیئت مدیرهی بنیاد نرمافزار آزاد از سمتشان کناره بگیرند. در زمان نوشتن این متن پای این نامه ۳۰۱۲ امضا از اشخاص و ۶۱ امضا از شرکتهای مختلف وجود دارد. اگر به لیست نگاه کنید اسامی شناختهشدهی زیادی در آن خواهید دید. از شرکتهای بزرگ تا افراد فعال در پروژههای مختلف و مانند اینها. هموطن از دور و نزدیک هم در لیست پیدا خواهید کرد.
این نامه بیپاسخ نماند و به فاصلهی کوتاهی یک نامهی اینترنتی دیگر در حمایت از استالمن منتشر شد. در این نامه از استالمن به عنوان نیروی محرک جنبش نرمافزار آزاد نام برده شده و از نامهی اول به عنوان یک حملهی اینترنتی سابقهدار نام برده میشود و از FSF میخواهد که تسلیم نشود. پای این نامه در لحظهی نوشتن این متن ۶۰۸۲ امضا از افراد مختلف وجود دارد. بیش از دو برابر نامهی اول. طرفداران استالمن و مخالفین نامهی اول (که آن را به یک حمله از نوع mob یا lynch تعبیر میکنند) وبسایتهای دیگری هم راه انداختهاند. یکی سایت گزارش نبرد است و دیگری در حمایت او یک هم فقط گزارش ارقام است.
هر کدام از نامهها را میتوان با پولریکوئست روی گیتهاب امضا کرد، حمایت اینجا و تقبیح اینجا. برای کسانی که به دلایل مختلف از گیتهاب صرفنظر کردهاند دیگران روی sourcehut و codeberg امکاناتی فراهم کردهاند.
بحث و گفتگو در مورد این جریان همچنان ادامه دارد. شاید یکی از مهمترینها رایگیری در دبیان باشد، چرا که پروژهی دبیان به نوعی الگوی ادارهی یک پروژه مثل یک کشور دموکراتیک است. حالا هم کابران پیشنهاداتی مطرح کردهاند از امضای نامهی تقبیح در یک سو تا امضای نامهی حمایت در سوی دیگر. این رایگیری تا چند روز دیگر ادامه خواهد داشت و خروجی در حال حاضر معلوم نیست. تعداد آرای ثبت شده پیوسته در حال افزایش است.
خوب حالا که شرح قصه تمام شد نظر خودم را مینویسم. من شخصا از دوقطبی شدن اجتماع بیزارم. این بیشتر یک محصول آمریکایی است. در جای دیگر با این شدت تجربه نکردهام. در آلمان هم ندیدهام. شخصا از حملات اینترنتی بیزارم. اینکه تصمیم من نوعی و سرنوشت یک انسان باید با یک حملهی اینترنتی و اعمال قدرت ناگهانی بدون آنکه مرتکب جرمی شده باشم تغییر بکند مرا منزجر میکند. گوئی که در اجتماع دیدگاههای مختلف وجود ندارد. منی که درخت وجودم در ایران شکل گرفته است و هستیام با فرهنگ و مشکلات آن تنیده شده است قادر نیستم با این قبیل حملات همذاتپنداری کنم. حملاتی از این دست در گذشته دیدهام ولی نمیخواهم سیاست و عقاید یک فرد در مورد یک موضوع به همهجای زندگی و همهی فعالیتهای آن فرد کشیده شود. من علاقهمند و نوع سنتی فرهنگ هکرها هستم (اگر چنین چیزی وجود دارد). آیا طرفدار چیزی هستید که من مخالف آنم؟ آیا باید این مخالفت روزنهی هرگونه مدارا و دیالوگ بویژه فنی را مسدود کند؟
طرفداران حذف استالمن دنبال چه چیزی هستند؟ فرض کنیم که او آدم خاص یا عجیب یا نچسبی است. آیا خاص یا عجیب یا نچسب بودن در دمکراسی غربی جرم است؟ (توجه کنید که اینجا در مورد ایران حرف نمیزنیم که یک انسان میتواند به واسطهی رفتار خصوصیاش یا رفتار جنسیاش به مرگ با چوبهی دار محکوم شود.) آیا باید استالمن از چیزی که خودش بوجود آورده و شاید موثرترین فرد بر علیه سلطهی نرمافزارهای بسته و تجاری بر تمام زندگی ما بوده است حذف بشود؟ این آدم زندگیاش با این جنبش معنی شده است. این از او گرفته شود چه بکند؟ خودش را از نزدیکتر پل محل زندگیاش پرت کند زیر اولین قطار عبوری؟ این درخواست حذف را من نمیفهمم. درخواست پاسخگو بودن و شفاف بودن را چرا.
تصور کنید ما بخواهیم اینکار را در جامعهی ایرانیان داخل و خارج ایران انجام بدهیم. نتیجه چه میشود؟ من طی زندگیام در ایران با آدمهای زیادی سر و کار داشتهام. انسان محبوبی را میشناختم که افکار نژادپرستانه راجع به اعراب داشت یا دیگری از همنجنسگرایان وحشت داشت و دیگری اعتقادات مذهبی خاصی داشت. البته معمولا تعصبی روی اعتقاداتشان نداشتند و معمولا چیزی بود موروثی و اگر از نزدیک با عواقب رویکردشان روبرو میشدند انعطافپذیر بودند و تجدیدنظر میکردند. و البته اگر میخواستم تبر تفکیک و تقبیح در دست بگیرم باید پیوسته به کوبیدن این یکی یا له کردن آن یکی میپرداختم. از این رویکرد در زندگی خیری ندیدهام بویژه که بواسطه تجربیات خانوادگی سالها تقاص رویکردهای انقلابی مشابه را پرداختهام. بازگردیم به استالمن که از نرمافزار آزاد و حواشی آن دور افتادیم.
در رابطه با انتقاداتی که به استالمن شده است خواندن مقالهی مفصل را که در بالاتر هم اشاره کردم توصیه میکنم. چرا که با دقت و با موشکافی و با نقل قول دقیق شرح میدهد که چرا بسیاری از اتهامات مطرح شده در سال ۲۰۱۹ از بیخ و بن یا بی اساسند یا قابل تردید. این به معنی تطهیر استالمن نیست، بلکه تقبیح سبک گزارشگری اینترنتی است، یعنی هرچه بیشتر کلیک و لایک جمع بکند محبوبتر است. حقیقت و رفرنس مهم نیست، مهم افزایش هیجان و شور و هیاهو است. چه کسی حوصله دارد یک مقالهی بلند بالا را بخواند؟ یک توئیت و چند جملهی حماسی کافی است تا آتشی بر افروخته شود و هر خوانندهای به این احساس برسد که باید یا طرف خیر را بگیر یا طرف شر را. مثلا استالمن را «ترنسهراس» خواندهاند بواسطهی مقالهای که در مورد استفاده از ضمایر خنثی منتشر کرده است. من این مقاله را خواندم و ترنسهراسی در آن ندیدم. ولی چند نفر از امضا کنندگان نامه آن را خواندهاند؟ حدس شما چیست؟ چند نفر اصلا زحمت پیدا کردن سایت او را به خودشان دادهاند؟ یا بیشتر با نیت خیر به کسی اعتماد کردهاند که شاید خودش به کس دیگری اعتماد کرده است و شاید هم اصلا خواهی نشوی رسوا همرنگ جماعت شو؟ شاید هم بگویید ترنس نیستی ولی چندین مقاله هم از ترنسها خواندهام که با وجود انتقاد به استالمن این حمله را نفی کردهاند.
اضافه کنم که من از دیدن امضای شرکتهای بزرگ زیر پای نامهی اول شگفتزده نیستم. همه این شرکتها PR یعنی روابط عمومی دارند که تصمیم میگیرد چه موضعی برای منافع شرکت مفید است و شرکت هم همان را اعلام میکند. ریسک نمیکنند، چیزی را میگویند که مشتریها دوست دارند بشنوند. بسیاری از نامهای بزرگ فنی هم شرکتهایی هستند که طی سالهای گذشته متاسفانه روی نرمافزار آزاد سایه انداختهاند.
نکتهی دیگری که توجه مرا جلب کرد نبود یا کمبود نام شرکتهای بزرگ میان امضا کنندگان نامهی حمایت از استالمن بود. عدهای این را تعبیر کردهاند به اعلام جنگ شرکتهای تجاری علیه نرمافزار آزاد. شاید اینگونه باشد، ولی من همانطور که در بالاتر گفتم آنها احتمالا مشتریان و برنامهنویسان خودشان را در نظر دارند. امضاکنندگان نامهی حمایت تکثر بیشتری دارند و در میانشان کسانی دیدم که از پلتفرمهایی مثل codeberg یا sourcehut استفاده میکنند که نشاندهندهی نگرانی آنها از تسلط شرکتهای بزرگ بر جهان نرمافزار است. این برای من نشانهی خوبی است هرچند دلیل به نفع یا بر علیه استالمن نیست.
در اینجا اضافه کنم که طبق چیزهایی که خواندهام استالمن ظاهرا آدم سختی است برای همکاری و به نرمافزار آزاد هم مثل یک ایدئولوژی اعتقاد دارد، مثلا اگر نرمافزار غیرآزاد روی یک سایت وجود داشته باشد و لینکش را برایش بفرستید آن را باز نخواهد کرد. لزوما هم به احساسات دیگران توجه نمیکند و البته نظراتش را هرچند بحثبرانگیز در وبسایت شخصیاش مینویسد. عدهای این را به کاستی مهارتهای اجتماعی او بواسطهی اختلالات رفتاری نظیر اوتیسم مرتبط میکنند. من شخصا تجربهی همکاری مستقیم و اینترنتی با متخصصان و هکرهای فنی مختلفی را داشتهام که بسیاری از قیود رایج کلامی یا رفتاری را مراعات نمیکردند (منظورم توهین یا سوءرفتار یا خشونت نیست بلکه انتخاب کلمات و ارتباط چشمی یا مکالمات روزمره و مانند اینهاست) و بسته به روحیه و فرهنگ یک آدم ممکن بود که رفتارشان سنگدلانه به نظر برسد. این را در جامعهی فنی زیاد دیدهام، آدمهایی که با کامپیوتر یا یک فن و تکنیک آشنایی زیادی دارند، میتوانند خوب بنویسند یا بخوانند اما از یک سلام و احوالپرسی ساده عاجزند. خودم هم تا حدودی اینطور هستم. مثلا ممکن از پاسخی به نظرات ندهم یا سلام نکنم یا ایمیلی را بدون پاسخ بگذارم یا تماسی تلفنی را جواب ندهم یا از پیوستن به یک گروه یا شبکهی اجتماعی و مانند اینها صرفنظر کنم. به دلایل مختلف. این میتواند برای کسی که با روحیات و افکار شما آشنا نیست عجیب به نظر برسد. حالا این تفاوت را یا باید پذیرفت یا انکار کرد و پنهان شد، از بیم اینکه جامعه ممکن است انسان را شماتت بکند یا از جمع کنار بگذارد.
در مجموع ترجیح شخصی من اینست که این قبیل حملات اینترنتی برچیده بشود. برداشت من غلبهی احساسات جمعی بر منطق جمعی است. من مخالفت شفافیت در FSF نیستم و فکر میکنم باید روی شفافیت بیشتر کار بکنند. متاسفانه طی هفتههای گذشته بسیاری از حمایت FSF دستکشیدهاند و افراد مختلفی در حال استعفا و کنارهگیری هستند و عدهای هم در حال حذف استالمن. مثلا GCC یک کمیتهی هماهنگی دارد که اعلام کرد نام استالمن را حذف میکند (ظاهرا بیشتر اعضایش برای شرکتهای بزرگ کار میکنند). و البته استالمن هم پیامبر من نیست. ارادت شخصی به او ندارم. اما از قدرتگیری حرکات اینچنینی برای حذف افراد بواسطهی ابراز عقایدشان نگرانم. استدلالهای منتقدین هم برایم قانع کننده نبود و چنین حملهی گستردهای را توجه نمیکرد. شاید مهمترین آنها این بود که عقیده استالمن در مورد حداقل سن برای داشتن رابطهی جنسی (در دفاع از مینسکی)، داینامیک قدرت بین یک بزرگسال و یک نوجوان را در نظر نمیگیرد (ارتباط عاطفی و عاشقانه بین دو انسان با سطوح قدرت مختلف میتواند به سوءاستفاده یکی از دیگری منجر بشود). و در نتیجه او برای ادارهی موارد مربوط به یک کامیونیتی که میتوان اعضای نوجوان داشته باشد مناسب نیست، که بین موافقین و مخالفین بحث است. انتقاداتی به نحوهی مدیریتش شده که به نظرم بلاموضوع است و آنچه از رفتارش با زنان نقل شده در مقالهی مفصلی که لینک دادم به شدت زیر سوال رفته است. موضوع داینامیک قدرت برای من معقول است و به نظرم نیاز است که اینجا استالمن خیلی شفاف این را بیان کند و او و FSF به اعضا با تغییرات جدی اطمینان بدهند که قادرند از محیط امن و سالمی برای اعضا فراهم بیاورند.
در خاتمه اشاره کنم که من هیچ کدام از این نامهها را امضا نکردهام. عقیدهام را در وبسایتم مینویسم که به نظرم کافیست و وقت خیلی بیشتری هم گرفته است نسبت به یک امضا. شما را هم تشویق به امضا نمیکنم. و اگر بخاطر نرمافزار آزاد نبود اصلا به این موضع نمیپرداختم چرا که یک موضع خیلی بعیدی است برای من ایرانی یا خوانندهی این وبلاگ. ولی از جایی که امواج این حوادث به ما هم میرسد بهتر دیدم که شرح بدهم چگونه فکر میکنم و لینکها را هم مستند بکنم شاید برای خوانندهای هم سودمند باشد. مثل هر مقالهی دیگری هم انسان ممکن است عقیدهاش را در مواجهه با استدلالی بهتر از استدلال خودش تغییر بدهد (همانگونه که استالمن هم تغییر داده است). و این حق برای هر انسانی محفوظ است.
]]>همین اواخر قصد داشتم از روی یک فایل YAML تعدادی صفحه استاتیک تولید کنم. مقداری گشتم ولی هیچ سایتسازی پیدا نکردم که اینکار را انجام بدهد. چند ساعتی وقت گذاشتم و خودم یک سایتساز مختصر ۶۷ خطی با پایتون نوشتم.
کاری که این سایتساز کوچک انجام میدهد اینست که تعدادی نقل قول را از یک فایل YAML به کمک پکیج pyyaml میخواند و برای هر کدام یک صفحهی وب جداگانه میسازد، یک صفحه ایندکس هم تولید میکند و دست آخر یک خوراک اتم هم ضمیمهاش میکند و والسلام.
برنامه صفحهها را به کمک پکیج مفید jinja2 میسازد. برای استایل هم از بوتاسترپ استفاده کردم. برنامهی خیلی سادهایست که نیاز من را به نحو احسن برطرف میکند. سورس آن را برای آزمایش روی سورسهات آپلود کردم. فایل gen.py را ببینید. خروجی سایت را هم میتوانید روی وبسایتم ببینید.
]]>طی سالهای گذشته من این وبسایت استاتیک را روی جکیل و گیتهاب و نتلیفای اداره کردهام. برای کامنتدونی هم از اول از دیسکاس و بعد از کامنتدونی دستساز خودم استفاده کردهام. الان در حال مهاجرت به سرور خودم هستم. شرح میدهم چرا.
در گذشته من انواع و اقسام روشها برای تولید و انتشار اتومات برای سایت استاتیک را شرح دادهام. بعضا هم ابزارهایی ساختهام که برای دیگران هم به همین منظور سودمند باشد. طی ماههای گذشته از سویی رفته رفته به این نتیجه رسیدهام که برای انتشار چهار خط نوشته به این همه قیل و قال نیازی نیست. چرا که یک سایت استاتیک را میتوان لوکال ساخت و در یک سرور ریموت با بسیاری ابزارها و پروتکلهای استاندارد لود کرد. حتی میشود شخصا تک تک فایلها را نوشت، یا روی یک ادیتور ساده متن را مستقیم در یک فایل ویرایش کرد، یا مستقیم تکست نوشت، چرا که نه؟ به نوعی از پیچیدگی وب مدرن و دنگ و فنگ سرویسهای ابری خسته شدهام. قدرت از کاربر و نرمافزارهای آزاد به سرویسدهندههای ابری منتقل شده است و برنامهنویس بجای یادگیری عصارهی علوم کامپیوتر به یادگیری رابطهای کاربری شرکتهای بزرگ میپردازد که درنهایت همان کاری را انجام میدهد که شاید خود برنامهنویس خیلی سادهتر به کمک نرمافزارهای آزاد از پس انجامش بربیاید. البته شروطی دارد، باید از بسیاری دنگ و فنگها گذشت کرد. باید از فرع گذشت و به اصل چسبید.
شاید بپرسید فرع چیست و اصل چیست. من از دید خودم اینها را برای خودم تعریف میکنم. برای من دانش خام کامپیوتر اصل است. مثلا اینکه چطور دو پراسس روی دو کامپیوتر با هم حرف میزنند؟ کامپیوتر که نمیتواند با کسی حرف بزند، هر چیزی که الان روی این صفحههای موبایل یا لیپتاپ که در مقابل شماست در یک پراسس تولید شده است. فهمیدن این اصل است. سیستم عامل اصل است. مهمترین اصل است. اینکه یک اپ یا برنامهی خوشگل روی صفحه چه وعده و وعیدی به کاربر میدهد فرع است. این سختافزاری که دارد دستوارت این پراسسها را پردازش میکند اصل است. دستوارت اسمبلی آن اصل است. فهمیدن اینکه چه میکند، بکدور دارد یا نه، نرمافزارهای بسته داخل سیپییو هست یا نه اصل است (از حدودا ۲۰۰۸ به این سو همه سیپییوها بکدور دارند، آنها میگویند برای آیتیو شرکتهای بزرگ است، ما میگوییم هر چیز که من کاربر نمیتوانم از کار بیندازمش بکدور است). مثلا اینکه یک پروتکل مثل http چطور کار میکند اصل است، اینکه یک درخواست و پاسخ آن چه شکلی است اصل است. فلان فریمورک وب فرع است. اینکه پروتکل ایمیل چطور کار میکند و یک پیام ایمیل چه هدرهایی دارد اصل است، سرویس میلیاردی ایمیل گوگل فرع است هرچند باور آن سخت باشد. کاربر یک برنامه اصل است، یک برنامهنویس اصل است، شرکت و سرمایهگذار و همه اینها فرع است. به آن فکر کنید، کسی نیست که در جهان بگوید ماست من ترش است و بدون من هم جهان به راه خودش خواهد رفت. و شاید بی ربط نباشد که اضافه کنم که وب را سودجویان به نابودی کشیدهاند و تبدیل کردهاند به باتلاقی از تراکینگ و سرقت اطلاعات و دزدی توجه کاربران و دستکاری اندیشههای آنان و تاثیرگذاری روی تصمیمات زندگی آنها که شرح آن مجالی دیگر میطلبد.
اگر جوان هستید، اگر دانشجو هستید و اگر تازه وارد این دنیا شدهاید و اگر به نرمافزار آزاد علاقه دارید قبل از هر تصمیم به استفاده از یک تکنولوژی «جدید» یا محصول فلان شرکت و مانند اینها دو بار فکر کنید. وقت گرانبهای خودتان را مجانی نفروشید چه بسا که با پرداختن به اصل چیزی خلق کنید که کسی باور نکند. با پرداختن به فرع امکان خرق عادت نخواهد بود و مجالی برای گریز از آنچه هست و اینکه همه چیز ساخته شده است و مانند اینها نخواهد بود.
از سوی دیگر حساسیتی ویژه پیدا کردهام به بکارگیری سرویسهای ابری و یکی پس از دیگری مشغول حذف آنها بودهام. چرا تابحال به این سادگی مشغول باز کردن اکانت روی هر سرویسدهندهی شناس و ناشناسی بودهام؟ به نوعی همواره گول زرق و برق یک سایت یا لندینگپیج طراحی شده توسط دپارتمان مارکتینگ یک شرکت معمولا خصوصی با پشتبیانی سرمایهگذارهایی که هر یک در صدد تزاید سود خویش بودهاند را خوردهام. همانطور که بالاتر گفتم عیب بزرگ این عادت دور ماندن از اصل و چسبیدن به فرع است. یک شرکت به شما یک رابط کاربری خوشدست میدهد ولی بین شما و دانش و نرمافزار و سختافزار فاصله میاندازد. از سویی هر زمان شرایط استفاده میتواند به دلایل مخلتف تغییر بکند که شوکی ناگهانی به برنامهنویس وارد میکند. سادهترینش شاید این باشد که فلان شرکت بگوید به خاطر تحریم به شما سرویس نمیدهم. یا شرکتی دیگری بگوید فلان ورژن را دیگر ساپورت نمیکنیم یا فلان را آپگرید میکنیم و مجبورت بکند که تن به تغییری ناخواسته بدهی.
چیزی که ما معمولا از آن غافل هستیم ارزش وقت و توجه ماست. وقتی بجای کنسول سرور شخصی خودت روی کنسول و وبسایت یک شرکت ثالث هستی، آن شرکت به راحتی با یک آپدیت یا یک نوتیفیکیشن این وقت و توجه قیمتی را به سرقت میبرد. کس دیگری تصمیم میگیرد که امروز من چه چیزی ببینم و نگاهم در هر ساعتی به چه چیزی خیره بشود. این بزرگترین خسارتی است که میتوانم تصور بکنم.
همین ماجرا هم به نوع دیگری وقتی از نرمافزارهای غولآسا استفاده میکنی اتفاق میافتد. مثلا مدتهاست که «اوپن سورس» به واژهای برای دپارتمانهای مارکتینگ شرکتهای مختلف تبدیل شده است. هر یک در تلاشند تا برنامهنویس را در تلهای گرفتار کنند و به او سرویسی بفروشند یا نگاهش را تغییر بدهند و به سرویسهای خودشان وابسته بکنند. این هم خسارتی بزرگ است.
به همین خاطر مثلا در حال مهاجرت از گیتهاب هستم به سورسهات. سورسهات سرویسی است در وضعیت آلفا. یعنی به شدت در حال توسعه. برنامهنویس اصلی آن برنامهنویس wlroots و sway است. یعنی پیش از این حداقل دو کار در خور و ارزنده انجام داده است. این سرویس کاملا از بیخ و بن اوپن سورس است اما پولی است. چرا از سرویس خوش رنگ و لعاب گیتهاب به کوزه شکستهی سورسهات میروم؟ (البته میتوانم خودتم مثلا با cgit یا مانند آن حتی ریپازیتاریهای خودم را هاست بکنم). جواب ساده است. اگر برای استفاده از سرویسی که میلیارها دلار ارزش دارد (ماکروسافت گیتهاب را به بهایی بیش از پنج یا شش میلیارد دلار خرید، حجم این مبلغ دیوانه کننده است) و سالیانه میلیونها دلار خرج دارد پولی نمیدهید محصول خودت شما هستید. و البته لازم به گفتن نیست که من در این جهان فانی تنها کاری که قصد انجامش را ندارم اینست که محصول باشم. قصد من توصیهی سورسهات نیست. این هم فقط یک مثال است. حسن آن چیست؟ سورسهات سرمایهگذار ندارد. فاینانس مستقیم از کاربران میاید. بله من برای این سرویس پول پرداخت میکنم چون میخواهم آلترناتیوری در برار ابرقدرتهای نرمافزاری بوجود بیاید. آلترناتیوی که از سرویسها و پروتکلهای آزاد استفاده میکند. من رابط کاربری سورسهات را برای فارسی و عربی تعمیر کردم. آیا میتوانستم اینکار را برای گیتهاب انجام دهم؟ نه. باید التماس میکردم. اما سورسهات نمونهی یک تیم کوچک مستقل است، میتوان مسقیتم با برنامهنویسان همکاری کرد که حسن بزرگی است.
نرمافزار آزاد فقط سورس آزاد نیست، هرچند آن هم ارزشمند است. نرمافزار آزاد برای من ابزاری است که فردی یا افرادی برای استفادهی خودشان و دیگران منتشر کردهاند و داخل آن قلابی برای به دام انداختن کاربر تعبیه نکردهاند، دنبال سرقت اطلاعات و وقت و توجه اون نیستند. دپارتمان مارکتینگ و روابط عمومی و فستیوال دعوت به پول ریکوئست و اینها ندارند. پولی برای اینکارها نیست.
بگذارید مثالی بزنم. یک شرکتی بود که الان نامش یادم نیست، تیشرت میداد به هرکس که فلان تعداد پولریکوئست روی گیتهاب داشته باشد. آنزمان برای من هم جالب بود، ولی بعدها جایی خواندم که با این کارش هزاران پولریکوئست اسپم بوجود میآورد که سرازیر میشود داخل پروژههای اوپنسورس که اغلب توسط علاقهمندان و داوطلبان اداره میشود و وقت آنها را میگیرد بدون اینکه سودی عملی در پی داشته باشد. آن شرکت هم در پاسخ اعتراض این برنامهنویس گفته بود که نمیتواند کاری بکند. ولی فکرش را بکنید هزار تا یا ده هزارتا تیشرت چقدر ارزش دارد؟ دپارتمان مارکتینگ آن شرکت این جریان را راهمیاندازد تا برای شرکت کسب شهرت بکند، و در ادامه وقت هزاران برنامهنویس دیگر را تلف میکند.
خلاصه بگویم که تا جایی که در توان دارم مشغول تزکیه هستم. هر جا بتوانم از آلترناتیوهایی استفاده میکنم که توسط برنامهنویسهایی ساخته شده است که آزادی و کاربر برایشان در اولویت بوده نه منافع تجاری شرکت. چرا که باید دیر یا زود بین منافع شرکت و سرمایهگذارانش و منافع کابران یکی را انتخاب بکند و سخت است که هر دو با هم بشود.
این شد که تصمیم گرفتم که هم از شر کنترل شرکتهای مختلف خلاص بشوم و هم وقتم را بی واسطه صرف دانش پایهای کامپیوتر بکنم، مثلا بجای یادگرفتم رابط کاربری فلان شرکت، یاد بگیرم چطور مستقیم برای شبکه برنامه بنویسم، پروتکلها را بشناسم و مانند اینها. لازمهاش اینست که وقتم را روی سرور خودم بگذارنم و مستقیم به دست خودم همه کارها را انجام بدهم. وقت یک منبع محدود است، یکجا که مصرف شد یعنی جای دیگر مصرف نشده. پس با حذف واسطهها و رابطهها میروم سروقت اصل مطلب که سودمندتر است و مفرح است.
این وبسایت هم مستثنی از جریان نیست. در حال مهاجرت هستم به سرور خودم. از سویی یکی از خوانندگان عزیز پیام داد که نتلیفای را مثل بسیاری چیزهای بدرد بخور دیگر در ایران از بیخ بستهاند که مبادا یک برنامهنویس خسته یک وبسایت آنچا آپ بکند، اما بهرحال پیش از این من چمدانها را بسته بودم. یعنی بیلد و هوکها و هاست وبسایت و ایمیل و کامنتها را باید خودم اداره بکنم.
خوانندهی عزیز، از اینکه وقت گذاشتی و این مطلب را خواندی تشکر میکنم. از دیدگاهها هم طبق معمول استقبال میکنم.
پینوشت: این مطلب روی لپتاپ پاینبوکپرو ۱۹۹ دلاریام با سیستم عامل مانجارو مبتنی بر آرچ لینوکس و در ادیتور gedit نوشته و منتشر شد.
]]>من چندان اهل بازی کردن نیستم، گهگاه بازیهای دوبعدی بازی میکنم و اواخر هم به اصرار شایگان کلی Stardew Valley دو نفری بازی کردیم که البته بسیار لذت بخش و حتی آموزنده بود.
وقتی که بازی سایبرپانک منتشر شد به درخواست شایگان نسخهای سفارش دادم. از جایی که او به خاطر باگهای بسیار گزارش شده در بازی فعلا از بازی کردن صرف نظر کرده، تصمیم گرفتم خودم بازی کنم.
به عنوان آدمی که از کوزه شکسته آب میخوره، سیستم عامل من ترکیبی از غریبترین نرمافزارهای موجوده. بواسطهی آرچ لینوکس بودن که همواره در لبهی تیغ حرکت میکنیم. ولی من پا رو از این فراتر گذاشتم و پس از سالها از xorg به Wayland و از GNOME به Sway مهاجرت کردم تا نفسی تازه کنم و در پی تصمیمی که اواخر گرفتم از نرمافزارهایی که توسط شرکتهای بزرگ اداره میشوند به طرف نرمافزارهای کوچکتر و سبکتر که توسط گروههای کوچک و مستقل اداره میشوند حرکت کنم.
بنابراین اصلا فکر نمیکردم امکان اجرای یک بازی ویندوزی روی چنین سیستمی وجود داشته باشه. ولی بخت با من یار بود و برنامههایی مثل Wine به قدری پیشرفت کردند که این امکان فراهم شده.
توجه کنید که من اینجا بازی رو مستقیم روی سیستم اجرا میکنم و کارت گرافیکی دومی هم ندارم. سیپییو من AMD Ryzen 3000 بدون گرافیک توکاره و کارت گرافیکم هم AMD RX580. علت انتخاب گرافیک AMD از ابتدا اطلاع از وجود درایورهای بهتر روی لینوکس بود.
اگر کارت گرافیکی دومی داشتم از GPU Passthrough استفاده میکردم. با یک سرچ کوچک راهنمای خوبی پیدا کردم که جزئیات کار رو شرح داده. در این روش دو کارت گرافیک نیازه و یکی اختصاصا به یک ماشین مجازی ویندوز داده میشه و به این طریق میشه با سرعت بالا بازی کرد.
از طرف دیگر اگر کسی بازی رو روی استیم خریداری کرده باشه، استیم میتونه مستقیما به کمک پروتون و واین در پشت صحنه بازی رو اجرا میکنه. هرچند از جایی که من از اسیتم بازی رو نخریده بودم امکان اینکار نبود. من برای بازی یک کد دانلود دریافت کرده بودم که بازی رو از gog store دانلود کنم. اما این فروشگاه فقط کلاینت ویندوز داره. یه انسان دوست داشتنی برنامهای عالی به نام مینی گلکسی برای لینوکس نوشته که اجازه استفاده از اکانت gog روی لینوکس رو فراهم میکنه.
اول به کمک مینی گلکسی بازی رو دانلود کردم. این برنامه هیچ فیچری نداره. فقط میتونه بازیها رو از اکانت دانلود کنه که من هم همین رو لازم داشتم. بعد از دانلود دیگه به برنامه نیازی نیست مگر برای آپدیت.
برای اجرا نیاز به نصب پروتون بود که از ریپازیتوری کاربران آرچ (aur: arch user repository) نصب کردم:
$ yay proton-ge-custom-bin
از جایی که من بدون استیم بازی رو میخواستم اجرا کنم با جستجوی متوجه شدم که نیاز به رانتایم استیم دارم که در ریپازیتوری اصلی آرچ فراهم بود:
$ sudo pacman -S steam-native-runtime
(قبلا مجبور شده بودم که mesa-git رو هم نصب کنم ولی الان نیازی نیست چون تغییرات لازم در ریپازیتوریهای اصلی اعمال و منتشر شده.)
با این تغییرات بازی روی کامپیوترم اجرا شد، البته از ترمینال باز میکنم:
$ proton GOG\ Games/Cyberpunk\ 2077/bin/x64/Cyberpunk2077.exe
بازی معمولا بدون مشکل اجرا میشه. من حتی استک صوتی کامپیوتر رو با برنامهی جدیدالتاسیس پایپوایر جایگزین کردم و تصورم این بود که اصلا از بازی صدا درنیاد (به هر دلیلی، مثل همیشه!) ولی کار کرد!
گاهی بعد از آپدیت پکیجها پیش آمده که بازی باز نمیشه که در این مواقع اول فایلهای سیو بازی رو از داخل پوشهی پروتون کپی میکنم و بعد پوشه رو کامل حذف میکنم:
$ cp -r .local/share/proton-pfx/0/pfx/dosdevices/c:/users/steamuser/Saved\ Games/CD\ Projekt\ Red ~/Backups/
$ rm -rf .local/share/proton-pfx
و بازی رو دوباره اجرا میکنم و میبندم و بعد سیوها رو برمیگردم سر جای اولشون:
$ cp -r Backups/Cyberpunk\ 2077/ .local/share/proton-pfx/0/pfx/dosdevices/c:/users/steamuser/Saved\ Games/CD\ Projekt\ Red/
بازی باگ کم نداره اوایل چند بار کرش کرد یا آرتیفکتهایی در هوا معلق بودند یکبار هم تو یک کوچه گیر کردم و هر کار کردم نتونستم در برم :) ولی در مجموع خیلی راضی هستم.
]]>در گذشته ۱۰۶ رباعی خیام را به فرمت YAML منتشر کرده بودم. طی روزهای گذشته همینها را با میکروفن ضبط کردم و فایلهای صوتی آنها را منتشر کردم.
هدفم این بود که بتوان رباعیها را علاوه بر خواندن گوش کرد. اکثر این رباعیها و هزاران شعر دیگر در سایت خوب گنجور هم در دسترس است و بسیاری از آنها را هم میتوان گوش کرد. من هم برای فهم تلفظ صحیح بعضی لغات به کامنتهای سایت گنجور و نیز فایلهای صوتی آن مراجعه کردم.
ابیات را با میکروفن Q2U ساخت SAMSON در خانه ضبط کردهام. این میکروفن صداهای مزاحم محیط را کمتر ضبط میکند. ابیات اول کمی کمجان از آب درآمدند ولی مجدد ضبط نکردم، از یک چهارم اول به بعد باید صدا خوب باشد.
برای ضبط از برنامهی Sound Recorder گنوم استفاده کردم. برنامه برای ضبط تعداد زیادی فایل چندان مناسب نیست چرا که نمیتوان همه فایلها را با هم ذخیره کرد ولی کار را انجام داد. فرمت فایلهای اصلی flac است اما نسخه ogg که کمحجمتر است را برای انتشار انتخاب کردم.
برای تبدیل فایلهای flac به ogg از برنامهی ffmpeg به صورت زیر استفاده کردم:
for i in `ls`; do ffmpeg -i $i $i.ogg; done
تمامی فایلها را هم پیش از تبدیل با برنامهی EasyTAG به نحو مطلوب تگگذاری کردهام. برنامههای مختلف مانند VLC و یا mpv تگها را موقع پخش به درستی نمایش میدهند. برای اینکه تگ عنوان هر فایل را به راحتی به شکل تزایدی تغییر بدهم از برنامهی lltag و bash استفاده کردم:
c=1;for i in `ls`; do lltag --yes --tag title="Quatrain No. `printf "%03d" $c`" $i && ((c=c+1)); done
برای هر فایل هم یک Album Art که همان تصویر خیام از سایت ویکیپدیاست با ذکر منبع به کار گرفتهام. همه چیز هم تحت مجوز CC BY-SA 4.0 قرار دارد. یعنی دست بزن اما خیانت مکن :)
البته شاید بگویید به چه درد میخورد؟ اول اینکه انتشار آزاد محتوای بیشتر با مجوز درست و تگ حسابی که ضرر ندارد. دیگر اینکه فکر کردم از این ۱۰۶ متن و صوت بتوان به عنوان یک دیتاست کوچک آزمایشی برای پردازش صوت استفاده کرد.
همهی فایلها روی گیتهاب است. فایل زیپ مستقیما قابل دانلود است.
]]>در مطلب قبلی در مورد بازی توضیح دادم که چطور بازی گربهی کوانتومی را به فارسی ترجمه کردهام و همزمان موتور بازی را هم تعمیر کردهام. حالا هم بازی را به وباسمبلی برگرداندهام که میتوانید بدون نصب روی همین وبسایت بازی کنید.
بفرمایید:
بازی را مستقیما هم میتوانید اینجا باز کنید. بازی را روی فایرفاکس و کروم امتحان کردهام. ممکن است روی مک اجرا نشود، تست نکردهام.
بازی شاید ساده به نظر برسد اما حاوی نکات مهمی است. گرافیک با SDL2 نوشته شده و برای فارسیسازی هم من HarfBuzz را به شکل غیرمستقیم بکار گرفتهام. فایلهای بازی هم همگی لود میشوند و صدا هم پخش میشود. توجه کنید که بازی اصلی به زبان C نوشته شده و وابستگیها هم به C یا CPP هستند. پیشرفت بازیکن هم در بازی داخل براوزر ذخیره میشود. حالا همگی اینها به وب تبدیل شدهاند و بدون اینکه احتیاجی به نصب باشد میتواند مستقیم آنرا بازی کرد.
نویسنده اصلی اسکریپتی برای تبدیل به وباسمبلی نوشته بود که من تغییرش دادم تا توابع لازم برای فارسیسازی را هم شامل بشود. کار اصلی را emscripten انجام میدهد. emscripten یک جعبهابزار کامل است برای تبدیل برنامههای سی و سیپلاسپلاس به وباسمبلی. آن هم به نوبه خودش از llvm استفاده میکند. من مستقیما کاری با llvm نداشتم اما با emscripten چرا.
از جایی که قصدم تنها انتشار نتیجهی کارم بود همینجا مطلب را تمام میکنم. امیدوارم از بازی لذت ببرید.
]]>دیروز بعد از مدتها تصمیم گرفتم یک برنامهی کوچک بنویسم که کاری بجز ساختن ترکیبات اسمی بامزه فارسی نمیکند. برنامه را به زبان برنامه نویسی Rust نوشتم و منتشر کردم.
این برنامه واقعا نادان است. ولی با وجود نادانی برنامهی خوبی است. چرا؟ اصلا مگر میشود به برنامهای که خروجیاش «میمونک جسور» یا «مورچهی خوشفکر» یا «کرگدن دلسوز» باشد گفت برنامهی بد؟ تصدیق میکنید که نمیشود. یعنی اصلا امکان ندارد که بشود. اصلا هم مهم نیست که این برنامه ده خط کد دارد یا ده میلیون خط. حتما برنامهی خوبی است!
هربار که این صفحه را ریفرش کنید اگر همه چیز بر وفق مراد پیش رفته باشد باید یک ترکیب اسمی در پایین ببینید:
برنامه را با Rust نوشتم چرا که میتوان آنرا تقریبا ساده به WebAssembly کامپایل کرد. کلمهای در بالا دیدید (اگر کار کرده باشد) در حقیقت در یک برنامهی ساده به زبان Rust نوشته شده. اما Rust که در وب اجرا نمیشود. در وب فقط جاوااسکریپت است که کار میکند. برنامه بالا به WebAssembly کامپایل شده و به همین خاطر در براوزرهای جدید کار میکند.
«وسم» زبانی است شبیه به اسمبلی. دو کاربرد مهم دارد. یکی اینکه پای هر برنامهای که به WebAssembly کامپایل بشود را به وب باز میکند. معنایش اینست که یک برنامه C/C++
میتواند به وسم کامپایل بشود و در مرورگر اجرا بشود، بدون اینکه کاربر چیزی نصب بکند. تکنولوژی همان تکنولوژی وب است منتها وسم هم به آن اضافه شده.
کاربرد دیگرش آنست که سرعت وب را بالا ببرد. برنامههای وسم به مراتب سریعتر از جاوااسکریپت اجرا میشوند چرا که وسم از بنیاد طوری طراحی شده است که مانند اسمبلی باشد، یعنی پرفرمنس از ابتدا در طراحی نقش داشته است.
در ضمن وسم جاوااسکریپت نیست اما میتوان از جاوااسکریپت توابع وسم را صدا زد و بالعکس. این هم یکی دیگر از معیارهای طراحی بوده است. دیگر اینکه زبان اسمبلی وسم طوری انتخاب شده که دستورالعملهای پردازندههای حال حاضر تا جای ممکن اشتراک داشته باشد تا از این راه مرورگر بتواند با سرعتی نزدیک به اجرا به زبان ماشین برنامههای وسم را روی کامپیوتر مقصد اجرا بکند.
بحث مفصلی است و من هم تازهکارم. بیشتر یادگرفتم دوباره مینویسم. جهت خالی نبودن عریضه:
برای نصب کافیست آنرا با «کارگو» (نصاب برنامههای Rust) نصب کنید:
$ cargo install felfel
$ felfel
اگر هم خواستید با وسم امتحان کنید یک پروژه ساده بسازید و به آن «فلفل» بزنید:
$ npm init wasm-app myapp && cd myapp
$ npm install felfel
$ npm run start
بعد هم کافیست تابع gen
را صدا بزنید:
import * as felfel from 'felfel';
console.log(felfel.gen());
شاد و سرافراز باشید
]]>مدتی پیش به طور اتفاقی به یک بازی ساده به سبک ماجراجویی متنی برخوردم و از بازی کردنش خیلی لذت بردم. تصمیم گرفتم بازی را فارسی کنم که منجر به فارسیسازی موتور بازی هم شد. در ادامه مینویسم که ماجرا چه بود.
میتوانید اینجا بازی کنید
اسم بازی The Returning of the Quantum Cat است که نسخه انگلیسی آن را میتوانید مستقیم روی itch.io بازی کنید. نام موتور بازی INSTEAD است و به زبان C نوشته شده و روی پلتفرمهای مختلف مانند لینوکس و ویندوز و اندروید قابل اجراست.
یک هکر و فیزیکدان کهنهکار از جهان بریده و به جنگلبانی مشغول است تا اینکه روزی گربهی محبوبش پس از ظاهر شدن یک فرد غریبهی مشکوک غیب میشود و او باید گربهاش را نجات بدهد…
این قبیل بازیها را به نام Interactive fiction یا IF میشناسند. در این سبک بازیکن داستان را «میخواند» و پیش میرود و هر از گاهی سوالاتی را پاسخ میدهد یا با اشیاء و افراد وارد تعامل میشود و بازی پیش میرود. گاهی بازی میتواند کاملا متنی باشد و در آنصورت تنها تخیل بازیکن است که باید بازی را تصور کند. البته گاهی هم کاغذ و مداد کمک میکند.
نسخه اصلی داستان بازی را یک برنامهنویس روس به روسی نوشته و کسی هم آنرا به انگلیسی برگردانده. من از روی نسخه انگلیسی بازی را به فارسی ترجمه آزاد گردم. یعنی در قید و بند اینکه هر کلمه و جمله را واو به واو به فارسی برگردانم نبودم. حدسم اینست که مترجم انگلیسی هم نبوده است! ترجمه را ببینید و دوست داشتید در کم و کیف آن در کامنتدونی اظهار نظر کنید. متن بازی روی گیتهاب است.
بازی از فضاهای مختلف تشکیل شده. بازیکن از یک نقطه شروع میکند و پس از تعامل با برخی اشیاء (مثلا برداشتن آن) و یا صحبت با افراد میتواند به نقاط جدیدی برود و بین آنها به پس و پیش حرکت کند. طبق معمول هم یک خورجین دارد که وسایلش را میریزد آن تو.
سبک کار موتور این بازی به این صورت است که یک اسکریپت به زبان برنامهنویسی لوئا را میخواند و بازی را از روی آن میسازد (مثلا فضاهای بازی یا همان اتاقها). لوئا بین بازیسازان خیلی محبوب است چرا که هم بسیار ساده است و هم سبک و براحتی در برنامههای C میتوان جاسازیاش کرد. از طرفی کار بازیسازان را راحت میکند چرا که نیاز نیست از پیچیدهگیهای موتور بازی سردربیاورند. شما براحتی میتونید با تغییر متن بازی (ترجمه و بازی با هم مخلوط هستند) بازی را تغییر بدهید، اتاقهایی به آن اضافه کنید، عکسها را دستکاری کنید و مانند اینها.
بعد از ترجمه مقداری از بازی متوجه شدم که موتور بازی راست به چپ را اصلا نمیفهمد. با مقدار زیادی تقلا توانستم سردربیاورم که مشکل کجاست و آنرا رفع کردم. مقدار زیادی تغییرات در موتور بازی دادهام که بتواند متنها را از راست به چپ رندر کند. برخلاف برنامههای سطح بالاتر که معمولا با اشیاء سر و کار داریم و ایونتها را میتوان هندل کرد، در برنامههای گرافیکی معمولا از این خبرها نیست و باید بسیاری چیزها را محاسبه و رندر کرد. مثلا وقتی بازیکن روی یک لغت کلیک میکند چه اتفاقی میافتد؟ یک روال در جایی از برنامه مختصات نقطه کلیک شده را پیدا میکند بعد میگردد ببیند که آنچا چیزی نوشته شده است یانه؟ اگر چیزی نوشته شده که از قضا قرار است که بازیکن با آن تعامل بکند میرود و روالی را صدا میزند که تعامل را انجام دهد و الی آخر. یا مثلا وقتی موس را حرکت میدهیم و رنگ یک کلمه تغییر میکند چه میشود؟ اینبار هم با اعمال شاقه جای لغت پیدا شده و فورا به رنگ دیگری نقاشی میشود. اینها چیزی است که همین الان در گوشی شما یا در فایرفاکس یا کروم و مانند اینها دارد هر لحظه اجرا میشود و ذهن ما اصلا متوجه این همه پیچیدگی نمیشود و فریب میخورد. در یک برنامه سطح بالا ما اصلا به این موارد برخورد نمیکنیم.
یک برنامهنویس روس دیگر برای موتور بازی یک لانچر اندروید نوشته است. لانچر به جاوا نوشته شده ولی برنامه سی کامپایل شده و توابع وابسته آنرا را روی اندروید اجرا میکند. فعلا نسخه آخر برنامه و موتور بازی با تغییرات من منتشر نشده (موتور بازی باید با یک فلگ کامپایل شود تا راست به چپ ساپورت کند، به خاطر Backward Compatibility). اگر دوست دارید بازی را با ترجمه فارسی بازی کنید پکیج بازی و فایل زیپ خود بازی را دانلود کنید و امتحانش کنید.
در عکسهای زیر هم اگر لود شده باشد میبینید که چطور باید فایل زیپ را در اپ اندروید باز کرد.
اول قصد داشتم حسابی در مورد SDL و SDL_ttf و HarfBuzz و JNI اینها هم بنویسم که همگی را برای رفع عیب موتور بکار گرفتهام و بلکه هنگام نوشتن خودم آنها را بهتر بفهمم. ولی فعلا به انتشار پکیج بازی اکتفا میکنم.
]]>