"ما المراسي؟" أو نتحكم في وحدة التحكم عبر البلوتوث باستخدام تطبيق محمول على Xamarin (Android)

في مقال سابق ، وعدت بالتحدث عن كيفية توصيل CANNY 3 صغير باستخدام UART بالبلوتوث. وبما أنك لا تمشي حقًا في عطلات شهر أيار (مايو) هذه ، فقد تقرر قضاء الوقت مع فائدة والاستمرار في الوفاء بالوعد. ولكن فقط لتوصيل وحدة التحكم بمحول Bluetooth HC-06 ، سيكون من السهل جدًا على Habr.

لذلك ، لن نقوم فقط بربط كل شيء ، ولكننا سنكتب أيضًا تطبيق Android البدائي لدائرتنا باستخدام C # و Xamarin.

إذا كنت ترغب في مراقبة "مفاتيح الحد" ومفاتيح القصب ، كما أحبها ، فأنت مرحب بك تحت القط.



إليك ما سنتحدث عنه اليوم:

الجزء الأول: مقدمة
الجزء الثاني: ربط الدائرة والبرنامج لـ CANNY 3
الجزء الثالث الصغير : نكتب طلبًا على Xamarin لنظام Android
الجزء الرابع: الخلاصة

الجزء الأول: مقدمة


سأبدأ بالأمر الجيد ، باستثناء إدراج رمز البرنامج في C # ، فعندئذ ستكون المقالة صغيرة نسبيًا ، لأننا فحصنا التقنيات الأساسية للعمل مع وحدة التحكم في وقت سابق. لكي لا تتكرر مرة أخرى ، إليك قائمة بالمقالات التي قمنا بالفعل بفحص الطرق الأساسية للعمل مع وحدة تحكم CANNY:

  1. "واحد ، اثنان ، ثلاثة - احرق شجرة عيد الميلاد!" أو أول نظرة على وحدة التحكم الصغيرة CANNY 3 - في هذه المقالة قمنا بتحليل ماهية وحدة التحكم ، بالإضافة إلى أساسيات العمل في بيئة تطوير CannyLab.
  2. "تحتوي الوجهة على الكثير من المظاهر ..." أو نقوم تلقائيًا بالتحكم في المصباح باستخدام CANNY 3 الصغير والمقاوم الضوئي - في هذه المقالة نظرنا في العمل مع منفذ USB الظاهري COM ، وربط أجهزة الاستشعار بـ ADC ، بالإضافة إلى PWM عالي التردد في مخرجات وحدة التحكم.
  3. « ...» (CANNY Arduino) Raspberry PI — UART, .

في إعداد هذه المقالة ، استخدمت الأجهزة التالية: وحدة تحكم صغيرة CANNY 3 ، ومحول بلوتوث HC-06 ، ومفتاح حد (مقطورة Trema module) ، ومبدل قصبة ، وسماعات رأس سلكية قديمة ، ولوح توصيل ، وأسلاك ، وتماسيح.

سننشئ نظامًا ، باستخدام تطبيق جوال ، يراقب حالة مستشعرين ، وإذا لزم الأمر ، يمكنه إصدار إنذار يدويًا.

يتم اختراع كل ما سيتم تقديمه في هذه المقالة للأغراض التعليمية والتوضيحية فقط. أردت فقط إظهار بعض الحيل للعمل مع وحدة التحكم ، وكذلك لقطع الحديد التي تم شراؤها في وقت واحد لتحديد قيمتها بطريقة أو بأخرى.

على الرغم من طبيعة المشكلة التي يتم حلها ، والتي هي أبعد ما تكون عن الواقع ، فإننا نتخيل أننا نصنع نظام مراقبة خلف الباب المنزلق للمقصورة. عندما يبدأ في التحرك ، سيعمل مفتاح القصب ، وفي نهاية المسار سيعطي إشارة للمقطورة. إذا احتجنا للفت الانتباه ، على سبيل المثال ، حتى يتم إغلاق الباب للخلف ، سنعطي إشارة "صرير" من خلال السماعة. صحيح ، ليس لدي مكبر صوت ، ولكن هناك سماعات قديمة.



