Keyence#KV8000 Socket通信

今回はKeyence KV8000を使用しSocket通信を実装します。ClientはKV8000でサーバーはPythonのものになります。よろしくおねがいします。

What is a Socket?

ソケットとは、簡単に言いますとIPアドレスとポート番号を組み合わせたものです。IPアドレスは通信端末を特定し、ポート番号は端末で利用するサービスを特定します。

TCPプロトコルはまさにそのIPアドレス+ポート番号間の接続になります。最初に確立され、確立された接続に基づくパスを使用してデータが送受信されます。

UDPプロトコルでは、IPアドレスとポート番号の組み合わせで通信先を指定し、データを送受信します。ただし、TCP とは異なり、通信先とのコネクションは最初から確立されていません。

KV socket communication?

KV ソケット通信とは、TCP/IP または UDP/IP プロトコルを使用して Ethernet 上の機器と任意のデータを送受信するための機能です。 PCやワークステーションだけでなくさまざまな対応機器と通信できます。

また、ソケット通信用に設定されたバッファメモリやリレーを使用しグラムを組むことで、CPUユニットと相手機器間のデータ送受信を行うことができます。

TCP (non-procedural)-based communication

TCP/IPベースのデータ送受信ではフロー制御を行っているため、実際に受信機が受信するデータ長は、1回の送信プログラムで送信したデータ長と異なる場合があります。この場合、送信するデータ長は受信側のユーザプログラムで制御する必要があります。

TCP(無手順)の場合、KV-8000/7500が実際に受信したデータ長は「受信データ長(結果)」Buffer Memoryに格納されます。 

Relays

Relayの先頭アドレスは=n+4000+(KV Socket番号*100)

n=はRelay Leading No.の設定になります。

例えば、私はSocket0を使用し、Leading Relay NoはR3000だとします。

プログラムの中に使用するRelayの先頭アドレスは:

30000+4000(0*100)=R34000になります。

Flow

TCP Active Open

こちらは今回の記事で使用するTCP Active OpenのFlowです。ここでLeading RelayはR30000、Socketは0だとします。

  1. U_SOPENを使用し、IPなどの情報を書き込みます。

R34002(n+4002)はTrueします。

R36002(n+6002)Complete Flagが回答します。

R34002(n+4002)をFalseします。

それでConnectionが確立され、もしR36003(n+6003)がTrueになったらConnectionエラーになり、エラー処理を行ってください。接続エラーが発生した場合、U_SSTAT関数を使用し詳しいエラー情報を取得できます。

TCP Send 

こちらは今回の記事で使用するTCP Active の送信Flowです。ここでLeading RelayはR30000、Socketは0だとします。

  1. U_SWRBUFを使用し、送信データなどの情報を書き込みます。
  2. R34006(n+4006)SendリクエストをTrueします。
  3. R36006(n+6006)Complete Flagが回答します。
  4. R34006(n+4006)をFalseします。

それで送信完了です。もしR36007(n+6007)がTrueになったらConnectionエラーになり、エラー処理を行ってください。接続エラーが発生した場合、U_SSTAT関数を使用し詳しいエラー情報を取得できます。

TCP Receive

こちらは今回の記事で使用するTCP Active の受信Flowです。ここでLeading RelayはR30000、Socketは0だとします。

  1. SRDBUFを使用し、Server受信データなどの情報を書き込みます。
  2. R34008(n+4008)ReceiveリクエストをTrueします。
  3. R36010(n+6010)ReceiveありのFlag返答きます。
  4. R36008(n+6010)Complete Flagが回答します。
  5. R34006(n+4006)をFalseします。

それで送信完了です。もしR36009(n+6009)がTrueになったらConnectionエラーになり、エラー処理を行ってください。接続エラーが発生した場合、U_SSTAT関数を使用し詳しいエラー情報を取得できます。

TCP Close

