[C#.NET][TCP Socket] 利用 Socket 控制 Advantech RU25 Reader-Active Mode

[C#.NET][TCP Socket] 利用 Socket 控制 Advantech RU25 Reader-Active Mode

續上篇,[C#.Net][TCP Socket] 利用 Socket 控制 Advantech RU25 Reader–Passive Mode,我已經可以對 Reader 的被動模式 set/get,這次我們來處理主動模式,所謂主動模式 Server 主動會拋出 inventory 訊息給 Client,首先要先設定 Reader 的主動模式,調用 command "set readmode 2",這個命令與其他的 command set 的回傳規則不一樣,雖然它同樣是回傳 "1101\r\n701\r\n1102\r\n",但它會緊接著它要回傳的訊息,這代表著我們必須要為它另外做處理,否則會收到錯誤的資料。

 

下圖,set readmode 2 與其他 command set 資料格式不同:

SNAGHTML1d30f1ab

以下是依照該台 Reader 特性處理的程式碼,"set readmode 2":


public bool SetReadMode(EnumWorkMode WorkMode)
{
    if (!this.IsConnected)
    {
        return false;
    }
    switch (WorkMode)
    {
        case EnumWorkMode.Passive:
            this.SendAndReceive("set readmode 0");
            var readmode = this.SendAndReceive("set readmode 0");
            if (readmode == MESSAGE_SUCCESS)
            {
                return true;
            }
            break;

        case EnumWorkMode.Active:
            var command = "set readmode 2\r";
            SocketError error = new SocketError();

            var sendData = this.Encode.GetBytes(command);
            this._socketCliect.Send(sendData, 0, sendData.Length, SocketFlags.None, out error);

            var bufferArray = new byte[17];
            var receiveCount = this._socketCliect.Receive(bufferArray);

            var receive = this.Encode.GetString(bufferArray, 0, receiveCount);
            return receive == MESSAGE_SUCCESS;

            break;

        default:
            throw new ArgumentOutOfRangeException("WorkMode");
    }
    return false;
}

當調用 "set readmode 2" 後,緊接著就可以收到設備拋出的資料,不過這段路我並沒有走的很順,有卡到一些時間,一開始我是很單純的調用 Socket.Receive ,很不幸的這樣做會掉包(lose package),造成後續處理會有很大的問題,我面臨到幾個問題:
1.inventory mode 會有不同的資料長度。
2.當 Reader 還沒有資料時,Socket.Receive 會等待太長的時間。
3.讀取特定長度 byte 會有掉包的情況,需要判斷補包或棄包。

 

解決步驟:
1.用 Smart Sniff 觀察一個完整的 package 有多少資料量,經過一些時間的實作及驗証,最後得知在 "set inventory 0" 模式下,會有 44 bytes,我佔定這樣的長度是一個 package。
2.設定 time out 旗標,縮短等待時間。
3.依一個 package 的資料長度,處理補包。

 

下圖表示,最後 pakcage 明顯的有錯誤,所以必須要判斷補包或棄包:

SNAGHTML1d2e04a5

 

程式碼如下:


public string ListeningReceive(int count)
{
    if (!this.IsConnected)
    {
        return "No Connect!";
    }
    if (this._socketCliect == null && !this._socketCliect.Connected)
    {
        return null;
    }
    int timeOut = 100;
    var tempTimeOut = this._socketCliect.ReceiveTimeout;
    this._socketCliect.ReceiveTimeout = timeOut;

    var arrayCount = 44 * count;
    var bufferArray = new byte[arrayCount];
    var socketError = new SocketError();
    var receiveCount = 0;
    Stopwatch sw = new Stopwatch();
    sw.Start();

    try
    {
        while (true)
        {
            this._remain = bufferArray.Length - receiveCount;
            receiveCount += this._socketCliect.Receive(bufferArray, receiveCount, this._remain, SocketFlags.None, out socketError);

            if (socketError != SocketError.Success)
            {
                if (this._socketCliect.Available == 0)
                {
                    break;
                }
                else
                {
                    continue;
                }
            }

            if (receiveCount >= arrayCount)
            {
                //已經拿到固定長度的資料,則離開
                break;
            }

            if (sw.Elapsed.Milliseconds <= timeOut)
            {
                continue;
            }

            sw.Stop();

            //時間到了
            int lostCount = receiveCount % 44;
            this._remain = 44 - lostCount;

            //資料不足44 bytes,則補足44 bytes 
            if (lostCount != 0)
            {
                receiveCount += this._socketCliect.Receive(bufferArray, receiveCount, this._remain, SocketFlags.None, out socketError);
            }

            break;
        }
        var result = this.Encode.GetString(bufferArray, 0, arrayCount);
        this._remain = 0;
        return result;
    }
    finally
    {
        this._socketCliect.ReceiveTimeout = tempTimeOut;
    }
}


完成這段之後,接下來,不同的 inventory mode 只要變更 package 的長度就可以了 。

還是要提醒一下每一個 TCP Server 的規則都不一樣,千萬別以為都一樣而傻傻的抄 。

 

範例下載:

RU25SocketClient.zip

若有謬誤,煩請告知,新手發帖請多包涵


Microsoft MVP Award 2010~2017 C# 第四季
Microsoft MVP Award 2018~2022 .NET

Image result for microsoft+mvp+logo