PJLinkを使いプロジェクターを操作する

Ricohのプロジェクターを操作する

研究室で使用しているRicohのプロジェクターを手元から操作をしたかったので,そのような規格がないか探していました.Ricohのプロジェクターで対応している規格は複数個あったのですが,一番ドキュメントが充実していたPJLinkという規格を使用して操作をしてみました.

PJLinkの仕組み

以下に図がPJLinkの一通りの流れになります(https://pjlink.jbmia.or.jp/data/5-1_PJLink_20131210.pdfから引用).

  1. TCPでコネクションを確立する.
  2. プロジェクタからネゴシエーションのためのコードを受け取る.
  3. クライアント側からコマンドを送信する.
  4. 30秒以内であれば,何回もコマンドを送信できる. https://pjlink.jbmia.or.jp/data/5-1_PJLink_20131210.pdfから引用

公式からPJLinkを試すためのソフトが公開されていますが,今回はGUIからではなくCLIから操作を行いたいので,RustでCLIツールを作りました.

use std::io::{Error, Read, Write};
use std::net::{TcpListener, TcpStream, Shutdown};
use std::str::from_utf8;
use std::net::ToSocketAddrs;
use structopt::{clap, StructOpt};

#[derive(StructOpt, Debug)]
#[structopt(name = "joseph")]
#[structopt(setting(clap::AppSettings::ColoredHelp))]
struct Opt {
    #[structopt(name = "CMD")]
    command: String,

    #[structopt(name = "parrameter")]
    transmission: String,
}


fn main() {
    //command argument
    let opt = Opt::from_args();
    //println!("{:#?}", &opt);
    
    let command = &opt.command;
    let transmission_parameters = &opt.transmission;
    println!("{} {}", command, transmission_parameters);

    match TcpStream::connect("[プロジェクターのIP]:4352") {
        Ok(mut stream) => {
            println!("Successfully connected to server");
            let mut data = [0 as u8; 9];
            
            stream.read_exact(&mut data);
            let negotiation = from_utf8(&data).unwrap();
            println!("{}", negotiation);
            send_command(stream, command, transmission_parameters);
        },
        Err(e) => {
            println!("Failed to connect: {}", e);
        }
    }
}

fn send_command(mut stream: TcpStream, command: &str, transmission_parameters: &str) {
    let command_header = "%1";
    let separater = " ";
    let terminal_symbol = "\r";
    let send_command = command_header.to_owned() + command + separater + transmission_parameters + terminal_symbol;
    println!("{}", send_command);
    let mut recv_data = [0 as u8; 9];
    stream.write(send_command.as_bytes()).unwrap();
    // recv_data 
    stream.read_exact(&mut recv_data);
    let result = from_utf8(&recv_data).unwrap();
    println!("{}", result);
}

コマンドの構造

PJLinkでのプロジェクターに送信するコマンドについて,示します.

ヘッダークラス コマンド本体 セパレータ 送信パラメータ 終端(CR)
2バイト 4バイト 1バイト 128バイト以内 1バイト

コマンドの例を示します.

ヘッダークラス コマンド本体 セパレータ 送信パラメータ 終端(CR)
%1 POWR 1 \r

コマンド一覧

以下のコマンドは実際にプロジェクターに送信して実行がされたものになります.(ヘッダークラスと終端記号は除く) 機種によってはコマンドのパラメータが違うと思うので,実際にパラメータを送信して確認してみてください.

コマンド パラメータ 期待される結果
POWR 0 電源オフ
POWR 1 電源オン
POWR ? 電源状態問合せ
INPT 31 HDMI入力に切り替わる
INPT 41 USB入力
INPT 51 ネットワーク経由入力
INPT 53 Miracast入力
NAME ? プロジェクタ名の問い合わせ

参考資料

PjLink仕様書