Seri Haberleşmede Frame oluşturma.

Başlatan Mucit23, 30 Ekim 2021, 17:36:15

Mucit23

Selamlar

İki adet aygıt arasında Seri port ile 4-8 Byte arasında bazı durum verileri göndermek istiyorum. Her bir Byte'de 8 Adet girişin durum bilgisi mevcut. Ben normalde Modbus benzeri standart bir frame oluşturmayacaksam eğer kendim paket başına ve sonuna bilindik bir karakteri ekleyip bu aralıktaki verileri alıyordum. Örneğin "{Veri}" gibi

Fakat şimdi gelen paket içerisinde daima binary veriler olacağı için 4-8 byte'lık veriler içerisinde rastgele olarak benim paket sonu karakterimin gelme olasılığı var. Böyle bir durum olursa Veri alma aşamasında sistemimin kafası karışır.

Bu durumun asla olmayacağını nasıl garantilerim? Böyle bir durum için nasıl teknik geliştirebiliriz biraz fikir alışverişi yapmak istedim.

Tagli

Önemli bir konu. Ben genelde Modbus kullandığım için bu durumun üzerinde çok durmadım, ancak zamanında üzerinde düşünüp araştırmıştım biraz.

Şöyle bir site var, birkaç yöntemden bahsetmiş ve içlerinden biri (byte stuffing) üzerinde durarak örnek vermiş.

Modbus frame'leri birbirinden ayırmak için aralarına zaman boşluğu koyuyor. Galiba CAN Bus'ta da durum benzer. Bunu işlemci tarafında gerçeklemek zor değil.

Diğer yaygın yöntem ise byte stuffing - yukarıda bahsettiğim site bunun üzerinde durmuş. Bunda şöyle ufak bir sorun var: En kötü ihtimal gerçekleşirse paket boyutu 2 katına çıkabilir. Ona karşı da COBS diye bir yöntem var, ben denemedim ama akla çok yatkın.
Gökçe Tağlıoğlu

Gediz1337

Daima binary demişsiniz ama yine de bahsetmek istedim çünkü ben de benzer uygulamalarda "mecbur binary" yaklaşımını belirli muhasebeler sonucu terk etmek durumunda kaldım.
Eğer overhead sizin için sorun olmayacaksa başlangıç ve bitiş flaglerini binary, payload'u da ASCII ile kodlanmış hex olarak gönderebilirsiniz, misal.

Diğer senaryoda veriyi parse etmek oldukça güç oluyor ve tüm özel durumları kapsayan bir parser yazmak epey emek istiyor maalesef.

Mucit23

Alıntı yapılan: Tagli - 30 Ekim 2021, 17:50:33Önemli bir konu. Ben genelde Modbus kullandığım için bu durumun üzerinde çok durmadım, ancak zamanında üzerinde düşünüp araştırmıştım biraz.

Şöyle bir site var, birkaç yöntemden bahsetmiş ve içlerinden biri (byte stuffing) üzerinde durarak örnek vermiş.

Modbus frame'leri birbirinden ayırmak için aralarına zaman boşluğu koyuyor. Galiba CAN Bus'ta da durum benzer. Bunu işlemci tarafında gerçeklemek zor değil.

Diğer yaygın yöntem ise byte stuffing - yukarıda bahsettiğim site bunun üzerinde durmuş. Bunda şöyle ufak bir sorun var: En kötü ihtimal gerçekleşirse paket boyutu 2 katına çıkabilir. Ona karşı da COBS diye bir yöntem var, ben denemedim ama akla çok yatkın.

