Thread overview
Arduino firmata derlerken hata
Nov 17, 2016
erdem
Nov 22, 2016
erdem
Nov 23, 2016
erdem
Nov 24, 2016
erdem
November 17, 2016

Uzun bir aradan sonra öncelikle merhaba :)

Hem size bir merhaba diyeyim, hem de bir soru sorayım dedim.

Arduino'nun firmata test programını (https://github.com/firmata/firmata_test) derlemeye çalışıyorum.

Derlerken şu şekilde bir hata alıyorum.

Alıntı:

>

firmata_test.cpp: In member function ‘virtual bool MyApp::OnInit()’:
firmata_test.cpp:669:93: error: conversion from ‘const char [13]’ to ‘const wxString’ is ambiguous
MyFrame *frame = new MyFrame( NULL, -1, "Firmata Test", wxPoint(20,20), wxSize(400,640) );

Hata veren satır burası:

   MyFrame *frame = new MyFrame( NULL, -1, "Firmata Test", wxPoint(20,20), wxSize(400,640) );

MyFrame sınıfının kurucu işlevi de şu şekilde:

MyFrame::MyFrame( wxWindow *parent, wxWindowID id, const wxString &title,
   const wxPoint &position, const wxSize& size, long style ) :
   wxFrame( parent, id, title, position, size, style )
{
   /* ... */
}

typedef struct {
	uint8_t mode;
	uint8_t analog_channel;
	uint64_t supported_modes;
	uint32_t value;
} pin_t;
pin_t pin_info[128];

Bir de bu yapı nasıl bir yapıydı. Sanırım C bilgilerini biraz unutmuşum.

D için de firmata protokülünün gerçekleşmesini yazsak nasıl olur. Baktım diğer diller arasında Go bile var.

https://github.com/firmata/arduino

Artık javascript ile bile Arduino uygulamalarının çalıştırılabilmesi çok ilginç geldi.

var five = require("johnny-five");
var board = new five.Board();

board.on("ready", function() {
 console.log("Ready!");

 var led = new five.Led(13);
 led.blink(500);
});

Örneğin yukarıdaki javascript programı 13 numaralı kapıya bağlı ledi yarım saniye aralıklarla yakıp söndürüyor.

Detaylar için bu sayfaya bakabilirsiniz.

https://github.com/rwaldron/johnny-five

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

November 21, 2016

"Firmata Test" yerine wxString("Firmata Test") dener misin. Eğer olmazsa, önce title diye yerel bir değişken tanımlayıp sonra onu parametre olarak göndermeyi deneyebilirsin:

   wxString title("Firmata Test");
   MyFrame *frame = new MyFrame( NULL, -1, title, wxPoint(20,20), wxSize(400,640) );

typedef'li satırda olan şu: İsimsiz bir yapı türü tanımlanıyor ve hemen ona pin_t diye yeni bir isim veriliyor. (Yapının ismi pin_t olsaydı ve typedef kullanılmasaydı uzunca 'struct pin_t' yazmak gerekirdi. (C++ ve D'de ise 'struct' yazmak gerekmezdi.))

Ali

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

November 22, 2016

Şu şekilde düzeldi.

   MyFrame *frame = new MyFrame( NULL, -1, wxString::FromAscii("Firmata Test"), wxPoint(20,20), wxSize(400,640) );

Ama bir tane değil. Dün biraz düzeltmeye çalıştım ama liste çok uzun. Bu sayfada wxString sınıfı ile ilgili bilgiler var.

https://wiki.wxwidgets.org/WxString

Anladığım kadarıyla wxWidgets kütüphanesi ANSII kullanacak şekilde tekrar derleyince bu hata mesajları oluşmuyormuş. Bir de onu deneyeyim bakalım.

