কম্পিউটার টিউটোরিয়াল

Fiddle দিয়ে যেকোনো C লাইব্রেরি রুবি থেকে এক্সেস করুন: রুবির লুকানো ক্ষমতা আনলক করুন

Fiddle হলো একটি কম পরিচিত মডিউল যা রুবির স্ট্যান্ডার্ড লাইব্রেরিতে 1.9.x-এ যোগ করা হয়েছিল। এটি আপনাকে C লাইব্রেরির সাথে সরাসরি ইন্টারঅ্যাক্ট করতে দেয় রুবি থেকে। এটি এমনকি রুবি ইন্টারপ্রেটারকে রানটাইমে ইন্সপেক্ট এবং অ্যাল্টার করতে দেয়।

এটি libffi কে র‍্যাপ করে কাজ করে, একটি জনপ্রিয় C লাইব্রেরি যা এক ভাষায় লিখা কোডকে অন্য ভাষায় লিখা মেথড কল করতে দেয়। আপনি যদি না শুনে থাকেন, "ffi" মানে "foreign function interface"। এবং আপনি শুধু C-এ সীমাবদ্ধ নন। একবার Fiddle শিখলে, আপনি Rust এবং অন্যান্য ভাষায় লিখা লাইব্রেরি ব্যবহার করতে পারেন যেগুলো এটিকে সাপোর্ট করে।

চলুন Fiddle-র ऊपर একটি নজর ফেলি। আমরা একটি সিম্পল উদাহরণ দিয়ে শুরু করব এবং শেষ করব একটি Arduino-কে সিরিয়াল পোর্টের মাধ্যমে এক্সেস করে। আপনাকে বেশি C জানতে হবে না। আমি প্রতিজ্ঞা করছি। :)

একটি সিম্পল উদাহরণ

সাদা পুরনো রুবিতে, আপনাকে একটি মেথড ডিফাইন করতে হয় সেটি কল করার আগে। Fiddle-ও একই। আপনি সরাসরি একটি C ফাংশন কল করতে পারবেন না। বদলে, আপনাকে C ফাংশনের জন্য একটি ওয়ার্পার তৈরি করতে হবে, তারপর ওয়ার্পারটি কল করতে হবে।

নিচের উদাহরণে, আমরা C-এর লগারিদম ফাংশনকে র‍্যাপ করছি। আমরা বাসিক্যালি রুবির Math.log ডুপ্লিকেট করছি।

require 'fiddle' # আমরা একটি লাইব্রেরি "open" করব, তাই Fiddle-কে বলতে হবে # সেটি ডিস্কে কোথায় লোকেটেড। এই উদাহরণটি OSX Yosemite-এ কাজ করে। libm = Fiddle.dlopen('/usr/lib/libSystem.dylib') # C ফাংশন "log" এর জন্য একটি ওয়ার্পার তৈরি করুন। log = Fiddle::Function.new( libm['log'], # আমরা যে ম্যাথ লাইব্রেরি ওপেন করলাম সেটি থেকে ফাংশনটি পান [Fiddle::TYPE_DOUBLE], # এর একটি আর্গুমেন্ট রয়েছে, একটি double, যা রুবির Float-এর মত Fiddle::TYPE_DOUBLE # এটি একটি double রিটার্ন করে ) # আমাদের ওয়ার্পার দিয়ে C ফাংশন কল করুন puts log.call(3.14159) 

इसे সুন্দর করা

পূর্বের উদাহরণটি কাজ করে, কিন্তু এটি একটু ভার্বোজ। আপনি কল্পনা করতে পারেন কতটুকু ক্লাটার্ড হয়ে যাবে যদি আপনাকে ১০০টি ফাংশন র‍্যাপ করতে হয়। এইজন্য Fiddle একটি সুন্দর DSL প্রদান করে। এটি Fiddle::Importer মিক্সিনের মাধ্যমে এক্সপোজ করা হয়েছে।

এই মিক্সিন ব্যবহার করে এক্সটার্নাল ফাংশনসম্বলিত একটি মডিউল তৈরি করা খুব সহজ। নিচের উদাহরণে, আমরা কিছু লগারিদম মেথড সম্বলিত একটি মডিউল তৈরি করছি।

