2022年4月20日 星期三

c# socket server, client, delegate, thread






using System;

using System.Collections.Generic;

using System.Net;

using System.Net.Sockets;

using System.Text;

using System.Threading;

using System.Windows.Forms;


namespace SocketTestApp

{

    public partial class SocketTest : Form

    {

        //建立一個和客戶端通訊的套接字

        Socket SocketWatch = null;

        //定義一個集合,儲存客戶端資訊

        Dictionary<string, Socket> ClientConnectionItems = new Dictionary<string, Socket> { };


        public SocketTest()

        {

            InitializeComponent();

        }


        private void button1_Click(object sender, EventArgs e)

        {

            //埠號(用來監聽的)

            int port = 6000;


            //string host = "127.0.0.1";

            //IPAddress ip = IPAddress.Parse(host);

            IPAddress ip = IPAddress.Any;


            //將IP地址和埠號繫結到網路節點point上 

            IPEndPoint ipe = new IPEndPoint(ip, port);


            //定義一個套接字用於監聽客戶端發來的訊息,包含三個引數(IP4定址協議,流式連線,Tcp協議) 

            SocketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            //監聽繫結的網路節點 

            SocketWatch.Bind(ipe);

            //將套接字的監聽佇列長度限制為20 

            SocketWatch.Listen(20);



            //負責監聽客戶端的執行緒:建立一個監聽執行緒 

            Thread threadwatch = new Thread(ServerWatchConnecting);

            //將窗體執行緒設定為與後臺同步,隨著主執行緒結束而結束 

            threadwatch.IsBackground = true;

            //啟動執行緒   

            threadwatch.Start();

            


            Console.WriteLine("開啟監聽......");

            Console.WriteLine("點選輸入任意資料回車退出程式......");

            richTextBox1.AppendText("開啟監聽......");

            /*

            Console.ReadKey();


            SocketWatch.Close();

            */

        }



        //監聽客戶端發來的請求 

        void ServerWatchConnecting()

        {

            Socket connection = null;


            //持續不斷監聽客戶端發來的請求   

            while (true)

            {

                try

                {

                    connection = SocketWatch.Accept();

                }

                catch (Exception ex)

                {

                    //提示套接字監聽異常   

                    Console.WriteLine(ex.Message);

                    break;

                }


                //客戶端網路結點號 

                string remoteEndPoint = connection.RemoteEndPoint.ToString();

                //新增客戶端資訊 

                ClientConnectionItems.Add(remoteEndPoint, connection);


                string strTotalMsg = "\r\n[客戶端\"" + remoteEndPoint + "\"建立連線成功! 客戶端數量:" + ClientConnectionItems.Count + "]";

                

                this.Invoke((MethodInvoker)delegate

                {

                    lock (this.listBox1)

                        listBox1.Items.Add(remoteEndPoint);

                });


                //顯示與客戶端連線情況

                Console.WriteLine(strTotalMsg);


                //獲取客戶端的IP和埠號 

                IPAddress clientIP = (connection.RemoteEndPoint as IPEndPoint).Address;

                int clientPort = (connection.RemoteEndPoint as IPEndPoint).Port;


                //讓客戶顯示"連線成功的"的資訊 

                string sendmsg = "[" + "本地IP:" + clientIP + " 本地埠:" + clientPort.ToString() + " 連線服務端成功!]";

                byte[] arrSendMsg = Encoding.UTF8.GetBytes(sendmsg);

                connection.Send(arrSendMsg);


                this.Invoke((MethodInvoker)delegate

                {

                    lock (this.richTextBox1)

                        this.richTextBox1.AppendText(strTotalMsg);

                });


                //建立一個通訊執行緒   

                Thread thread = new Thread(ServerRecv);

                //啟動執行緒   

                thread.Start(connection);

            }

        }



        void ServerRecv(object socket_obj)