@Tagli Teşekkürler. Son bir saattir kara kara nasıl bir yöntem uydururum diye düşündüm. En son üst üste iki adet eof eklemeyi düşündüm. Ard arda gelirse paketi bitir şeklinde. Fakat bu yöntemden se vermiş olduğun linkteki byte stuffing yöntemi aklıma baya yattı. Uygulaması zor değil gibi. Veri kaybı bu uygulama için çok önemli değil ama buna birde CRC8 ile doğrulama eklersem harika olur. CRC yine de yine paket sonuna eklemek gerekiyor sanırım. Artık sistem paket sonu verisi geldikten sonra CRC yi bekleyecek. CRC veriside geldikten sonra paket geldi diyip tekrardan paket başını beklemek lazım.

@Gediz1337 Girişleri Mecbur Binary olarak kodlamam gerekiyor çünkü Max boyutta 8 byte data eder. Bufa 64 adet durum verisi anlamına gelir. '0' ve '1' karakterleri ile String olarak göndermeye kalksam sadece 64 Byte data ederki veri boyutu çok fazla artmış olacak. Buda beraberinde daha fazla sorun oluşturacak.

foseydon

#4
- 2ser karakter koy
- frame icerisinde frame uzunlugunu da yolla

birde, veri her zaman binary zaten. string vs. bir yorumlama sekli. ben her zaman binary olarak isliyorum gelen verileri. string bile olsa bu sekilde, bence daha mantikli ve dha hizli.

ziyaretci

#5
-Paket geldi uç nokta(0xa0, 0x50) (Bu değerler, otomatik baud rate özellikli denetleyiciler için seçiliyor diye biliyorum)
-Paket ID
-Paket sırası
-Paket data uzunluğu(byte)
-Paket data(lar)(...)
-Paket CRC, CS vs.

Genel, profesyonel kullanım bu şekilde. Tabii uygulamanızın ihtiyacına göre bu durum değişir.

Gediz1337

Alıntı yapılan: Mucit23 - 30 Ekim 2021, 18:21:42Girişleri Mecbur Binary olarak kodlamam gerekiyor çünkü Max boyutta 8 byte data eder. Bufa 64 adet durum verisi anlamına gelir. '0' ve '1' karakterleri ile String olarak göndermeye kalksam sadece 64 Byte data ederki veri boyutu çok fazla artmış olacak. Buda beraberinde daha fazla sorun oluşturacak.

Anladım. Aslında şunu kastetmiştim, sanırım bir önceki gönderide düzgün izah edemedim.

Mesela göndermek istediğimiz veri seti 5, 15, 40, 60, 100, 145, 180, 250 olsun.

Hex olarak ifade edersek: 0x05, 0x0F, 0x28, 0x3C, 0x64, 0x91, 0xB4, 0xFA.

Başlangıç ve bitiş karakterlerini tamamen farazi olarak veriyorum.

Başlangıç: 0x02
Bitiş: 0x03

Köşeli parantez içerisinde gösterilenler zaten anlayacağınız üzere direkt binary, diğerleri de payload'un hex değerlerinin ASCII olarak ifade edilmiş hali.

[0x02]050F283C6491B4FA[0x03]

Tamamını binary olarak göndermek istediğimizde de 18 bayt yetiyor.

0x02 0x30 0x35 0x30 0x46 0x32 0x38 0x33 0x43 0x36 0x34 0x39 0x31 0x42 0x34 0x46 0x41 0x03

yas

Genelde modbus ın kullanımı rtu modda tercih ediliyor. Modbus ın birde ascii modu var. Eğer bayt sayısın iki katına çıkması problem değilse aynı mantıkta bir frame oluşturabilirsiniz. Tam bu iş için uygun bence.

Mucit23

Alıntı yapılan: Gediz1337 - 30 Ekim 2021, 23:36:02Anladım. Aslında şunu kastetmiştim, sanırım bir önceki gönderide düzgün izah edemedim.

Mesela göndermek istediğimiz veri seti 5, 15, 40, 60, 100, 145, 180, 250 olsun.

Hex olarak ifade edersek: 0x05, 0x0F, 0x28, 0x3C, 0x64, 0x91, 0xB4, 0xFA.

