melsec_mc 0.3.0

A small Rust library to talk to Mitsubishi PLCs via MC Protocol (Ethernet) - transport layer and helpers
Documentation
# melsec_mc

三菱電機 PLC と MC プロトコル(Ethernet)用の軽量な Rust ライブラリです。

提供内容(概要)
- 非同期 TCP トランスポート(Tokio ベース)と簡易クライアント
- エラー型とレスポンス/リクエストの最低限の構造
- 生のフレーム送受信を行うサンプルとユーティリティ

注: 高レベルなバッチ読み書き API は一部実装済みですが、今後拡張予定です。

## 目次

- [melsec\_mc]#melsec_mc
  - [目次]#目次
  - [クイックスタート]#クイックスタート
  - [リリース v0.2.0]#リリース-v020
  - [ライブラリとして使う]#ライブラリとして使う
    - [Using an existing MelsecClient (recommended for multiple operations)]#using-an-existing-melsecclient-recommended-for-multiple-operations
    - [ワンショットヘルパー]#ワンショットヘルパー
    - [高レベル API の使い方]#高レベル-api-の使い方
  - [MC4E(拡張)に関する注意]#mc4e拡張に関する注意
  - [read\_4e サンプル]#read_4e-サンプル
  - [sled DB およびウォッチャー]#sled-db-およびウォッチャー
  - [今後の作業]#今後の作業

## クイックスタート

1. ビルド:

```powershell
cargo build
```

2. サンプルを実行(PLC の IP/ポートやバイト列を適宜変更してください):

```powershell
cargo run --example simple
```

## リリース v0.2.0

このリポジトリは `v0.2.0` タグが付与されています。変更の詳細は `CHANGELOG.md` を参照してください(プロトコル定数名の整理、2 バイト長プレフィックス処理の削除、ビットパッキングの修正、サンプルの更新など)。

GitHub Release を作成済みです。crates.io に公開されたら通常の依存指定で使えますが、公開前でもタグを指定して git 経由で利用できます:

```toml
[dependencies]
melsec_mc = { git = "https://github.com/tyaro/melsec_com", tag = "v0.2.0" }
```
## ライブラリとして使う

このクレートは他の Rust プロジェクトから利用できます。主な使い方は 2 通りです。

- crates.io から(公開後):

`Cargo.toml` に追加します:

```toml
[dependencies]
melsec_mc = "0.2.0"
```

- Git リポジトリから(開発中に便利):

```toml
[dependencies]
melsec_mc = { git = "https://github.com/tyaro/melsec_com", tag = "v0.2.0" }
```

基本的な使用例(async, Tokio ランタイム):

```rust
use melsec_mc::{MelsecClient, ConnectionTarget};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
	// Connect to PLC at 192.168.1.40:4020
	let mut client = MelsecClient::connect_with_timeout("192.168.1.40:4020", std::time::Duration::from_secs(5)).await?;
	// Optional: set a ConnectionTarget (access route / monitor timer) for convenience helpers
	let target = ConnectionTarget::direct("192.168.1.40:4020".to_string());
	client.set_target(target);

	// Read 3 bits from M10
	let bits = client.read_bits_for("M", 10, 3).await?;
	println!("bits: {:?}", bits);

	// Read 2 words from D100
	let words = client.read_words_for("D", 100, 2).await?;
	println!("words: {:?}", words);

	Ok(())
## リリースとアーティファクト

このリポジトリのビルド成果物(実行ファイルや ZIP アーカイブ)は Git 管理下には含めていません。ビルド成果物は GitHub Release または CI のアーティファクトとして提供します。下記は入手方法と簡単な検証手順です。

### リリースの入手方法

- GitHub の Releases ページ(https://github.com/tyaro/melsec_com/releases)から目的のタグ(例: `v0.2.4`)を選び、添付アセット(ZIP)をダウンロードしてください。

### アーティファクトの命名規約

- 生成されるファイル名の例:
	- `melsec_com-v{version}-linux-x86_64.zip`
	- `melsec_com-v{version}-linux-aarch64.zip`
	- `melsec_com-v{version}-macos-x86_64.zip`
	- `melsec_com-v{version}-macos-aarch64.zip`

- CI 実行の一時的なアーティファクト名は `melsec_com-{ref}-...zip` になることがありますが、リリースアセットとして公開する際は `v{version}` を含めるようにしています。

### チェックサム検証手順(SHA256)

- 各 ZIP ファイルには同名の `.sha256` ファイルが付属します(例: `melsec_com-v0.2.4-linux-x86_64.zip.sha256`)。ダウンロード後、ローカルで次のコマンドで検証できます。

Linux / macOS:

```sh
# ファイルの SHA256 を表示
shasum -a 256 melsec_com-v0.2.4-linux-x86_64.zip
# または
sha256sum melsec_com-v0.2.4-linux-x86_64.zip