حسنا ، وكالعادة ، ملاحظة. لا أنصح بشدة باستخدام المواد الواردة في هذه المقالة باعتبارها الحقيقة المطلقة. فعلت أشياء كثيرة لأول مرة بنفسي ، بالتأكيد يمكن القيام بها بشكل أفضل.


الجزء الثاني: ربط الدائرة وبرنامج CANNY 3 الصغير


للبدء ، حتى لا تسيء إلى أي شخص في حقوق الطبع والنشر ، اقترضت من المنتدى ، ولكني قمت بتكييفهم لفكرة توصيل وحدة التحكم بـ HC-06 ، من خلال التحكم في ذلك من خلال تطبيق "Bluetooth الطرفية التسلسلي" وبعض الحيل عند تطوير الرسم التخطيطي مهمتك.

مخطط الاتصال هو كما يلي:



مفتاح الحد ومفتاح القصب متصلان بأطراف وحدة التحكم رقم 6 ورقم 5 ، سماعات الرأس إلى المحطة رقم 4 (لديها RF PWM) ، UART RX هو محطة رقم 1 ، UART TX هو محطة رقم 2 ، محطة رقم 3 يتم استخدامه لتوريد "+ 5V" ، الإخراج "-" - للتواصل مع "الأرض".

إليك ما يبدو في التجميع:



لقد طورت الرسم التخطيطي (البرنامج) لـ CANNY 3 الصغير في CannyLab الإصدار 1.42 ، ربما في إصدارات أخرى من بيئة التطوير ومع وحدات التحكم الأخرى ، سيكون من الضروري إجراء تغييرات على الرسم التخطيطي.

إليك ما حدث:



تم تفكيك الكتل المرتبطة بإعداد وحدة التحكم وإرسال الرسائل عبر UART في مقالة سابقة .

دعونا نفحص بمزيد من التفصيل الاثنين المتبقيين.

كتلة " تلقي رسالة UART " مسؤولة عن تشغيل صفارة الإنذار (سماعات الرأس). من حيث المبدأ ، هناك حاجة إلى تحليل مثال لتلقي رسالة عبر UART.

أولاً ، نتحقق مما إذا كانت البيانات المستلمة في UART ، إذا كانت موجودة ، ثم نرسل واحدة إلى إدخال D-launcher "E" ، وفي هذه الحالة يقوم المشغل بنسخ القيمة من الإدخال "D" الذي سنكتب فيه أول حرفين من الرسالة المستلمة عبر UART. لم أكن أرغب في تعقيد كل شيء ، لذلك سنستخدم مخططًا بسيطًا أكثر. نفترض أن أي رقم من 00 إلى 99 سيأتي إلينا بواسطة UART ، وسوف نترجم هذا الرقم من نموذج رمزي إلى رقمي (أوصي بقراءة كيفية عمل كتلة المحول ؛ كان لدي "قابس" صغير به). علاوة على ذلك ، فإن أي قيمة "> 0" عند إدخال كاشف الحافة الرائدة تتسبب في إشارة واحدة ، والتي تعمل على إخراج 5 لمدة 5 ثوان ، تعمل في وضع RF PWM.

يمكنك اللعب في الإعدادات مع فترة تعبئة RF PWM ، سيعتمد الصوت في سماعات الرأس على هذا.

دعنا ننتقل إلى الكتلة"تشكيل الرسالة" . قد يبدو تنفيذه للوهلة الأولى غير عادي. ويفسر ذلك حقيقة أنني لم أقم حقًا بكيفية العمل مع برنامج Bluetooth الطرفية التسلسلي وبنفس بروتوكول البلوتوث في Xamarin.

سأركض قليلاً إلى الأمام وأقول أنني لم أتعلم كيفية تلقي الرسائل المرسلة من وحدة التحكم على هاتفي الذكي. إذا كان كل شيء واضحًا مع UART السلكي في المقالة الأخيرة ، فعندئذٍ مع Bluetooth ، في الواقع ، بدلاً من الرسالة المرسلة ، يمكن قراءة الجزء الخاص بها فقط وانتهاك معنى الأمر الذي تم إرساله.

قررت أن أبسط حل هو إرسال رقم واحد ، يضمن الوصول إلى المتلقي دون خسارة.

