三菱IQ-R#Socket通信

なんだか最近Socket通信に書くこと多いと気がします…まぁ、なぜかよく問い合わせきましたから。
なので今回三菱RCPUとPythonを通信すること書きます。

前書き

Socket通信すには、Port番号の設定によって異なる外部デバイスと通信することができます。それらのデバイスはTCP/IP・UDP/IPも使えます。
image.png

そしてTCP/IP protocolはActive openとPassive Openがあります。
簡単にいいますと、Active OpenはClientですね。
Passive OpenはServerですね。

Active Open Flow

image.png

Passive Open Flow

image.png

Connectionを切断するタイミング

  • Timeout
  • 相手側から切断要求きたとき。そして同じのConnectionを再接続には最低限500msの間隔をあげましょう。(Manualがそういっただけですー)

TCP/IP protocolに必要なもの

  • 自分のIP
  • 自分のPort
  • 相手のIP
  • 相手のPort

Flow

image.png

使用するFunction

SP_SOCOPEN

Connectionを開くFunctionです。
image.png

  • EN:Bool
    • 立ち上げるとFunctionを実行する
  • U:String[1]
    • Dummyです。
  • S1:Word
    • Connectionの番号です。
  • S2: Array [0..9] of Word
    • Control Data最初から始まるメモリ番地。
  • d:Array[0..1]of Bool
    • Function実行後の状態、もしエラーがある場合Array[0]とArray[1]も1サイクルOnになります。
  • ENO:Bool
    • 実行結果。

Control Word

  • S2+0
    • 0000H-Open setting のエンジニアツールを使う、なんらんかはしりません。
    • 8000H-S2+2~+9のコントロールデータを使います。今回はこれを利用します。
  • S2+1
    • 実行後のStatusです。もし0でなければエラーがあります。エラーコードはここで格納します。
  • S2+2
    • Connectionの設定ですね。
    • image.png
  • S2+3
    • 自分のPort番号です。
  • S2+4、+5
    • 相手のIPアドレスです。
  • S2+6
    • 相手のPort番号です。
  • S2+7-+9
    • 使用禁止です。

Time-Chart

image.png

SP_SOCCLOSE

Connectionを切断するFunctionです。
image.png

  • EN:Bool
    • 立ち上げるとFunctionを実行する
  • U:String[1]
    • Dummyです。
  • S1:Word
    • Connectionの番号です。
  • S2: Array [0..1] of Word
    • Control Data最初から始まるメモリ番地。
  • d:Array[0..1]of Bool
    • Function実行後の状態、もしエラーがある場合Array[0]とArray[1]も1サイクルOnになります。
  • ENO:Bool
    • 実行結果。

Time Chart

image.png

SP_SOCCINF

Connectionの設定をもらうFunctionです。
image.png

  • EN:Bool
    • 立ち上げるとFunctionを実行する
  • U:String[1]
    • Dummyです。
  • S1:Word
    • Connectionの番号です。
  • S2::Array [0..1] of Word
    • Control Data最初から始まるメモリ番地。Function実行後の状態、もしエラーがある場合Array[1]がエラーコードが格納されます。
  • d:Array[0..4]of Word
    • Connectionの設定格納されます。
  • ENO:Bool
    • 実行結果。

d

  • S2+0,+1
    • 相手のIPアドレス
  • S2+2
    • 相手のPort
  • S2+3
    • 自分のPort
  • S2+4
    • Connectionの構成Word
    • image.png

SP_SOCSND

データを送信するFunctionです。
image.png

  • EN:Bool
    • 立ち上げるとFunctionを実行する
  • U:String[1]
    • Dummyです。
  • S1:Word
    • Connectionの番号です。
  • S2:Array[0..1] of Word
    • ControlデータでもしFunction実行エラーがある場合Word[1]がエラーコードが格納されます。
  • S3: Array [0..n] of Word
    • 送信するデータ最初から始まるメモリ番地。Function実行後の状態、もしエラーがある場合Array[1]がエラーコードが格納されます。
  • d:Array[0..4]of Word
    • Connectionの設定格納されます。
  • ENO
    • Boolで実行結果。

