USBでニコンのカメラをコントロールするリモートコントローラの続きです。ソフトウェアはオープンソースのPTPライブラリを使って実装しましたが、これは単にリモコンからカメラをコントロールするだけで、逆にカメラ側の設定をリモコンに反映させたり、撮影が終わったことをカメラから教えてもらったりすることができませんでした。今回はそこを実装します。
ニコンのカメラはカメラに記録されているイベントを取得するのに
GetEvent 0x9C07
というベンダコードが用意されています。これを呼び出すと、その前に起こった、例えばシャッタスピードが変化した、とか、撮影が完了した、とか、ファイルが追加された、というイベントが一覧として取得できます。このコマンドを定期的にポーリングしてやると、カメラ内部で起こっている変化を常に取得することができます。
が、このコマンドを呼び出してみると、
直すところは
・nkeventparser.cpp
の43行目
ニコンから取り寄せられるPTPコマンド仕様書によると、GetEventコマンドで取得できるデータは
というふうに、最初の2バイトでイベント数、その後2バイトでイベントコード、4バイトでイベントのパラメータが繰り返す、という作りになっています。上記で変更したNKEventは、そのイベントデータを受け取るための構造体で、nkeventparser.hで次のように定義されています。
ちょうど2バイトのイベントコードと4バイトのパラメータの組み合わせとなっていて、パラメータは2バイトx2あるいは4バイトのどちらかを共用体で選べるようになっています。そして
theBuffer.valueSize = sizeof(NKEvent)
で、GetEventで受信したイベントデータをパースするために、イベントデータの繰り返しサイズを指定しています。
ですが、このPTPライブラリはオリジナルのArduinoで使われている8bitのAVRマイコン向けに作られたもの。8bit環境だとsizeof()で構造体の実データサイズ6を返してくれますが、ESP32は32bitマイコンなので、パディングが入って4の倍数の8を返してしまいます。そのためPTPで取得したデータサイズ以上のアドレスにアクセスして、落ちていた、ということでした。
実際には数字直打ちでなくて、defineするとか、マナーは守りましょう。
ついでに前回とりあえずビルドを通すためにいい加減に直した
無事イベントが取れるようになりました。
これはシャッタを切ったときに発生するイベントで、古い順に
撮影した画像が追加された。
撮影完了
動画記録禁止条件変更
カードに記録可能な枚数が変更
になります。RAWとJPEGを両方記録するような設定になっているときはObject Addedイベントが2回飛んできます。
ニコンのカメラはカメラに記録されているイベントを取得するのに
GetEvent 0x9C07
というベンダコードが用意されています。これを呼び出すと、その前に起こった、例えばシャッタスピードが変化した、とか、撮影が完了した、とか、ファイルが追加された、というイベントが一覧として取得できます。このコマンドを定期的にポーリングしてやると、カメラ内部で起こっている変化を常に取得することができます。
が、このコマンドを呼び出してみると、
17:19:11.730 -> Guru Meditation Error: Core 1 panic'ed (Double exception) 17:19:11.730 -> Core 1 register dump: 17:19:11.730 -> PC : 0x400803c0Guru Meditation Error: Core 1 panic'ed (LoadStoreError). Exception was unhandled. 17:19:11.730 -> Core 1 register dump: 17:19:11.730 -> PC : 0x4008bfc5Guru Meditation Error: Core 1 panic'ed (LoadStoreError). Exception was unhandled.と落ちてしまいます。
直すところは
・nkeventparser.cpp
の43行目
case 3: theBuffer.valueSize = sizeof(NKEvent); valueParser.Initialize(&theBuffer); nStage = 4;を
case 3: theBuffer.valueSize = 6; valueParser.Initialize(&theBuffer); nStage = 4;に変更します。オリジナルのソースはこちらから見られます。
ニコンから取り寄せられるPTPコマンド仕様書によると、GetEventコマンドで取得できるデータは
| Offset | Value | Name | 行Discription |
| 0 | N | EventCount | イベント数 |
| 2 | EventCode | EventCode[0] | 最も古いイベント |
| 4 | EventParameter[0] | 最も古いイベントに付随するパラメータ | |
| 8 | EventCode | EventCode[1] | 二番目に古いイベント |
| 10 | EventParameter[1] | 二番目に古いイベントに付随するパラメータ |
というふうに、最初の2バイトでイベント数、その後2バイトでイベントコード、4バイトでイベントのパラメータが繰り返す、という作りになっています。上記で変更したNKEventは、そのイベントデータを受け取るための構造体で、nkeventparser.hで次のように定義されています。
struct NKEvent
{
uint16_t eventCode;
union
{
struct
{
uint16_t wParam1;
uint16_t wParam2;
};
uint32_t dwParam;
};
};
ちょうど2バイトのイベントコードと4バイトのパラメータの組み合わせとなっていて、パラメータは2バイトx2あるいは4バイトのどちらかを共用体で選べるようになっています。そして
theBuffer.valueSize = sizeof(NKEvent)
で、GetEventで受信したイベントデータをパースするために、イベントデータの繰り返しサイズを指定しています。
ですが、このPTPライブラリはオリジナルのArduinoで使われている8bitのAVRマイコン向けに作られたもの。8bit環境だとsizeof()で構造体の実データサイズ6を返してくれますが、ESP32は32bitマイコンなので、パディングが入って4の倍数の8を返してしまいます。そのためPTPで取得したデータサイズ以上のアドレスにアクセスして、落ちていた、ということでした。
実際には数字直打ちでなくて、defineするとか、マナーは守りましょう。
ついでに前回とりあえずビルドを通すためにいい加減に直した
{
uint32_t tmp = (uint32_t)varBuffer;
numEvents = (uint16_t)tmp;
}をnumEvents = varBuffer[0];に修正 。ここがGetEventコマンドで取得できる最初のデータ コマンド数 になります。
無事イベントが取れるようになりました。
17:27:42.846 -> OnEvent Object Added handle = 0x1F322919 17:27:42.846 -> OnEvent CaptureComplete Transaction ID = 0x1F320000 17:27:42.846 -> OnEvent DevicePropChanged Changed prop code = 0xD0A4 17:27:42.879 -> OnEvent DevicePropChanged Changed prop code = 0xD1F1
これはシャッタを切ったときに発生するイベントで、古い順に
撮影した画像が追加された。
撮影完了
動画記録禁止条件変更
カードに記録可能な枚数が変更
になります。RAWとJPEGを両方記録するような設定になっているときはObject Addedイベントが2回飛んできます。
コメント