Bagaimana Saya Membaca Keluaran Serial Microcontroller Tanpa IDE-nya
On this page
- Pendahuluan
- A. Alasan terakhir membuka IDE
- B. Untuk apa keluaran serial itu sebenarnya
- C. Enam hambatan yang menghalangi
- Metode
- A. Programnya memang sudah ada di mesin
- B. Menjawab dua kesalahan yang benar-benar terjadi
- C. Default yang benar sebagian besar waktu, dan bisa ditimpa sisanya
- D. Menolak memusnahkan rekaman sebelumnya
- E. Kenapa exec, dan apa yang sebenarnya ia ubah
- F. Merekam sebagai mode, bukan sebagai default
- Hasil dan Pembahasan
- A. Yang dikerjakan IDE tanpa pernah disebutkan
- B. Pola di balik keenamnya
- C. Ketika pendekatan ini berhenti jadi yang tepat
- Simpulan
- Istilah
Pendahuluan
A. Alasan terakhir membuka IDE
Firmware yang sedang saya kerjakan menyasar CH32V203RBT6 — microcontroller berbasis RISC-V yang toolchain resminya MounRiver Studio. Seperti kebanyakan IDE bawaan vendor, ia jalan resmi untuk mengerjakan semuanya: menulis code, mengompilasi, mem-flash chip, dan menonton apa yang chip itu katakan balik.
Satu per satu, pekerjaan itu pindah keluar. Menulis code pindah ke VS Code, sebab di sanalah seluruh project saya yang lain sudah tinggal. Kompilasi pindah ke terminal, sebab build yang bisa dijalankan dari terminal adalah build yang bisa dijalankan dari mana saja. Flash pindah ke terminal dengan alasan serupa. Yang tersisa cuma satu: membaca keluaran serial, aliran baris printf yang memberitahukan apakah yang baru saja di-flash berperilaku seperti yang dibayangkan.
Satu pekerjaan itulah yang masih menahan IDE tetap terbuka. Bukan karena sulit, melainkan karena ia satu-satunya bagian yang belum pernah dipindahkan. Pekerjaan semacam itu bertahan bukan lewat perlawanan, melainkan lewat kebiasaan: selama ada satu alasan menyalakan aplikasi besar, aplikasi itu tetap terpasang, tetap diperbarui, dan tetap menuntut perhatian saat dibuka.
Tantangannya: membaca keluaran serial dari microcontroller yang sedang dikembangkan, di Linux, tanpa memasang IDE yang seharusnya dipakai untuk chip itu.
Gampang dirumuskan, canggung dibangun. Kecanggungannya bukan pada membaca byte dari port serial — program yang mengerjakan itu sudah ada di tiap sistem Unix sejak puluhan tahun lalu. Melainkan pada segala yang diam-diam dikerjakan IDE di sekeliling pembacaan itu, yang baru kelihatan justru setelah IDE-nya pergi.
B. Untuk apa keluaran serial itu sebenarnya
Dua hal tentang cara keluaran ini dipakai menentukan seluruh keputusan di bawah, dan keduanya tak kelihatan dari luar.
Pertama, lalu lintasnya satu arah. Ini pembacaan untuk debugging, bukan sesi interaktif: firmware mencetak, saya membaca. Tak perlu mengetik perintah balik ke perangkat, tak ada protokol yang harus dijawab, tak ada prompt di seberang yang menunggu masukan. Tool yang cuma membaca bukan keterbatasan di sini; justru itulah seluruh kebutuhannya. Perbedaan itu menghapus banyak pertanyaan sekaligus: tak perlu memikirkan line ending yang dikirim, tak perlu mengurus echo lokal, tak perlu menimbang siapa yang bicara lebih dulu.
Kedua, kadang membaca saja tak cukup, dan keluarannya harus disimpan. Ketika bug muncul sesekali saja — persoalan timing, atau peripheral yang salah inisialisasi satu kali dari sepuluh kali boot — yang berguna bukan menonton jalan yang sekarang, melainkan membandingkannya dengan jalan sebelumnya. Artinya keluaran itu harus mendarat di sebuah file, dan artinya log yang musnah bukan sekadar merepotkan melainkan hilangnya bukti yang mungkin tak bisa diulang. Bug yang muncul satu kali dari sepuluh tak menunggu sampai kita siap merekamnya; ketika akhirnya tertangkap, rekaman itu satu-satunya salinan yang ada.
Dua kenyataan itu menjelaskan kenapa tool ini berbentuk begini: pembaca secara default, perekam bila diminta, dan luar biasa berhati-hati soal rekamannya.
C. Enam hambatan yang menghalangi
Serial monitor cuma menumpang di dalam aplikasi yang selebihnya tak saya butuhkan. MounRiver Studio ada untuk menulis dan mem-build firmware, dan keduanya sudah pindah. Menyalakan IDE utuh demi menonton aliran teks lewat adalah mesin besar untuk pekerjaan kecil, dan alternatif yang ditolak pantas disebut namanya: serial monitor bawaan Arduino IDE, tawar-menawar yang sama dalam bungkus berbeda. Yang saya pakai screen — sudah terpasang, sudah dipahami, dan tak menuntut apa pun ditambahkan ke mesin.
screen tak memeriksa apa pun sebelum gagal. Arahkan ia ke nama device yang tak ada, atau berikan baudrate yang bukan angka, dan yang kembali tak menyatakan dengan jelas mana dari keduanya yang keliru. Inilah dua kesalahan yang benar-benar terjadi, dan keduanya pantas dijawab sebelum screen sempat dipanggil, dengan pesan yang menyebut apa yang salah.
Nama device serial berubah sendiri. Chip dengan USB-CDC bawaan muncul sebagai /dev/ttyACM0; yang dicapai lewat adapter USB-ke-serial muncul sebagai /dev/ttyUSB0. Lebih repot lagi, nomornya bergeser — cabut board lalu pasang kembali saat ada perangkat lain menancap, dan ttyACM0 kemarin jadi ttyACM1 hari ini. Tool dengan nama device yang dipatok akan sering keliru, sedangkan tool tanpa default membuat kasus yang paling sering jadi merepotkan. Keduanya keliru dari arah berlawanan, dan jalan tengahnya bukan kompromi melainkan dua mekanisme terpisah yang masing-masing menutup satu sisi.
Log yang tertimpa diam-diam adalah bukti yang hilang. Karena rekaman itu ada untuk dibandingkan satu sama lain, memangkas rekaman sebelumnya tanpa bilang adalah tindakan paling mahal yang bisa tool ini lakukan. Alternatif yang ditolak justru yang paling lazim: timpa saja, sebab begitulah perilaku redirection di shell. Keputusan yang sama sudah saya ambil di dua tool sebelumnya — satu penyalin folder dan satu pembersih folder build — dengan default jawaban tidak untuk pertanyaan yang merusak.
Yang menjalankan screen harus screen itu sendiri. Inilah yang paling halus di antara keenamnya dan paling gampang keliru, sebab pembungkus yang memanggil program lalu menunggunya tampak benar dan sebagian besar waktu memang berperilaku benar. Untuk program interaktif satu layar penuh yang dikemudikan tombol kontrol, proses tambahan di antaranya tidak gratis. Ongkosnya pun tak muncul sebagai error yang bisa dibaca, melainkan sebagai perilaku tombol yang sesekali meleset — bentuk kegagalan yang paling lama dilacak.
Menonton dan merekam adalah dua mode, bukan satu. Logging menyala hanya ketika diminta. Alternatif yang menggoda — rekam terus, toh penyimpanan murah — menghasilkan folder berisi file yang tak pernah dibuka siapa pun, sekaligus membuat rekaman yang benar-benar menarik lebih sulit ditemukan di antara yang tak pernah diinginkan.
Urutannya berarti. Hambatan pertama menjelaskan kenapa tool ini ada; tiga berikutnya dikerjakan IDE atas nama saya tanpa pernah memberitahukannya; dua terakhir soal bagaimana pembungkus mestinya berperilaku begitu ia yang berdiri di antara terminal dan sebuah program. Digabung, keenamnya menggambarkan apa saja yang ditinggalkan kalimat "pakai screen saja".
Metode
A. Programnya memang sudah ada di mesin
Inilah jawaban atas hambatan pertama: tak ada yang perlu dipasang, sebab terminal serial sudah jadi bagian Unix jauh lebih lama ketimbang umur chip-nya.
Itulah seluruh mekanisme yang jadi fondasi tool ini — sebuah device dan sebuah baudrate. screen biasanya dikenal sebagai cara menjaga sesi shell tetap hidup melewati putusnya koneksi, dan kemampuannya menempel langsung ke jalur serial adalah pekerjaan kedua yang jauh lebih jarang dibicarakan. Memakainya tak berongkos, sebab ia memang sudah di sana.
Nilai default-nya berasal dari hardware, bukan dari selera. 115200 memang yang dipakai firmware-nya, dan /dev/ttyACM0 adalah cara chip ini menampilkan diri, sebab CH32V203 menyediakan USB-CDC di dalam chip ketimbang lewat adapter terpisah.
BAUDRATE=115200
INTERFACE="/dev/ttyACM0"Dua baris, dan keduanya memuat satu klaim: kasus yang paling sering mestinya tak butuh argumen sama sekali. Mengetik nama tool-nya tanpa apa pun sesudahnya mestinya langsung membaca board yang hampir pasti tertancap, pada kecepatan yang hampir pasti ia pakai.
B. Menjawab dua kesalahan yang benar-benar terjadi
Ini menjawab hambatan kedua. Kedua pemeriksaan berjalan sebelum screen dipanggil, dan keduanya ada sebab inilah dua kekeliruan yang meleset dalam praktik, bukan dalam teori.
Baudrate wajib berupa angka, dan pemeriksanya sebuah regular expression, bukan rentang nilai:
|| Jangkar di kedua ujungnya mengerjakan pekerjaan sungguhan. Tanpa keduanya, polanya akan cocok dengan apa pun yang sekadar memuat angka, dan begitulah salah ketik semacam -b 115200x bisa lolos lalu berubah jadi kegagalan membingungkan jauh belakangan. Dengan keduanya, segala yang bukan bilangan bulat positif polos ditolak di pintu masuk — desimal, negatif, maupun kata.
Pemeriksaan device adalah separuh yang lain:
if ; then
Pesannya menyertakan path yang tadi diberikan, dan itu terdengar sepele padahal justru inti persoalannya. Bentuk kegagalan yang dicegah bukan "tool-nya berhenti" melainkan "tool-nya berhenti dan saya tak bisa membedakan apakah saya salah ketik nama device, boardnya tercabut, atau saya sedang melihat nomor port yang keliru". Menyebutkan nilainya menjawab ketiganya sekaligus.
C. Default yang benar sebagian besar waktu, dan bisa ditimpa sisanya
Ini menjawab hambatan ketiga. Karena nama device berpindah, tool ini butuh sekaligus dua hal: default yang menutup kasus paling sering, dan cara menyatakan sebaliknya tanpa menyunting apa pun.
Alasan ini lebih penting bagi perangkat serial ketimbang bagi kebanyakan hal lain: namanya diberikan menurut urutan pendataan, bukan menurut identitas. ttyACM0 bukan nama board saya; ia nama bagi perangkat CDC mana pun yang terlihat lebih dulu. Tancapkan yang kedua, atau pasang ulang yang pertama sesudah nomornya diambil perangkat lain, dan argumen yang benar berganti tanpa ada apa pun pada board-nya yang berubah.
Alternatif yang saya tolak adalah mencocokkan device lewat vendor dan product identifier USB-nya, yang merupakan tugas aturan udev — mekanisme Linux yang bertindak atas device saat device itu dicolokkan — dan akan menghasilkan nama tetap yang selalu menunjuk board ini. Itu jawaban yang lebih baik untuk tool yang dipasang banyak orang. Untuk tool dengan satu pemakai dan satu board di atas meja, default plus satu flag penimpa menyelesaikan persoalan yang sama tanpa menyuruh siapa pun memasang aturan lebih dulu.
D. Menolak memusnahkan rekaman sebelumnya
Ini menjawab hambatan keempat. Ketika logging diminta dan file tujuannya sudah ada, tool berhenti dan bertanya:
case "" in
y|Y|yes|Yes) ;;
*) ; ;;
esacRincian pentingnya ada pada bentuk case itu. Cuma empat ejaan yang berarti ya; segala yang lain — termasuk jawaban kosong akibat menekan Enter — jatuh ke * dan membatalkan. Itulah sebabnya prompt-nya ditulis [y/N] dengan N huruf besar: huruf besar itu janji tentang apa yang terjadi bila pertanyaannya tak dibaca dengan saksama, dan code-nya wajib menepati janji tersebut.
Urutannya pun berarti. Pemangkasan file terjadi di sini, di cabang ya, sebelum screen dinyalakan — bukan sebagai efek samping membuka log belakangan. Itu membuat langkah yang merusak dan konfirmasinya bersebelahan, ketimbang terpisah oleh segala yang dikerjakan tool ini di antaranya.
Dan keluarnya saat dibatalkan memakai kode 0, bukan error. Memutuskan tidak menimpa sebuah file adalah hasil yang berhasil dari sebuah pertanyaan, bukan kegagalan tool-nya.
E. Kenapa exec, dan apa yang sebenarnya ia ubah
Ini menjawab hambatan kelima, dan inilah yang pantas diukur ketimbang sekadar dinyatakan. Tool ini berakhir dengan exec:
Tanpa exec, script akan memanggil screen, lalu duduk menunggunya selesai. Kedua versi sama-sama tampak bekerja. Bedanya ada pada bentuk pohon prosesnya, dan itu bisa diamati langsung memakai program pengganti.
# with-exec.sh runs: exec sleep 30
&
|
Proses milik script itu berubah menjadi sleep. Tak ada shell yang tersisa — exec mengganti program yang sedang berjalan sambil mempertahankan proses yang sama, sehingga yang tersambung ke terminal adalah program sasarannya sendiri. Bandingkan dengan versi tanpa exec:
# no-exec.sh runs: sleep 30
&
|
Di sini prosesnya masih bash, dan sleep jadi anaknya — satu proses tambahan duduk di antara terminal dan program yang semestinya memegang kendali.
Untuk program yang mencetak keluaran lalu selesai, lapisan tengah itu tak berbahaya. Untuk screen, berbahaya. screen dikemudikan sepenuhnya oleh tombol kontrol: Ctrl-A adalah prefix perintahnya, dan melepas sesi, menggulung balik buffer, serta keluar semuanya rangkaian tombol yang wajib ia terima sebagai program foreground di terminal tersebut. Shell yang menyela mengubah siapa pemilik terminal dan siapa yang menerima sinyal — persis jenis bug yang menampakkan diri sebagai "kadang Ctrl-C berlaku salah" dan makan waktu lama untuk dilacak balik ke satu kata enam huruf yang hilang.
Ada manfaat kedua yang khusus berarti bagi sebuah pembungkus: dengan exec, pembungkusnya tak meninggalkan jejak. Status keluarnya adalah status keluar screen, sebab tak ada lagi proses terpisah yang melaporkannya, dan tak ada yang perlu diteruskan atau diterjemahkan.
F. Merekam sebagai mode, bukan sebagai default
Ini menjawab hambatan keenam. Ada dua cara mengakhiri, dan mana yang berjalan bergantung pada diminta atau tidaknya log:
if ; then
else
Kedua cabang memakai exec, jadi penalaran di atas berlaku untuk keduanya; bedanya cuma dua flag yang menyalakan logging. Menaruhnya di cabang terpisah ketimbang menyusun daftar argumen secara bersyarat membuat tiap mode terbaca sebagai satu perintah utuh, yang lebih gampang dicocokkan dengan dokumentasi screen sendiri.
Alasan merekam bersifat diminta dan bukan menyala terus bukanlah ruang disk. Melainkan bahwa folder penuh log dari tiap sesi membuat tiga rekaman yang benar-benar berarti jadi lebih sulit ditemukan, dan file yang terus-menerus ditulisi adalah file yang tak terpikir untuk dilihat siapa pun. Meminta log lewat -d sekaligus jadi catatan bagi diri sendiri bahwa jalan yang ini memang hendak didatangi kembali.
Hasil dan Pembahasan
A. Yang dikerjakan IDE tanpa pernah disebutkan
IDE itu tak pernah lagi dibuka untuk keluaran serial sejak saat itu. Bagian menariknya bukan bahwa penggantinya bekerja — screen memang sudah pasti bekerja — melainkan apa saja yang harus diputuskan begitu IDE berhenti memutuskannya.
| Keputusan | Yang dibeli | Alternatif yang ditolak |
|---|---|---|
screen sebagai mesinnya | tak ada yang dipasang; sudah ada di tiap mesin | monitor Arduino IDE — tawar-menawar sama, bungkus beda |
| default dari hardware | kasus paling sering tak butuh argumen | argumen wajib — merepotkan untuk 90% kasus |
^[0-9]+$ berjangkar | 115200x ditolak di pintu, bukan belakangan | pola tanpa jangkar — salah ketik jadi kegagalan telat |
| pesan error menyebut nilainya | membedakan salah ketik dari board tercabut | kegagalan generik — tiga sebab, satu pesan |
[y/N] dengan penampung * | Enter membatalkan; rekaman lama selamat | timpa langsung — bukti yang mungkin tak terulang hilang |
exec | 0 proses perantara; tombol kontrol sampai utuh | panggil-lalu-tunggu — 1 proses tambahan memegang terminal |
logging di balik -d | rekaman yang ada adalah yang memang diinginkan | rekam terus — folder yang tak pernah dibuka |
B. Pola di balik keenamnya
Dibaca sebagai daftar, keenam hambatan itu tampak tak saling berhubungan: satu soal pemasangan, dua soal validasi masukan, satu soal tidak memusnahkan file, satu soal semantik proses, satu soal nilai default. Yang menyatukannya: IDE menangani setiap satunya secara diam-diam, dan tak satu pun menampakkan diri sampai IDE-nya dilepas.
Itulah bentuk umum mengganti sepotong tooling terpadu dengan script kecil. Fungsi yang kelihatan — membaca dari port serial — adalah bagian mudahnya sekaligus bagian yang diperkirakan orang. Ongkosnya justru di keputusan-keputusan sekeliling yang sudah diambil versi terpadunya, cukup benar sampai tak seorang pun perlu memikirkannya. Pembungkus yang cuma mengerjakan fungsi yang kelihatan akan terasa lebih buruk ketimbang IDE-nya, dan menggoda untuk disimpulkan bahwa IDE memang lebih baik — padahal yang sebenarnya terjadi: empat atau lima keputusan kecil terlewat.
Pantas disebut sebagai batas, bukan sebagai kemenangan: tool ini benar untuk satu orang dengan satu board. Aturan udev yang saya tolak, arah kirim yang tak pernah saya butuhkan, rotasi log yang tak saya tulis — masing-masing kebutuhan sungguhan bagi seseorang, dan ketiadaannyalah yang menjaga script ini tetap cukup kecil untuk dibaca sekali duduk.
C. Ketika pendekatan ini berhenti jadi yang tepat
Batasan satu arah itu batas yang jujur. Karena ini pembacaan untuk debugging, tool yang cuma menerima sudah memadai, dan screen cocok. Perangkat dengan command prompt interaktif di seberangnya — yang menunggu ketikan lalu meresponsnya — adalah pekerjaan berbeda, dan meskipun screen sanggup mengirim karakter, membangun pembungkus di sekitarnya berarti memikirkan line ending, local echo, dan flow control, yang tak satu pun dipertimbangkan tool ini.
Hal serupa berlaku bagi apa pun yang menuntut keluarannya diurai ketimbang dibaca. Mengintai baris tertentu, menghitung kemunculan, atau memicu tindakan pada suatu pola adalah pekerjaan bagi program yang memperlakukan port serial sebagai aliran untuk diproses, bukan layar untuk dipandangi. Begitu kebutuhannya berhenti berbunyi "biar saya lihat", mekanismenya mesti berganti, dan itu tool yang berbeda ketimbang menambah flag pada yang ini.
Simpulan
IDE bawaan vendor bertahan lewat satu pekerjaan terakhir yang belum dipindahkan darinya, dan untuk firmware RISC-V ini pekerjaan tersebut adalah membaca keluaran serial. Memindahkannya cuma butuh program yang sudah terpasang, ditambah enam keputusan yang selama ini diambil IDE tanpa berkomentar: pilih default dari hardware supaya kasus paling sering jadi telanjang, tolak dua masukan yang memang sering salah ketik sebelum sampai ke program terminalnya, sebut nilai yang bermasalah di dalam pesan error, perlakukan log yang sudah ada sebagai bukti dan bukan sekadar file, serahkan terminal sepenuhnya lewat exec, dan jadikan merekam sebagai yang diminta ketimbang yang diandaikan.
Pengukuran yang pantas disimpan adalah yang soal exec, sebab itulah keputusan yang ketiadaannya paling sulit didiagnosis. Dengannya, proses script berubah menjadi screen dan tak punya anak; tanpanya, prosesnya tetap bash dan screen jadi anak, meninggalkan satu lapisan di antara terminal dan program yang dikemudikan sepenuhnya oleh tombol kontrol. Enam huruf, dan itulah beda antara pembungkus yang lenyap dengan pembungkus yang mengganggu.
Yang membuat keseluruhannya kecil adalah kebutuhan yang memang benar-benar sempit — satu board, satu arah, satu orang. Tiap fitur yang tak dimiliki tool ini adalah fitur yang dibuat tak perlu oleh kesempitan tersebut.
Istilah
- baudrate
- Kecepatan pensinyalan jalur serial, dalam simbol per detik. Kedua ujung wajib sepakat; ketidakcocokan menghasilkan keluaran yang tiba sebagai sampah yang tampak masuk akal, bukan sebagai error.
- USB-CDC
- USB Communications Device Class — standar yang membuat microcontroller bisa menampilkan diri ke host sebagai port serial tanpa adapter di antaranya. Di Linux perangkat semacam itu muncul sebagai
/dev/ttyACM*. /dev/ttyUSB*- Nama device untuk port serial yang disediakan chip adapter USB-ke-serial terpisah, berbeda dari port yang diimplementasikan microcontroller itu sendiri.
exec- Builtin shell yang mengganti proses yang sedang berjalan dengan program yang disebut, ketimbang menyalakan proses baru. Process id-nya tetap; shell yang memanggilnya tak lagi ada.
screen- Terminal multiplexer, lebih dikenal sebagai penjaga sesi shell agar tetap hidup melewati putusnya koneksi, yang juga sanggup menempel langsung ke jalur serial bila diberi device dan baudrate.
- RISC-V
- Arsitektur set instruksi terbuka. Relevan di sini cuma sebab itulah alasan toolchain vendor chip-nya berupa IDE tersendiri ketimbang salah satu environment embedded yang dukungannya lebih luas.
Technologies covered
- Bash
- Microcontrollers
- RISC-V