في حالتنا ، نحن نراقب الحالة المنفصلة لمفتاح القصب ومفتاح الحد. بمعنى ، لدينا 4 مجموعات ممكنة فقط: مفتاح القصب ومفتاح الحد مغلقان ، واحد فقط قيد التشغيل ، كلاهما قيد التشغيل.

نظرًا لأن مفتاح القصب ومفتاح الحد يعطيان إشارة منفصلة (0/1) ، فأنت بحاجة إلى تمييزهما بطريقة أو بأخرى. للقيام بذلك ، نضرب قيمة إشارة القصب في 2. الآن يتبين أن مجموع الإشارات سيعطينا قيمًا من 0 إلى 3.

الآن سنقوم بتحليل خيار غير واضح مع إضافة خمسين إلى هذه القيمة. الحقيقة هي أن CannyLab يرسل زوجين من الشخصيات إلى UART ، أي بدلاً من 3 ، دعنا نقول 03 ، ولكن كما قلت هناك خطر فقدان بعض المعلومات. على سبيل المثال ، من القيمة 01 ، يمكن للبرنامج على الهاتف الذكي قراءة "0" الأولى فقط ، وسيكون هذا بالفعل خطأ.

قد يكون من الممكن الخلط بين البيانات وتحويلها ، على سبيل المثال استبدال الحرف "D1" في السجل بحرف أو مسافة ، لكنني قررت تسهيل الأمر. قمت بتحويل القيمة 01 إلى 51 (02 إلى 52 ، وما إلى ذلك). الخمسة لا يحملون إشارة وقمت بقطعها على مستوى البرنامج لهاتف ذكي. وبالتالي ، فإننا نضمن دائمًا بقاء الجزء المفيد من الرسالة.

نقوم بتحميل البرنامج في وحدة التحكم ، انقر فوق "تشغيل" ، إذا كان كل شيء يعمل كما هو مخطط له ، فإن HC-06 سيومض بشكل دوري بضوء LED أحمر.

بعد ذلك ، نقوم بإقران الهاتف الذكي بالمحول. الآن يمكنك التحقق من الأداء في تطبيق "Serial Bluetooth terminal" أو أي تطبيق آخر بوظائف مماثلة.

اكتب عنوان محول Bluetooth ، وسيكون مفيدًا لنا في الفصل التالي.



كما ترى ، تأتي البيانات ، اعتمادًا على حالة المستشعرات ، وإذا قمت بإرسال "11" ، فسيتم سماع صوت صرير سيء في سماعات الرأس. يمكن أن نتوقف هنا ، لكن دعونا نرسم تطبيقًا بدائيًا.

يمكن تنزيل برنامج وحدة التحكم والشفرة المصدر للبرنامج للهاتف الذكي من GitHub

أود أن أشير إلى أنه ليس عليك تنفيذ كل شيء في الأجهزة على وجه التحديد على وحدات تحكم CANNY ، يمكنك كتابة برنامج لـ Arduino أو وحدة تحكم أخرى تريدها. في البداية ، خططت بنفسي أيضًا لكتابة نسخة إضافية من الرسم التخطيطي لـ Arduino ، ولكن منذ أن قتلت جميع عطلات شهر مايو تقريبًا ، لم أعد أملك القوة لتوصيل CANNY وتطبيق الهاتف الذكي.

الجزء الثالث: كتابة تطبيق Xamarin Android


أعلم أن Xamarin ، بعبارة ملطفة ، ليس الحل الأكثر شيوعًا لتطوير الأجهزة المحمولة. وربما لديك سؤال بالفعل: "لماذا اخترت ذلك؟" . أود أن أجيبه بكلمات من أغنية تحمل نفس الاسم لبسويا كورولينكو:



بصراحة ، لا توجد أسباب موضوعية. منذ بضع سنوات فقط تعلمت أساسيات C # وأراد الجميع معرفة ما هو Xamarin. والآن ، وبسبب "العزلة الذاتية" ، وصلت الأيدي أخيرًا.

حسنًا ، دعني أذكرك مرة أخرى. هذه هي المرة الأولى التي أقابل فيها Xamarin وهذا هو أول تطبيق Android. لا تنسخ رمز المنحنى بشكل أعمى ، إذا تمكنت فجأة من العثور على حل أكثر جمالا ، استخدمه.