Denemek için serial (https://github.com/wjwwood/serial/) kütüphanesini kullanan bir test programı yazdım.

#include <iostream>
#include "serial/serial.h"
#include <bitset>
#include <string>

using std::cout;
using std::string;

typedef serial::Serial SeriPort;

constexpr char onaltilik[] = {'0', '1', '2', '3', '4', '5', '6', '7',
                          '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};

std::string onaltili(uint8_t * veri, int uzunluk)
{
 std::string s(uzunluk * 2, ' ');
 for (int i = 0; i < uzunluk; ++i)
 {
   s[2 * i]     = onaltilik[(veri[i] & 0xF0) >> 4];
   s[2 * i + 1] = onaltilik[veri[i] & 0x0F];
 }
 return s;
}

void baytYazdir(uint8_t bayt)
{
   uint8_t *gBayt = &bayt;
   cout << "Veri = " << onaltili(gBayt,sizeof(bayt)) << std::bitset<8>(bayt) << '\n';
}

std::ostream& operator<<(std::ostream& cikis, uint8_t bayt)
{
   return cikis << " " << std::bitset<8>(bayt) << " " << onaltili(&bayt,sizeof(bayt)) << '\n';
}

#define START_SYSEX             0xF0 // MIDI Sysex iletisinin başlangıcı
#define END_SYSEX               0xF7 // MIDI Sysex iletisinin sonu
#define REPORT_FIRMWARE         0x79 // aygıt sürücüsü yazılımının adı ve sürümünü raporla

int main()
{
   SeriPort seriPort("/dev/ttyACM0", 57600, serial::Timeout::simpleTimeout(5000));
   cout << "Seri port açık mı ?\n";
   if (seriPort.isOpen())
   {
       cout << "Evet\n";

       serial::Timeout timeout = seriPort.getTimeout();

       uint8_t alinan[3];

       uint8_t  * okunan = alinan;

       seriPort.waitReadable();
       for (int i = 0; i < 10; ++i)
       {

           seriPort.read(okunan,3);

           cout << "alinan[0]" << alinan[0];
           cout << "alinan[1]" << alinan[1];
           cout << "alinan[2]" << alinan[2];
       }

       // aygıt sürücüsü yazılımı bilgilerini iste
       uint8_t gonderilen[3];
       gonderilen[0] = START_SYSEX;    // MIDI Sysex iletisinin başlangıcı
		gonderilen[1] = REPORT_FIRMWARE;// aygıt sürücüsü yazılımının adı ve sürümünü raporla
		gonderilen[2] = END_SYSEX;      // MIDI Sysex iletisinin sonu

       cout << "gonderilen[0] " << gonderilen[0];
       cout << "gonderilen[1] " << gonderilen[1];
       cout << "gonderilen[2] " << gonderilen[2];

       seriPort.write(gonderilen, 3);

       // 13 numaralı ledi yak
       gonderilen[0] = 0x91;
       gonderilen[1] = 0x20;
       gonderilen[2] = 0x00;

       cout << "gonderilen[0] " << gonderilen[0];
       cout << "gonderilen[1] " << gonderilen[1];
       cout << "gonderilen[2] " << gonderilen[2];

       seriPort.write(gonderilen, 3);
       seriPort.close();
   }

   else
       cout << "Hayır\n";
}

Bu program 13 numaralı ledi yakıyor. Ama dikkat ederseniz rastgele bir for döngüsüyle verileri okuyoruz. Aslında seri port üzerinde veri olduğu sürece okumaya devam et gibi bir komut kullanmak gerekiyor sanırım.

Coolterm programı (http://freeware.the-meiers.org/) ile verilere baktığınızda F0 ve F7 arasındaki verileri okumamız gerekecek.

http://www.erdem.tk/resim/CoolTerm_0%20-_050.png

Bunun içinde alınan baytları işlemek gerekecek anladığım kadarıyla. Haberleşme protokolüne (https://github.com/firmata/protocol/blob/master/protocol.md) baktığımızda komutlar 8 bit, veriler 7 bit oluyormuş.

İkili G/Ç mesajı 0x90 port LSB(bitler 0-6) MSB(bitler 7-13)

Yalnız ben bu bitlerin sıralamasını tam anlamadım. Örneğin 0x91 20 00

Burada 0x91'den sonra bitlerin sıralaması Boş 0 1 2 3 4 5 6 ve Boş 7 8 9 10 11 12 13 şeklinde mi yoksa Boş 6 5 4 3 2 1 0 ve Boş 13 12 11 10 9 8 7 şeklinde mi.

D için bu protokolü yazmayı denesek nasıl olur :-)

Ya da belki siz söylerseniz D topluluğu içinden yazmayı düşünenler çıkabilir. Ama sanırım D için bir de seri port kütüphanesi gerekecek.

Program çıktısını da buraya (http://www.erdem.tk/resim/cikti.txt) ekledim.

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

November 22, 2016

Alıntı (erdem):

>

Yalnız ben bu bitlerin sıralamasını tam anlamadım. Örneğin 0x91 20 00

Burada 0x91'den sonra bitlerin sıralaması Boş 0 1 2 3 4 5 6 ve Boş 7 8 9 10 11 12 13 şeklinde mi yoksa Boş 6 5 4 3 2 1 0 ve Boş 13 12 11 10 9 8 7 şeklinde mi.

0x90 yazmak istediğini varsayıyorum. Bu gibi konularda bayt içindeki bitlerin sırası değişmez. Ama tabii senin bitleri nasıl numaraladığın da önemli. :) Ben LSB'ye 0, MSB'ye de 13 diyeceğim. Veri '13 12 11 10 9 8 7 6 5 4 3 2 1 0' bitlerinden oluşuyorsa, ilk bayta '6 5 4 3 2 1 0' değeri, ikinci bayta da '13 12 11 10 9 8 7' değeri gelir.

İkinci baytın bitleri 7 bit sağa öteleyerek elde edildiğini söylemeye herhalde gerek yok: '(veri >> 7) & 0b0111_1111)'. Veya D'deki '>>>' işleci ile: '(veri >>> 7)'.

Ali

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

November 23, 2016

Bilmiyordum ama onu da buldum Allah 'ın izniyle ;-)

void ikiliKapiyaGonder(uint8_t portNumarasi, uint16_t portBilgileri)
{
   cout << "İkili Mesaj Gönder = " << uint8_t(DIGITAL_MESSAGE | (portNumarasi & 0xF));
   cout << "Port Bilgileri = " << uint8_t((uint8_t)portBilgileri % 128);
   cout << "Tx 7-13 bitleri =" << uint8_t(portBilgileri >> 7);
}

Program içinden çağırırken de şöyle çağırıyorum.

       uint16_t portBilgileri = 0x0020;
       ikiliKapiyaGonder(1, portBilgileri);

Programın çıktısı da şu şekilde:
Alıntı:

>

İkili Mesaj Gönder = 10010001 91
Port Bilgileri = 00100000 20
Tx 7-13 bitleri = 00000000 00

Port bilgilerini de şuradan öğreniyoruz.

http://www.erdem.tk/resim/arduinoportlari.png

Şimdi sırada işleve 13 gönderdiğimizde portBilgileri = 0x0020 oluşturmak kalıyor. Bunun için benim aklıma gelen örneğin 0000_0001 değerini işleve gelen değer kadar sola kaydırmak; örneğin 0 göndermişse yok, 1 göndermişse 1 sola kaydırmak olabilir.

Arduino Uno üzerinde 16 tane ikili çıkış kapısı var. Ama benim asıl merak ettiğim örneğin yeni modellerde 32 tane ikili çıkış kapısı varsa o zaman 4 tane port oluyor. Bu durumda ne yapabiliriz.

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

November 23, 2016

Belirli bitin değerini 1 yapmak için dediğin yöntem olur. Biraz daha hızlı olabilen bts() de var:

https://dlang.org/phobos/core_bitop.html#.bts

Ayrıca, belki derleyici de aynı eniyileştirmeyi yapacaktır ama '% 128' yerine '& 0b_0111_1111' (veya '& 0x7f') yazmanı öneririm. Bölme işlemi bit işleminden daha yavaş olacaktır. (Tabii ki farketmeyeceksin bile ama yine de bile bile yavaş işlemi seçmeye gerek yok. :) )
Ali

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

November 24, 2016

Ben de C++ çözümünü yazdım ;-)

inline void birYap(uint16_t * dizi, int bit)
{
   asm("bts %1,%0" : "+m" (*dizi) : "r" (bit));
}

Peki çıkış akımına verileri 16'lı olarak yazdırmak istediğimizi düşünelim.

constexpr char onaltilar[] = {'0', '1', '2', '3', '4', '5', '6', '7',
                             '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};

std::string onaltili (uint8_t * veri)
{
   int uzunluk = sizeof (*veri);
   std::string s (uzunluk * 2, ' ');

   for (int i = 0; i < uzunluk; ++i)
   {
       s[2 * i]     = onaltilar[(veri[i] & 0xF0) >> 4];
       s[2 * i + 1] = onaltilar[veri[i] & 0x0F];
   }
   return s;
}

template <typename Tur>
string onaltiliGoster(Tur deger)
{
   const int uzunluk = sizeof(deger);
   std::string s;

   s += (std::bitset<8 * uzunluk>(deger)).to_string() + string(" ");


   vector<uint8_t> baytlar;
   uint8_t * bayt = (uint8_t *)&deger;

   for (int i = 0; i < uzunluk; ++i)
       baytlar.push_back(bayt[i]);
   reverse(baytlar.begin(), baytlar.end());
   for (auto i = baytlar.begin(); i != baytlar.end(); ++i)
       s += onaltili(&(*i));

   s +='\n';

   return s;
}

std::ostream& operator<<(std::ostream& cikis, uint8_t bayt)
{
   return cikis << " " << std::bitset<8>(bayt) << " " << onaltili(&bayt) << '\n';
}

int main()
{
       /* ... */
       uint16_t deger = 0X0000;
       cout << onaltiliGoster(deger);
       birYap(&deger, 13);
       cout << onaltiliGoster(deger);
}

Bu durumda sizce çıkış akımına verileri yukarıdaki gibi bir işlevin mi göndermesi uygun olur yoksa çıkış akımına farklı görev yükleyebilirmiyiz.

Sadece 'template ' şeklinde şablon olanağını kullanmaya çalıştığımda bu sefer cout<<'a giden tüm verileri bu işleve gönderiyor.

Çıkış akımında sadece işaretsiz tamsayılarla çalış şeklinde şablon kullanılabiliyor mu acaba.

Bunun dışında '0b_0111_1111' yazım biçimi C++'de ya da ek derleyici olanağı olarak kullanılabiliyor mu.

Sizce gelen iletileri nasıl okutalım. İletinin başını ve sonunu gösteren gösterge kullanarak mı yoksa bir vektör'e mi atalım. Bu konuda da fikirlerinizi merak ediyorum.

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

November 24, 2016

C++'tan bu soruları hemen cevaplayamayacak kadar kopmuşum. :)

Hatırladığım kadarıyla, uint8_t'nin genel olarak nasıl yazdırıldığını değiştirmek istemediğine göre öyle bir yükleme tanımlaman doğru değil. Onun yerine akım düzenleyici türler kullanılıyordu. Manipulator mı deniyordu? Bunlar kullanıldıktan sonra akımı tekrar eski haline sokuyordu. Ne kadar unutmuşum... :)

Ben nedense D yazıyorsun diye düşünüp 0b söz dizimini önermişim. C++ 14'e de "binary literal" diye geldi.

Ali

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]