Neler yeni

[Çözüm] Seri Port Bağlantısı ile Cep Telefonuna Erişim

Mehmetkarahanlı

Özel Üye
Özel Üye
Katılım
19 Haz 2016
Mesajlar
8,528
Beğeniler
99
#1
Bu makalede bluetooth destekli bir cep telefonunun bilgisayara nasıl bağlanacağı ve daha sonra, COM port üzerinden nasıl kontrol edileceği anlatılacaktır. Bluetooth bilgisayar ve çevre birimleri arasında kablo gereksinimi olmadan kısa mesafe radyo frekansı ile haberleşmeyi sağlayan teknolojinin adıdır. Bu teknoloji 2.4 GHz frekans bandı civarında çalışmakta olup, veri ve ses iletimi yapabilmektedir. Veri aktarma hızı 720 kbps’ye kadar ulaşabilmektedir. Etkinlik mesafesi cihazın modeline göre yaklaşık 10 ile 100 metre arasındadır. Telefona hiç dokunmadan konuşma imkanı, bluetooth ürünlerinin en önemli özelliğidir. Markası ne olursa olsun, telefonda bluetooth özelliğinin olması, bunun için yeterlidir. Bluetooth takılı bir PC veya cihaz diğer cihazlara radyo frekansıyla rahat bağlanabilmektedir. Farklı cihazların bağlanabilmesi, düşük maliyet ve az güç tüketimi önemli bir avantaj sunmaktadır.

Bilgisayarla dış aygıtlar arasındaki kablo ile iletişimi sağlayan veri kanallarına port denir. Bunlara bağlantı noktası da diyebiliriz. Portlar seri (COM) ve paralel (LPT) olmak üzere iki temel kısımda incelenir. Paralel port, seri port gibi yerini USB’ye bırakmaya başlamıştır. USB ise dış donanımların bilgisayar ile bağlantı kurabilmesini sağlayan seri yapılı bir bağlantı biçimidir. Anakartlarda en az 4 USB portu bulunmaktadır. Plug and Play özelliğinden dolayı birçok cihazın bağlantısında kullanılmaktadır.

Öncelikle bilgisayarımızda hazır bir bluetooth olması ve cep telefonumuzun bluetooth destekli olması gerekmektedir. Eğer bilgisayarınızda takılı bir bluetooth yoksa bir bluetooth dongle satın almanız gerekir. Bluetooth dongle, PC sisteminin USB arabirimini kullanarak çalışır hale getirilebilir. Kullandığım bluetooth cihazını boş bir USB’ye takıp ayarlamaları yaptım. Yalnız ürünle beraber verilen kurulum CD’sini kullanmakta fayda var.
Microsoft XP Bluetooth kullanılacaksa, Windows XP SP2 kurulu bir PC’de buna gerek yoktur. Kurulumu bitirdikten sonra COM port numarasına bakmak için “Denetim Masası” içinden “Bluetooth Devices” a veya “Aygıt Yöneticisi” ne giriniz. Windows XP SP2 yüklü bir makinede aşağıdakine benzer bir durum görürsünüz. Sizdeki COM portların numarası farklı olabilir. Başka bir deyişle, farklı bir port kullanılarak seri port bağlantısı oluşturulabilir.


Şekil 1. Bluetooth COM portlar.


Şekil 2. Aygıt yöneticisinden Bluetooth portlar. Bluetooth Radio altında Microsoft Bluetooth Enumerator ve Generic Bluetooth Radio adlarını bulursunuz. Microsoft XP Bluetooth Stack dışında başka bir bluetooth driver yüklü ise (Widcomm veya IVT BlueSoleil gibi) farklı bir isim görebilirsiniz. Ports (COM & LPT) altında ise portların adları vardır. Portun özelliklerine bakmak için sağ tıklayıp “Properties” veya “Özellikler”i tıklarsanız aşağıdakine benzer bir resim görebilirsiniz. Burada bluetooth dongle’ un seri port profiline karşılık gelen COM port numarası bulunmaktadır.