        {

            Socket socketServer = socket_obj as Socket;


            while (true)

            {

                //建立一個記憶體緩衝區,其大小為1024*1024位元組 即1M   

                byte[] arrServerRecMsg = new byte[1024 * 1024];

                //將接收到的資訊存入到記憶體緩衝區,並返回其位元組陣列的長度  

                try

                {

                    int length = socketServer.Receive(arrServerRecMsg);

                    if (length == 0)

                        continue;

                    //將機器接受到的位元組陣列轉換為人可以讀懂的字串   

                    string strSRecMsg = Encoding.UTF8.GetString(arrServerRecMsg, 0, length);


                    string strTotalMsg = "\r\n[客戶端:" + socketServer.RemoteEndPoint + " 時間:" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff") + "]\r\n" + strSRecMsg;


                    this.Invoke((MethodInvoker)delegate

                    {

                        lock (this.richTextBox1)

                            this.richTextBox1.AppendText(strTotalMsg);

                    });


                    //將傳送的字串資訊附加到文字框txtMsg上   

                    Console.WriteLine(strTotalMsg);


                    //Thread.Sleep(3000);

                    //socketServer.Send(Encoding.UTF8.GetBytes("[" + socketServer.RemoteEndPoint + "]:"+strSRecMsg));

                    //傳送客戶端資料

                    if (ClientConnectionItems.Count > 0)

                    {

                        foreach (var socketTemp in ClientConnectionItems)

                        {

                            socketTemp.Value.Send(Encoding.UTF8.GetBytes("[" + socketServer.RemoteEndPoint + "]:" + strSRecMsg));

                        }

                    }

                }

                catch (Exception)

                {

                    listBox1.Items.Remove(socketServer.RemoteEndPoint.ToString());

                    ClientConnectionItems.Remove(socketServer.RemoteEndPoint.ToString());

                    //提示套接字監聽異常 

                    Console.WriteLine("\r\n[客戶端\"" + socketServer.RemoteEndPoint + "\"已經中斷連線! 客戶端數量:" + ClientConnectionItems.Count + "]");

                    //關閉之前accept出來的和客戶端進行通訊的套接字 

                    socketServer.Close();

                    break;

                }

            }

        }

        private void button4_Click(object sender, EventArgs e)

        {

            if (ClientConnectionItems.Count > 0)

            {

                foreach (var socketTemp in ClientConnectionItems)

                {

                    for(int cnt =0; cnt < listBox1.SelectedItems.Count; cnt++)

                    {

                        foreach (var item in listBox1.SelectedItems)

                        {

                            if (item.ToString() == socketTemp.Key)

                            {

                                socketTemp.Value.Send(Encoding.UTF8.GetBytes("[Msg from server]:" + textBox2.Text));

                            }

                        }

                    }

                   

                }

            }


        }







        //建立1個客戶端套接字和1個負責監聽服務端請求的執行緒 

        Thread ThreadClient = null;

        Socket SocketClient = null;


        private void button2_Click(object sender, EventArgs e)

        {


            try

            {

                int port = 6000;

                //string host = "127.0.0.1";//伺服器端ip地址

                string host = textBox_target_ip.Text;


                IPAddress ip = IPAddress.Parse(host);

                IPEndPoint ipe = new IPEndPoint(ip, port);


                //定義一個套接字監聽 

                SocketClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);


                try

                {

                    //客戶端套接字連線到網路節點上,用的是Connect 

                    SocketClient.Connect(ipe);

                }

                catch (Exception)

                {

                    Console.WriteLine("連線失敗!\r\n");

                    Console.ReadLine();

                    return;

                }


                ThreadClient = new Thread(ClientRecv);

                ThreadClient.IsBackground = true;

                ThreadClient.Start();


                Thread.Sleep(1000);

                Console.WriteLine("請輸入內容<按Enter鍵傳送>:\r\n");

                while (true)

                {

                    string sendStr = Console.ReadLine();

                    ClientSendMsg(sendStr);

                }


                //int i = 1;

                //while (true)

                //{

                //  Console.Write("請輸入內容:");

                //  string sendStr = Console.ReadLine();


                //  Socket clientSocket = new Socket(AddressFamily.InterNetwork,ProtocolType.Tcp);

                //  clientSocket.Connect(ipe);

                //  //send message

                //  //byte[] sendBytes = Encoding.ASCII.GetBytes(sendStr);

                //  byte[] sendBytes = Encoding.GetEncoding("utf-8").GetBytes(sendStr);


                //  //Thread.Sleep(4000);


                //  clientSocket.Send(sendBytes);


                //  //receive message

                //  string recStr = ""; 

                //  byte[] recBytes = new byte[4096];

                //  int bytes = clientSocket.Receive(recBytes,recBytes.Length,0);

                //  //recStr += Encoding.ASCII.GetString(recBytes,bytes);

                //  recStr += Encoding.GetEncoding("utf-8").GetString(recBytes,bytes);

                //  Console.WriteLine(recStr);


                //  clientSocket.Close();

                //  if (i >= 100)

                //  {

                //    break;

                //  }

                //  i++;

                //}


                //Console.ReadLine();

                //return;


                //string result = String.Empty;


            }