# 付属の .sha256 と照合する
sha256sum -c melsec_com-v0.2.4-linux-x86_64.zip.sha256
```

PowerShell (Windows):

```powershell
Get-FileHash .\melsec_com-v0.2.4-linux-x86_64.zip -Algorithm SHA256 | Format-List
```

- 出力のハッシュ値が `.sha256` の値と一致すれば、ファイル整合性は確認できます。

### 備考

- リポジトリには生成物(`release_artifacts/``ci_artifacts_*` など)をコミットしない方針です(`.gitignore` に追加済み)。
- 必要であれば GPG 署名付きのチェックサムや署名の配布に対応できます(導入が必要なら手順を用意します)。

詳細は `docs/release_artifacts.md` にもまとめています。


### Using an existing MelsecClient (recommended for multiple operations)

If your program performs several operations in a row, create a single `MelsecClient`, set a `ConnectionTarget`, and reuse it for multiple reads/writes. This avoids reconnect overhead and keeps session-related behavior (MC4E serials, monitor timer) consistent.

```rust
use melsec_mc::{MelsecClient, ConnectionTarget};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
	let mut client = MelsecClient::connect_with_timeout("192.168.1.40:4020", std::time::Duration::from_secs(5)).await?;
	let target = ConnectionTarget::direct("192.168.1.40:4020".to_string());
	client.set_target(target);

	// reuse the same client for multiple operations
	let bits = client.read_bits_for("M", 10, 3).await?;
	println!("bits: {:?}", bits);

	let words = client.read_words_for("D", 100, 2).await?;
	println!("words: {:?}", words);

	Ok(())
}
```

### ワンショットヘルパー

短いスクリプトや一度だけ実行するコマンド向けに、接続を開いて単一の操作を実行し、接続を閉じるワンショットのヘルパー関数を提供しています。これらはクレートから再エクスポートされており、CLI 的な用途に便利です。

```rust
use melsec_mc::high_level;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
	let bits = high_level::read_bits("192.168.1.40:4020", "M", 10, 3, Some(5)).await?;
	println!("bits: {:?}", bits);
	Ok(())
}
```

#### ワンショットでの書き込み例(日本語)

短いスクリプトで PLC に値を書き込む例です。`write_words` / `write_bits` は内部で接続を開き、操作の後に切断します。

```no_run
use melsec_mc::high_level;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
	let addr = "192.168.1.40:4020";

	// ワード書き込みの例: D100 に 2 ワードを書き込む
	let words = vec![0x1122u16, 0x3344u16];
	high_level::write_words(addr, "D", 100, &words, Some(5)).await?;

	// ビット書き込みの例: M10 から 4 点を設定
	let bits = vec![true, false, true, true];
	high_level::write_bits(addr, "M", 10, &bits, Some(5)).await?;

	Ok(())
}
```


### 高レベル API の使い方

このライブラリは `high_level` モジュールといくつかの関数を上位で再エクスポートしています。
以下は代表的な使い方の例です。

- ワンショット関数(接続・実行・終了を自動で行う):

```no_run
use melsec_mc::read_bits; // または use melsec_mc::high_level::read_bits;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
	// 192.168.1.40:4020 の PLC から M10 を 3 点読み出す(タイムアウト 5 秒)
	let bits = read_bits("192.168.1.40:4020", "M", 10, 3, Some(5)).await?;
	println!("bits: {:?}", bits);

	// ワンショットでワード書き込み(例)
	let words = vec![0x1122u16, 0x3344u16];
	melsec_mc::write_words("192.168.1.40:4020", "D", 1000, &words, Some(5)).await?;

	Ok(())
}
```

- 既存の `MelsecClient` を使う場合(再接続を行わない。複数操作に向く):

```no_run
use melsec_mc::{MelsecClient, ConnectionTarget};
use melsec_mc::high_level::{read_bits_with_client, write_words_with_client};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
	let target = ConnectionTarget::direct("192.168.1.40:4020".to_string());
	let mut client = MelsecClient::connect_with_target(&target, std::time::Duration::from_secs(5)).await?;
	client.set_target(target.clone());

	// クライアントを渡してビット読み出し(再接続しない)
	let bits = read_bits_with_client(&mut client, "M", 10, 3).await?;
	println!("bits: {:?}", bits);

	// クライアントを渡してワード書き込み
	let values = vec![0x1122u16, 0x3344u16];
	write_words_with_client(&mut client, "D", 1000, &values).await?;

	Ok(())
}
```

注: ワンショット関数は短いスクリプトや一度きりの操作に便利です。長時間運用や複数回の読み書きを行う場合は、`MelsecClient` を生成して再利用する方式が効率的で安全です。

## MC4E(拡張)に関する注意

本ライブラリは MC4E 形式(サブヘッダ 0x54 / 0xD4)を基本的にサポートしています。MC4E ではリクエストと応答を対応付けるために 2 バイトのシリアルフィールドが含まれます。

- シリアルの自動付与: 送信する MC4E 要求のシリアルが 0(未設定)であれば、トランスポート層が自動で新しい u16 シリアルを割り当て、ペイロード内の該当バイトを書き換えて送信します。これによりサンプルでシリアルを書き忘れても問題になりません。
 
詳細な過去定義(旧 `mc3e.rs`)はドキュメントに移動しました: `docs/legacy_mc3e.md` を参照してください。


## read_4e サンプル

`examples/read_4e.rs` は MC4E の読み取りを試すためのサンプルです。使い方例:

```powershell

