三菱PLC通信 構造体でトライ -コマンド送信

前回の記事三菱PLCとイーサネット通信では、文字列に書いたコマンドを送信して受信データを文字列で表示しましたが、今回はそれを構造体にして書いてみます。

コードはまたgistsにアップします。
melsec_struct_test.cpp

それではコードを説明します。まずは送信コマンドのヘッダの構造体です。

#pragma pack(push,1)

//送信コマンドヘッダ
struct QNa3E_Frame_Send{
    std::uint16_t subheader=0x0050;
    std::uint8_t network_number=0x00;
    std::uint8_t pc_number=0xFF;
    std::uint16_t request_IO_number=0x03FF;
    std::uint8_t request_station_number=0x00;
    std::uint16_t request_data_length;
    std::uint16_t cpu_monitoring_timer=0x10;
} qna;

pragma pack(push,1)を入れることにより、バイナリで転送したときの間を開けずに詰める事ができます。もし入れない場合は「std::uint8_t request_station_number=0x00; //要求先ユニット局番号」の後に00が入ってしまいます。構造体宣言の最後にはpragma pack(pop)と書きます。

構造体はリファレンスマニュアルのQnA互換3Eフレームのバイナリコードで更新する場合を見ながら作成しました。

次に一括読み出しの構造体です。

//一括読み出しコマンド
struct ReadAllCommand{
    std::uint16_t command=0x0401;
    std::uint16_t sub_command=0x0000;
    std::uint32_t top_device;
    std::uint16_t number_of_device;
} read_all;

デバイスはDが0xA8、Mが0x90と値が決められているので列挙体で作成しました。std c++11からは列挙体の基礎となる型を指定できます。

//デバイス
enum struct Device_type : std::uint32_t{
    D = 0xA8,
    X = 0x9C,
    Y = 0x9D,
    M = 0x90,
};

次にmain関数に移ります。まずはデバイス番号を設定します。前回の例と一緒でD300から3ワードという設定です。

/デバイス番号を設定
std::uint32_t device = static_cast<std::uint32_t>(Device_type::D);

列挙体ではキャストして変数へ格納します。

read_all.top_device = ( device << 24) | 300;  // D300
read_all.number_of_device = 3; // 3ワード

デバイスは4バイトのうち先頭の1バイトがDとかMなどの種類で、残り3バイトがアドレスになります。列挙体で格納したデータを3バイト分(24bit)シフトしました。デバイス数はそのまま数値を入力します。

qna.request_data_length=sizeof(qna.cpu_monitoring_timer) + sizeof(read_all)

で、要求データ長を計算しています。
次にUDP送信です。

// UDP送信
std::string const host = "192.168.0.10";
short const port = 1025;
asio::io_context context;
asio::ip::udp::endpoint endpoint(
    asio::ip::address::from_string(host), port);
asio::ip::udp::socket socket(context);
socket.open(asio::ip::udp::v4());
socket.send_to(asio::buffer(&qna, sizeof(qna)), endpoint);
socket.send_to(asio::buffer(&read_all, sizeof(read_all)), endpoint);

ASIOについては前回の記事を参照してください。send_toで送信するところは、送信ヘッダと受信コマンドを構造体毎に送っています。

レスポンスの受信については次回説明します。