require 'fiddle' require 'fiddle/import' module Logs extend Fiddle::Importer dlload '/usr/lib/libSystem.dylib' extern 'double log(double)' extern 'double log10(double)' extern 'double log2(double)' end # আমরা এক্সটার্নাল ফাংশনগুলোকেই রুবি মেথডের মত কল করতে পারি! puts Logs.log(10) # 2.302585092994046 puts Logs.log10(10) # 1.0 puts Logs.log2(10) # 3.321928094887362 

সিরিয়াল পোর্ট কন্ট্রোল করা

ঠিক আছে, তো আপনি অবশেষে সেই Arduino কিনলেন যা আপনি বছর পর বছর কিনতে চাচ্ছিলেন। আপনি সিরিয়াল পোর্ট দিয়ে প্রতি সেকেন্ডে একবার "hello world" টেক্স্ট আপনার কম্পিউটারে পাঠাচ্ছেন।

এখন, খুব ভালো হত যদি আপনি রুবি ব্যবহার করে সেই ডেটা পড়তে পারতেন। এবং আপনি আসলে রুবির স্ট্যান্ডার্ড IO মেথড ব্যবহার করে সিরিয়াল পোর্ট থেকে পড়তে পারেন। কিন্তু এই IO মেথডগুলো আমাদের সিরিয়াল ইনপুট কনফিগার করার জন্য যে গ্রানুলারিটির লেভেল দরকার হয় যদি আমরা হার্ডকোর হার্ডওয়্যার হ্যাকার হতে চাই, সেটি দেয় না।

সৌভাগ্যবশত, C স্ট্যান্ডার্ড লাইব্রেরি সিরিয়াল পোর্টের সাথে কাজ করার জন্য আমাদের যা সকল ফাংশন দরকার সেগুলো প্রদান করে। এবং Fiddle ব্যবহার করে আমরা এই C ফাংশনগুলো রুবিতে এক্সেস করতে পারি।

অবশ্য, ইতিমধ্যে এমন জেম রয়েছে যা আপনার জন্য এটি করে। যখন আমি এই কোডে কাজ করছিলাম, আমি rubyserial জেম থেকে কিছু ইন্সপিরেশন নিলাম। কিন্তু আমাদের লক্ষ্য হলো কীভাবে নিজেরা এই জিনিসগুলো করব সেটি শিখা।

termios.h পরীক্ষা করা

C-এ, .h দিয়ে শেষ হওয়া যেকোনো ফাইলনেম হলো একটি হেডার ফাইল। এতে থেকো লাইব্রেরি থার্ড পার্টি কোড (আমাদের কোড) এর জন্য উপলব্ধ করে এমন সকল ফাংশন এবং কনস্ট্যান্টের লিস্ট থাকে। যেকোনো C লাইব্রেরি র‍্যাপ করার প্রথম ধাপ হলো এই ফাইলটি খুঁজে বের করা, ওপেন করা এবং ঘুরে বের করা।

আমরা যে লাইব্রেরি ব্যবহার করছি সেটি হলো termios। OSX Yosemite-এ, হেডার ফাইলটি লোকেটেড /usr/include/sys/termios.h। লিনাক্সে এটি অন্য কোথাও থাকবে।

termios.h কেমন দেখে সেটি নিচে। ক্লেরিটির জন্য আমি এটিকে কافی কনডেন্স করলাম।

typedef unsigned long tcflag_t; typedef unsigned char cc_t; typedef unsigned long speed_t; struct termios { tcflag_t c_iflag; /* input flags */ tcflag_t c_oflag; /* output flags */ tcflag_t c_cflag; /* control flags */ tcflag_t c_lflag; /* local flags */ cc_t c_cc[NCCS]; /* control chars */ speed_t c_ispeed; /* input speed */ speed_t c_ospeed; /* output speed */ }; int tcgetattr(int, struct termios *); int tcsetattr(int, int, const struct termios *); int tcflush(int, int); 