            catch (Exception ex)

            {

                Console.WriteLine(ex.Message);

                Console.ReadLine();

            }

        }


        //接收服務端發來資訊的方法  

        public void ClientRecv()

        {

            int x = 0;

            //持續監聽服務端發來的訊息 

            while (true)

            {

                try

                {

                    //定義一個1M的記憶體緩衝區,用於臨時性儲存接收到的訊息 

                    byte[] arrRecvmsg = new byte[1024 * 1024];


                    //將客戶端套接字接收到的資料存入記憶體緩衝區,並獲取長度 

                    int length = SocketClient.Receive(arrRecvmsg);


                    //將套接字獲取到的字元陣列轉換為人可以看懂的字串 

                    string strRevMsg = Encoding.UTF8.GetString(arrRecvmsg, 0, length);

                    if (x == 1)

                    {

                        string strTotalMsg = "\r\n伺服器:" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff") + "\r\n" + strRevMsg + "\r\n";

                        Console.WriteLine(strTotalMsg);

                        this.Invoke((MethodInvoker)delegate

                        {

                            lock (this.richTextBox2)

                                this.richTextBox2.AppendText(strTotalMsg);

                        });

                    }

                    else

                    {

                        string strTotalMsg = strRevMsg + "\r\n";


                        Console.WriteLine(strTotalMsg);

                        this.Invoke((MethodInvoker)delegate

                        {

                            lock (this.richTextBox2)

                                this.richTextBox2.AppendText(strTotalMsg);

                        });

                        x = 1;

                    }

                }

                catch (Exception ex)

                {

                    Console.WriteLine("遠端伺服器已經中斷連線!" + ex.Message + "\r\n");

                    break;

                }

            }

        }


        //傳送字元資訊到服務端的方法 

        public void ClientSendMsg(string sendMsg)

        {

            //將輸入的內容字串轉換為機器可以識別的位元組陣列   

            byte[] arrClientSendMsg = Encoding.UTF8.GetBytes(sendMsg);

            //呼叫客戶端套接字傳送位元組陣列   

            SocketClient.Send(arrClientSendMsg);

        }


        private void button3_Click(object sender, EventArgs e)

        {

            ClientSendMsg(textBox1.Text);

        }

    }

}


2022年4月8日 星期五

C# serial port example

using System;

using System.IO.Ports;

using System.Windows.Forms;


namespace UART_SCOPE

{

    public partial class Form1 : Form

    {

        delegate void Display(string buffer);


        public Form1()

        {

            InitializeComponent();

            scan_set_comport();

            serialPort1.DataReceived += DataReceivedHandler;

        }


        private void button1_Click(object sender, EventArgs e)

        {

        }

        private void scan_set_comport()

        {

            if (!serialPort1.IsOpen)

            {

                for (int cnt = 3; cnt < 5; cnt++)

                {

                    serialPort1.PortName = "COM" + cnt;

                    try

                    {

                        serialPort1.Open();

                    }

                    catch

                    {

                        continue;

                    }

                    if (serialPort1.IsOpen)

                    {

                        comboBox1.Text = serialPort1.PortName;

                        comboBox1.Items.Add(serialPort1.PortName);

                        break;

                    }

                }

            }

        }

        private void DisplayText(string buffer)

        {

            listBox1.Items.Add(buffer);

        }

        private void DataReceivedHandler(

                            object sender,

                            SerialDataReceivedEventArgs e)

        {

            SerialPort sp = (SerialPort)sender;

            String indata = sp.ReadLine();

            Console.WriteLine("Data Received:");

            Console.Write(indata);

            Display d = new Display(DisplayText);

            this.Invoke(d, indata);

        }

    }

}


2022年4月7日 星期四

DigiSpark USB Scope

 

USB-Graphing-Meter

A simple graphing meter that collects samples from a DigiSpark USB device.






https://github.com/RaysceneNS/USB-Graphing-Meter


Setup Arduino IDE for Digispark Attiny85 on Linux

