LoginSignup
6
3

More than 5 years have passed since last update.

Theta V の Client Mode設定を間違えてしまってハマった話

Last updated at Posted at 2018-07-22

モチベーション

Theta VのイメージをRouter経由でPCで接続し、他の機器へ送りたい。
theta_router_pc.png

そこで、以下を参考にClient Modeの設定を変更しようとした。
WiFiのsecurityとpasswordを空にしたかったので、
空のstringでHTTP Post送ったらThetaがどこのWiFiにもアクセスできなくてハマった。
https://www.blacklab-blog.net/entry/theta_v/2

サポートデスクに連絡したら以下の通りリセットを推奨されましたが、
上手くいきませんでした。

■TEHTA V本体のリセット

THETA V本体が「電源オフ」の状態で、電源ボタンと
無線ボタンを同時に長押し(6秒以上)します。

※通常、ボタンを同時に長押している間に状態ランプ
  (シャッターボタンの上のランプ)が点滅し、点滅が
  終わってランプが消灯するとリセット完了となりま
  す。

■THETA V無線機能のリセット

THETA V本体が「電源オン」の状態で、無線ボタンを
長押し(6秒以上)します。カメラの電源が自動的にな
ってリセット完了となります。

USBを使ってMTP接続

APIの発見

THETAにはWiFiのほかにもUSBのAPIが用意されています。
https://developers.theta360.com/ja/docs/v2/usb_reference/

USB経由でコマンド送ればいいんだなーーーと思ったんですけど、
どうやるんだと???

ライブラリを作っている人発見

しっかり作ってくれている人がいました。

https://qiita.com/soundkonchan/items/d392794d57dc849720f3
https://github.com/kon0524/WpdMtp

早速試していきます

1. まずはダウンロード

git clone git@github.com:kon0524/WpdMtp.git

2. Visual Studio 2017で開く

WpdMtpLib.slnを開きます
Testプロジェクトを「スタートアッププロジェクトに設定」するのを忘れないでください
image.png

Testプロジェクトの中のProgram.csを変えていきます。

2.1 デバイスの名前を自分のThetaに変更する

MtpResponse res;
MtpCommand command = new MtpCommand();

// 接続されているデバイスIDを取得する
string[] deviceIds = command.GetDeviceIds();
if (deviceIds.Length == 0) { return; }