এই কোডে তিনটি গুরুত্বপূর্ণ জিনিস লক্ষ্য করুন। প্রথমে, কিছু typedef রয়েছে। তারপর একটি ডেটা স্ট্রাকচার রয়েছে যা কানেকশনের কনফিগারেশন ইনফো হোল্ড করতে ব্যবহৃত হয়। শেষে, মেথডগুলো রয়েছে जिन्हें আমরা ব্যবহার করব।

Fiddle-এর ইমপোর্টার ব্যবহার করে, আমরা এই সেকশনগুলো প্রায় ভেরবেটিম আমাদের রুবি কোডে কপি-পেস্ট করতে পারি। চলুন একটা একটা করে নেওয়া যাক।

টাইপ এলিয়াস এবং typedefs

C-এ ডেটা টাইপের জন্য এলিয়াস তৈরি করা খুব কমন। উদাহরণস্বরূপ, termios.h ফাইলটি speed_t নামে একটি নতুন টাইপ তৈরি করে যা শুধু একটি long integer। Fiddle ইমপোর্টার এইগুলোকে তার typealias ফিচার দিয়ে হ্যান্ডেল করতে পারে।

# equivalent to `typedef unsigned long tcflag_t;` typealias "tcflag_t", "unsigned long" 

Structs

C-এ ক্লাস বা মডিউল নেই। আপনি যদি কিছু ভেরিয়েবল গ্রুপ করতে চান, তবে আপনি একটি struct ব্যবহার করবেন। Fiddle রুবিতে structs নিয়ে কাজ করার জন্য একটি সুন্দর মেকানিজম প্রদান করে।

প্রথম ধাপ হলো Fiddle ইমপোর্টারে struct ডিফাইন করা। আপনি দেখতে পাচ্ছেন, আমরা প্রায় হেডার ফাইল থেকে কপি-পেস্ট করতে পারছি।

Termios = struct [ 'tcflag_t c_iflag', 'tcflag_t c_oflag', 'tcflag_t c_cflag', 'tcflag_t c_lflag', 'cc_t c_cc[20]', 'speed_t c_ispeed', 'speed_t c_ospeed', ] 

এখন আমরা `malloc` মেথড ব্যবহার করে struct-এর একটি "ইনস্ট্যান্স" তৈরি করতে পারি। আমরা ভ্যালু সেট এবং রিট্রিভ করতে পারি ঠিক যেকোনো নরমাল রুবি ক্লাস ইনস্ট্যান্সের মত।

s = Termios.malloc s.c_iflag = 12345 

সব কিছু একসাথে করা

আমরা typedefs এবং structs সম্পর্কে যা শিখলাম সেটি আগে যা দেখিয়েছিলাম ফাংশনসহ কাম্বাইন করলে, আমরা termios লাইব্রেরির একটি ওয়ার্কিং র‍্যাপার বানাতে পারি।

আমাদের র‍্যাপার শুধু সেগুলো মেথড ধারণ করে যা সিরিয়াল পোর্ট কনফিগার করার জন্য দরকার। বাকি কাজের জন্য আমরা সাদা পুরনো রুবি ব্যবহার করব।

require 'fiddle' require 'fiddle/import' # এই মডিউলের সব কিছু প্রায় termios.h থেকে সরাসরি কপি করা। Yosemite-এ এটি /usr/include/sys/termios.h-এ আছে module Serial extend Fiddle::Importer dlload '/usr/lib/libSystem.dylib' # টাইপ ডেফিনিশনস typealias "tcflag_t", "unsigned long" typealias "speed_t", "unsigned long" typealias "cc_t", "char" # একটি স্ট্রাকচার যা কনফিগারেশন ডেটা হোল্ড করবে। ইনস্ট্যান্সিয়েট করতে হবে: `Serial::Termios.malloc()` Termios = struct [ 'tcflag_t c_iflag', 'tcflag_t c_oflag', 'tcflag_t c_cflag', 'tcflag_t c_lflag', 'cc_t c_cc[20]', 'speed_t c_ispeed', 'speed_t c_ospeed', ] # সিরিয়াল ডিভাইসের সাথে কাজ করার ফাংশনস extern 'int tcgetattr(int, struct termios*)' # একটি সিরিয়াল ডিভাইসের কনফিগারেশন পান extern 'int tcsetattr(int, int, struct termios*)' # একটি সিরিয়াল ডিভাইসের কনফিগারেশন সেট করুন extern 'int tcflush(int, int)' # ডিভাইসের সকল বাফার ফ্লাশ করুন end 