عند تطوير برنامجي ، اعتمدت على هذه المواد. لا يتم مضغ المقالة بشكل خاص ، وحتى باللغة الإسبانية ، لذلك ما زلت أجد أنه من المناسب أن أشارك معك الاختلاف حول هذا الموضوع.

لقد بنيت البرنامج في إصدار مجتمع Visual studio 2019.

بادئ ذي بدء ، قم بإنشاء مشروع أندرويد فارغ جديد (Xamarin) ، كما في الصورة.



لقد أجريت تغييرات في ثلاثة ملفات فقط ، ويمكن عرضها بالكامل على GitHub ، وهنا

سنحلل الأجزاء المهمة فقط:

تتم إضافة أذونات AndroidManifest.xml 2 إلى النموذج القياسي:

  <uses-permission android:name="android.permission.BLUETOOTH"/>
  <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>

Activity_main.xml
تمت إزالة الحاوية الافتراضية (RelativeLayout). بدلاً من ذلك ، تمت إضافة حاوية LinearLayout ببساطة لأنها أبسط. في هذه الحاوية ، تتم محاذاة جميع العناصر رأسيًا ، وتمتد عبر عرض الشاشة بالكامل.

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:minWidth="25px"
    android:minHeight="25px"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/linearLayout1">
    <TextView
        android:text="Reed switch status - undefined"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/rSwitch"
        android:textSize="12pt" />
    <TextView
        android:text="End sensor status - undefined"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/EndSensor"
        android:textSize="12pt" />
    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/startSiren"
        android:text="Send signal to siren" />
    <Switch
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/bltSwitch"
        android:checked="false"
        android:showText="true"
        android:text="Connect bluetooth" />
    <TextView
        android:text="status"
        android:textAppearance="?android:attr/textAppearanceSmall"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/status" />
</LinearLayout>

يمكن لأي شخص على دراية بسيطة بتخطيط HTML أو XML فهم بنية واجهة المستخدم بسهولة. لدينا ثلاثة حقول نصية للقراءة فقط (TextView) ، ومفتاح واحد (Switch) ، والذي يعمل بشكل أساسي مثل مربع الاختيار وزر عادي واحد (زر). يمكن وضع العناصر في النموذج عن طريق السحب والإسقاط من المُنشئ ، وفي نافذة الخصائص أو في التعليمات البرمجية لتعيين معرف أكثر ملاءمة ، وأجزاء نصية ومعلمات أخرى.

يبقى لوصف منطق البرنامج.

MainActivity.cs

أدناه ، تحت المفسد ، الرمز بأكمله للراحة

كود MainActivity.cs الكامل
// based on http://alejandroruizvarela.blogspot.com/2014/01/bluetooth-arduino-xamarinandroid.html
// for this article https://habr.com/ru/post/500454/


// based on http://alejandroruizvarela.blogspot.com/2014/01/bluetooth-arduino-xamarinandroid.html
// for this article https://habr.com/ru/post/500454/


using Android.App;
using Android.OS;
using Android.Support.V7.App;
using Android.Runtime;
using Android.Widget;
using System.Linq;
using System;
using System.IO;
using Java.Util;
using Android.Bluetooth;
using System.Threading.Tasks;

namespace _6.Canny_Xanarin_Bluetooth_Android
{
    [Activity(Label = "Control Canny 3 tiny via bluetooth", Theme = "@style/AppTheme", MainLauncher = true)]
    public class MainActivity : AppCompatActivity
    {

        Button startSiren;
        TextView rSwitch;
        TextView EndSensor;
        Switch bltSwitch;
        TextView status;
        private Java.Lang.String dataToSend;
        private BluetoothAdapter mBluetoothAdapter = null;
        private BluetoothSocket btSocket = null;
        private Stream outStream = null;
        // don't forget change addres to your device:
        private static string address = "98:D3:91:F9:6C:F6";
        // MY_UUID can be saved as is
        private static UUID MY_UUID = UUID.FromString("00001101-0000-1000-8000-00805F9B34FB");
        private Stream inStream = null;


