AIに“RSフリップフロップつくって”と言うだけで、連枝にラダーが書き込まれ→HEX生成→PIC/H8へ書込み→即動作
やりたいこと=「AIに“RSフリップフロップつくって”と言うだけで、連枝にラダーが書き込まれ→HEX生成→PIC/H8へ書込み→即動作」ですね。
以下の最小実装をそのまま置けば動線がつながります。
---
全体フロー(ワンコマンド)
AI → MCPコマンド rsff_build_and_flash
① RS-FFのラダー生成(テキストDSL)
② 連枝をヘッドレス操作してHEX生成(renri-cli ラッパ)
③ PIC/H8へ書込み(pk3cmd など)
④ 必要ならシミュレーションログ返却
---
1) RSフリップフロップのラダー(テキストDSL例)
入力: X0=R, X1=S
出力: Y0=Q(自己保持つき), Y1=/Q(オプション)
TITLE: RS Flip-Flop
CPU: PIC16F84A
SCAN_MS: 5
I: X0 R, X1 S
O: Y0 Q, Y1 NQ
M: M0 LATCH_Q ; 内部ビット
; RUNG1: セット
RUNG: X1 -> (SET M0) ; S で M0=1
; RUNG2: リセット
RUNG: X0 -> (RST M0) ; R で M0=0
; RUNG3: 出力Q(自己保持は M0 が担うのでそのまま反映)
RUNG: M0 -> Y0
; RUNG4: 反転出力NQ(任意)
RUNG: /M0 -> Y1
> 連枝への食わせ方は後述の「renri-cli(自作ラッパ)」で .renri 相当のプロジェクトに流し込みます。
---
2) MCPサーバ(Node/TypeScript・最小)
> rsff_build_and_flash が “生成→コンパイル→書込み” を一気にやります。
ここで呼んでいる renri-cli は、後ろにある AutoHotkey スクリプトで 連枝GUIを自動操作してHEXを吐かせるラッパです(ファイル監視→保存→コンパイル→out.hex)。
// src/server.ts
import { Server } from "@modelcontextprotocol/sdk";
import { execFile } from "child_process";
import fs from "fs/promises";
import path from "path";
const srv = new Server({ name: "renri-mcp", version: "0.1.0" });
function rsffDSL(cpu: "PIC16F84A" | "PIC16F877A" | "H8/3694" = "PIC16F84A") {
return [
"TITLE: RS Flip-Flop",
`CPU: ${cpu}`,
"SCAN_MS: 5",
"I: X0 R, X1 S",
"O: Y0 Q, Y1 NQ",
"M: M0 LATCH_Q",
"RUNG: X1 -> (SET M0)",
"RUNG: X0 -> (RST M0)",
"RUNG: M0 -> Y0",
"RUNG: /M0 -> Y1",
""
].join("\n");
}
// ① 生成(単独で呼べるようにも定義)
srv.command("generate_rsff_ladder", async ({ cpu }: { cpu?: string }) => {
return { ladderSrc: rsffDSL((cpu as any) ?? "PIC16F84A") };
});
// ② 連枝コンパイル(renri-cli は自作ラッパ。後述)
srv.command("compile_ladder", async ({ ladderSrc, cpu }: { ladderSrc: string, cpu: string }) => {
const work = await fs.mkdtemp(path.join(process.cwd(), "build-"));
const inFile = path.join(work, "in.renri.txt");
const hexFile = path.join(work, "out.hex");
await fs.writeFile(inFile, ladderSrc, "utf8");
await new Promise<void>((resolve, reject) => {
execFile("renri-cli", ["--compile", inFile, "--cpu", cpu, "-o", hexFile],
{ timeout: 120000 }, (err, stdout, stderr) => err ? reject(new Error(stderr || err.message)) : resolve());
});
return { hexPath: hexFile };
});
// ③ 書込み(PICkit3 例:pk3cmd。H8の書込みツールに差替可)
srv.command("flash_hex", async ({ hexPath, device, port }: { hexPath: string, device: string, port?: string }) => {
const args = ["-M", "-P", device, "-F", hexPath];
if (port) args.push("-B", port);
await new Promise<void>((resolve, reject) => {
execFile("pk3cmd", args, { timeout: 60000 }, (err, stdout, stderr) =>
err ? reject(new Error(stderr || err.message)) : resolve());
});
return { status: "flashed", device };
});
// ④ ワンショット(生成→コンパイル→書込み)
srv.command("rsff_build_and_flash", async ({ cpu, device, port }:
{ cpu?: string, device: string, port?: string }) => {
const ladderSrc = rsffDSL((cpu as any) ?? "PIC16F84A");
const { hexPath } = await srv.invoke("compile_ladder", { ladderSrc, cpu: (cpu ?? "PIC16F84A") });
const res = await srv.invoke("flash_hex", { hexPath, device, port });
return { ...res, hexPath };
});
srv.listen();
---
3) 連枝GUI自動化ラッパ(AutoHotkey v1 例)
> 連枝の「ファイルを開く→テキストを流し込む→コンパイル→HEX保存」手順を自動化。
renri-cli.exe --compile in.renri.txt --cpu PIC16F84A -o out.hex のように呼ばれます。
; renri-cli.ahk → exe化して PATH に置く
; 使い方: renri-cli --compile input.txt --cpu PIC16F84A -o out.hex
#NoEnv
SendMode Input
SetWorkingDir %A_ScriptDir%
; 引数解析
compile := false
infile := ""
cpu := ""
outfile := ""
Loop, %0%
{
p := %A_Index%
if (p = "--compile") { compile := true, A_Index++, infile := %A_Index% }
else if (p = "--cpu") { A_Index++, cpu := %A_Index% }
else if (p = "-o") { A_Index++, outfile := %A_Index% }
}
if (!compile || infile="")
{
MsgBox, 48, renri-cli, Usage: renri-cli --compile input.txt --cpu PIC16F84A -o out.hex
ExitApp, 1
}
; 1) 連枝起動
Run, "C:\Program Files\Renri\renri.exe"
WinWaitActive, 連枝
; 2) 新規/開く等 → テキスト投入(ここは連枝の画面構成に合わせて調整)
; 例:メニュー操作やショートカットでエディタ枠へ貼り付け
FileRead, ladder, %infile%
Send, ^a
Sleep, 100
Clipboard := ladder
Send, ^v
Sleep, 200
; 3) CPU 選択(ダイアログに合わせてキー送り)
; 例: Alt+C で CPU 設定 → PIC16F84A を選ぶ、のような手順を記録
; ここは各自の連枝バージョンに合わせて微調整
; Send, !c
; ...(選択操作)...
; 4) コンパイル
; 例:Alt+B でビルド
; Send, !b
; ビルド完了待ち(ログウィンドウの文字列待ちに置換OK)
Sleep, 1500
; 5) HEX 保存
; 例:Ctrl+Shift+S で保存ダイアログ
; Send, ^+s
; 待ってからパス入力
; WinWaitActive, 名前を付けて保存
; ControlSetText, Edit1, %outfile%
; Send, {Enter}
; 簡略化のため、仮に連枝が既定フォルダに out.hex を吐く前提でコピー:
FileCopy, %A_MyDocuments%\Renri\out.hex, %outfile%, 1
; 6) 終了
WinClose, 連枝
ExitApp, 0
> 上記は雛形です。実機の連枝UI(メニュー名/ショートカット/ウィンドウ名)に合わせて数行調整すれば動きます。exe化して renri-cli.exe として使ってください。
---
4) 書込み(PICkit3 の例)
例:pk3cmd -M -P PIC16F84A -F out.hex
H8なら、使うROMライタ(秋月/RENESAS等)のCLIに差し替え。同じ MCP の flash_hex に接続するだけです。
---
5) AI側からの使い方(例)
MCP対応のクライアント(ChatGPTや自作UI)で、以下のどちらかを呼ぶだけ。
素直にワンショット:
rsff_build_and_flash({ cpu: "PIC16F84A", device: "PIC16F84A" })
分割(確認しながら):
1. generate_rsff_ladder({ cpu: "PIC16F84A" })
2. compile_ladder({ ladderSrc, cpu: "PIC16F84A" })
3. flash_hex({ hexPath, device: "PIC16F84A" })
---
6) 配線と確認(最小)
X0=R, X1=S はプルダウン/プルアップどちらかに統一し、接点の正論理/負論理を実機に合わせてDSLの /(反転)を調整。
Y0(Q)はLED等で視認、Y1(/Q)は任意。
初期化で Q=0 始動にしたい場合、電源投入直後に RST M0 の一発タイマを足す手も有効。
---
7) つまずき対策
HEXが出ない:renri-cli のステップ(起動→貼付→CPU選択→ビルド→保存)を AutoHotkey で一度手動記録し、WinWaitActive と Control* 系で確定待ちを入れる。
書込み失敗:pk3cmd の -B(ツールポート/ボード選択)や電圧、デバイス名を見直し。
S/R同時1:RS-FF仕様上は未定義。必要なら「S優先」「R優先」のどちらかにブロッキング論理を1行追加(例:RUNG: X0 & /X1 -> (RST M0) など)。
---
この構成なら、「AIに“RSフリップフロップ作って”と頼む→実機が即Qを保持する」までワンコマンドで回せます。
次にやることは、(A) ターゲットMCU型番, (B) 連枝のメニュー/ショートカット確認, (C) ライタCLIの決定の3点です。ここが固まれば、renri-cli.ahk の数行調整と device 名をあなたの環境に合わせるだけで完成します。
コメント
コメントを投稿