S3

  • S3+0
    • 送るデータの長さ(Byteで計算)
  • S3+1-N
    • データの番地
image.png

Time Chart

image.png

S_SOCRCVS

データ受信するFunctionです。
image.png

  • EN:Bool
    • ONするとFunctionを実行する
  • U:String[1]
    • Dummyです。
  • S:Word
    • Connectionの番号です。
  • d: Word
    • データ受信するときこの番地から始まります。Dは受信するデータの長さ・D+1からはデータの格納先です。
  • ENO:Bool
    • 実行結果。

d

image.png

Time Chart

image.png

実装

バージョン

image.png

CPU

image.png

Hardware設定

Parameter>R08CPU>Module ParameterでIPを設定します。
そしてExternal Device Configurationの隣“Detailed Setting”をクリックしConnectionの設定をします。
image.png
右のModule List>Ethernet Device(General)でActive Connection Moduleを選んでひっばります。
次はSocket Communicationを選んで、自分のPort番号設定します。今回の例は4000にします。次はちょっと右にScrollし…
image.png
こちらで相手側のIPとPortを設定し、
“Close with Reflecting the Setting”を。
image.png
最後はApply。
よし、これでConnection完了です。
image.png

プログラム

Socket設定するためにFunctionを3つ作っています。
image.png

  • FC_SocketIPConfig
    • IPアドレスを綺麗に一つのDWORDにまとめるFunction。
  • FC_SocketConectionConfig
    • Active使うか、なにないツール使うかのに設定するワードをまとめるFunction。
  • FC_SocketConfig
    • FC_SocketIPConfig、FC_SocketConectionConfigも含め、Port番号を全部設定するFunctionです。

FC_SocketIPConfig

Interface

image.png

Program

例え192.168.0.251はHC0A800FBです。このように百倍ずつ大きくしてプラスすれば同じの値になります。

IPConfig1:=iConfig[1];
IPConfig2:=iConfig[2];
IPConfig3:=iConfig[3];
IPConfig4:=iConfig[4];

ipConfig:=IPConfig4+int_to_Dint(IPConfig3*H100)
+(IPConfig2*H10000)
+(IPConfig1*H1000000);

FC_SocketIPConfig:=ipConfig;

Properties

image.png

FC_SocketConectionConfig

このようなワークを組みます。
image.png

Interface

  • IConfig[0]はTCPを使うかどうか。
  • IConfig[1]はSubFeatures、つまりPredefined Protocol Settingを使うかどうか。
  • IConfig[2]はActive Open使うとき。
  • IConfig[3]はFull Passive使うとき。
  • IConfig[2]とIConfig[3]もONしないならUnPassiveを使う。
image.png

Program

//init
ConnectionConfig:=0;


TCP:=iCconfig[0];
SubFeatures:=iCconfig[1];
Active:=iCconfig[2];
FullPassive:=iCconfig[3];


//b0-b7 Always OFF
ConnectionConfig.0:=FALSE;
ConnectionConfig.1:=FALSE;
ConnectionConfig.2:=FALSE;
ConnectionConfig.3:=FALSE;
ConnectionConfig.4:=FALSE;
ConnectionConfig.5:=FALSE;
ConnectionConfig.6:=FALSE;
ConnectionConfig.7:=FALSE;

IF TCP THEN
    ConnectionConfig.8:=FALSE;
ELSE
    ConnectionConfig.8:=TRUE;
END_IF;

//b9 Always ON
ConnectionConfig.9:=TRUE;

IF SubFeatures THEN
    ConnectionConfig.a:=TRUE;
ELSE
    ConnectionConfig.a:=FALSE;
END_IF;

//b11-13 Always OFF
ConnectionConfig.b:=FALSE;
ConnectionConfig.c:=FALSE;
ConnectionConfig.d:=FALSE;


IF Active THEN
    ConnectionConfig.e:=FALSE;
    ConnectionConfig.f:=FALSE;

ELSIF FullPassive THEN
    ConnectionConfig.e:=TRUE;
    ConnectionConfig.f:=TRUE;