        protected override void OnCreate(Bundle savedInstanceState)
        {

            base.OnCreate(savedInstanceState);
            Xamarin.Essentials.Platform.Init(this, savedInstanceState);
            // Set our view from the "main" layout resource
            SetContentView(Resource.Layout.activity_main);

            startSiren = FindViewById<Button>(Resource.Id.startSiren);
            rSwitch = FindViewById<TextView>(Resource.Id.rSwitch);
            EndSensor = FindViewById<TextView>(Resource.Id.EndSensor);
            status = FindViewById<TextView>(Resource.Id.status);
            bltSwitch = FindViewById<Switch>(Resource.Id.bltSwitch);


            startSiren.Click += startSiren_ClickOnButtonClicked;
            bltSwitch.CheckedChange += bltSwitch_HandleCheckedChange;
            CheckBt();
        }

        private void CheckBt()
        {
            mBluetoothAdapter = BluetoothAdapter.DefaultAdapter;

            if (!mBluetoothAdapter.Enable())
            {
                Toast.MakeText(this, "Bluetooth Off",
                    ToastLength.Short).Show();
            }

            if (mBluetoothAdapter == null)
            {
                Toast.MakeText(this,
                    "Bluetooth does not exist or is busy", ToastLength.Short)
                    .Show();
            }
        }

        void startSiren_ClickOnButtonClicked(object sender, EventArgs e)
        {
            if (bltSwitch.Checked)
            {
                try
                {
                    dataToSend = new Java.Lang.String("11");
                    writeData(dataToSend);
                    System.Console.WriteLine("Send signal to siren");
                }
                catch (System.Exception execept)
                {
                    System.Console.WriteLine("Error when send data" + execept.Message);
                }

            }
            else status.Text = "bluetooth not connected";
        }
        void bltSwitch_HandleCheckedChange(object sender, CompoundButton.CheckedChangeEventArgs e)
        {
            if (e.IsChecked)
            {
                Connect();
            }
            else
            {
                status.Text = "bluetooth not connected";
                if (btSocket.IsConnected)
                {
                    try
                    {
                        btSocket.Close();
                        System.Console.WriteLine("Connection closed");
                    }
                    catch (System.Exception ex)
                    {
                        Console.WriteLine(ex.Message);
                    }
                }
            }
        }

        public void Connect()
        {
            BluetoothDevice device = mBluetoothAdapter.GetRemoteDevice(address);
            System.Console.WriteLine("Connection in progress" + device);
            mBluetoothAdapter.CancelDiscovery();
            try
            {
                btSocket = device.CreateRfcommSocketToServiceRecord(MY_UUID);
                btSocket.Connect();
                System.Console.WriteLine("Correct Connection");
                status.Text = "Correct Connection to bluetooth";
            }
            catch (System.Exception e)
            {
                Console.WriteLine(e.Message);
                try
                {
                    btSocket.Close();
                    System.Console.WriteLine("Connection closed");
                }
                catch (System.Exception)
                {
                    System.Console.WriteLine("Impossible to connect");
                    status.Text = "Impossible to connect";
                }
                System.Console.WriteLine("Socket Created");
  
            }
            beginListenForData();

        }

        public void beginListenForData()
        {
            try
            {
                inStream = btSocket.InputStream;
            }
            catch (System.IO.IOException ex)
            {
                Console.WriteLine(ex.Message);
            }
            Task.Factory.StartNew(() => {
                byte[] buffer = new byte[1024];
                int bytes;
                
                while (true)
                {

                    try
                    {
                        bytes = inStream.Read(buffer, 0, 1024);
                        System.Console.WriteLine("bytes " + bytes.ToString());
                        if (bytes > 0)
                        {
                            
                            RunOnUiThread(() => {
                                string valor = System.Text.Encoding.ASCII.GetString(buffer).Replace("5",String.Empty);
                                // transform string for deleate all symbols except 1-4(command from canny).
                                string command = new string(valor.Where(char.IsDigit).ToArray());

                                if (command.Length > 0)
                                {
                                     status.Text="data successfully readed";
                                    System.Console.WriteLine("command  " + command);
                                    switch (Int32.Parse(command))
                                    {
                                        case 0:
                                            rSwitch.Text = "reed switch - disconnected ";
                                            EndSensor.Text = "end sensor - not pressed ";
                                            break;
                                        case 1:
                                            rSwitch.Text = "reed switch - disconnected ";
                                            EndSensor.Text = "end sensor - pressed ";
                                            break;
                                        case 2:
                                            rSwitch.Text = "reed switch - connected ";
                                            EndSensor.Text = "end sensor - not pressed ";
                                            break;
                                        case 3:
                                            rSwitch.Text = "reed switch - connected ";
                                            EndSensor.Text = "end sensor - pressed ";
                                        break;
                                    }
                                }
                            });
                        }
                    }
                    catch (Java.IO.IOException)
                    {
                        RunOnUiThread(() => {
                            EndSensor.Text = "End sensor status - undefined";
                            rSwitch.Text = "Reed switch status - undefined ";
                        });
                        break;
                    }
                }
            });
        }

