Salam, yang terkasih!
Pada tahap tertentu dalam hidup mereka, setiap kotak DIY keras kepala yang keras kepala berhenti untuk kehilangan Kantian Arduino sebagai "benda-benda" yang
mereka tidak bisa! : Berkedip LED, mengambil data dari sensor dan mentransfernya melalui kabel ke PC tentu menyenangkan, tetapi grail suci dalam mobilitas, dalam pembebasan dari "ikatan tembaga", dalam kebebasan sejati di antara gelombang eter universal.
Di sinilah kenyataan pahit saluran komunikasi yang tidak stabil, kesalahan transmisi, pesan yang tidak terkirim terbuka untuk kita.
Tuhan melarang untuk mengklaim orisinalitas di bidang ini: manusia telah lama menggunakan sejumlah protokol untuk semua kesempatan.
Tetapi tujuan kami adalah untuk belajar, dan karena saya adalah pendukung pengintaian yang gigih dalam pertempuran, kami akan belajar dengan menciptakan "sepeda" protokol kami sendiri.
Hari ini saya mengusulkan untuk mengembangkan protokol yang memastikan pengiriman terjamin, integritas dan urutan pesan antara dua pelanggan (point-to-point, Point-to-Point), tahu bagaimana dan menerapkan algoritma
Nagle dan
pipelining protokol protokol , apa pun artinya. Pada saat yang sama, itu harus memiliki
overhead minimal dan masuk ke dalam bahkan Arduino UNO yang sempit.

Saya bertanya kepada semua yang tertarik di atas kapal, kami menutup palka, membuka batu raja, mengisi tangki pemberat. Kami bertamasya ke masa lalu, tujuan: tahun 1974!
Untuk yang tidak sabar (saya sendiri juga begitu!)Berikut adalah repositori github di mana implementasinya adalah:
Menurut tradisi lama yang baik, setidaknya dua ahli yang diakui dalam bidang ini terlibat dalam menggambarkan algoritma dan protokol kriptografi, jika orang lain tidak mengetahuinya, berkenalan:
Dan
Pertama kita menggambarkan tugas sederhana
Alice dan Bob duduk di parit yang berdekatan dan tidak bisa mengangkat kepala untuk saling melihat. Mereka hanya dapat berbicara dengan suara, di sebelahnya peluit dan peluru meledak, menenggelamkan teriakan mereka, dan di samping itu, ketika salah satu dari mereka berbicara, Anda harus berteriak sehingga Anda tidak mendengar apa-apa sama sekali.
Situasi menjadi rumit oleh fakta bahwa mereka didengar oleh musuh - dan Anda harus menggunakan bahasa kode, untuk beberapa alasan yang terdiri dari urutan angka yang panjang.
Karena Alice dan Bob adalah manusia, mereka secara berkala harus keluar untuk makan atau pergi ke toilet, dan mereka sangat tidak sabar sehingga mereka bisa tidak sabar pada saat yang paling tidak tepat!
Bagaimana dan mengapa membuat koneksi?
Bagaimana kita bisa mengatur transfer data yang andal dalam situasi yang menekan seperti ini, padahal kelihatannya semuanya akan gagal?
Solusi pertama yang mungkin terlintas dalam pikiran adalah menggunakan frasa kode
kata berhenti untuk memulai dan mengakhiri transfer.
Nah, katakanlah jika Alice ingin mengirim pesan, maka dia perlu berteriak "Mulai transmisi!" Dan tunggu sampai Bob menjawab "Mulai penerimaan!".
Jika Alice tidak menunggu respons Bob, ia hanya mengulangi permintaannya untuk memulai transfer. Secara alami, Anda tidak harus melakukan ini terlalu sering, jika tidak, seperti yang kita tahu, Anda hanya tidak mendengar jawaban Bob.
Bagus Tetapi apa yang terjadi jika Alice sebagai tanggapan mendengar dari parit berikutnya, "Mulai Transmisi!"?
Ternyata Bob juga memutuskan untuk mentransfer beberapa informasi penting saat ini. Alice memiliki karakter yang lembut, dan dia mungkin berpikir: "Oke, aku akan menunggu, pesan saya pada prinsipnya, tidak mendesak, biarkan Bob meneruskannya terlebih dahulu." Berpikir ini, dia menjawab, "Mulailah resepsi!".
Karena
pada masa perang nilai sinus dapat mencapai empat, kecepatan suara terbatas, dan butuh beberapa waktu untuk memahami apa yang telah didengar Alice dan Bob, dan bahkan Bob, sebagai pria terhormat, dapat memutuskan untuk menyerah pada wanita itu, ia mengangkat bahu dan berteriak, "Aku mulai menerima!" ...
Untuk mengilustrasikan kemarahan itu, kita akan menggunakan grafik waktu. Waktu berlalu ke mereka.
Kasus ketika Alice dan Bob tidak setuju tepat waktu:

Kasus saat pesan hilang:

Ini kegagalan. Semuanya menjadi terlalu membingungkan dan diperparah oleh kenyataan bahwa penerima dapat mendengar atau tidak mendengar frasa tersebut, dan dalam setiap kasus lawan bicara tidak tahu apakah pesannya didengar oleh penerima.
Sekarang baik Alice dan Bob mengharapkan sambutan. Adalah logis untuk menyadari bahwa konflik telah terjadi, dan seseorang perlu melanjutkan transmisi. Tetapi bagaimana jika semuanya terjadi lagi dengan cara yang baru? Dan di sinilah kita lagi di mana kita mulai.
Jika Anda berpikir bahwa situasinya sangat langka, ingat kapan terakhir kali Anda berbicara dengan seseorang melalui suara, ketika pelanggan Anda atau Anda (atau keduanya) memiliki koneksi Internet yang lambat. "Halo halo halo, kamu menghilang." "Kamu tidak bisa mendengar halo halo."
Sementara itu, di parit, situasi memanas, para komandan menuntut pengiriman laporan.
Saatnya
beralih ke sumber-sumber utama: untuk mempelajari Marx, Engels akan kembali lebih dari 40 tahun yang lalu dan melihat bagaimana masalah tersebut diselesaikan oleh para insinyur
DEC ketika merancang protokol
DDCMP .
Menurut pengembang DDCMP, Alice dan Bob perlu menolak emosi dan menjadi seperti
mesin negara yang terbatas .
Ini berarti bahwa mulai sekarang, Alice dan Bob kita hanya akan memiliki beberapa kondisi tetap, transisi antara negara-negara ini dapat terjadi secara ketat sesuai dengan aturan tertentu ketika peristiwa tertentu terjadi.
Pertama, kami hanya daftar negara:
- Terhenti
- AWAL AWAL
- ACKNOWLEDGED MULAI
- MENJALANKAN
Seperti yang Anda lihat, hanya ada empat. Dan sekarang, apa pun yang terjadi, masing-masing pelanggan setidaknya tahu pasti bahwa vis-a-vis-nya hanya ada di salah satu negara bagian ini. Faktanya, dengan melihat sedikit ke depan, saya akan mengatakan bahwa hampir selalu satu pelanggan akan tahu seperti apa pelanggan kedua itu,
tetapi ini tidak akurat .
Mari kita pertimbangkan negara secara terpisah, secara terperinci
HALTED adalah keadaan paling sederhana, tidak ada yang pergi ke mana pun, semua orang tetap di tempat mereka, tidak ada yang ditransmisikan dan tidak diterima, rangsangan eksternal diabaikan. Semua kecuali satu - kehendak otoritas yang lebih tinggi. Dalam protokol DDCMP asli, transisi dari keadaan
HALTED hanya bisa dalam keadaan
MULAI AWAL atas permintaan pengguna - Alice atau Bob menerima pesanan untuk membuat koneksi.
Apa yang terjadi ketika Alice atau Bob menerima pesanan seperti itu?
Mereka segera mencatat kepada diri mereka sendiri bahwa negara telah berubah dari
HALTED menjadi
AWAL AWAL , transisi ini, seperti yang lainnya, melibatkan serangkaian tindakan yang didefinisikan secara ketat. Dalam hal ini, Anda perlu berteriak "LAKUKAN ITU!" Dan mengatur jam pada jam. Itu saja.
Jadi, Alice menjerit apa yang diminta darinya, dan menekan tombol pada stopwatch. Sekarang, untuk memahami apa yang diharapkan dari Bob, kami akan mencari tahu apa yang dapat terjadi pada Alice ketika ia berada dalam status
MULAI AWAL .
- Dari saat Alice menyadari waktu telah berlalu, katakanlah 10 detik dan dia tidak mendengar reaksi dari Bob (perhatikan, saya tidak mengatakan bahwa Bob tidak meneriakkan apa pun kepadanya - ini tidak diketahui, tetapi hanya bahwa Alice tidak tahu apa-apa) terdengar selama ini, Alice adalah wanita yang bijaksana dan rasional dan hanya mengandalkan fakta). Kami menyebut acara ini sebagai batas waktu - interval tunggu telah terlampaui. Dalam kasus ini, protokol memberitahu kita untuk mengulang: berteriak "LAKUKAN SEKALI!" Dan waktunya lagi. Belum tebal.
- Jika Alice mendengar bahwa Bob meneriakkan hal yang sama - “LAKUKAN SATU WAKTU!”, Maka Alice secara
non-selektif masuk ke kondisi
ACKNOWLEDGED START , yang tentangnya ia harus segera berteriak “LAKUKAN DUA!” Dan mengatur jam lagi.
- Lagi-lagi, jika Alice mendengar dari Bob “DO TWO!”, Maka dia segera masuk ke status
RUNNING (!), Teriakan “DITERIMA NOOOOOL!”. Jika stopwatch-nya telah dimulai, dia mematikannya dari garis depan kehati-hatian.
Sangat penting untuk tidak membuat gerakan yang tidak perlu yang tidak disediakan oleh kondisi saat ini. Apa pun yang menangis Bob, tidak peduli seberapa mengutuk atau memohon, Alice hanya bereaksi sesuai kesepakatan.
Hal-hal seperti itu disajikan dengan nyaman dalam sebuah tabel. Jadi, mari kita mulai dengan status
HALTED dan
INITIAL START yang sudah dijelaskan, dan kemudian kita akan mengisi tabel lebih lanjut.
Saya secara sadar menghilangkan beberapa poin dari deskripsi asli DDCMP - kami tidak membutuhkannya, kami ingin tidak hanya mengulangi DDCMP, tetapi membangun atas dasar
yang sama, hanya protokol baru lainnya.
Tetapi kembali ke deskripsi negara dan transisi. Status selanjutnya adalah
DIAKUI DIMULAI .
Berada dalam keadaan ini, yang bisa membuat khawatir Alice atau Bob adalah:
- seperti sebelumnya, berakhirnya waktu tunggu, dalam hal ini Anda harus tetap dalam keadaan yang sama, berteriak "LAKUKAN DUA!" Dan mulai timer lagi
- "DO DUA!" yang terdengar diterjemahkan ke dalam status
MENJALANKAN , sambil meneriakkan "DITERIMA NOOOOL!" Dan hentikan timernya;
- "DO IT!" yang didengar meninggalkan dalam keadaan yang sama, Anda perlu berteriak "DO TWO!" Dan mulai timer;
- mendengar "NOOOL DITERIMA!" - transisi ke status
MENJALANKAN , hentikan timer.
Kami menempatkan semua hal di atas dalam sebuah tabel.
Dengan jabat tangan, hampir semuanya sudah siap - masih mempertimbangkan hanya satu keadaan
MENJALANKAN , karena salah satu pelanggan sudah bisa masuk ke dalamnya, dan yang kedua - segera berlari ke toilet, dan ketika dia kembali, lupakan semuanya dan cobalah untuk membangun koneksi baru.
Dari sudut pandang prosedur jabat tangan (kami belum berurusan dengan transfer data, yang semuanya dimulai - ini adalah cerita yang terpisah) dalam keadaan
MENJALANKAN kami tertarik pada dua peristiwa:
- jika mereka berteriak kepada kami "LAKUKAN SEKALI!" - semuanya sangat buruk, itu adalah desync yang lengkap, semuanya harus dimulai lagi. Protokol asli
mengarahkan Anda untuk cukup memasuki kondisi
HALTED . Tetapi ini tidak akan membantu kita dengan cara apa pun - jika karena alasan tertentu ini terjadi pada Arduino otonom, yang mentransmisikan beberapa data dari beberapa sensor, maka bagi kami ini adalah kegagalan total. Seperti yang kita ketahui, dari
HALTED Anda dapat pergi ke
MULAI AWAL hanya atas perintah pihak berwenang.
Oleh karena itu, kami memodifikasi protokol di sini: penerimaan dalam keadaan
HALTED dari "DO ONCE!" Perintah harus bekerja seperti perintah dari pihak berwenang - yaitu.
beralih ke status
MULAI AWAL , berteriak "LAKUKAN SEKALI!", mulai timer. Selain itu, dalam beberapa kasus lebih mudah untuk memberi perintah untuk membangun komunikasi segera setelah memasok daya ke diri sendiri.
Jadi, sekarang, dalam kasus yang paling tidak nyaman, kita hanya perlu mengatur ulang koneksi.
- Peristiwa kedua yang diperlukan untuk bereaksi dalam keadaan
MENJALANKAN - jika kita mendengar "LAKUKAN DUA!" Dari parit tetangga. Ini sudah lebih menarik. Dalam hal ini, Anda perlu meneriakkan “ER DITERIMA!” Di mana, oleh ER berarti jumlah pesan yang berhasil diterima dalam sesi komunikasi saat ini. Ini adalah konsep baru. Di bawah ini kami akan mempertimbangkan segala sesuatu dengan lebih terperinci, tetapi untuk saat ini kami akan membawa semua yang telah kami pelajari hingga saat ini ke dalam tabel:
Sekarang, jika Alice dan Bob benar-benar mengikuti protokol, maka mereka tidak punya pilihan
untuk masuk ke sesuatu yang
tidak dapat dipahami , kecuali bagaimana membangun koneksi, bersama-sama beralih ke keadaan
MENJALANKAN atau, dalam kasus yang buruk, mencoba membangunnya sebelum kemenangan
diklik .
Pembaca yang agresif dapat mencoba memilah-milah semua opsi dan sampai pada kesimpulan bahwa rangkaian keadaan dan transisi ternyata tertutup dan ditentukan dengan ketat. Kami (dengan bantuan pikiran para insinyur DEC) sekarang telah mengikat Alice dan Bob dengan seperangkat aturan yang hanya dengan mengikuti yang mereka akan membangun koneksi, jika dalam kondisi saat ini secara umum dimungkinkan pada prinsipnya.
Bagaimana cara mentransfer data sekarang?
Oke, itu latihan yang bagus. Periode permen-buket dalam hubungan dua node jaringan. Ingatlah bahwa kami memulai bisnis: kami perlu mentransfer data dengan pengiriman yang terjamin dan prioritas! Dengan pemulihan bencana. Sejauh sumber daya perangkat keras memungkinkan ini (lagipula, Alice dan Bob mungkin terbukti sebagai pengontrol 8-bit yang lemah dengan 2 kilobyte RAM!).
Teknisi DEC mengajarkan kepada kita bahwa pesan yang perlu kita beri nomor, kita perlu menghitung berapa banyak yang kita kirim, berapa banyak yang kita terima dan berapa banyak pesan yang kita kirim mencapai penerima.
Sudah waktunya untuk penyimpangan!Akui saja. ketika saya melihat nama-nama variabel dalam deskripsi protokol DDCMP, saya memutuskan bahwa itu bukan kebetulan: Orang Amerika sangat suka menarik singkatan yang indah di telinga mereka.
Untuk kenyamanan kita, bahkan ada beberapa sumber daya di mana mereka yang tertarik dapat menyentuh keindahan.
Favorit saya adalah yang ini -
Situs Akronim Astronomi yang Bodoh atau Terlalu Dipaksa (atau DOOFAAS)Apa nilai-nilai palsu ini!
Berikut ini sebuah contoh:
WASP - Wideband Analog SPectrometer (Tapi tidak semua yang Anda pikirkan!)
SAURON - Unit Areal Spektroskopi untuk Penelitian tentang Nebula Optik
CISCO - Cooled Spectrograph Inframerah dan Kamera untuk OHS (Jadi itulah artinya!)
Dan di sini, tembak saja:
SQUIRT (oh ya, artikel 18+!) - Satettile QUick Research Testbed
SHIT (Tidak lebih dan tidak kurang!) - Teleskop Interferometrik Super Besar, dengan tulisan “cari sendiri”, di mana tautan ke abstrak dilampirkan ke artikel dengan nama yang sama.
Jadi, variabel yang menunjukkan jumlah paket yang diterima, dikirim dan dikirim pada node dalam deskripsi asli protokol disebut sebagai
RNA .
Ah, mengapa mereka tidak menyebutkan protokol seperti itu - RNA! Semacam jaringan RNA. Protokol DECnet memiliki setiap kesempatan untuk menjadi protokol Internet jika ceritanya berubah secara berbeda.
Tapi kembali ke parit kita
Standar protokol asli menetapkan bahwa semua penghitung adalah 8-bit dan modulo peningkatan 256. Ini berarti bahwa mungkin ada maksimum 256 pesan terkirim yang konfirmasi belum diterima.
Dan jika konfirmasi tidak diterima, maka mereka mungkin perlu dikirim ulang, dan jika mungkin diperlukan, maka mereka harus disimpan sampai konfirmasi. Bagaimanapun, kami telah menjamin pengiriman!
Parameter fisik Alice dan Bob kita menentukan bagi kita kondisi yang berbeda. Dalam Arduino 8-bit, jumlah data ini tidak bisa disimpan dan kita harus berkompromi. Dan saya tidak berbicara tentang fakta bahwa dalam standar panjang paket (pesan) dalam byte terbatas pada angka 16-bit, yaitu 64 kilobyte adalah kemewahan yang tidak dapat diterima!
Jadi, koneksi terjalin. Apa selanjutnya
Saat Alice atau Bob
memasuki keadaan
MENJALANKAN , penghitung diatur ulang.
Seperti yang sudah saya sebutkan, protokol asli melibatkan penomoran pesan modulo 256, tetapi kita harus mengurangi jumlah ini agar sesuai dengan sedikit memori dalam hal-hal seperti Arduino.
Agar dapat segera membatasi semua peningkatan penghitung, kami akan memperkenalkan UMCP_PACKETS_NUMBER konstan tertentu, dan sekarang semua peningkatan akan terjadi dalam modul ini.
Jika Anda menggunakan UMCP_PACKETS_NUMBER = 8, dan ukuran paket maksimum adalah UMCP_PACKET_DATA_SIZE - bagian dari data yang dikirimkan pada suatu waktu dibatasi hingga 64 byte, maka semuanya akan sesuai dengan UNO Arduino dan akan tetap sedikit untuk kebutuhan pengguna.
Penting untuk diingat bahwa kedua parameter ini harus sama untuk kedua belah pihak.
Jelas, sekarang, jika Alice dan Bob telah berhasil membuat koneksi, dan salah satunya perlu mentransfer data, maka data pertama-tama harus dibagi menjadi bagian-bagian yang tidak melebihi ukuran 64 byte, dan kedua, setiap paket juga harus berisi keadaan dua penghitung pengirim: jumlah pesan yang diterima dan dikirim (R dan N).
Lihat betapa mudahnya sekarang mengatur apa yang disebut pipelining dan betapa mudahnya menangani situasi kesalahan!
Jika Alice mengirim 3 paket berturut-turut tepat setelah koneksi tersambung, maka semuanya akan memiliki counter R yang diatur ke 0 (dia belum menerima paket apa pun), dan counter N akan bertambah satu dengan setiap paket baru.
Jika Bob berhasil menerima semuanya, maka untuk mengonfirmasi penerimaan ketiga paket, cukup baginya untuk mengirim konfirmasi hanya untuk yang terakhir, pada kenyataannya, jika ia hanya mengirim kembali status counter-nya R = 3 dan N = 0, maka Alice akan segera memahami bahwa semua yang dikirim pesannya mencapai penerima.
Itu adalah kasus yang ideal ketika force majeure tidak terjadi. Sekarang mari kita lihat apa yang mungkin salah dan bagaimana mengatasinya.
Jika Bob karena alasan tertentu melewatkan paket pertama dan menerima salah satu dari yang berikutnya, maka ia segera menarik perhatian pada fakta bahwa penghitung N di dalamnya (jumlah paket yang dikirimkan oleh Alice) jelas melebihi penghitung R di sisi Bob dan Bob dengan mudah menyadari bahwa ia melewatkan paket pertama. . Dalam hal ini, ia hanya perlu memainkan Captain Evidence paling datar dan memberi tahu Alice status counter dari paket yang diterima (R = 0). Alice pada saat yang sama memahami bahwa dia adalah N = 3, dan Bob memiliki R = 0, yaitu, perlu untuk mentransfer paket dengan cara yang baru, mulai dari yang pertama.
Jika Anda melihat skema ini dengan hati-hati, Anda dapat melihat bahwa setiap pengiriman status penghitungnya oleh pelanggan mana pun segera memberitahukan kepadanya tentang hasil pengiriman paket data, dan perbedaan antara penghitung yang dikirimkan di satu sisi dan yang diterima di sisi lain menunjukkan berapa banyak paket yang hilang dan mulai dari nomor berapa.
Artinya, dalam kasus terburuk, ada pengiriman ulang lengkap transmisi, dalam kasus rata-rata, penghitung A di sisi pemancar meningkat ke nilai penghitung R di sisi penerima, dan "mengirim" paket yang hilang.Sangat mudah untuk memahami bahwa dengan cara ini, kontinuitas kenaikan penghitung dipertahankan, yang berarti bahwa pengiriman pesan (paket) dijamin.Selain variabel RNA, setiap pelanggan memiliki dua flag SACK dan SPEP. Jika yang pertama diinstal, maka Anda harus mengirim konfirmasi (Kirim pengakuan), jika yang kedua - maka Anda perlu mengirim permintaan konfirmasi (Kirim REPly ke pesan).Omong-omong, bendera lain tersirat dalam DDCMP asli - SNAK (Kirim pengakuan negatif). Instalasinya melibatkan pengiriman pesan kesalahan dengan beberapa jenis kode. Tetapi dalam versi protokol kami, kami akan menyelesaikan semua kesalahan secara eksklusif menggunakan mekanisme batas waktu, karena protokol tersebut dapat digunakan, misalnya, dalam komunikasi sonar atau radio dalam pita frekuensi yang sama - tidak masuk akal untuk menyumbat lingkungan umum dengan kode kesalahan.Jika pesan diterima dengan kesalahan integritas, maka secara tegas itu adalah pesan yang tidak dapat diterima.Pada titik ini, pembaca yang korosif harus memiliki perasaan bahwa ada sesuatu yang hilang. Ada yang salah dengan skema ramping ini. Dan itu benar.
Lebih lanjut tentang ini nanti.Sementara itu, saya mengusulkan, mengikuti contoh proses pengaturan koneksi, untuk mengumpulkan semua pemikiran terpisah tentang mentransfer data ke tabel.Karena kita sekarang hanya memiliki satu negara, tabel hanya akan berisi dua kolom - acara dan tindakan yang harus diambil. Untuk menghindari kebingungan antara variabel-variabel yang menjadi milik variabel, kami menandai yang lokal dengan indeks L dan yang dihapus (yang terkandung dalam pesan yang diterima dengan indeks R).Sekarang perhatikan dari dekat, gulir ke seluruh sirkuit di kepala. Kami menyadari apa yang hilang di sini.Dalam uraian asli DDCMP, yang telah kami tinggalkan dengan sangat kuat, ini disebut flag SELECT - sebuah simpul (Alice atau Bob) mungkin atau mungkin tidak “dipilih”.Yang membingungkan kami adalah tidak ada mekanisme yang diizinkan untuk mengizinkan atau melarang transfer.Nah, ini dia: ini adalah flag SELECT. Ini diterapkan dengan sangat sederhana: jika bendera diatur, maka dimungkinkan untuk mengirimkan, jika tidak, itu tidak mungkin.Semua pesan kontrol seperti ACK dan REP harus mengandung panji ini. Paket terakhir dalam antrian juga harus mengandung flag ini. Jika sebuah simpul “menjahit” sebuah bendera ke dalam sebuah paket, maka ia “memberikannya”, dan karenanya tidak lagi dipasang. Node yang mendeteksi flag ini dalam paket, sebaliknya, harus menginstalnya sendiri. Ini mirip dengan mengoper tongkat atau bermain daging cincang (ingat itu?).Hal terpenting dalam bekerja dengan flag ini adalah bahwa salah satu node harus memiliki flag ini secara default, dan yang lainnya tidak. Itu adalah timer lain yang sangat penting - timer kembali flag SELECT.Sekarang kami memiliki seperangkat aturan lengkap untuk membuat koneksi dan mengirimkan data di atasnya.Kami tidak menyentuh hanya pada implementasi konkret dari set aturan ini.Baiklah, perbaiki!Formasi dan Format Paket
Ini disebut Pembingkaian Pesan - aturan untuk menganalisis dan menghasilkan pesan dan format.Mari kita hitung berapa yang kita butuhkan.1. Minimal, kami membutuhkan setiap pesan untuk memuat status penghitung R dan N pengirim. Untuk Arduino, kami sepakat bahwa kami dapat memiliki maksimal 8 pesan terkirim tetapi belum dikonfirmasi. Tetapi karena kita mentransfer byte, kita mendorong kedua penghitung menjadi satu byte, biarkan mereka menjadi 4-bit.Byte ini akan dibentuk seperti ini: = (RL & 0x0F) | (NL << 4);
Dan kita akan membaca status penghitung seperti ini:
NR = (c >> 4) & 0x0F; RR = c & 0x0F;
c - byte yang sesuai dari pesan
2. Kami juga ingat bahwa setiap pesan harus mengandung keadaan bendera SELECT. Dan berbagai jenis pesan itu sendiri adalah:
Artinya, hanya 6 jenis pesan yang berbeda. Semua pesan kecuali DTA "melepaskan" bendera SELECT - mereka membutuhkan respons langsung dari pelanggan jarak jauh, dan tanpa bendera ia tidak akan dapat mengirimkannya. Pesan DTA tidak mengembalikan bendera untuk memungkinkan pipelining.
Secara umum, kami memiliki cukup 3 bit untuk jenis pesan, tetapi agar tidak mengacaukan bit, kami menetapkan satu byte penuh ke jenis pesan - dalam kasus revisi kami akan memiliki beberapa kebebasan bertindak.
Jika pesan berisi data, maka kami perlu mentransfer kuantitas dan checksumnya. Karena ukuran paket maksimum adalah 64 byte, kami juga akan mengambil byte untuk checksum dan panjangnya - tiba-tiba Anda harus menambah ukuran paket.
3. Kami juga membutuhkan beberapa tanda tangan dari awal pesan dan checksum terpisah untuk header.
Dengan semua ini dalam pikiran, header (alias mengontrol pesan) terlihat seperti ini:
Dan blok data adalah seperti ini:
Itu saja. Ini adalah deskripsi lengkap protokol yang kami dapatkan dari DDCMP.
Sekarang Anda bisa melalui implementasi.
Bagaimana cara mengaturnya dan bagaimana menggunakannya?
Pertama, sedikit tentang struktur repositori.
Seperti yang saya sebutkan di awal, kode proyek terletak di github:
uMCPInoUntuk melihat cara kerja semuanya, Anda dapat menjalankan
aplikasi uji pada PC.
Di arsip, jalankan uMCPIno_Test.exe, pilih port COM yang diinginkan dan coba cara kerjanya.
Anda dapat memeriksa sepasang port COM virtual (saya biasanya melakukan ini).
Mengapa Anda dapat menjalankan dua salinan aplikasi. Hanya saja, jangan lupa untuk menyalakan "PILIHAN OLEH DEFAULT" dalam satu salinan - ini akan menjadi Master, dan yang lain - matikan. Omong-omong, jika tertarik, Anda dapat melihat apa yang terjadi jika Anda tidak mematuhi aturan ini =)
Opsi EXTRAS memungkinkan Anda untuk melihat semua gerakan pikiran di dalam otak protokol. Semua perubahan dalam keadaan flag SELECT, peristiwa dari penghitung waktu, perubahan status node, serta nilai variabel R dan N dalam pesan yang dikirim dan diterima akan ditampilkan.
Saya menghubungkan UNO Arduino ke laptop saya melalui konverter USB <-> UART. Konektor pin memungkinkan Anda mensimulasikan pemutusan saluran kapan saja:

Jika sekarang Anda menjalankan aplikasi di laptop, maka setelah menekan tombol "CONNECT", arduina akan membuat koneksi:

Dan ini adalah bagaimana sistem bereaksi terhadap upaya untuk mengirim melalui garis "sobek":

Untuk menanamkan uMCPIno di aplikasi Anda untuk PC:
- Repositori memiliki pustaka uMCPIno. Hubungkan ke referensi proyek Anda
- Ini berisi kelas uMCPInoPort. Kami menyatakan contohnya:
uMCPInoPort port; port = new uMCPInoPort("COM1", UCNLDrivers.BaudRate.baudRate9600, true, 8100, 2000, 64, 8);
Parameter berurutan: nama port, lalu kecepatan port, status SELECT default, interval untuk SELECT, interval waktu habis, ukuran paket, dan jumlah maksimum pesan yang tidak diakui.
- Berlangganan acara:
ketika SELECT - port. Pilih flag yang berubah:
OnSelectChangedEventHandler
ketika keadaan berubah - port.State:
OnStateChangedEventHandler
Host jarak jauh mengonfirmasi penerimaan kode:
OnDataBlockAcknowledgedEventHandler
kapan paket data tiba:
OnDataBlockReceivedEventHandler
- Sebelum bekerja, buka porta
port.Open();
- Untuk mengirim data, kami memanggil metode:
port.Send(byte[] data);
- Setelah selesai, tutup port:
port.Close();
Cukup kirim dua byte!
Sekarang mari kita beralih ke implementasi untuk Arduino. Dua contoh ada di folder
github.com/AlekUnderwater/uMCPIno/tree/master/ArduinoYang pertama hanyalah konverter dari dan ke uMCP. Serial pertama berfungsi untuk berkomunikasi dengan Host, dan Serial1 (jika ada di papan Anda) atau SoftwareSerial pada pin 2 dan 3 - untuk berkomunikasi dengan simpul uMCPIno lainnya. Anda dapat menghubungkan Bluetooth atau modul radio di sini.
Yang kedua adalah templat proyek dengan dukungan untuk protokol uMCPIno
Kedua proyek memiliki pengaturan di mana Anda dapat dan harus memanjat. Inilah mereka:
Status default dari flag SELECT. Jika diatur ke (true), maka bahkan jika node jauh tidak mengembalikan bendera, itu akan diatur ke true oleh timer.
#define CFG_SELECT_DEFAULT_STATE (false)
Untuk mengatur periode timer ini, ada pengaturan berikut: interval untuk mengembalikan flag SELECT dalam milidetik
#define CFG_SELECT_DEFAULT_INTERVAL_MS (4000)
Interval untuk menunggu respons dalam milidetik, lebih baik meninggalkannya sedikit kurang dari interval untuk mengembalikan bendera SELECT.
#define CFG_TIMEOUT_INTERVAL_MS (3000)
Tingkat baud aktual dari garis. Parameter ini diperlukan untuk menentukan kapan transfer akan berakhir.
#define CFG_LINE_BAUDRATE_BPS (9600)
Interval akumulasi data untuk algoritma Nagle. Kurang ajar sama dengan 100 milidetik. Selama ini, kami sedang menunggu satu set paket, jika tidak diketik, maka kami mengirimkannya apa adanya. Tugas algoritma Nagle adalah membersihkan jaringan dari tumpukan paket-paket kecil dari ukuran satu hingga beberapa byte.
#define CFG_NAGLE_DELAY_MS (100)
Pengaturan ini mengatur kecepatan port untuk komunikasi dengan sistem kontrol (Host) dan saluran. Jangan bingung kecepatan port dengan saluran dengan kecepatan transfer fisik.
#define CFG_HOST_CONNECTION_BAUDRATE_BPS (9600)
Jika pengaturan ini diaktifkan, maka ketika daya disuplai ke controller, protokol itu sendiri akan memerintahkan dirinya untuk mulai membuat koneksi.
#define CFG_IS_AUTOSTART_ON_POWERON (true)
Ini adalah ukuran dalam byte buffer untuk paket data yang masuk.
#define CFG_IL_RING_SIZE (255)
Selanjutnya, mari kita lihat seperti apa loop sketsa utama:
void loop() { uMCP_ITimers_Process(); DC_Input_Process(); DC_Output_Process();
Sekarang mari kita lihat bagaimana protokol bekerja. Logika utama terkandung dalam fungsi uMCP_Protocol_Perform (); Ini kodenya:
void uMCP_Protocol_Perform() { if (state == uMCP_STATE_RUNNING) {
Paket parser yang hidup dalam suatu fungsi
On_NewByte_From_Line
juga diatur oleh prinsip mesin negara terbatas dan bekerja "byte-by-byte". Ini dilakukan untuk menghemat memori.
Sisa implementasi bukan merupakan kepentingan khusus. Kami akan lebih baik menganalisis bagaimana pengguna berinteraksi dengan protokol. Dalam contoh ini, ada empat "titik kontak".
Yang pertama adalah fungsi pengiriman data di jalur uMCPIno:
bool uMCPIno_SendData(byte* dataToSend, byte dataSize);
Semuanya sederhana di sini - Anda memiliki buffer byte dataToSend, ukurannya adalah dataSize. Fungsi mengembalikan true jika pengiriman dimungkinkan (ada ruang untuk menambahkan data), dan false jika tidak.
Agar tidak mengemudi dengan sia-sia, Anda dapat segera memeriksa ketersediaan ruang yang cukup menggunakan fungsi:
bool uMCP_IsCanSend(byte dataSize);
Untuk menganalisis paket data yang masuk, Anda perlu menambahkan kode Anda ke badan fungsi
void USER_uMCPIno_DataPacketReceived();
Data yang masuk ditulis ke buffer ring il_ring. Membaca darinya dapat diatur byte seperti ini:
while (il_Cnt > 0) { c = il_ring[il_rPos]; il_rPos = (il_rPos + 1) % CFG_IL_RING_SIZE; il_Cnt--;
Untuk kesenangan canggih ada fungsi
void USER_uMCP_OnTxBufferEmptry();
Yang disebut ketika semua data berhasil dikirim. Mungkin juga dan perlu untuk meletakkan beberapa jenis kode di dalamnya.
Mengapa ini semua dan di mana?
Saya berurusan terutama dengan Hanya untuk bersenang-senang. Selain itu, saya membutuhkan beberapa protokol sederhana dan, yang paling penting, "ringan" untuk mengirim data melalui modem sonar
uWAVE kami. Karena mereka mentransmisikan data melalui air pada kecepatan hanya 80 bps, dan dengan jangkauan komunikasi maksimum 1000 meter dan kecepatan suara dalam air sekitar 1500 m / s, transmisi dikaitkan dengan penundaan yang nyata, dan hanya ada satu saluran sonar (jika bukan yang paling !) dari yang paling berisik, paling lambat dan paling tidak stabil.
Sebagian besar karena ini, saya harus meninggalkan mekanisme pengakuan negatif (NAK) - jika mungkin untuk tidak mengirimkan - dalam air lebih baik untuk tidak mengirimkan 100%.
Pada kenyataannya, protokol ini sangat berguna ketika mentransmisikan data melalui saluran radio menggunakan modul
DORJI dan
NS-012 yang terkenal untuk Arduino.
Apa selanjutnya
Jika ada waktu, saya berencana untuk menambahkan kemungkinan pengalamatan (yang, omong-omong, ada di DDCMP). Karena tugas utama dari protokol ini sekarang adalah untuk memberikan kemudahan untuk semua jenis pengujian modem sonar kami dan Jaringan Sensor lainnya, maka ada (secara harfiah!) Perangkap di sana. Saya hanya bisa mengatakan bahwa masalahnya tidak dapat diselesaikan dengan hanya menambahkan bidang "Pengirim" dan "Target".
Mungkin akan datang ke
Geographic Routing dan semua jazz itu.
PS
Secara tradisional, saya akan sangat berterima kasih atas kritik, harapan, dan saran yang membangun. Selalu penting untuk memahami apakah Anda melakukan sesuatu yang bermanfaat bagi orang atau membuang-buang waktu.
Mungkin, dalam upaya untuk menghindari transisi dari longread ini ke novel "War and Peace", saya telah melewatkan beberapa detail - jangan ragu untuk bertanya.
PPS
Banyak terima kasih untuk mempermalukan buta huruf saya, menunjukkan kesalahan (tata bahasa dan logis):
Proyek ini awalnya open source, tetapi sekarang artikelnya juga open source.