Simulinkから生成されたCコードをRustから呼び出す

# これはなに？
完全に車輪の再発明と思いますがSimulinkから生成されたCコードをRustから呼び出すことをためしてみました。

今後、もしかするとベアメタル組み込み開発の足回りがRustで開発される未来がくるかもな～と妄想したので試してみた次第です。

# 環境
OS: Windows 10 
VS Code: 1.66.2

Rust
```
> cargo --version
cargo 1.51.0 (43b129a20 2021-03-16)
> rustc -V
rustc 1.51.0 (2fd73fabe 2021-03-23)
> rustup -V
rustup 1.23.1 (3df2264a9 2020-11-30)
info: This is the version for the rustup toolchain manager, not the rustc compiler.
info: The currently active `rustc` version is `rustc 1.51.0 (2fd73fabe 2021-03-23)`
```
MATLAB
```
>> ver
---------------------------------------------------------------------------------------------------
MATLAB バージョン: 9.12.0.1884302 (R2022a)
MATLAB ライセンス番号: ======ひみつ=====
オペレーティング システム: Microsoft Windows 10 Enterprise Version 10.0 (Build 19044)
Java バージョン: Java 1.8.0_202-b08 with Oracle Corporation Java HotSpot(TM) 64-Bit Server VM mixed mode
```

# やってみたこと

## 1. cargo new でプロジェクト作成と.tomlの編集
slcode_call_from_rustって名前で作ってみます。

えっCargoって何？ Rustってどうやって環境整えるの？って人はこの辺を御覧ください。
+ Cargoについて学ぶ: https://qiita.com/yoshii0110/items/6d70323f01fefcf09682
+ Rustコーディング環境構築@VSCode: https://zenn.dev/23prime/articles/74cda5a096a3b3


```
> cargo new slcode_call_from_rust
     Created binary (application) `slcode_call_from_rust` package
```
そうすると勝手にフォルダとファイルができますがそのうちのCargo.tomlファイルを編集しましょう。
これをやっておくと後々やる``cargo run ``とか`` cargo build ``したタイミングで指定したcソースをライブラリとしてコンパイルする作業もまとめてやってくれるようになります。


Cargo.tomlファイルはパッケージマネージャ及びRustのビルドシステムであるCargoの設定を記述できます。

### Cargo.toml
```Rust
[package]
name = "slcode_call_from_rust"
version = "0.1.0"
authors = ["griffin921"]
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
```

ここで下記のように追加しました。

+ links は依存ライブラリを記述するもの - http://doc.crates.io/build-script.html#the-links-manifest-key
+ build はパッケージビルドパスを指定します。ここで指定したbuild.rsにビルドを実行する際の動作をRustで記述します。
+ [dependencies]に追加した[libc](https://crates.io/crates/libc) は char や int などの C API の型が定義されているクレートで、こいつを依存関係に含めることでC言語の型を扱えます
+ [build-dependencies]に追加した[cc](https://crates.io/crates/cc)はC/C++/アセンブリをRustライブラリ/アプリケーションにコンパイルするための機能を提供するクレートでビルドスクリプトに利用するのでここに追加しています。

```Rust
[package]
name = "slcode_call_from_rust"
version = "0.1.0"
authors = ["griffin921"]
edition = "2018"

links = "counter_model"
build = "build.rs"

[dependencies]
libc = "0.2.0"

[build-dependencies]
cc = "1.0.72"
```

### build.rs

外部クレート ccを使ってビルド定義を行います。
ビルド対象となるCソースは.fileに、
インクルードパスは.includeに
cをコンパイルしてライブラリファイルとして出力する際のファイル名を.compileに記述しました。


.fileに記述したPassは今はまだないですが、src/simulinkフォルダを後ほど作り、
counter_model.slxというモデルをコード生成した際に
counter_model_ert_rtwというフォルダがSimulinkが自動生成して、その下にコードを生成してくれるので
それを見越してこのPassにしています。

こちらは生成されるコードのディレクトリ名が異なればその都度変更が必要なので注意しましょう。

```Rust
extern crate cc;

fn main(){
    cc::Build::new()
                .file("src/simulink/counter_model_ert_rtw/counter_model.c")
                .include("src")
                .compile("libsl.a");
}
```

## 2. Simulinkモデルの作成
Cargoが自動生成してくれたslcode_call_from_rust直下のsrcフォルダに"simulink"フォルダを作成しましょう。

```
\slcode_call_from_rust> mkdir src/simulink
```
そのフォルダに下記のようなモデルを作ってみました。モデル名はbuild.rsの定義に合わせて
"counter_model"にしました。
非常に簡単なモデルですね。入力信号に対して加算をしていく処理になっています。
データ型はint32としました。

![Snag_3f233a9f.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/331637/639caf9a-adbf-708b-0156-06b311783dc6.png)

## 3. コード生成
次にコード生成のために必要な設定をしていきましょう。
+ モデル設定を押してソルバータイプを固定ステップに変更し、ソルバーを離散（連続状態なし）とする
![Snag_3f27e11c.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/331637/9f3de9e8-3bef-a1f8-6190-faa391afec37.png)

+ コード生成の設定から　ターゲットの選択でシステムターゲットファイルをert.tlcに変更
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/331637/370398d4-0d29-6fea-98b5-9539786b2120.png)

+ アプリタブからEmbedded CoderをクリックしてCコードタブを開く（ここでEmbedded CoderのライセンスをMATALBが掴みます）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/331637/69d9f458-a5d2-e357-b153-e7b37c59edbd.png)