こちらは今回の記事で使用するTCP Active のConnection Close Flowです。ここでLeading RelayはR30000、Socketは0だとします。

  1. R34012(n+4012)CloseリクエストをTrueします。
  2. R36012(n+6012)Complete Flagが回答します
  3. R36013(n+6013)接続OpenしてるFlagがFalseになります。
  4. R34012(n+4012)をFalseします。

Function 

次は今回の記事で使用する関数を紹介します。

U_SOPEN

Connectionの接続パラメータをBuffer Memoryに転送する関数です。

Format

U_SOPEN ([EN,] Unit, Socket, Setting)

Argument

Parameter NameDescription
ENTrue=関数実行する
UnitUnit番号を指定します。0=KV8000本体のPort
SocketKV Socket番号を指定します。0-15まで設定できます。
SettingKV Socketの設定データ

Settings Mapping

MemeoryBuffer MemoryDescription
Setting+0#25000+Socket番号x1500KV8000のLcocal Port
Setting+1#25001+Socket番号x1500接続先のIPアドレス Byte1
Setting+2#25002+Socket番号x1500接続先のIPアドレス Byte2
Setting+3#25003+Socket番号x1500接続先のIPアドレス Byte3
Setting+4#25004+Socket番号x1500接続先のIPアドレス Byte4
Setting+5#25005+Socket番号x1500接続先のPort番号
Setting+6#25006+Socket番号x1500TimeOut(ms)
Setting+7#25007+Socket番号x1500UDP Flag,1=UDP

U_SWRBUF

該当するConnectionに送信するデータをBuffer Memoryに送信する関数です。

Format

U_SOPEN ([EN,] Unit, Socket, SendData)

Argument

Parameter NameDescription
ENTrue=関数実行する
UnitUnit番号を指定します。0=KV8000本体のPort
SocketKV Socket番号を指定します。0-15まで設定できます。
SendData送信するデータ(Bytes数)

Settings Mapping

MemeoryBuffer MemoryDescription
SendData+0#25009+Socket番号x1500送信データの長さ(Byte)
SendData+1#25010+Socket番号x1500送信データ(Byte0,1)
SendData+2#25011+Socket番号x1500送信データ(Byte2,3)
SendData+3#25012+Socket番号x1500送信データ(Byte4.5)
Etc..Etc..Etc..

U_SRDBUF

該当するConnectionに受信するデータをBuffer Memoryからプログラムデバイスに転送する関数です。

Format

U_SRDBUF([EN,] Unit, Socket, Dst)

Argument

Parameter NameDescription
ENTrue=関数実行する
UnitUnit番号を指定します。0=KV8000本体のPort
SocketKV Socket番号を指定します。0-15まで設定できます。
Dst受信するデータの格納先(Bytes)

Settings Mapping

MemeoryBuffer MemoryDescription
Dst+0#25759+Socket番号x1500受信データの長さ(Byte)
Dst+1#25760+Socket番号x1500受信データ(Byte0,1)
Dst+2#25761+Socket番号x1500受信データ(Byte2,3)
Dst+3#25762+Socket番号x1500受信データ(Byte4.5)
Etc..Etc..Etc..

U_SSTAT

該当するConnectionのStatusを取得する関数です。

Format

U_SOPEN ([EN,] Unit, Socket, Dst)

Argument

Parameter NameDescription
ENTrue=関数実行する
UnitUnit番号を指定します。0=KV8000本体のPort
SocketKV Socket番号を指定します。0-15まで設定できます。
Dst受信するデータの格納先

Settings Mapping

MemeoryBuffer MemoryDescription
Dst+0#25748+Socket番号x1500接続状態
Dst+1#25749+Socket番号x1500接続先IPアドレス(Bye1)
Dst+2#25750+Socket番号x1500接続先IPアドレス(Bye2)
Dst+3#25751+Socket番号x1500接続先IPアドレス(Bye3)
Dst+4#25752+Socket番号x1500接続先IPアドレス(Bye4)
Dst+5#25753+Socket番号x1500接続先のPort
Dst+6#25754+Socket番号x1500接続Open状態
Dst+7#25755+Socket番号x1500送信状態
Dst+8#25756+Socket番号x1500Response状態
Dst+9#25757+Socket番号x1500受信状態
Dst+10#25758+Socket番号x1500接続Close状態
Dst+11#25759+Socket番号x1500受信したデータ長さ