Digispark Attiny85 Linux driver
Digispark and compatible boards


Arduino IDE Digispark Linux Mint Setup Tutorial Steps

The following steps show how to set up a Digispark board for programming with the Arduino IDE in Linux Mint.

1. Install the Arduino IDE

Go to the Arduino website and download and install the Arduino IDE.

Download the Linux 64 bits file for 64-bit Linux Intel systems or the Linux 32 bits file for Linux 32-bit Intel systems. There are also equivalent files for 32-bit and 64-bit ARM systems. Unzip the downloaded file, and extract the folder found in the zipped file to a convenient location, such as the Desktop. To run the Arduino IDE application, open the extracted folder and double-click the Arduino executable file.

The image below shows the contents of the folder extracted from the downloaded zipped file, with the Arduino application selected. Simply double-click this file to start the Arduino IDE application.

Unzipped Arduino IDE folder with Arduino application highlighted

After double-clicking the Arduino executable file, a dialog box pops up, as shown below. Click the Run button in the dialog box to start the Arduino IDE application.

Arduino run dialog box in Linux Mint

2. Install the Digispark Board Support Package

Start the Arduino IDE application that you downloaded in the previous step.

Open Preferences Dialog box

From the top menu of the Arduino IDE application, select File → Preferences to open the Preferences dialog box.

Paste the following in the Additional Boards Manager URLs: box of the Preferences dialog box.

http://digistump.com/package_digistump_index.json

The image below shows the Additional Boards Manager URLs field of the Preferences dialog box.

Additional Boards Manager URLs field of the Arduino IDE Preferences dialog box

Click the OK button to close the dialog box.

Open Boards Manager Dialog Box

In the Arduino IDE, use the top menu to navigate to Tools → Board → Boards Manager... to open the Boards Manager dialog box.

Type Digispark into the search field at the top of the Boards Manager dialog box that contains the text "Filter your search..." to easily find the Digispark package.

After filtering the packages, Digistump AVR Boards is displayed in the Boards Manager dialog box. Click the Install button at the bottom right of the Digistump item in the dialog box, as shown in the image below.

Digispark board support package in the Arduino IDE Boards Manager dialog box

After clicking the Install button, the package will start installing. This may take a while, depending on the internet speed.

When installation completes, click the Close button at the bottom right of the dialog box.