Şekil 3. Port özellikleri. Bir başka yol da kurulu modem bağlantısını kontrol etmektir. Aygıt Yöneticisi içindeyken modemlere bakınız. Port numarasına ve hızına bakmak için özelliklere bakmanız yeterlidir. Bu bağlantıyı kullanmak hız bakımından avantaj getirebilir.


Şekil 4. Aygıt yöneticisinden bluetooth modem. Java uygulamalarını tam olarak desteklemeyen veya JSR-82 Bluetooth API’ den yoksun olan düşük modelli cep telefonlarında bile, bu makalede olduğu gibi, AT komutları üzerine kurulu projeler geliştirilebilir. JSR-82 Bluetooth/Obex destekleyen telefonlarda ise başka alternatifler var olmakla beraber bunlar makalemizin konusu dışındadır. Oluştaracağımız proje, AT komut seti kullanarak, bilgisayar ile cep telefonu arasında iletişim sağlayan bir uygulama olacaktır. Cep telefonu üreticileri, ürettikleri modellerde kendilerine özgü AT komut setlerini uygulamaktalar. Standart AT komutları dışındaki diğer özelliklere erişmek için kendi telefonunuzun üretici web sayfasına bakmanız yeterlidir. Örnek vermek gerekirse, telefonun GSM operatörü adını sorguladığınızda, farklı markalardan farklı yanıt alabilirsiniz. Kodlamaya başlamadan önce bluetooth bağlantınızı ve AT komutlarının bazılarını denemenizi tavsiye ederim.

HyperTerminal bağlantısı
Bunun için Başlat -> Programlar ->Donatılar-> İletişim -> HyperTerminal programını kullanabilirsiniz. Aynı şekilde Başlat -> Çalıştır içinde hypertrm yazarsanız, hyperterminal programını başlatabilirsiniz. Programı çalıştırmadan önce cep telefonunuzun ayarlar kısmından bluetooth’un açık olmasına dikkat ediniz. Yeni bağlantı kurmak için aşağıdakilere benzer pencereler gelecektir. İlk önce oluşturacağınız bağlantıda kullanılacak oturum adı ve simgesi belirtmeniz gerekiyor.

Şekil 5. Oturum adı belirleme.

Daha sonra cep telefonunuz bilgisayarınıza hangi portttan bağlanmışsa, onu seçiniz. Bendeki bağlantı COM7’ye karşılık geliyor. Sizdeki farklı olabilir. Listeden kendinize uygun olanı seçiniz.


Şekil 6. Bağlantıda kullanılacak portun listeden seçimi. Bağlantı başarıyla oluşturulduktan sonra karşımıza hyperterminal ekranı gelir. Bu ekrandayken AT yazıp Enter’a basalım. OK karşılığı alınıyorsa, AT komutlarının desteklendiğini anlarız. Bundan sonra istediğimiz AT komutunu çalıştırabiliriz.


Şekil 7. Hyperterminal ekranındaki komutlar. Şimdi bilgisayara bağlı bir bluetooth portu kullanarak cep telefonumuzun bazı özelliklerini ekrana yazdıracağız. Ben bu uygulamayı SonyEricsson T630 ve Nokia 6280 gibi düşük modelli telefonlarda kullanarak denedim. Erişmek istediğimiz özellikler, telefon üreticisinin adı, modeli, IMEI numarası ve bağlı olduğu operatörün adıdır. İlk önce bunları yapacak olan sınıfımızı yazalım. Daha sonra formumuzu tasarlayacağız. Yeni bir windows uygulama projesi açalım ve ClassPhoneInfo adlı sınıfımızı yazalım. Sınıf ve üyeleri ile ilgili diğer kavramlar, kodlar içerisinde yer alan yorum satırlarında açıklanmıştır.

using System;
using System.Windows.Forms;
using System.Text;
using System.Text.RegularExpressions;
using System.IO.Ports;