Status

自分は基本的に0,4見ればよいだと思います。

CodeDescription
0CLOSED,Connection がClose中
1LISTEN,Connection持っています
2SYS SENT,Active Open稼働中、SYNは送信した
3SYS RCVD,ServerからSYN受信した
4ESTABLISHED,Connectionが確立された
5CLOSE WAIT,FINが受信された
6FIN WAIT1,FINが送信した
7FIN WAIT2,1,FINが受信された
8CLOSING,FINが受信されConnectionがClose中
9LAST AKC,FIN受信されFINも送信した

Implmentation

ここからは実装です。

Keyence Side

Configuration

KV Studioを起動し、Unit Editorを開きます。

Socket Function 

Function>Socket functionをUsedで機能を有効化します。

Leading relay No

Leading relay No.DefaultはR3000になっており、つまりConnectionの制御やStatusデータはR3000から始めます。

IP address

IP addressもアプリケーションに合わせて設定してください。

Socketx Setting

Socket0からSocket15までの設定ができます。

Kv SocketをTCP(Non-procedure)TCP無手順に設定します。

H->LはByteをSwapかどうかを設定します。

Program

次はプログラムを組みます。

DUT

DUT_U_SSTAT_TCPStatus

こちらの構造体は関数U_SSTATのConnections Statusを明確にするためです。

Closed BOOL
Listen BOOL
SynSent BOOL
SynRCVD BOOL
Established BOOL
CloseWait BOOL
FinWait1 BOOL
FinWait2 BOOL
Closing BOOL
LastAck BOOL

Variable

Global

Global変数Socket0が必要なリクエストとResponseを絶対アドレスの代わりに変数に代用します。

gbTcp0ActiveOpenReq BOOL R34002
gbTcp0ActiveOpenComp BOOL R36002
gbTcp0ActiveOpenFail BOOL R36003
gbSocket0SendReq BOOL R34006
gbSocket0SendComp BOOL R36006
gbSocket0SendFail BOOL R36007
gbSocket0ReceveData BOOL R36010
gbSocket0ReceveInCorrect BOOL R36011
gbSocket0ReceveReq BOOL R34008
gbSockte0ReceveEnd BOOL R36008
gbSocket0CloseReq BOOL R34012
gbSocket0ReceveFail BOOL R36009
Local

Local変数はUnit番号・Socket番号など通信プログラムを制御するデバイスを定義します。

wUnitNo INT
wstextLen UINT
wSomeValue UINT
wKVSocketNo INT
stSocket0Status DUT_U_SSTAT_TCPStatus
stext STRING[255]
sSomeText STRING[10]
iStep UINT
iCounter UINT
bStart BOOL
bReset BOOL
bError BOOL
arrControlData ARRAY[0..7] OF UINT

Main

Configure your Sending Data

ランダムの整数を文字列に変換しHello from Keyence KV8000!の一番うしろに付けてPython Serverに送信します。そうすると実際データが送信されたか、常に確認できます。

また、整数の現在値によって変換された文字列数も定数ではなくなりますので、LEN()関数を使用し文字列の長さを取得します。

wSomeValue:=wSomeValue+1;
stext:=’Hello from Keyence KV8000!’;
sSomeText:=STR(wSomeValue);

stext:=CONCAT(stext,sSomeText);
wstextLen:=LEN(stext);
Move to DM

Keyenceの関数ではどうしても絶対アドレスのほうが取り扱いやすいので、SMOV関数を使用し先程設定した文字列を一括転送でDM101を送信します。(DM100は送信サイズを格納する場所なので)

Get Connection Status

CR2004を使用し100ms CycleでSocket0の状態を取得します。