// RICOH THETA V デバイスを取得する
string targetDeviceId = String.Empty;
foreach (string deviceId in deviceIds)
{
    Console.WriteLine(command.GetDeviceFriendlyName(deviceId));
    if ("RICOH THETA V".Equals(command.GetDeviceFriendlyName(deviceId)))
    {
        targetDeviceId = deviceId;
        break;
    }

2.2 デバイス情報(deviceInfo)の上手くいくか試してみます。

メイン文にいろいろ書いてありますが、とりあえずDeviceInfoだけ取得してみます。
DeviceInfo以外のcommand.Executeはすべて消します。

            // DeviceInfo
            res = command.Execute(MtpOperationCode.GetDeviceInfo, null, null);
            DeviceInfo deviceInfo = new DeviceInfo(res.Data);
            Console.WriteLine(deviceInfo.Manufacturer);

コンソールが最後閉じてしまうので、キーが押されるまで閉じないようにします


            Console.WriteLine();
            Console.WriteLine("Press any key to continue.");
            Console.ReadKey();

            // デバイスよさようなら
            command.Close();

実行するとTheta Vの情報が取れます。

2.3 DeviceInfoに見習ってAcccessPointを取得するExecute Commandを書いていきます。

            res = command.Execute(MtpOperationCode.GetAccessPointHandles, null, null);
            uint[] accessPointHandles = Utils.GetUIntArray(res.Data);

この時MtpOperationCodeGetAccessPointHandlesはないので追加していきます。
他のAPIもついでに追加してしまいましょう。

MtpOperationCode.cs
namespace WpdMtpLib
{
    /// <summary>
    /// MTPオペレーションコード(Thetaでサポートしている値のみ)
    /// </summary>
    public enum MtpOperationCode : ushort
    {
        GetDeviceInfo           = 0x1001,
        OpenSession,
        CloseSession,
        GetStorageIDs,
        GetStorageInfo,
        GetNumObjects,
        GetObjectHandles,
        GetObjectInfo,
        GetObject,
        GetThumb,
        DeleteObject,
        InitiateCapture         = 0x100E,
        GetDevicePropDesc       = 0x1014,
        GetDevicePropValue,
        SetDevicePropValue,
        TerminateOpenCapture    = 0x1018,
        GetPartialObject        = 0x101B,
        InitiateOpenCapture,
        StopSelfTimer           = 0x99A2,
        GetAccessPointHandles   = 0x99A3,
        GetAccessPointInfo      = 0x99A4,
        SetAccessPoint          = 0x99A5,
        DeleteAccessPoint       = 0x99A6,
        SetAccessPointPassword  = 0x99AD
    }
}

OperationCodeは分かったのでGetAccessPointInfoが何をする子なのか教えてあげます。
MtpOperation.csファイルにデータを書き込むのか読み込むのかを記述します。

MtpOperation.cs
        private static Dictionary<MtpOperationCode, DataPhase> OperationCode2DataPhase
            = new Dictionary<MtpOperationCode, DataPhase>()
            {
                // データフェーズのないオペレーション
                {MtpOperationCode.OpenSession,          DataPhase.NoDataPhase},
                {MtpOperationCode.CloseSession,         DataPhase.NoDataPhase},
                {MtpOperationCode.GetNumObjects,        DataPhase.NoDataPhase},
                {MtpOperationCode.DeleteObject,         DataPhase.NoDataPhase},
                {MtpOperationCode.InitiateCapture,      DataPhase.NoDataPhase},
                {MtpOperationCode.TerminateOpenCapture, DataPhase.NoDataPhase},
                {MtpOperationCode.InitiateOpenCapture,  DataPhase.NoDataPhase},
                {MtpOperationCode.StopSelfTimer,        DataPhase.NoDataPhase},
                {MtpOperationCode.DeleteAccessPoint,    DataPhase.NoDataPhase},

                // R->Iのデータフェーズがあるオペレーション
                {MtpOperationCode.GetDeviceInfo,            DataPhase.DataReadPhase},
                {MtpOperationCode.GetStorageIDs,            DataPhase.DataReadPhase},
                {MtpOperationCode.GetStorageInfo,           DataPhase.DataReadPhase},
                {MtpOperationCode.GetObjectHandles,         DataPhase.DataReadPhase},
                {MtpOperationCode.GetObjectInfo,            DataPhase.DataReadPhase},
                {MtpOperationCode.GetObject,                DataPhase.DataReadPhase},
                {MtpOperationCode.GetThumb,                 DataPhase.DataReadPhase},
                {MtpOperationCode.GetDevicePropDesc,        DataPhase.DataReadPhase},
                {MtpOperationCode.GetDevicePropValue,       DataPhase.DataReadPhase},
                {MtpOperationCode.GetPartialObject,         DataPhase.DataReadPhase},
                {MtpOperationCode.GetAccessPointHandles,    DataPhase.DataReadPhase},
                {MtpOperationCode.GetAccessPointInfo,       DataPhase.DataReadPhase},
                // I->Rのデータフェーズがあるオペレーション
                {MtpOperationCode.SetDevicePropValue,       DataPhase.DataWritePhase},
                {MtpOperationCode.SetAccessPoint,           DataPhase.DataWritePhase},
                {MtpOperationCode.SetAccessPointPassword,   DataPhase.DataWritePhase}
            };

2.4 ハンドラーからAccessPointInfoを取得する

最終的にこうなります。

            res = command.Execute(MtpOperationCode.GetAccessPointHandles, null, null);
            uint[] accessPointHandles = Utils.GetUIntArray(res.Data);
            foreach(uint handle in accessPointHandles)
            {

                res = command.Execute(MtpOperationCode.GetAccessPointInfo, new uint[1] { handle }, null);
                foreach(byte b in res.Data)
                {
                    Console.Write(b);
                    Console.Write(" ");
                }
                AccessPointInfo accessPointInfo = new AccessPointInfo(res.Data);
                Console.WriteLine("");
                Console.WriteLine(accessPointInfo.SSID);

情報を抽出するためにはAccessPointInfo型を定義しないといけないので、定義します。
新しくAccessPointInfo.csファイルを作成し

AccessPointInfo.cs
using System;

namespace WpdMtpLib
{
    public class AccessPointInfo
    {
        public string   SSID                { get; private set; }
        public ushort   SSIDStealth         { get; private set; }
        public string   Security            { get; private set; }
        public ushort   ConnectionPriority  { get; private set; }
        public ushort   IpAddressAllocation { get; private set; }
        public uint     IPAddress           { get; private set; }
        public uint     SubnetMask          { get; private set; }
        public uint     DefaultGateway      { get; private set; }


        public AccessPointInfo(byte[] data)
        {
            int pos = 0;
            SSID                = Utils.GetString(data, ref pos);
            SSIDStealth         = BitConverter.ToUInt16(data, pos); pos += 2;
            Security            = Utils.GetString(data, ref pos);
            ConnectionPriority  = BitConverter.ToUInt16(data, pos); pos += 2;
            IpAddressAllocation = BitConverter.ToUInt16(data, pos); pos += 2;
            IPAddress           = BitConverter.ToUInt32(data, pos); pos += 4;
            SubnetMask          = BitConverter.ToUInt32(data, pos); pos += 4;
            DefaultGateway      = BitConverter.ToUInt32(data, pos);
        }
    }
}

2.5 最後に消したいAccessPointを削除します。

                res = command.Execute(MtpOperationCode.DeleteAccessPoint, new uint[1] { handle }, null);

実行

Ctrl + F5で実行して消します。

最終的なProgram.csのMain文コード

Program.cs
        static void Main(string[] args)
        {
            MtpResponse res;
            MtpCommand command = new MtpCommand();

            // 接続されているデバイスIDを取得する
            string[] deviceIds = command.GetDeviceIds();
            if (deviceIds.Length == 0) { return; }

            // RICOH THETA V デバイスを取得する
            string targetDeviceId = String.Empty;
            foreach (string deviceId in deviceIds)
            {
                Console.WriteLine(command.GetDeviceFriendlyName(deviceId));
                if ("RICOH THETA V".Equals(command.GetDeviceFriendlyName(deviceId)))
                {
                    targetDeviceId = deviceId;
                    break;
                }
            }
            if (targetDeviceId.Length == 0) { return; }
            command.Open(targetDeviceId);

            // イベントを受け取れるようにする
            command.MtpEvent += MtpEventListener;


            // DeviceInfo
            res = command.Execute(MtpOperationCode.GetDeviceInfo, null, null);
            DeviceInfo deviceInfo = new DeviceInfo(res.Data);
            Console.WriteLine(deviceInfo.Manufacturer);

            res = command.Execute(MtpOperationCode.GetAccessPointHandles, null, null);
            uint[] accessPointHandles = Utils.GetUIntArray(res.Data);
            foreach(uint handle in accessPointHandles)
            {

                res = command.Execute(MtpOperationCode.GetAccessPointInfo, new uint[1] { handle }, null);
                foreach(byte b in res.Data)
                {
                    Console.Write(b);
                    Console.Write(" ");
                }
                AccessPointInfo accessPointInfo = new AccessPointInfo(res.Data);
                Console.WriteLine("");
                Console.WriteLine(accessPointInfo.SSID);

                res = command.Execute(MtpOperationCode.DeleteAccessPoint, new uint[1] { handle }, null);
            }

            Console.WriteLine();
            Console.WriteLine("Press any key to continue.");
            Console.ReadKey();

            // デバイスよさようなら
            command.Close();
        }
6
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
3