Başlangıç ve bitiş karakterlerini tamamen farazi olarak veriyorum.

Başlangıç: 0x02
Bitiş: 0x03

Köşeli parantez içerisinde gösterilenler zaten anlayacağınız üzere direkt binary, diğerleri de payload'un hex değerlerinin ASCII olarak ifade edilmiş hali.

[0x02]050F283C6491B4FA[0x03]

Tamamını binary olarak göndermek istediğimizde de 18 bayt yetiyor.

0x02 0x30 0x35 0x30 0x46 0x32 0x38 0x33 0x43 0x36 0x34 0x39 0x31 0x42 0x34 0x46 0x41 0x03

Evet Aslında sizin dediğiniz yöntemde belki uygulanabilir. Ama başlangıç karakterini string olarak almak biraz daha zor ve kontrol gerektiren bir yöntem olur diye düşündüm. Çünkü string olarak gelmesi için yine belirli bir düzende gelmesi gerekecek. Ard arda birkaç tane eof alıp birleştirmek gibi birşey oluyor.

@yas 
Eğer 8 byte yerine 16 byte ile aynı veriyi eksiksiz aktarabileceksem olabilir biraz daha açıklayabilirmisin

brandice5

#9
Binary veriyi base64 e çevir öyle gönder. Karşı tarafda da tekrar decode edersin.

Base64 zaten binary veriyi ASCII karakterler ile göndermek için icad edilmiş bir kodlama.

bymrz

Yanlış anlaşılmasın fakat yukarıda sayılanların hiç birine gerek yok.

Hocam, cevabı sorunun içinde kendiniz vermişsiniz zaten. Anahtar kelimeniz frame, daha doğrusu "Frame Error".

Paketin başında "Break" sinyali gönderirseniz ve alıcı tarafta da "Frame Error" ü algıladıktan sonra paketinizi okuyabilirsiniz...


Kolay gelsin.

brandice5

O dediğiniz yöntem base64 kadar güvenilir değil. Base64 artık bu işte dünya satandardı olmuş bir yöntem. Özellikle http de.

Mucit23

Base64'ü tam olarak anlayamadım. 6 Bitlik kodlama yapılıyor ve 6 bit'i temsil eden 64 tane string karakter var bu karakterler ile veri gönderiliyor.

Base64 paketleme yaparken 6 biti nasıl seçeceğimizi geriye kalan 2 biti ne yaptığımızı tam anlayamadım.

0x7E, 0x9A, 0x38 gibi verileri Base64 olarak kodlamak istersek 6 bitlik paketleri nasıl seçeceğiz? Base 64'de gelen dataların string aralığı belirli. Dolayısıyla gelen verinin hangi aralıkta olduğunu bildiğimden dolayı paket başı ve paket sonu karakterlerimi bu aralığın dışında seçersem hiçbir sorun yaşamam. Base 64'ü kafama yatırmam lazım öncelikle.

Mucit23

Base64 için kendim nasıl kodlama yaparım diye düşünüyordum. Ama MBED TLS kütüphanesi varmış. ARM MBED platformunda bu kütüphaneyi ücretsiz olarak veriyor. Bu kütüphane içerisinde birçok şifreleme algoritmaları ücretsiz olarak veriliyor. Baktım Base64'ü görünce hemen indirip projeme dahil ettim.

https://github.com/ARMmbed/mbedtls/releases

Şöyle bir deneme yaptım.

mbedtls_base64_encode((unsigned char *)dest_String,sizeof(dest_String),&output_len,(unsigned char *)"Deneme123",9);
	mbedtls_base64_decode((unsigned char *)src_string,sizeof(src_string),&src_len,(dest_String),output_len);

Decode işleminin sonunda "Deneme123" Stringine ulaştım.

CLR

Base64 ile yapılıyor bu işler ama 1/3 oranında veriyi büyütür.
Knowledge and Experience are Power