U_SSTAT(
EN:=CR2004
,Unit:=wUnitNo
,Socket:=wKVSocketNo
,Dst:=DM10
);


stSocket0Status.Closed:=DM10 =0;
stSocket0Status.Listen:=DM10 =1;
stSocket0Status.SynSent:=DM10 =2;
stSocket0Status.SynRCVD:=DM10 =3;
stSocket0Status.Established:=DM10 =4;
stSocket0Status.CloseWait:=DM10 =5;
stSocket0Status.FinWait1:=DM10 =6;
stSocket0Status.FinWait2:=DM10=7;
stSocket0Status.Closing:=DM10=8;
stSocket0Status.LastAck:=DM10=9;
Socket Communication 

こちらはMainの部分でbstartでプログラムを開始します。

  • Step10
    Connectionのパラメータを設定・受信Bufferをクリア・各関数を実行してない状態にリセットします。
  • Step20
    U_SOPENを使用し、ConnectionパラメータをBuffer Memoryに転送します。gbTcp0ActiveOpenReqをTrueしてPython Serverと接続開始しgbTcp0ActiveOpenComp FlagがTrueになったら次のStepに進む。
  • Step30
    Connection OpenしてたときエラーがあるかをCheck、エラーであれば999に進み、問題なければ次のStepに進む。
  • Step40
    gbTcp0ActiveOpenReqをリセットします。U_SWRBUF関数を使用し送信するデータをBuffer Memoryに転送、gbSocket0SendReqをTrueにしてデータをPython Serverに送信します。gbSocket0SendCompがTrueになると、送信完了だと示すので次のStepに進む。
  • Step50
    データ送信してたときエラーがあるかをCheck、エラーであれば999に進み、問題なければ次のStepに進む。
  • Step60
    受信Bufferをリセットします。
  • Step70
    U_SRDBUF関数を使用しPython Serverから受信したデータの格納先をBuffer Memoryに転送します。gbSocket0ReceveReqをTrueにして受信開始する。gbSockte0ReceveEndがTrueになると、受信完了だと示すので次のStepに進む。
  • Step80
    データ受信してたときエラーがあるかをCheck、エラーであれば999に進み、問題なければ次のStepに進む。
  • Step90
    次の送信オペレーションまでのDelay Stepです。
  • Step999
    エラー処理のStepです。
if bStart and iStep =0 then
iStep:=10;
bStart:=FALSE;
end_if;


CASE iStep of
10: //Init the data
//Control Data
arrControlData[0]:=9000; //local port
arrControlData[1]:=192; //Server ip byte1
arrControlData[2]:=168; //Server ip byte2
arrControlData[3]:=1; //Server ip byte3
arrControlData[4]:=194; //Server ip byte4
arrControlData[5]:=5000; //Server Port
arrControlData[6]:=1000; //Timeout
arrControlData[7]:=0; //UDP Flag
//Receive Data Buffer
FMOV(0,DM1000,100);
//Function Block
U_SRDBUF(
en:=False
,Unit:=wUnitNo
,Socket:=wKVSocketNo
,Dst:=DM1000
);
U_SWRBUF(
EN:=False
,Unit:=wUnitNo
,Socket:=wKVSocketNo
,SendData:=DM100
);
U_SOPEN(EN:=False
,Unit:=wUnitNo
,Socket:=wKVSocketNo
,Setting:=arrControlData
);
U_SSTAT(
EN:=False
,Unit:=wUnitNo
,Socket:=wKVSocketNo
,Dst:=DM10
);
iStep:=20;
20://TCP Open Req
gbTcp0ActiveOpenReq:=True;
U_SOPEN(
EN:=True
,Unit:=wUnitNo
,Socket:=wKVSocketNo
,Setting:=arrControlData
);
if gbTcp0ActiveOpenComp then
iStep:=30;
end_if;
30://Check TCP Open Status
if gbTcp0ActiveOpenFail then
iStep:=999;
ELSE
iStep:=40;
end_if;
40://TCP Send Data
gbTcp0ActiveOpenReq:=False;
DM100:=wstextLen;

