Dalam komunikasi UART saya, saya perlu mengetahui byte awal dan byte berhenti dari pesan yang dikirim. Byte awal itu mudah tetapi byte berhenti, tidak begitu banyak. Saya telah mengimplementasikan dua stop byte pada akhir pesan saya, yaitu \ n dan \ r (10 dan 13 desimal). UART hanya bekerja pada nilai byte 0-255 jadi bagaimana gagal-amannya ini? Saya bisa membayangkan, meskipun probabilitasnya rendah, bahwa pesan saya mungkin berisi nilai "10 dan 13" satu sama lain ketika mereka bukan byte berhenti.
Apakah ada cara yang lebih baik untuk mengimplementasikan ini?
"\x0D\x0A"
.\r\n\r\n
yang berisi\n\r
urutan di tengah ...Jawaban:
Ada berbagai cara untuk mencegah hal ini:
Jika pesan Anda maksimal 256 byte, kirim:
Jadi, Anda tahu setelah menerima 6 byte data yang akhirnya; Anda tidak harus mengirim 10 13 sesudahnya. Dan Anda dapat mengirim 10 13 ke dalam pesan. Jika pesan Anda bisa lebih panjang, Anda dapat menggunakan 2 byte untuk ukuran data.
Pembaruan 1: Cara lain untuk mendefinisikan paket
Alternatif lain adalah mengirim perintah yang memiliki panjang tertentu dan dapat memiliki banyak varian, misalnya
Pembaruan 2: Koneksi buruk / kehilangan byte
Semua hal di atas hanya berfungsi ketika jalur UART mengirim byte dengan benar. Jika Anda ingin menggunakan cara pengiriman yang lebih andal, ada juga banyak kemungkinan. Berikut beberapa di antaranya:
Perhatikan bahwa semua mekanisme di atas bisa sederhana atau serumit yang Anda inginkan (atau perlu). Dalam hal mengirim ulang pesan, juga diperlukan mekanisme untuk mengidentifikasi pesan (misalnya menambahkan nomor urut ke dalam paket).
sumber
Jika Anda mengirim mengirim data acak -> mungkin tidak cukup aman.
Solusi umum adalah menggunakan melarikan diri:
Mari kita tentukan bahwa karakter 0x02 (STX - frame start) dan 0x03 (ETX - frame end) harus unik dalam aliran data yang dikirim. Dengan cara ini, awal dan akhir pesan dapat dideteksi dengan aman.
Jika salah satu dari karakter ini harus dikirim dalam bingkai pesan, itu diganti dengan awalan karakter melarikan diri (ESC = 0x1b) dan menambahkan 0x20 ke karakter asli.
Karakter asli digantikan oleh
Penerima membalikkan proses ini: Setiap kali ia menerima karakter melarikan diri, karakter ini dijatuhkan dan karakter berikutnya dikurangi dengan 0x20.
Ini hanya menambahkan beberapa overhead pemrosesan tetapi 100% dapat diandalkan (dengan asumsi tidak ada kesalahan transmisi yang terjadi, yang dapat / harus Anda verifikasi dengan tambahan menerapkan mekanisme checksum).
sumber
'\x10'
DLE (Data Link Escape). Beberapa halaman Wikipedia menunjukkan bahwa DLE sering digunakan dengan cara yang berlawanan: untuk mengatakan bahwa byte berikutnya adalah karakter kontrol daripada byte data. Dalam pengalaman saya, itu umumnya arti sebaliknya untuk melarikan diri.Anda tahu, ASCII sudah memiliki byte untuk fungsi-fungsi ini.
Ini juga memiliki kode untuk berbagai kegunaan di dalam payload.
Protokol Anda harus menentukan rincian terbaik dari ACK (0x06) dan NAK (0x15), sehingga data yang diakui negatif dapat dikirim kembali. Turun ke granularity terbaik ini, adalah bijaksana untuk memiliki bidang panjang segera setelah indikator awal (unescaped) dan (seperti yang dijelaskan dalam jawaban lain) adalah bijaksana untuk mengikuti indikator berhenti (unescaped) dengan CRC.
sumber
Pada dasarnya, UART tidak aman dari kesalahan - kita berbicara tentang teknologi 1960-an di sini.
Akar masalahnya adalah bahwa UART hanya menyinkronkan sekali per 10 bit, memungkinkan banyak omong kosong untuk melewati antara periode sinkronisasi tersebut. Berbeda dengan misalnya BISA yang sampel setiap individu bit beberapa kali.
Setiap kesalahan bit ganda yang terjadi di dalam data akan merusak bingkai UART dan lulus tidak terdeteksi. Kesalahan bit dalam bit mulai / berhenti mungkin atau mungkin tidak terdeteksi dalam bentuk kesalahan overrun.
Oleh karena itu, tidak masalah jika Anda menggunakan data mentah atau paket, selalu ada kemungkinan bahwa bit yang disebabkan oleh EMI menghasilkan data yang tidak terduga.
Ada banyak cara "perdukunan UART tradisional" untuk memperbaiki situasi sedikit. Anda dapat menambahkan byte sinkronisasi, bit sinkronisasi, paritas, bit stop ganda. Anda bisa menambahkan checksum yang menghitung jumlah semua byte (dan kemudian membalikkannya - karena mengapa tidak) atau Anda bisa menghitung jumlah biner sebagai checksum. Semua ini banyak digunakan, sangat tidak ilmiah dan dengan kemungkinan besar kesalahan yang hilang. Tetapi inilah yang dilakukan orang-orang dari tahun 1960 hingga 1990-an dan banyak hal aneh seperti kehidupan ini pada hari ini.
Cara paling profesional untuk menangani transmisi yang aman melalui UART adalah memiliki checksum CRC 16 bit di akhir paket. Segala sesuatu yang lain tidak terlalu aman dan memiliki kemungkinan besar kesalahan yang hilang.
Kemudian pada tingkat perangkat keras Anda dapat menggunakan diferensial RS-422 / RS-485 untuk secara drastis meningkatkan kekasaran transmisi. Ini adalah suatu keharusan untuk transmisi yang aman jarak jauh. Level TTL UART hanya boleh digunakan untuk komunikasi on-board. RS-232 tidak boleh digunakan untuk tujuan lain tetapi kompatibilitas dengan hal-hal lama.
Secara keseluruhan, semakin dekat ke perangkat keras mekanisme deteksi kesalahan Anda, semakin efektif itu. Dalam hal efektivitas, sinyal diferensial menambah paling banyak, diikuti dengan memeriksa kesalahan pembingkaian / overrun dll CRC16 menambahkan beberapa, dan kemudian "perdukunan UART tradisional" menambahkan sedikit.
sumber
Situasi ketika sebagian data sama dengan terminating sequence harus dipertimbangkan ketika merancang format paket data serial. Hal lain yang perlu dipertimbangkan adalah bahwa karakter apa pun dapat rusak atau hilang selama transmisi. Karakter awal, karakter berhenti, byte payload data, checksum atau CRC byte, byte koreksi kesalahan maju tidak kebal terhadap korupsi. Mekanisme pembingkaian harus dapat mendeteksi ketika suatu paket memiliki data yang rusak.
Ada beberapa cara untuk mendekati semua ini.
Saya membuat asumsi yang berfungsi bahwa paket hanya dibingkai dengan byte serial. Garis jabat tangan tidak digunakan untuk membingkai. Penundaan waktu tidak digunakan untuk membingkai.
Kirim panjang paket
Kirimkan panjang paket di awal, alih-alih [atau sebagai tambahan] karakter penghentian di akhir.
pro: Muatan dikirim dalam format biner yang efisien.
Kontra: Perlu mengetahui panjang paket pada awal transmisi.
Melarikan diri dari karakter khusus
Keluar dari karakter khusus saat mengirim data payload. Ini sudah dijelaskan dalam jawaban sebelumnya .
pro: Pengirim tidak perlu tahu panjang paket di awal pengiriman.
kontra: Agak kurang efisien, tergantung pada berapa banyak byte muatan yang harus diloloskan.
Data payload dikodekan sedemikian sehingga tidak dapat memuat karakter awal dan berhenti
Payload paket dikodekan sedemikian sehingga tidak dapat berisi karakter awal atau berhenti. Biasanya, ini dilakukan dengan mengirimkan nomor sebagai representasi ASCII atau Hex-ASCII mereka.
pro: Dapat dibaca manusia dengan program terminal umum. Tidak perlu kode untuk menangani pelolosan. Tidak perlu tahu panjang paket di awal pengiriman
kontra: efisiensi yang lebih rendah. Untuk satu byte data payload, beberapa byte dikirim.
sumber