        private void writeData(Java.Lang.String data)
        {
            try
            {
                outStream = btSocket.OutputStream;
            }
            catch (System.Exception e)
            {
                System.Console.WriteLine("Error with OutputStream when write to Serial port" + e.Message);
            }

            Java.Lang.String message = data;

            byte[] msgBuffer = message.GetBytes();

            try
            {
                outStream.Write(msgBuffer, 0, msgBuffer.Length);
                System.Console.WriteLine("Message sent");
            }
            catch (System.Exception e)
            {
                System.Console.WriteLine("Error with  when write message to Serial port" + e.Message);
                status.Text = "Error with  when write message to Serial port";
            }
        }


    public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Android.Content.PM.Permission[] grantResults)
        {
            Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);

            base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
        }
    }
 }


الآن في أجزاء.

كتل مع اتصال مساحات الأسماء ، إعلان الفئة ، إلخ. سوف افتقد.


ننشئ متغيرات سنربط بها فيما بعد عناصر واجهة المستخدم:

   Button startSiren;
   TextView rSwitch;
   TextView EndSensor;
   Switch bltSwitch;
   TextView status;

بعد ذلك يأتي الرمز من المثال الذي اعتمدت عليه. المتغيرات (الحقول) اللازمة لتشغيل طرق معينة.

  private Java.Lang.String dataToSend;
        private BluetoothAdapter mBluetoothAdapter = null;
        private BluetoothSocket btSocket = null;
        private Stream outStream = null;
        // don't forget change addres to your device:
        private static string address = "98:D3:91:F9:6C:F6";
        // MY_UUID can be saved as is
        private static UUID MY_UUID = UUID.FromString("00001101-0000-1000-8000-00805F9B34FB");
        private Stream inStream = null;

من المهم بالنسبة لنا هنا دفع عنوان وحدة HC-06 الخاصة بك إلى حقل العنوان.

نظرًا لأن هذه هي أول تجربة تطوير لي للهواتف الذكية ، بما في ذلك العمل مع Xamarin ، فقد قررت عدم تعقيد أي شيء ، لذلك تم إصلاح عنوان الجهاز ، كما هو الحال في المثال الأصلي. إذا أردت ، يمكنك مشاهدة هذه المقالة ، يبدو أنه تم تنفيذ تعداد لأجهزة Bluetooth المتوفرة.

استمر.


        protected override void OnCreate(Bundle savedInstanceState)
        {

            base.OnCreate(savedInstanceState);
            Xamarin.Essentials.Platform.Init(this, savedInstanceState);
            // Set our view from the "main" layout resource
            SetContentView(Resource.Layout.activity_main);

            startSiren = FindViewById<Button>(Resource.Id.startSiren);
            rSwitch = FindViewById<TextView>(Resource.Id.rSwitch);
            EndSensor = FindViewById<TextView>(Resource.Id.EndSensor);
            status = FindViewById<TextView>(Resource.Id.status);
            bltSwitch = FindViewById<Switch>(Resource.Id.bltSwitch);


            startSiren.Click += startSiren_ClickOnButtonClicked;
            bltSwitch.CheckedChange += bltSwitch_HandleCheckedChange;
            CheckBt();
        }

يتم إنشاء هذه الطريقة تلقائيًا ، ومهمتنا هي ربط كائنات واجهة المستخدم بداخل حقول الفصل ، وكذلك إرفاق معالجات لردود الفعل على الأحداث ( startSiren.Click bltSwitch.CheckedChange).