U_SWRBUF(EN:=True
,Unit:=wUnitNo
,Socket:=wKVSocketNo
,SendData:=DM100
);
gbSocket0SendReq:=True;
if gbSocket0SendComp then
iStep:=50;
U_SWRBUF(EN:=False
,Unit:=wUnitNo
,Socket:=wKVSocketNo
,SendData:=DM100
);
gbSocket0SendReq:=False;
end_if;

50://Check TCP Send Status
if gbSocket0SendFail then
iStep:=999;
else
iStep:=60;
gbSocket0SendReq:=False;
end_if;
60: //Rset the Receive Buffer
FMOV(0,DM1000,100);
iStep:=70;
70://TCP Receive Data
U_SRDBUF(
en:=true
,Unit:=wUnitNo
,Socket:=wKVSocketNo
,Dst:=DM1000
);
gbSocket0ReceveReq:=True;
if gbSockte0ReceveEnd or not stSocket0Status.Established  then
U_SRDBUF(
en:=False
,Unit:=wUnitNo
,Socket:=wKVSocketNo
,Dst:=DM1000
);
gbSocket0ReceveReq:=false;
iStep:=80;
end_if;
80://Check Receive Status
if gbSocket0ReceveInCorrect or gbSocket0ReceveFail then
iStep:=999;
else
iStep:=90;
iCounter:=0;
end_if;
90://10ms Pulse,Step Back Delay
if CR2004 then
iCounter:=iCounter+1;
end_if;

if iCounter>=600 THEN
iStep:=40;
iCounter:=0;
end_if;
999://Error,Wait Reset
bError:=True;
bReset:=True;//Auto Reset
U_SRDBUF(
en:=False
,Unit:=wUnitNo
,Socket:=wKVSocketNo
,Dst:=DM1000
);
U_SWRBUF(
EN:=False
,Unit:=wUnitNo
,Socket:=wKVSocketNo
,SendData:=DM100
);
U_SOPEN(EN:=FALSE
,Unit:=wUnitNo
,Socket:=wKVSocketNo
,Setting:=arrControlData
);

if CR2004 and bReset then
iCounter:=iCounter+1;
end_if;


gbSocket0CloseReq:=True;
gbSocket0ReceveReq:=False;
gbTcp0ActiveOpenReq:=False;
gbSocket0SendReq:=False;
if iCounter>=600 then
gbSocket0CloseReq:=False;
iStep:=10;
bError:=False;
bReset:=False;
iCounter:=0;
end_if;
END_CASE;

Python Side

こちらはPython側の実装です。

import socket

HOST = ‘192.168.1.194’
PORT = 12344

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind((HOST, PORT))
s.listen()
conn, addr = s.accept()
with conn:
print(f’Connected by {addr}’)
while True:
data = conn.recv(1024)
if not data:
break
print(‘data from client:’.encode()+data)
conn.sendall(data+’,Data back from Server’.encode())

Implementation-2

次はREST APIを使用するよくあるGET リクエストの実装方法を簡単に紹介します。

Keyence Side

最初に文字列の設定するところをGET リクエストに必要な内容をすべて無理やり書いておけばOKです。

stext:=’GET /mydata HTTP/1.1$R$LHost: $R$LUSER-Agent: Keyence$R$LAccept: text/html$R$LAccept-Encoding: identity$R$LAccept-Charset: utf-8$R$L$R$L’;
wstextLen:=LEN(stext);

Python Side

from flask import Flask

app=Flask(__name__)

@app.route(‘/’)
def hello_world():
return “hello”

@app.route(‘/mydata’)
def get_data():
return “data-1-2-3-4”,200


if __name__==’__main__’:
app.run(host=”192.168.1.194″)

Result

Download Source Project

GithubからSample ProjectをDownloadしてください。

https://github.com/soup01Threes/Keyence/blob/main/SocketTest_Get_Finally.7z

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

シェアする

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

フォローする