ELSE
    ConnectionConfig.e:=FALSE;
    ConnectionConfig.f:=TRUE;
END_IF;


FC_SocketConnectionConfig:=ConnectionConfig;

Properties

image.png

FC_SocketConfig

このControl Dataを組みます。
image.png

Interface

image.png

Program

Z0:=iOffset;

//+0
IF iUseControlWord THEN
    D0Z0:=H8000;
ELSE
    D0Z0:=H0000;
END_IF;

//+2
Z0:=iOffset+2;
D0Z0:=FC_SocketConnectionConfig(iMyConfig);

//+3
Z0:=iOffset+3;
D0Z0:=iMyPort;

//+4,5
Z0:=iOffset+4;
_tDWord:=FC_SocketIPConfig(iParnterIP);
//D0Z0:D:=_tDWord;
DMOV(TRUE,_tDWord,D0Z0);

//+6
Z0:=iOffset+6;
D0Z0:=iParnterPort;

Properties

image.png

Main Program

まずこんな感じの流れです。
STの文法などの説明ここでやめとおきます。ネット上で自分よりう前説明がたくさんあると思いますので…
無題の図形描画.jpg

Interface

image.png

Program

//Init

    insConNums      :=1;
    insConnDelay    :=30;
    insSendDelay    :=2;
    insRetry        :=3;

    insENO:=OUT_T(
                    NOT insInit                     //Timer Trigger1
                    AND NOT  insSOCOPENSts[1]       //Timer Trigger2
                    ,InsT2                          //Timer Register
                    ,insConnDelay                   //Time Setup
                    );

//OPEN Connection    

    //IP Settings
    insMyIP[1]      :=192;
    insMyIP[2]      :=168;
    insMyIP[3]      :=0;
    insMyIP[4]      :=251;

    //Connection Configs
    insMyConfig[0]  :=TRUE;
    insMyConfig[1]  :=FALSE;
    insMyConfig[2]  :=TRUE;
    insMyConfig[3]  :=FALSE;

    //Config Setup Function
    insENO:=FC_SocketConfig( 
                4000            //DB Offset
                ,TRUE           //Use Control Word Or not
                ,insMyConfig    //[0]=Use TCP?,
                                //[1]=SubFeatures?,
                                //[2]=Active Connection?,
                                //[3]=Full Passive Connection
                ,4000           //My Port
                ,4000           //Parnter Port
                ,insMyIP        //Parnter IP
                );


    //Connection Delay
    insSOCOPEN:=InsT2.S;

    //Function
    SP_SOCOPEN( 
                insSOCOPEN  //EN
                ,insString  //Dummy
                ,insConNums //Connection Numbers
                ,D4000      //Control Word
                ,insSOCOPENSts//Status
                );

    //Result
    IF insSOCOPENSts[0] AND NOT insSOCOPENSts[1] THEN
        insConnected:=TRUE;
        insInit:=TRUE;
        insSendRetry:=0;
        insConnRetry:=0;
    ELSIF  insSOCOPENSts[0] AND  insSOCOPENSts[1] THEN
        insConnected:=FALSE;

    END_IF;

    //Retry Count
    IF insSOCOPENSts[1] THEN
        insConnRetry:=insConnRetry+1;
    END_IF;


//Get Connection Info

    //Config ControlWord for SP_SOCCINF
    D200:D:=D4004:D;        //Parnter IP
    D202:=HFA0;             //Parnter Port
    D203:=HFA0;             //My Port
    D204:=D4002;            //Connection Config

    //Function
    SP_SOCCINF(
                insSOCCINF  //EN
                ,insString  //Dummy
                ,insConNums //Connection Numbers
                ,D200       //Control Words
                ,D600       //Result
                );