التحقق من الاتصال عبر البلوتوث:


        private void CheckBt()
        {
            mBluetoothAdapter = BluetoothAdapter.DefaultAdapter;

            if (!mBluetoothAdapter.Enable())
            {
                Toast.MakeText(this, "Bluetooth Off",
                    ToastLength.Short).Show();
            }

            if (mBluetoothAdapter == null)
            {
                Toast.MakeText(this,
                    "Bluetooth does not exist or is busy", ToastLength.Short)
                    .Show();
            }
        }

قم بتشغيل صفارة الإنذار. بشكل أساسي فقط إرسال الأحرف "11" إلى وحدة التحكم:


   void startSiren_ClickOnButtonClicked(object sender, EventArgs e)
        {
            if (bltSwitch.Checked)
            {
                try
                {
                    dataToSend = new Java.Lang.String("11");
                    writeData(dataToSend);
                    System.Console.WriteLine("Send signal to siren");
                }
                catch (System.Exception execept)
                {
                    System.Console.WriteLine("Error when send data" + execept.Message);
                }

            }
            else status.Text = "bluetooth not connected";
        }

التحقق من حالة المفتاح (إذا تم تحويله إلى اليمين ، فهذا يعني أنه قيد التشغيل):

   void bltSwitch_HandleCheckedChange(object sender, CompoundButton.CheckedChangeEventArgs e)
        {
            if (e.IsChecked)
            {
                Connect();
            }
            else
            {
                if (btSocket.IsConnected)
                {
                    try
                    {
                        btSocket.Close();
                        System.Console.WriteLine("Connection closed");
                    }
                    catch (System.Exception ex)
                    {
                        Console.WriteLine(ex.Message);
                    }
                }
            }
        }

عند التشغيل ، نبدأ الاتصال بـ Bluetooth.

تنفيذ الاتصال نفسه:

   public void Connect()
        {
            BluetoothDevice device = mBluetoothAdapter.GetRemoteDevice(address);
            System.Console.WriteLine("Connection in progress" + device);
            mBluetoothAdapter.CancelDiscovery();
            try
            {
                btSocket = device.CreateRfcommSocketToServiceRecord(MY_UUID);
                btSocket.Connect();
                System.Console.WriteLine("Correct Connection");
                status.Text = "Correct Connection to bluetooth";
            }
            catch (System.Exception e)
            {
                Console.WriteLine(e.Message);
                try
                {
                    btSocket.Close();
                    System.Console.WriteLine("Connection closed");
                }
                catch (System.Exception)
                {
                    System.Console.WriteLine("Impossible to connect");
                    status.Text = "Impossible to connect";
                }
                System.Console.WriteLine("Socket Created");
  
            }
            beginListenForData();

        }

وإليك واحدة من أهم الطرق - قراءة البيانات مباشرة:


    public void beginListenForData()
        {
            try
            {
                inStream = btSocket.InputStream;
            }
            catch (System.IO.IOException ex)
            {
                Console.WriteLine(ex.Message);
            }
            Task.Factory.StartNew(() => {
                byte[] buffer = new byte[1024];
                int bytes;
                
                while (true)
                {

                    try
                    {
                        bytes = inStream.Read(buffer, 0, 1024);
                        System.Console.WriteLine("bytes " + bytes.ToString());
                        if (bytes > 0)
                        {
                            
                            RunOnUiThread(() => {
                                string valor = System.Text.Encoding.ASCII.GetString(buffer).Replace("5",String.Empty);
                                // transform string for deleate all symbols except 1-4(command from canny).
                                string command = new string(valor.Where(char.IsDigit).ToArray());

                                if (command.Length > 0)
                                {
                                     status.Text="data successfully readed";
                                    System.Console.WriteLine("command  " + command);
                                    switch (Int32.Parse(command))
                                    {
                                        case 0:
                                            rSwitch.Text = "reed switch - disconnected ";
                                            EndSensor.Text = "end sensor - not pressed ";
                                            break;
                                        case 1:
                                            rSwitch.Text = "reed switch - disconnected ";
                                            EndSensor.Text = "end sensor - pressed ";
                                            break;
                                        case 2:
                                            rSwitch.Text = "reed switch - connected ";
                                            EndSensor.Text = "end sensor - not pressed ";
                                            break;
                                        case 3:
                                            rSwitch.Text = "reed switch - connected ";
                                            EndSensor.Text = "end sensor - pressed ";
                                        break;
                                    }
                                }
                            });
                        }
                    }
                    catch (Java.IO.IOException)
                    {
                        RunOnUiThread(() => {
                            EndSensor.Text = "End sensor status - undefined";
                            rSwitch.Text = "Reed switch status - undefined ";
                        });
                        break;
                    }
                }
            });
        }