লাইব্রেরি ব্যবহার করা

নিচের উদাহরণে আমরা আমাদের সিরিয়াল ডিভাইসটি রুবিতে ওপেন করি, তারপর এর ফাইল ডেসক্রিপ্টর পাই। আমরা আমাদের termios ফাংশনগুলো ব্যবহার করে ডিভাইসটি পড়ার জন্য কনফিগার করি। তারপর পড়ি।

এখানে আমি কিছু ম্যাজিক নাম্বার ব্যবহার করছি। এগুলো একাধিক বিটওয়াইজ কনফিগারেশন অপশন কাম্বাইন করার ফলাফল যা আর্ডুইনোর সাথে কমিউনিকেশনের জন্য জরুরি। আপনি যদি জানতে চান ম্যাজিক নাম্বারগুলো কোথা থেকে আসছে, এই ব্লগ পোস্ট চেক করুন।

file = open("/dev/cu.wchusbserial1450", 'r') fd = file.to_i # আমাদের কনফিগারেশন স্ট্রাকচারের একটি নতুন ইনস্ট্যান্স তৈরি করুন config = Serial::Termios.malloc # ডিফল্ট কনফিগারেশন অপশনগুলো আমাদের স্ট্রাকচারে লোড করুন Serial.tcgetattr(fd, config); # আর্ডুইনোর জন্য গুরুত্বপূর্ণ কনফিগ অপশন সেট করুন। # ম্যাজিক নাম্বারগুলোর জন্য দুঃখিত। config.c_ispeed = 9600; config.c_ospeed = 9600; config.c_cflag = 51968; config.c_iflag = 0; config.c_oflag = 0; # রিড রিটার্ন করার আগে ১২ ক্যারেক্টার আসার জন্য অপেক্ষা করুন। config.c_cc[17] = 12; # রিড রিটার্ন করার আগে মিনিমাম টাইম অপেক্ষা করুন না config.c_cc[16] = 0; # আমাদের কনফিগারেশন সেভ করুন Serial.tcsetattr(fd, 0, config); # আর্ডুইনো রিবুটের জন্য ১ সেকেন্ড অপেক্ষা করুন sleep(1) # পড়ার জন্য অপেক্ষামান যেকোনো এক্সিস্টিং সিরিয়াল ইনপুট রিমুভ করুন Serial.tcflush(fd, 1) buffer = file.read(12) puts "#{ buffer.size } bytes: #{ buffer }" file.close 

সিরিয়াল রিডার একশনে

যদি আমি এখন আমার আর্ডুইনোকে একটি প্রোগ্রাম দিয়ে লোড করি যা liên tục hello world প্রিন্ট করে সিরিয়ালে, তবে আমি আমার রুবি স্ক্রিপ্ট দিয়ে সেটি পড়তে পারি।

Fiddle দিয়ে যেকোনো C লাইব্রেরি রুবি থেকে এক্সেস করুন: রুবির লুকানো ক্ষমতা আনলক করুন এই আর্ডুইনো প্রোগ্রাম শুধু "hello world" সিরিয়ালে লিখে, বারবার

এবং এখানে দেখুন আমার সিরিয়াল মনিটর রান করলে কেমন দেখায়।

Fiddle দিয়ে যেকোনো C লাইব্রেরি রুবি থেকে এক্সেস করুন: রুবির লুকানো ক্ষমতা আনলক করুন


  1. রুবি মাস্টারিং: মেথড এলিয়াস তৈরি করার জন্য Alias কিওয়ার্ড ব্যবহার

  2. রুবি Enumerable মেথড মাস্টারিং: Any, All, None এবং One

  3. রুবির grep মেথড মাস্টারিং: কোড উদাহরণসহ একটি ব্যবহারিক গাইড

  4. রুবির Map মেথড মাস্টারিং: উদাহরণসহ একটি ব্যবহারিক গাইড