3. Add Linux User Name to the Dialout Group(I didn't do this on ubuntu)

In order to be able to program any board from the Arduino IDE, the Linux user must be added to the dialout group.

Open a terminal window in Linux and enter the following command:

sudo adduser $USER dialout

Enter your Linux password when prompted.

You will need to log out and then log back in, or reboot, for the changes to take effect.

4. Add udev Rules to the System

To be able to program the Digispark board from the Arduino IDE in Linux, udev rules must be added to the system. This is done by creating a file in /etc/udev/rules.d/ that contains the rules.

Create a text file called 49-micronucleus.rules in /etc/udev/rules.d/ and add the following rules to it.

# UDEV Rules for Micronucleus boards including the Digispark.
# This file must be placed at:
#
# /etc/udev/rules.d/49-micronucleus.rules    (preferred location)
#   or
# /lib/udev/rules.d/49-micronucleus.rules    (req'd on some broken systems)
#
# After this file is copied, physically unplug and reconnect the board.
#
SUBSYSTEMS=="usb", ATTRS{idVendor}=="16d0", ATTRS{idProduct}=="0753", MODE:="0666"
KERNEL=="ttyACM*", ATTRS{idVendor}=="16d0", ATTRS{idProduct}=="0753", MODE:="0666", ENV{ID_MM_DEVICE_IGNORE}="1"
#
# If you share your linux system with other users, or just don't like the
# idea of write permission for everybody, you can replace MODE:="0666" with
# OWNER:="yourusername" to create the device owned by you, or with
# GROUP:="somegroupname" and mange access using standard unix groups.

In order to be able to create this file in the file system, you will need root permission. This can be done by opening a terminal window and entering:

sudo nano /etc/udev/rules.d/49-micronucleus.rules

The above line opens a new file called 49-micronucleus.rules with root permission from /etc/udev/rules.d/ in the nano command line text editor.

After running the above line to start the nano editor, copy all of the udev rules code from the listing above and paste them into the nano editor using the keyboard combination Ctrl + Shift + V.

In the nano editor, press Ctrl + O and then press the Enter key save the file and then Ctrl + X to exit the application.

Finally enter the following in the terminal window to reload the udev rules.

sudo udevadm control --reload-rules

5. Testing the Digispark Linux Mint Installation

Uploading a sketch to a Digispark board works differently from other Arduino boards. The board must not be plugged into a USB port, but must first be selected in the Arduino IDE. No port is selected. The sketch is uploaded, and when a prompt appears in the Arduino IDE, the board is plugged into a USB port. The following tutorial steps show how to load a sketch to a Digispark board.

Digispark Blink Sketch

The following sketch works on both Model A and Model B Digispark boards. The difference is that Model A boards have the on-board LED connected to pin 1, while the Model B boards have the on-board LED connected to pin 0.

Copy the following sketch and paste it into the Arduino IDE window. Save it as digispark_blink or a name of your choice.

void setup() {                
  pinMode(0, OUTPUT);      // LED on Model B
  pinMode(1, OUTPUT);      // LED on Model A   
}

void loop() {
  digitalWrite(0, HIGH);   // Turn the LED on
  digitalWrite(1, HIGH);
  delay(1000);             // Wait for a second
  digitalWrite(0, LOW);    // Turn the LED off
  digitalWrite(1, LOW); 
  delay(1000);             // Wait for a second
}

Select the Digispark Board in the Arduino IDE

From the top menu in the Arduino IDE, select Tools → Board → Digistump AVR Boards → Digispark (Default - 16.5MHz) to select the Digispark board.

Load the Blink Sketch to the Digispark Board

Click the Arduino Upload button on the top toolbar before plugging the Digispark board into a USB port.

Wait for the prompt at the bottom of the Arduino IDE window, as shown in the following image.

Arduino IDE with Digispark uploader prompting for device to be plugged in

When the prompt Plug in device now... (will timeout in 60 seconds) appears, plug the Digispark board into a USB port of the computer.

After the sketch finishes uploading, a success message running: 100% complete and >> Micronucleus done. Thank you! appears at the bottom of the Arduino IDE window, as can be seen in the following image.

Arduino IDE displaying Digispark upload success message

資料來源:https://startingelectronics.org/tutorials/arduino/digispark/digispark-linux-setup/


儘管以 root 身份運行 arduino IDE 並創建這些文件,但我仍然收到此錯誤:



/etc/udev/rules.d/49-micronucleus.rules AND /lib/udev/rules.d/49-micronucleus.rules:

代碼:[選擇]

SUBSYSTEMS=="usb", ATTRS{idVendor}=="16d0", ATTRS{idProduct}=="0753", MODE:="0666", GROUP="dialout"
KERNEL=="ttyACM*", ATTRS{idVendor}=="16d0", ATTRS{idProduct}=="0753", MODE:="0666", ENV{ID_MM_DEVICE_IGNORE}="1"


/etc/udev/rules.d/90-digispark.rules 和 /lib/udev/rules.d/90-digispark.rules:
代碼:[選擇]

SUBSYSTEMS=="usb", ATTRS{idVendor}=="16d0", ATTRS{idProduct}=="0753", MODE:="0666"
KERNEL=="ttyACM*", ATTRS{idVendor}=="16d0", ATTRS{idProduct}=="0753", MODE:="0666", ENV{ID_MM_DEVICE_IGNORE}="1"


(我還嘗試了 sudo cp 90-digispark.rules /etc/udev/rules.d/90-digispark.rules,正如預編譯二進制壓縮包中的 README.udev 所建議的那樣。)


我正在嘗試上傳示例/Digispark/開始草圖,但是,當我插入我的 Digispark kickstarter 版本 rev2(當請求時)時,它在上傳時達到 79%,然後失敗:


代碼:[選擇]

Running Digispark Uploader...
Plug in device now...
> Please plug in the device ...
> Press CTRL+C to terminate the program.
> Device is found!
connecting: 40% complete
> Device looks like ATtiny85!
> Available space for user application: 6010 bytes
> Suggested sleep time between sending pages: 8ms
> Whole page count: 94
> Erase function sleep duration: 752ms
parsing: 60% complete
> Erasing the memory ...
erasing: 79% complete
>> Abort mission! -1 error has occured ...
>> Please unplug the device and restart the program.

 

資料來源:https://digistump.com/board/index.php?topic=106.0