تركت العديد من عناصر الطريقة كما في المثال ، كما أفهمها ، في البداية يتم إنشاء اتصال بتدفق البيانات ، إذا كان هناك شيء في المخزن المؤقت مع البيانات المقروءة ، ثم يتم قراءته في متغير valor. علاوة على ذلك ، كما وعدت ، نحذف ببساطة الرقم "5".

بعد ذلك ، نقوم بإزالة جميع الأحرف باستثناء الأرقام من رسالة القراءة. string command = new string(valor.Where(char.IsDigit).ToArray());

حسنًا ، بعد ذلك كل شيء بسيط ، اعتمادًا على الرقم الذي وصلنا ، نعرض هذه الحالة أو تلك في واجهة المستخدم.

لم أغير هاتين الطريقتين بشكل جذري:

  private void writeData(Java.Lang.String data)
        {
            try
            {
                outStream = btSocket.OutputStream;
            }
            catch (System.Exception e)
            {
                System.Console.WriteLine("Error with OutputStream when write to Serial port" + e.Message);
            }

            Java.Lang.String message = data;

            byte[] msgBuffer = message.GetBytes();

            try
            {
                outStream.Write(msgBuffer, 0, msgBuffer.Length);
                System.Console.WriteLine("Message sent");
            }
            catch (System.Exception e)
            {
                System.Console.WriteLine("Error with  when write message to Serial port" + e.Message);
                status.Text = "Error with  when write message to Serial port";
            }
        }


    public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Android.Content.PM.Permission[] grantResults)
        {
            Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);

            base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
        }
    }
 }

كما أفهمها ، فإن كتلة التعليمات البرمجية هذه تنفذ إرسال رسالة ومعالج حدث لتجاوز الإذن للوصول إلى Bluetooth.

حسنا، هذا كل ما تبقى لاقامة اتصال الهاتف الذكي ل تصحيح التطبيق .

من الغريب ، لكنه يعمل:



الجزء الرابع: الخاتمة


إليك كيفية عمل البرنامج بالمثل:



كانت هذه تجربتي الأولى في تطوير التطبيقات لهاتف ذكي على Android.

أود أن أشير إلى أن VS 2019 و Xamarin على جهاز الكمبيوتر القديم يعملان ببطء شديد.

في التجمع الأول للمشروع ، تمكنت حقًا من تناول هذه اللفائف الفرنسية الناعمة وشرب الشاي. أيضًا ، تبين أن التطبيق نفسه بائسًا بصراحة ، لا يعمل مفتاح التشغيل / الإيقاف بشكل ملائم للغاية ، ولكن من ناحية أخرى ، نظرًا لأنني مألوف قليلًا لتقنيات التطوير الأساسية لـ .NET ، وأنني لست مبرمجًا على الإطلاق ، حتى أنني أستطيع دون المرور ببرنامج تعليمي واحد أو درس واحد ، حدد أول تطبيق لك في يوم واحد. لذلك ، فإن حد الدخول لإنشاء تطبيق أولي منخفض جدًا.

كما أفهمها ، يمكن استخدام وحدات التحكم في CANNY عند ضبط السيارات ، وخاصةً السيارات المحلية ، بحيث يكون من الممكن تمامًا إنشاء نوع من "الميزة" وكتابة تطبيق لهاتف ذكي. الشيء الرئيسي الذي يجب تذكره هو أنه عند تشغيله من شبكة السيارة الموجودة على متن السيارة ، سيكون لمخرجات وحدة التحكم نفس الجهد مثل الإدخال (على سبيل المثال ، 12 فولت بدلاً من 5 فولت). لا تنس حماية محول البلوتوث حتى لا يفشل عن غير قصد.

تبين أن المقالة شاقة للغاية بالنسبة لي ، وآمل أن كل شيء لم يذهب سدى وستحبه.

All Articles