/// <summary>
/// ClassPhoneInfo sınıfı bluetooth takılı bir PC’den seri portu kullanarak,
/// cep telefonumuzla bağlantı kurar. Böylece telefonun bazı özelliklerine erişimi
/// sağlar. Bunlar AT komutları yollanarak elde edilmektedir.
/// </summary>
public class ClassPhoneInfo
{
// Değişken üyeler private olarak tanımlanıyor.
// Bununla sınıf dışından erişim engelleniyor.
private string m_PhoneManufacturer = ""; // Üretici ismi değişkeni
private string m_PhoneModel = ""; // Model değişkeni
private string m_PhoneSerialNo = ""; // IMEI nosu değişkeni
private string m_OperatorName = ""; // GSM operatörü değişkeni
// Seri port nesnesini alacak değişkeni tanımlıyoruz.
private SerialPort myPort = null;

// Statik üyeler
//
// AT komutlarını sabit string olarak tanımlıyoruz.
private static string AT_CMD_PHONEMANUFACTURER = "AT+GMI";
private static string AT_CMD_PHONEMODEL = "AT+GMM";
private static string AT_CMD_PHONESERIALNO = "AT+CGSN";
private static string AT_CMD_OPERATORNAME = "AT+COPS?";
// AT komutunu desteklemeyen servis için string tipindeki sonuç.
private static string VALUE_NOT_SUPPORTED = "Desteklenmiyor";
// Regular Expression için desenleri tanımlıyoruz.
//
// OK mesajı deseni
private static Regex rgxOK = new Regex("\\s+OK\\s",
RegexOptions.Compiled | RegexOptions.IgnoreCase);
// ERROR mesajı deseni
private static Regex rgxERROR1 = new Regex("\\s+ERROR\\s",
RegexOptions.Compiled | RegexOptions.IgnoreCase);
// ERROR: mesajı deseni. Error ile beraber sayı gelebilir.
private static Regex rgxERROR2 = new Regex("\\s+ERROR:\\s\\d+\\s",
RegexOptions.Compiled | RegexOptions.IgnoreCase);

// ClassPhoneInfo sınıfı özellikleri
//
// PhoneManufacturer özelliği okunduğunda telefon üreticisi ismini verir.
public string PhoneManufacturer
{
get
{
return m_PhoneManufacturer;
}
}

// PhoneModel özelliği okunduğunda telefonun modelini verir.
public string PhoneModel
{
get
{
return m_PhoneModel;
}
}

// PhoneSerialNo özelliği okunduğunda IMEI numarasını verir.
public string PhoneSerialNo
{
get
{
return m_PhoneSerialNo;
}
}

// OperatorName özelliği okunduğunda GSM operatörü adını verir.
public string OperatorName
{
get
{
return m_OperatorName;
}
}

// Kurucu metodumuzun amacı girilen parametreye uygun bir
// seri port nesnesini kullanmaktır.
public ClassPhoneInfo(SerialPort serialPort)
{
// SerialPort parametresini myPort değişkenine atama.
myPort = serialPort;

try
{
// Connect tanımlı metodumuzu çağır.
Connect();
}
catch (Exception ex)
{
// Close tanımlı metodumuzu çağır ve uyarı mesajı ver.
ClosePort();
MessageBox.Show(ex.Message);
}
}

// Connect() metodu ile port kapalıysa açılıyor ve sınıf değişkenlerine
// telefondan okunacak değerlerin alınabilmesi sağlanıyor.
private void Connect()
{
try
{
// Eğer port kapalıysa?
if (!myPort.IsOpen)
{
myPort.Open(); // Portu aç
}

// Telefon üreticisinin ismi değişkene aktarılıyor.
m_PhoneManufacturer = GetPhoneManufacturer();

// Telefonun modeli değişkene aktarılıyor.
m_PhoneModel = GetPhoneModel();

// Telefon IMEI numarası değişkene aktarılıyor.
m_PhoneSerialNo = GetPhoneSerialNo();

// GSM operatörünün ismi değişkene aktarılıyor.
m_OperatorName = GetOperatorName();
}
catch (Exception ex)
{
ClosePort();
MessageBox.Show(ex.Message);
}
}//end Connect()

// Port açıksa kapatan metodumuz.
public void ClosePort()
{
// Eğer port açıksa ve nesne null değilse
if ((myPort != null) && (myPort.IsOpen))
{
myPort.Close();
myPort = null;
}//end if
}//end ClosePort()

// Verileri portumuza yollayan metod.
private void SendData(string str)
{
myPort.WriteLine(str + "\r");
}//end SendData()

// GetPortResponse() metodu porttaki verileri string olarak döndürür.
private string GetPortResponse()
{
// Döngünün max. kaç kez çalıştırılacağını tanımlıyoruz.
const int numCounts = 3;
// Sayac
int count = 0;

// Döndürülecek string değer değişkeni.
string sResponse = "";
// StringBuilder nesnesi oluştur.
StringBuilder sb = new StringBuilder();

try
{
// Döngünün şartını verilen hak sayısı kadar tanımlıyoruz.
// Bu sayı duruma göre arttırılıp azaltılabilir.
while (count < numCounts)
{
// Okunan veriler "sb" değişkenine ard arda eklenir.
sb.AppendLine(myPort.ReadLine());
// "sb" değişkeni içindekileri string tipine çevir.
sResponse = sb.ToString();

// Okunan veriler içersinde OK veya ERROR kelimesi varsa?
if ((sResponse.IndexOf("OK") > 0) ||
(sResponse.IndexOf("ERROR") > 0))
{
// İçerikte desenlere göre karşılaştırma yap.
if ((rgxOK.Match(sResponse).Success) ||
(rgxERROR1.Match(sResponse).Success) ||
(rgxERROR2.Match(sResponse).Success))
break;
}//end if

count++; // Sayacı arttır
}//end while true

if (myPort.BytesToRead > 0)
{
myPort.DiscardInBuffer();
}//end if
}
catch (Exception ex)
{
//Hata yakalandı ve hata mesajı gösteriliyor.
MessageBox.Show(ex.Message);
}//end try-catch

// StringBuilder nesnesi içindeki sonucu string tipine çevir.
return sb.ToString();
}//end GetPortResponse()

// Telefon üreticisi ismini veren metod.
private string GetPhoneManufacturer()
{
// Telefon üreticisi sorgulayan AT komutunu yolla.
SendData(AT_CMD_PHONEMANUFACTURER);
// GetPortResponse() metodunu çağırıyoruz ve gönderilen veriyi
// string değişkene atıyoruz.
string sResponse = GetPortResponse();

// Eğer hata mesajı varsa (ERROR kelimesini yakala)?
if (sResponse.IndexOf("ERROR") > 0)
{
// Gönderilen komut geçersiz veya AT komutu yanlışsa,
// telefon tarafından desteklenmiyor mesajı yolla.
return VALUE_NOT_SUPPORTED;
}
else
{
// Gönderilen komut başarılıysa, dönen string içerikte
// OK desenine göre OK mesajını kaldırıyoruz.
sResponse = rgxOK.Replace(sResponse, "");
// String içerisindeki AT komutunu yakalayıp boşlukları atıyoruz.
sResponse = (Regex.Replace(sResponse, @"(AT\+GMI)", "")).Trim();

return sResponse;
}//end if
}//end GetPhoneManufacturer()

// Telefon modelini veren metod.
private string GetPhoneModel()
{
// Telefon modeli sorgulayan AT komutunu yolla.
SendData(AT_CMD_PHONEMODEL);
// Gönderilen veri string değişkene atanıyor.
string sResponse = GetPortResponse();

// Eğer hata mesajı varsa (ERROR kelimesini yakala)?
if (sResponse.IndexOf("ERROR") > 0)
{
return VALUE_NOT_SUPPORTED;
}
else
{
// Gönderilen komut başarılıysa, dönen string içerikte
// OK desenine göre OK mesajını kaldırıyoruz.
sResponse = rgxOK.Replace(sResponse, "");
// String içerisindeki AT komutunu yakalayıp boşlukları atıyoruz.
sResponse = (Regex.Replace(sResponse, @"(AT\+GMM)", "")).Trim();

return sResponse;
}//end if
}//end GetPhoneModel()

// Telefonun IMEI numarasını veren metod.
private string GetPhoneSerialNo()
{
// Telefon seri numarasını sorgulayan AT komutunu yolla.
SendData(AT_CMD_PHONESERIALNO);
// Gönderilen veri string değişkene atanıyor.
string sResponse = GetPortResponse();

// Eğer hata mesajı varsa (ERROR kelimesini yakala)?
if (sResponse.IndexOf("ERROR") > 0)
{
return VALUE_NOT_SUPPORTED;
}
else
{
// Gönderilen komut başarılıysa, dönen string içerikte
// OK desenine göre OK mesajını kaldırıyoruz.
sResponse = rgxOK.Replace(sResponse, "");
// String içerisindeki AT komutunu yakalayıp boşlukları atıyoruz.
sResponse = (Regex.Replace(sResponse, @"(AT\+CGSN)", "")).Trim();

return sResponse;
}//end if
}//end GetPhoneSerialNo()

// Telefonun GSM operatörü adını veren metod.
private string GetOperatorName()
{
// GSM operatörü ismini sorgulayan AT komutu desenimiz.
Regex rgx1 = new Regex("AT\\+COPS\\?\\s+", RegexOptions.IgnoreCase);
// Dönen mesajın deseni
// Örnek: +COPS: 0, 0 TR TURKCELL ifadesi gibi
Regex rgx2 = new Regex("\\+COPS\\:?\\s+\\d\\,\\d\\,", RegexOptions.IgnoreCase);

// Telefon GSM operatörü ismini sorgulayan AT komutunu yolla.
SendData(AT_CMD_OPERATORNAME);
// Gönderilen veri string değişkene atanıyor.
string sResponse = GetPortResponse();

// Eğer hata mesajı varsa (ERROR kelimesini yakala)?
if (sResponse.IndexOf("ERROR") > 0)
{
return VALUE_NOT_SUPPORTED;
}
else
{
// Gönderilen komut başarılıysa, dönen string içerikte
// OK desenine göre OK mesajını kaldırıyoruz.
sResponse = rgxOK.Replace(sResponse, "");
// rgx1 ve rgx2 desenlerine göre değiştirmeleri yapıyoruz.
sResponse = rgx2.Replace(rgx1.Replace(sResponse, ""), "");

// İfadeden tırnak ve boşlukları atıyoruz.
return (sResponse.Replace(""", "")).Trim();
}//end if
}//end GetOperatorName();

}//end class ClassPhoneInfo




Şimdi ClassPhoneInfo sınıfımızı çağıracak olan ve ayarları verebileceğimiz formumuzu tasarlamaya başlayalım. Projemizi çalıştırdığımızda, görüntüsü aşağıdakine benzer şekilde olacaktır. Şekilde yeralan telefon bilgileri, güvenlik nedeniyle değiştirilmiştir.


Şekil 8. Projemizin ana formu. Projemize yeni bir form ekleyelim ve adını frmBTHCOMPort olarak verelim. Üzerine iki adet GroupBox, beş adet ComboBox, üç adet Button ve beş adet Label kontrollerini yerleştirelim. Daha sonra bir adetSerialPortbileşeni de koyalım. Bu bileşenin özellikleri üzerinde bir değişiklik yapmayalım. Bunları daha sonra kodla vereceğiz. İsim uzayına System.IO.Ports eklemeyi ihmal etmeyelim. Proje kodumuz aşağıdaki gibi devam etmektedir:

using System;
using System.Windows.Forms;
using System.Threading;
using System.Text;
using System.Text.RegularExpressions;
using System.IO.Ports;

namespace BTHCOMPortProject
{
public partial class frmBTHCOMPort : Form
{
// İş parçacığı tanımla
private Thread myThread;
// ClassPhoneInfo nesnesi
private ClassPhoneInfo PhoneInfo;


public frmBTHCOMPort()
{
InitializeComponent();

// Form üzerindeki kontrollerinin ayarlamalarını yapan metodu çağır.
InitializeFormControls();
}

// Form üzerindeki kontrollerin ayarlamalarını yapar.
private void InitializeFormControls()
{
buttonSearch.Enabled = false; // Kullanıma kapalı
// Combobox bileşenlerinde ilk elemanları seç.
comboBoxBaudRate.SelectedIndex = 0;
comboBoxDatabits.SelectedIndex = 0;
comboBoxParity.SelectedIndex = 0;
comboBoxStopbits.SelectedIndex = 0;
}//end InitializeFormControls()


// SerialPort bileşeninin özelliklerini ayarlıyoruz.
private void InitializeCOMPort()
{
// Kullanacağımız portu belirliyoruz.
serialPort1.PortName = comboBoxCOMPorts.Text;
// Seri portun veri iletişim hızını ayarlıyoruz.
serialPort1.BaudRate = int.Parse(comboBoxBaudRate.Text);
// Seri portun veri bitleri özelliğini ayarlıyoruz.
serialPort1.DataBits = int.Parse(comboBoxDatabits.Text);
// Seri portun Parity (eşlik biti) özelliğini ayarlıyoruz.
serialPort1.Parity = (Parity)Enum.Parse(typeof(Parity),
comboBoxParity.Text);
// Seri portun StopBits (dur biti) özelliğini ayarlıyoruz.
serialPort1.StopBits = (StopBits)Enum.Parse(typeof(StopBits),
comboBoxStopbits.Text);
// Seri porttaki handshaking protokolünü ayarlıyoruz.
serialPort1.Handshake = Handshake.RequestToSend;
// Seri porttaki veri terminal hazırlamanın durumunu belirliyoruz.
serialPort1.DtrEnable = true;
}//end InitializeCOMPort()


// PhoneInfo nesnesi örneği yaratılarak cep telefonuna bağlantı
// yapılıyor ve bazı özellikleri ekrana yazdırılıyor.
private void PhoneInfoWork()
{
try
{
// SerialPort bileşenini ayarlayan metodu çağır.
InitializeCOMPort();

// PhoneInfo nesnesini oluştur.
PhoneInfo = new ClassPhoneInfo(serialPort1);

// PhoneInfo nesnesinin özelliklerini kullanarak, telefonun
// üreticisi, modeli, IMEI nosu ve operatör adı
// bilgilerini okuyup metin kutusuna yazdır.
richTextBox1.Text = ("Üretici:").PadRight(21, ’.’) +
PhoneInfo.PhoneManufacturer + "\n" +
("Model:").PadRight(20, ’.’) +
PhoneInfo.PhoneModel + "\n" +
("IMEI:").PadRight(21, ’.’) +
PhoneInfo.PhoneSerialNo + "\n" +
("Operatör:").PadRight(20, ’.’) +
PhoneInfo_OperatorName;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
// Portu kapatatıyoruz.
PhoneInfo.ClosePort();
}//end try-catch-finally
}//end PhoneInfoWork()

// "Port listesi" düğmesine basılınca,
// port adlarını combo kutusuna doldurur.
private void buttonPorts_Click(object sender, EventArgs e)
{
buttonSearch.Enabled = false; // Kullanıma kapalı
comboBoxCOMPorts.Items.Clear();

try
{
// Port isimlerini combobox içine doldur.
comboBoxCOMPorts.Items.AddRange(SerialPort.GetPort Names());
// Listeden ilk elemanı seç.
comboBoxCOMPorts.SelectedIndex = 0;
// Butonu aktifleştir.
buttonSearch.Enabled = true; // Kullanıma açık
}
catch (Exception ex)
{
// Portlar sorgulanırken hata oluştu.
MessageBox.Show(ex.Message);
}
}

// "Araştır" düğmesine basılınca, cep telefonu bilgilerini
// metin kutusuna yazdırır.
private void buttonSearch_Click(object sender, EventArgs e)
{
richTextBox1.Clear();
// Port adı boşsa kontrol et.
if (comboBoxCOMPorts.Text != "")
{
// PhoneInfoWork() metodunu iş parçacığı-thread haline getirelim.
myThread = new Thread(new ThreadStart(PhoneInfoWork));
// İş parçacığı nesnesini başlatalım.
myThread.Start();
}
else
{
MessageBox.Show("COM port adı seçiniz.");
}
}

// "Kapat" düğmesine basılınca, uygulmadan çıkılır.
private void buttonClose_Click(object sender, EventArgs e)
{
// Uygulamayı sonlandır
Application.Exit();
}
}
}