SLMPでPLCレジスタのリード/ライトを試します。
バイナリコードでのビットアクセスについてはこちらの記事に書きました。
接続
まずPLCとコネクションを張ります。
HOST = '192.168.1.1'
PORT = 1026
BUFSIZE = 4096
import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((HOST, PORT))
sock.settimeout(3)
基本パラメータ
SLMPの要求伝文に設定する基本パラメータです。
アクセス先設定
ホストPCと直接Ethernet接続されているPLCのCPUユニットレジスタを読みます。
この場合、SLMPの規定によりPLCアクセス先の設定は下記のようにします。
| 項目 | 値 | 
|---|---|
| 要求先ネットワーク番号 | 00h | 
| 要求先局番 | FFh | 
| 要求先ユニットI/O番号 | 3FFh | 
| 要求先マルチドロップ局番 | 0 | 
監視タイマ
監視タイマは250ms単位で設定します。今回は 4 (1秒) に設定します。
デバイスコード
今回はデータレジスタを使用します。ワードアクセスです。
ASCIIコードででは "D*"、バイナリコードでは A8h となります。
リード
要求伝文を組み立ててフレームを送信します。
Readコマンド(0401h)のワードアクセスとします。
バイナリコード時には、サブヘッダ以外はリトルエンディアンで値を格納する必要があります。
サブヘッダだけは何故かビッグエンディアンなので気を付けましょう。
D0001 ~ D0003 の3つのレジスタの値を読み込みます。
# '5000 00 FF 03FF 00 0018 0020 0401 0000 D* 000001 0003'
data = [
    0x50,0x00,      # サブヘッダ
    0x00,           # 要求先ネットワーク番号
    0xFF,           # 要求先局番
    0xFF,0x03,      # 要求先ユニットI/O番号
    0x00,           # 要求先マルチドロップ局番
    0x0C,0x00,      # 要求データ長 (後で設定)
    0x20,0x00,      # 監視タイマ
    0x01,0x04,      # コマンド
    0x00,0x00,      # サブコマンド
    0x01,0x00,0x00, # 先頭デバイス番号
    0xA8,           # デバイスコード
    0x03,0x00       # デバイス点数
]
# 要求データ長を設定
data[7] = len(data[9:]) & 0xFF
data[8] = (len(data[9:]) >> 16) & 0xFF
# 要求送信
sock.send(bytes(data))
# 応答受信
res = sock.recv(BUFSIZE)
print (*[format(i,'02X') for i in res])
受信データは下記のようになります。
現在のレジスタ値はすべて 0 でした。
D0 00 00 FF FF 03 00 08 00 00 00 00 00 00 00 00 00
ライト
要求伝文を組み立ててフレームを送信します。
Writeコマンド(1401h)のワードアクセスとします。
D0000 ~ D0004 の5つのレジスタに値を書き込みます。
# '5000 00 FF 03FF 00 0018 0020 0401 0000 D* 000000 0005 1122 3344 5566 7788 99AA'
data = [
    0x50,0x00,      # サブヘッダ
    0x00,           # 要求先ネットワーク番号
    0xFF,           # 要求先局番
    0xFF,0x03,      # 要求先ユニットI/O番号
    0x00,           # 
    0x00,0x00,      # 要求データ長 (後で設定)
    0x04,0x00,      # 監視タイマ
    0x01,0x14,      # コマンド (1401H)
    0x00,0x00,      # サブコマンド
    0x00,0x00,0x00, # 先頭デバイス番号
    0xA8,           # デバイスコード
    0x05,0x00,      # デバイス点数
    0x11,0x22,      # D0000
    0x33,0x44,      # D0001
    0x55,0x66,      # D0002
    0x77,0x88,      # D0003
    0x99,0xAA,      # D0004
]
# 要求データ長を設定
data[7] = len(data[9:]) & 0xFF
data[8] = (len(data[9:]) >> 16) & 0xFF
# 要求送信
sock.send(bytes(data))
# 応答受信
res = sock.recv(BUFSIZE)
ライト完了後、先ほどのReadコマンドを再度実行すると、実行結果は下記のようになります。
D0 00 00 FF FF 03 00 08 00 00 00 33 44 55 66 77 88
正しく書込みと読み出しができていることが分かります。
コネクション切断
sock.close()