# 単発読み出し(シリアルを指定する例)
cargo run --example read_4e -- tcp 192.168.1.140 10 1 1

# TCP 送信で読み出す場合(ポート 4020 を使用)
cargo run --example read_4e -- tcp 192.168.1.140 10 1 1

# UDP で読み出す場合
cargo run --example read_4e -- udp 192.168.1.140 10 1 1

# 連続(順次)読み出し: アドレス 10 から 5 回の順次読み出し
cargo run --example read_4e -- tcp 192.168.1.140 10 1 0 seq:5

# 並列読み出し: 8 個の並列 MC4E リクエストを実行
cargo run --example read_4e -- tcp 192.168.1.140 10 1 0 parallel:8
```

サンプルは送信したペイロードと解析結果を表示します。MC4E ではライブラリが応答のシリアルを照合します(ペイロード内のシリアルまたは自動割当されたシリアルを使用します)。
## sled DB およびウォッチャー

<!-- removed per user request -->

## 今後の作業
- MC プロトコルのフレーム作成ヘルパー(サブヘッダ、コマンドコード、デバイスコードのエンコード)を実装する
- PLC やシミュレータを使ったユニットテスト/統合テストを追加する
- より高レベルな API(read_bits/read_words/write_bits/write_words)を追加する

## リリースとアーティファクト(補足)
詳細は \'docs/release_artifacts.md\' を参照してください。