//Send    

    //Data
    D999:=20;               //Length of bytes that need to sent
    D1000:=H23;             //Data
    D1002:=H59;             //Data
    D1004:=H99;             //Data
    D1009:=H53;             //Data

    //Send Trigger
    IF insConnected 
        AND NOT insSOCSNDSts[0] 
        AND NOT insSOCSNDSts[1]  
        AND insSendRetry < insRetry THEN
        insSend:=TRUE;
    ELSE
        insSend:=FALSE;
    END_IF;

    //Retry Count
    IF insSOCSNDSts[1] THEN
        insSendRetry:=insSendRetry+1;
    END_IF;

    //Send Delay
    insENO:=OUT_T(
                    insSend             //Trigger
                    ,insT1              //Timer Register
                    ,insSendDelay       //Time Setup
                    );

    //Send Command
    insSOCSND:=insT1.S;

    //Function
    SP_SOCSND(
                insSOCSND       //EN
                ,insString      //Dummy
                ,insConNums     //Connection Numbers
                ,D400           //Control Data,if Error,+1<>0
                ,D999           //Data Trasnfer
                ,insSOCSNDSts   //Status
                );

//Recv

    //Data
    D1099:=10;

    //Function
    S_SOCRCVS(
                TRUE            //EN
                ,insString      //Dummy
                ,insConNums     //Connection Numbers
                ,D1099          //Data
                );

//Close

    //Close Command
    insSOCCLOSE:=    insSendRetry >= insRetry;

    //Function
    SP_SOCCLOSE(
                insSOCCLOSE     //EN
                ,insString      //Dummy
                ,insConNums     //Connection Numbsers
                ,D300           //Control Data,if Error,+1<>0
                ,insSOCCLOSESts //Status
                );

    //Connect Again
    IF insSOCCLOSESts[0] THEN
        insInit:=FALSE;
    END_IF;

Python

import socket
import time

DESTINATION_ADDR = '192.168.0.39'
SOURCE_PORT, DESTINATION_PORT = 4000, 4000
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(('192.168.0.251', SOURCE_PORT))
sock.listen(1)
conn, addr = sock.accept()
i =0
while i<3000:

    if i %2 == 0:
        ba1 = bytearray(b"4abcdefas0")
    else:
        ba1 = bytearray(b"9kaekfyei2")

    response = conn.recv(1440)

    conn.send(ba1)
#     print(response)
    print("current:"+str(i))
    i+=1

sock.close()
conn.close()
Footer_Basic

Please Support some devices for my blog

Amazon Gift List

Find ME

Twitter:@3threes2
Email:soup01threes*gmail.com (* to @)
YoutubeChannel:https://www.youtube.com/channel/UCQ3CHGAIXZAbeOC_9mjQiWQ

シェアする

  • このエントリーをはてなブックマークに追加

フォローする

コメント

  1. 通りすがり より:

    SP_SOCSNDのControl dataの先頭デバイス番号は、D400→D4000の間違いでしょうか?
    SP_SOCOPENはD4000を使用していますが・・・

  2. 通りすがり より:

    先ほどのD4000の質問をした者です。
    引数の説明を読み、授受するデータの内容が異なることに気付きました。(同じデバイス番号を指定すると、SOCOPENのコントロールデータを壊してしまいますね)
    先ほどの質問は取り下げます。ご迷惑お掛けしました。

    • gomamenotes より:

      コメントありがとうございます。

      大分前書いてプログラムなので…自分も忘れてしまいました 笑
      SP_SOCSNDのControl WordはD400で、SP_SOCOPENはD4000ですねね。
      SP_SOCSNDは多分Connection番号さえ指定しておけばOKです。

      自分はあまり三菱使わないので。。そのへんのアドレス間隔も少しあけてたほうがよいかもしれませんね!

  3. tatachi より:

    教えて下さい。
    U:String[1]
    Dummyです。
    ダミーとあるのは特に文字列ならば何でもいいって事ですか?
    S1:Word
    Connectionの番号です。
    デバイスが2台、3台と増えれば2、3と変化すればいいのですか?
    Soket通信については素人なのでご教授頂ければ助かります。

    • gomamenotes より:

      Commentありがとうございます。
      U:String[1]
      なんでもいいだと思いますが、なにも書き込まないほうが一番よいだと思います。

      S1:Word
      基本はそのとおりです。ですが実際のDoneやBusyの状態をみてからConnection番号を切り替えてください。