+ Cコードタブの”コードインタフェース”->”規定のコードマッピング"を選んでモデル画面下にコードマッピングウィンドウを表示させます。
![Snag_3f2dad3e.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/331637/2c5a6137-69e5-d634-2d09-2363a9646062.png)

+ functionsタブ を開き、下の図の通り操作して、コード生成後の関数の引数、戻り値を指定しておきます。
+ ここらへんのインタフェースの変え方、たとえば引数でなくてグローバル変数にしたいとか。色々変えれるみたいなのですがワイは実はEmbedded Coderの詳細機能についてはよくわからんのです・・・
+ ここらへん知りたい方はぜひ[MATALB Answers](https://jp.mathworks.com/matlabcentral/answers/index)に投稿してみてください。僕より詳しい人が教えてくれます。
![Snag_3f3371ae.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/331637/8e97633b-bf01-dc1f-79f9-b0eb7d0f764f.png)

+ コード生成ボタンでCコードを生成します。
+ counter_model_stepというところにSimulinkモデル記述と等価なCコードがでているのがわかります。
![Snag_3f35a25a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/331637/e1828cae-c1cd-0e39-0434-1e038825ce9d.png)

## 5. .hファイルから.rsファイルを生成
bindgenを使ってEmbedded Coderが吐き出してくれたヘッダ"counter_model.h"からcounter_model.rsを作りましょう。

あ、事前に``cargo install bindgen``でインストールをしておいてくださいね。
main.rsから見える位置にcounter_model.rsを作りたいのでこのようにします。
```
slcode_call_from_rust\src\simulink\counter_model_ert_rtw> bindgen .\counter_model.h > ../../counter_model.rs
```
ちゃんとできとります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/331637/07ba28ed-db87-943b-0572-8cf3e5830b38.png)

## 6. main.rsを書く

bindgenから生成されたcounte_model.rsをモジュールとして指定し、
useでcounter_model.rs内のcounter_model_step関数を使えるようにします。

生成したコード、counter_model_stepに引数１を与えてfor文で4回実行してみましょう。
Rustでは外部のソースで記述された関数の安全性までは担保できないので、
unsafeスコープ内で実行します。

```RUST
mod counter_model;
pub use counter_model::counter_model_step;

fn main() {
    println!("Hello, world!");

    for n in 1..=4{
        unsafe{
            println!("Step:{}",counter_model_step(1));
        }
    }
    
}
```

## 7. cargo runする

```
slcode_call_from_rust> cargo run
```
こうするとなんだか大量にワーニングが出ますが、ほとんどがSimulinkから生成されたコードに対して
キャメル型ではなくスネーク型で変数名を宣言せよ！等というアドバイスなので無視します。
でも逆にビルドシステムがこういうの言ってくれるのはスゴイですよね。
うざったい人もいるかもしれないけれど私はこういうところは好きです。

そして実行結果はこうなります。

```
Hello, world!
Step:1
Step:2
Step:3
Step:4
```

おおおおおお！！
ちゃんとステップごとに加算していますね！
同じ引数１を与えて同じ関数を実行していますが、ちゃんとSimulinkでつくったUnitDelayに相当するコードが
前回値を覚えてくれているので加算していっています。

# まとめ
普通に下記参考文献でかいてあったことをまとめただけなような気がしますが・・・
ご参考になれば幸いです。

あ、あとRustホントにわかってないんで使い方間違ってたらコメントください！
いつもありがとうございます！


# 参考文献
+ rustでCで書いた関数を呼ぶ / Cからrustで書いた関数を呼ぶ: https://mmi.hatenablog.com/entry/2017/02/28/213656
+ Rust公式ドキュメント FFI: Foreign Function Interface：https://doc.rust-lang.org/nomicon/ffi.html
+ rust-bindgen で手軽に共有ライブラリを動的読み込み　https://tech-blog.optim.co.jp/entry/2021/05/27/100000