From 50518875cd928a9061008ee869fe01e8a725c252 Mon Sep 17 00:00:00 2001 From: MRSa Date: Sun, 20 Dec 2020 00:15:17 +0900 Subject: [PATCH] =?utf8?q?PowerShotZoom=E3=81=A7=E5=8B=95=E4=BD=9C?= =?utf8?q?=E3=81=99=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB=E3=81=97=E3=81=A6?= =?utf8?q?=E3=81=BF=E3=82=8B=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- .../canon/wrapper/CanonInterfaceProvider.java | 21 +- .../connection/CanonCameraConnectSequence.java | 30 +-- .../connection/CanonCameraConnectSequenceType1.kt | 264 +++++++++++++++++++++ .../connection/CanonCameraDisconnectSequence.java | 7 +- .../canon/wrapper/connection/CanonConnection.java | 36 ++- .../wrapper/liveview/CanonLiveViewControl.java | 59 ++++- .../wrapper/liveview/CanonLiveViewImageReceiver.kt | 16 +- .../preference/IPreferencePropertyAccessor.java | 3 + .../preference/canon/CanonPreferenceFragment.java | 3 + app/src/main/res/values-ja/strings.xml | 3 + app/src/main/res/values/arrays.xml | 12 + app/src/main/res/values/strings.xml | 3 + app/src/main/res/xml/preferences_canon.xml | 8 + 13 files changed, 418 insertions(+), 47 deletions(-) create mode 100644 app/src/main/java/net/osdn/gokigen/a01d/camera/canon/wrapper/connection/CanonCameraConnectSequenceType1.kt diff --git a/app/src/main/java/net/osdn/gokigen/a01d/camera/canon/wrapper/CanonInterfaceProvider.java b/app/src/main/java/net/osdn/gokigen/a01d/camera/canon/wrapper/CanonInterfaceProvider.java index 237e67c..edb0fab 100644 --- a/app/src/main/java/net/osdn/gokigen/a01d/camera/canon/wrapper/CanonInterfaceProvider.java +++ b/app/src/main/java/net/osdn/gokigen/a01d/camera/canon/wrapper/CanonInterfaceProvider.java @@ -69,6 +69,8 @@ public class CanonInterfaceProvider implements IPtpIpInterfaceProvider, IDisplay String ipAddress; int delayMs = 30; + int sequenceType = 0; + boolean isSearchJpegHeader = false; try { SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context); @@ -93,6 +95,23 @@ public class CanonInterfaceProvider implements IPtpIpInterfaceProvider, IDisplay { e.printStackTrace(); } + try + { + String sequenceTypeStr = preferences.getString(IPreferencePropertyAccessor.CANON_CONNECTION_SEQUENCE, IPreferencePropertyAccessor.CANON_CONNECTION_SEQUENCE_DEFAULT_VALUE); + if (sequenceTypeStr != null) + { + sequenceType = Integer.parseInt(sequenceTypeStr); + } + } + catch (Exception e) + { + e.printStackTrace(); + } + if (sequenceType == 1) + { + Log.v(TAG, " --- search JPEG header : true "); + isSearchJpegHeader = true; + } } catch (Exception e) { @@ -101,7 +120,7 @@ public class CanonInterfaceProvider implements IPtpIpInterfaceProvider, IDisplay } Log.v(TAG, " Canon IP : " + ipAddress); commandPublisher = new PtpIpCommandPublisher(ipAddress, CONTROL_PORT, false, false); - liveViewControl = new CanonLiveViewControl(context, this, delayMs); // + liveViewControl = new CanonLiveViewControl(context, this, delayMs, isSearchJpegHeader); // asyncReceiver = new PtpIpAsyncResponseReceiver(ipAddress, ASYNC_RESPONSE_PORT); statusChecker = new CanonStatusChecker(context, commandPublisher, ipAddress, EVENT_PORT); canonConnection = new CanonConnection(context, provider, this, statusChecker); diff --git a/app/src/main/java/net/osdn/gokigen/a01d/camera/canon/wrapper/connection/CanonCameraConnectSequence.java b/app/src/main/java/net/osdn/gokigen/a01d/camera/canon/wrapper/connection/CanonCameraConnectSequence.java index ff849c0..08872e6 100644 --- a/app/src/main/java/net/osdn/gokigen/a01d/camera/canon/wrapper/connection/CanonCameraConnectSequence.java +++ b/app/src/main/java/net/osdn/gokigen/a01d/camera/canon/wrapper/connection/CanonCameraConnectSequence.java @@ -1,6 +1,5 @@ package net.osdn.gokigen.a01d.camera.canon.wrapper.connection; - import android.app.Activity; import android.graphics.Color; import android.util.Log; @@ -19,6 +18,10 @@ import net.osdn.gokigen.a01d.camera.ptpip.wrapper.command.IPtpIpMessages; import net.osdn.gokigen.a01d.camera.ptpip.wrapper.command.messages.PtpIpCommandGeneric; import net.osdn.gokigen.a01d.camera.canon.wrapper.status.CanonStatusChecker; +/** + * 従来のCanonカメラ接続シーケンス + * + */ public class CanonCameraConnectSequence implements Runnable, IPtpIpCommandCallback, IPtpIpMessages { private final String TAG = this.toString(); @@ -157,8 +160,7 @@ public class CanonCameraConnectSequence implements Runnable, IPtpIpCommandCallba case SEQ_GET_EVENT1: Log.v(TAG, " SEQ_GET_EVENT1 "); interfaceProvider.getInformationReceiver().updateMessage(context.getString(R.string.canon_connect_connecting7), false, false, 0); - //commandIssuer.enqueueCommand(new PtpIpCommandGeneric(this, SEQ_DEVICE_INFORMATION, isDumpLog, 0, 0x1001)); - commandIssuer.enqueueCommand(new PtpIpCommandGeneric(this, SEQ_SET_REMOTE_SHOOTING_MODE, isDumpLog, 0, 0x1001)); + commandIssuer.enqueueCommand(new PtpIpCommandGeneric(this, SEQ_DEVICE_INFORMATION, isDumpLog, 0, 0x1001)); break; case SEQ_DEVICE_INFORMATION: @@ -208,29 +210,9 @@ public class CanonCameraConnectSequence implements Runnable, IPtpIpCommandCallba case SEQ_SET_DEVICE_PROPERTY_3: Log.v(TAG, " SEQ_SET_DEVICE_PROPERTY_3 "); interfaceProvider.getInformationReceiver().updateMessage(context.getString(R.string.canon_connect_connecting12), false, false, 0); - //commandIssuer.enqueueCommand(new CanonSetDevicePropertyValue(this, SEQ_SET_REMOTE_SHOOTING_MODE, isDumpLog, 0, 300, 0xd1b0, 0x08)); commandIssuer.enqueueCommand(new CanonSetDevicePropertyValue(this, SEQ_DEVICE_PROPERTY_FINISHED, isDumpLog, 0, 300, 0xd1b0, 0x08)); break; - case SEQ_SET_REMOTE_SHOOTING_MODE: - Log.v(TAG, " SEQ_SET_REMOTE_SHOOTING_MODE "); - interfaceProvider.getInformationReceiver().updateMessage(context.getString(R.string.canon_connect_connecting12), false, false, 0); - try - { - // ちょっと(250ms)待つ - Thread.sleep(250); - - // コマンド発行 - //commandIssuer.enqueueCommand(new PtpIpCommandGeneric(this, SEQ_DEVICE_PROPERTY_FINISHED, isDumpLog, 0, 0x9086, 4, 0x00000001)); - commandIssuer.enqueueCommand(new PtpIpCommandGeneric(this, SEQ_DEVICE_INFORMATION, isDumpLog, 0, 0x9086, 4, 0x00000001)); - - } - catch (Exception e) - { - e.printStackTrace(); - } - break; - case SEQ_DEVICE_PROPERTY_FINISHED: Log.v(TAG, " SEQ_DEVICE_PROPERTY_FINISHED "); interfaceProvider.getInformationReceiver().updateMessage(context.getString(R.string.connect_connect_finished), false, false, 0); @@ -293,7 +275,7 @@ public class CanonCameraConnectSequence implements Runnable, IPtpIpCommandCallba interfaceProvider.getInformationReceiver().updateMessage(context.getString(R.string.connect_connected), false, false, 0); // ちょっと待つ - Thread.sleep(1000); + Thread.sleep(500); // 接続成功!のメッセージを出す interfaceProvider.getInformationReceiver().updateMessage(context.getString(R.string.connect_connected), false, false, 0); diff --git a/app/src/main/java/net/osdn/gokigen/a01d/camera/canon/wrapper/connection/CanonCameraConnectSequenceType1.kt b/app/src/main/java/net/osdn/gokigen/a01d/camera/canon/wrapper/connection/CanonCameraConnectSequenceType1.kt new file mode 100644 index 0000000..1975d33 --- /dev/null +++ b/app/src/main/java/net/osdn/gokigen/a01d/camera/canon/wrapper/connection/CanonCameraConnectSequenceType1.kt @@ -0,0 +1,264 @@ +package net.osdn.gokigen.a01d.camera.canon.wrapper.connection + +import android.app.Activity +import android.graphics.Color +import android.util.Log +import net.osdn.gokigen.a01d.R +import net.osdn.gokigen.a01d.camera.ICameraConnection +import net.osdn.gokigen.a01d.camera.ICameraStatusReceiver +import net.osdn.gokigen.a01d.camera.canon.wrapper.command.messages.specific.CanonRegistrationMessage +import net.osdn.gokigen.a01d.camera.canon.wrapper.command.messages.specific.CanonSetDevicePropertyValue +import net.osdn.gokigen.a01d.camera.canon.wrapper.status.CanonStatusChecker +import net.osdn.gokigen.a01d.camera.ptpip.IPtpIpInterfaceProvider +import net.osdn.gokigen.a01d.camera.ptpip.wrapper.command.IPtpIpCommandCallback +import net.osdn.gokigen.a01d.camera.ptpip.wrapper.command.IPtpIpMessages +import net.osdn.gokigen.a01d.camera.ptpip.wrapper.command.messages.PtpIpCommandGeneric + +class CanonCameraConnectSequenceType1(val context: Activity, val cameraStatusReceiver: ICameraStatusReceiver, val cameraConnection: ICameraConnection, val interfaceProvider: IPtpIpInterfaceProvider, val statusChecker: CanonStatusChecker) : Runnable, IPtpIpCommandCallback, IPtpIpMessages +{ + private val isDumpLog = false + private val commandIssuer = interfaceProvider.commandPublisher + + override fun run() + { + try + { + // カメラとTCP接続 + val issuer = interfaceProvider.commandPublisher + if (!issuer.isConnected) + { + if (!interfaceProvider.commandCommunication.connect()) + { + // 接続失敗... + interfaceProvider.informationReceiver.updateMessage(context.getString(R.string.dialog_title_connect_failed_canon), false, true, Color.RED) + cameraConnection.alertConnectingFailed(context.getString(R.string.dialog_title_connect_failed_canon)) + return + } + } + else + { + Log.v(TAG, "SOCKET IS ALREADY CONNECTED...") + } + // コマンドタスクの実行開始 + issuer.start() + + // 接続シーケンスの開始 + sendRegistrationMessage() + } + catch (e: Exception) + { + e.printStackTrace() + interfaceProvider.informationReceiver.updateMessage(context.getString(R.string.dialog_title_connect_failed_canon), false, true, Color.RED) + cameraConnection.alertConnectingFailed(e.message) + } + } + + override fun onReceiveProgress(currentBytes: Int, totalBytes: Int, body: ByteArray?) + { + Log.v(TAG, " $currentBytes/$totalBytes") + } + + override fun isReceiveMulti(): Boolean + { + return false + } + + @ExperimentalUnsignedTypes + override fun receivedMessage(id: Int, rx_body: ByteArray) + { + when (id) + { + IPtpIpMessages.SEQ_REGISTRATION -> if (checkRegistrationMessage(rx_body)) { + sendInitEventRequest(rx_body) + } else { + cameraConnection.alertConnectingFailed(context.getString(R.string.connect_error_message)) + } + IPtpIpMessages.SEQ_EVENT_INITIALIZE -> if (checkEventInitialize(rx_body)) { + interfaceProvider.informationReceiver.updateMessage(context.getString(R.string.canon_connect_connecting1), false, false, 0) + commandIssuer!!.enqueueCommand(PtpIpCommandGeneric(this, IPtpIpMessages.SEQ_OPEN_SESSION, isDumpLog, 0, 0x1002, 4, 0x41)) + } else { + cameraConnection.alertConnectingFailed(context.getString(R.string.connect_error_message)) + } + IPtpIpMessages.SEQ_OPEN_SESSION -> { + Log.v(TAG, " SEQ_OPEN_SESSION ") + interfaceProvider.informationReceiver.updateMessage(context.getString(R.string.canon_connect_connecting2), false, false, 0) + commandIssuer.enqueueCommand(PtpIpCommandGeneric(this, IPtpIpMessages.SEQ_INIT_SESSION, isDumpLog, 0, 0x902f)) + } + IPtpIpMessages.SEQ_INIT_SESSION -> { + Log.v(TAG, " SEQ_INIT_SESSION ") + interfaceProvider.informationReceiver.updateMessage(context.getString(R.string.canon_connect_connecting3), false, false, 0) + commandIssuer.enqueueCommand(PtpIpCommandGeneric(this, IPtpIpMessages.SEQ_CHANGE_REMOTE, isDumpLog, 0, 0x9114, 4, 0x15)) + } + IPtpIpMessages.SEQ_CHANGE_REMOTE -> { + Log.v(TAG, " SEQ_CHANGE_REMOTE ") + interfaceProvider.informationReceiver.updateMessage(context.getString(R.string.canon_connect_connecting4), false, false, 0) + commandIssuer.enqueueCommand(PtpIpCommandGeneric(this, IPtpIpMessages.SEQ_SET_EVENT_MODE, isDumpLog, 0, 0x9115, 4, 0x02)) + } + IPtpIpMessages.SEQ_SET_EVENT_MODE -> { + Log.v(TAG, " SEQ_SET_EVENT_MODE ") + interfaceProvider.informationReceiver.updateMessage(context.getString(R.string.canon_connect_connecting5), false, false, 0) + commandIssuer.enqueueCommand(PtpIpCommandGeneric(this, IPtpIpMessages.SEQ_GET_EVENT, isDumpLog, 0, 0x913d, 4, 0x0fff)) + } + IPtpIpMessages.SEQ_GET_EVENT -> { + Log.v(TAG, " SEQ_GET_EVENT ") + interfaceProvider.informationReceiver.updateMessage(context.getString(R.string.canon_connect_connecting6), false, false, 0) + commandIssuer.enqueueCommand(PtpIpCommandGeneric(this, IPtpIpMessages.SEQ_GET_EVENT1, isDumpLog, 0, 0x9033, 4, 0x00000000)) + } + IPtpIpMessages.SEQ_GET_EVENT1 -> { + Log.v(TAG, " SEQ_GET_EVENT1 ") + interfaceProvider.informationReceiver.updateMessage(context.getString(R.string.canon_connect_connecting7), false, false, 0) + //commandIssuer.enqueueCommand(new PtpIpCommandGeneric(this, SEQ_DEVICE_INFORMATION, isDumpLog, 0, 0x1001)); + commandIssuer!!.enqueueCommand(PtpIpCommandGeneric(this, IPtpIpMessages.SEQ_SET_REMOTE_SHOOTING_MODE, isDumpLog, 0, 0x1001)) + } + IPtpIpMessages.SEQ_DEVICE_INFORMATION -> { + Log.v(TAG, " SEQ_DEVICE_INFORMATION ") + interfaceProvider.informationReceiver.updateMessage(context.getString(R.string.canon_connect_connecting8), false, false, 0) + //commandIssuer.enqueueCommand(new PtpIpCommandGeneric(this, SEQ_DEVICE_PROPERTY, isDumpLog, 0, 0x9127, 4, 0x0000d1a6)); + commandIssuer.enqueueCommand(PtpIpCommandGeneric(this, IPtpIpMessages.SEQ_DEVICE_PROPERTY, isDumpLog, 0, 0x9127, 4, 0x0000d1a6)) + commandIssuer.enqueueCommand(PtpIpCommandGeneric(this, IPtpIpMessages.SEQ_DEVICE_PROPERTY, isDumpLog, 0, 0x9127, 4, 0x0000d169)) + commandIssuer.enqueueCommand(PtpIpCommandGeneric(this, IPtpIpMessages.SEQ_DEVICE_PROPERTY, isDumpLog, 0, 0x9127, 4, 0x0000d16a)) + commandIssuer.enqueueCommand(PtpIpCommandGeneric(this, IPtpIpMessages.SEQ_DEVICE_PROPERTY, isDumpLog, 0, 0x9127, 4, 0x0000d16b)) + commandIssuer.enqueueCommand(PtpIpCommandGeneric(this, IPtpIpMessages.SEQ_DEVICE_PROPERTY, isDumpLog, 0, 0x9127, 4, 0x0000d1af)) + } + IPtpIpMessages.SEQ_DEVICE_PROPERTY -> { + Log.v(TAG, " SEQ_DEVICE_PROPERTY ") + interfaceProvider.informationReceiver.updateMessage(context.getString(R.string.canon_connect_connecting9), false, false, 0) + if (rx_body[8] == 0x01.toByte() && rx_body[9] == 0x20.toByte()) { + // コマンドが受け付けられたときだけ次に進む! + try { + // ちょっと(250ms)待つ + Thread.sleep(250) + + // コマンド発行 + commandIssuer.enqueueCommand(CanonSetDevicePropertyValue(this, IPtpIpMessages.SEQ_SET_DEVICE_PROPERTY, isDumpLog, 0, 150, 0xd136, 0x00)) + } catch (e: Exception) { + e.printStackTrace() + } + } + } + IPtpIpMessages.SEQ_SET_DEVICE_PROPERTY -> { + Log.v(TAG, " SEQ_SET_DEVICE_PROPERTY ") + interfaceProvider.informationReceiver.updateMessage(context.getString(R.string.canon_connect_connecting10), false, false, 0) + commandIssuer.enqueueCommand(CanonSetDevicePropertyValue(this, IPtpIpMessages.SEQ_SET_DEVICE_PROPERTY_2, isDumpLog, 0, 150, 0xd136, 0x01)) + } + IPtpIpMessages.SEQ_SET_DEVICE_PROPERTY_2 -> { + Log.v(TAG, " SEQ_SET_DEVICE_PROPERTY_2 ") + interfaceProvider.informationReceiver.updateMessage(context.getString(R.string.canon_connect_connecting11), false, false, 0) + commandIssuer.enqueueCommand(CanonSetDevicePropertyValue(this, IPtpIpMessages.SEQ_SET_DEVICE_PROPERTY_3, isDumpLog, 0, 150, 0xd136, 0x00)) + } + IPtpIpMessages.SEQ_SET_DEVICE_PROPERTY_3 -> { + Log.v(TAG, " SEQ_SET_DEVICE_PROPERTY_3 ") + interfaceProvider.informationReceiver.updateMessage(context.getString(R.string.canon_connect_connecting12), false, false, 0) + //commandIssuer.enqueueCommand(new CanonSetDevicePropertyValue(this, SEQ_SET_REMOTE_SHOOTING_MODE, isDumpLog, 0, 300, 0xd1b0, 0x08)); + commandIssuer!!.enqueueCommand(CanonSetDevicePropertyValue(this, IPtpIpMessages.SEQ_DEVICE_PROPERTY_FINISHED, isDumpLog, 0, 300, 0xd1b0, 0x08)) + } + IPtpIpMessages.SEQ_SET_REMOTE_SHOOTING_MODE -> { + Log.v(TAG, " SEQ_SET_REMOTE_SHOOTING_MODE ") + interfaceProvider.informationReceiver.updateMessage(context.getString(R.string.canon_connect_connecting12), false, false, 0) + try { + // ちょっと(250ms)待つ + Thread.sleep(250) + + // コマンド発行 + //commandIssuer.enqueueCommand(new PtpIpCommandGeneric(this, SEQ_DEVICE_PROPERTY_FINISHED, isDumpLog, 0, 0x9086, 4, 0x00000001)); + commandIssuer.enqueueCommand(PtpIpCommandGeneric(this, IPtpIpMessages.SEQ_DEVICE_INFORMATION, isDumpLog, 0, 0x9086, 4, 0x00000001)) + } catch (e: Exception) { + e.printStackTrace() + } + } + IPtpIpMessages.SEQ_DEVICE_PROPERTY_FINISHED -> { + Log.v(TAG, " SEQ_DEVICE_PROPERTY_FINISHED ") + interfaceProvider.informationReceiver.updateMessage(context.getString(R.string.connect_connect_finished), false, false, 0) + connectFinished() + Log.v(TAG, "CHANGED MODE : DONE.") + } + else -> { + Log.v(TAG, "RECEIVED UNKNOWN ID : $id") + cameraConnection.alertConnectingFailed(context.getString(R.string.connect_receive_unknown_message)) + } + } + } + + private fun sendRegistrationMessage() + { + interfaceProvider.informationReceiver.updateMessage(context.getString(R.string.connect_start), false, false, 0) + cameraStatusReceiver.onStatusNotify(context.getString(R.string.connect_start)) + commandIssuer.enqueueCommand(CanonRegistrationMessage(this)) + } + + @ExperimentalUnsignedTypes + private fun sendInitEventRequest(receiveData: ByteArray) + { + interfaceProvider.informationReceiver.updateMessage(context.getString(R.string.connect_start_2), false, false, 0) + cameraStatusReceiver.onStatusNotify(context.getString(R.string.connect_start_2)) + try + { + var eventConnectionNumber: Int = receiveData[8].toUByte().toInt() and 0xff + eventConnectionNumber += (receiveData[9].toUByte().toInt() and 0xff shl 8) + eventConnectionNumber += (receiveData[10].toUByte().toInt() and 0xff shl 16) + eventConnectionNumber += (receiveData[11].toUByte().toInt() and 0xff shl 24) + statusChecker.setEventConnectionNumber(eventConnectionNumber) + interfaceProvider.cameraStatusWatcher.startStatusWatch(interfaceProvider.statusListener) + commandIssuer.enqueueCommand(PtpIpCommandGeneric(this, IPtpIpMessages.SEQ_OPEN_SESSION, isDumpLog, 0, 0x1002, 4, 0x41)) + } + catch (e: Exception) + { + e.printStackTrace() + } + } + + private fun checkRegistrationMessage(receiveData: ByteArray?): Boolean + { + // データ(Connection Number)がないときにはエラーと判断する + return !(receiveData == null || receiveData.size < 12) + } + + private fun checkEventInitialize(receiveData: ByteArray?): Boolean + { + Log.v(TAG, "checkEventInitialize() ") + return receiveData != null + } + + private fun connectFinished() + { + try + { + // 接続成功のメッセージを出す + interfaceProvider.informationReceiver.updateMessage(context.getString(R.string.connect_connected), false, false, 0) + + // ちょっと待つ + Thread.sleep(1000) + + // 接続成功!のメッセージを出す + interfaceProvider.informationReceiver.updateMessage(context.getString(R.string.connect_connected), false, false, 0) + onConnectNotify() + } + catch (e: Exception) + { + e.printStackTrace() + } + } + + private fun onConnectNotify() + { + try + { + val thread = Thread { + // カメラとの接続確立を通知する + cameraStatusReceiver.onStatusNotify(context.getString(R.string.connect_connected)) + cameraStatusReceiver.onCameraConnected() + Log.v(TAG, " onConnectNotify()") + } + thread.start() + } + catch (e: Exception) + { + e.printStackTrace() + } + } + + companion object + { + private const val TAG = "CanonConnectSeq.1" + } +} \ No newline at end of file diff --git a/app/src/main/java/net/osdn/gokigen/a01d/camera/canon/wrapper/connection/CanonCameraDisconnectSequence.java b/app/src/main/java/net/osdn/gokigen/a01d/camera/canon/wrapper/connection/CanonCameraDisconnectSequence.java index 6ab510d..9f75bec 100644 --- a/app/src/main/java/net/osdn/gokigen/a01d/camera/canon/wrapper/connection/CanonCameraDisconnectSequence.java +++ b/app/src/main/java/net/osdn/gokigen/a01d/camera/canon/wrapper/connection/CanonCameraDisconnectSequence.java @@ -1,7 +1,5 @@ package net.osdn.gokigen.a01d.camera.canon.wrapper.connection; -import android.app.Activity; - import androidx.annotation.NonNull; import net.osdn.gokigen.a01d.camera.ptpip.IPtpIpInterfaceProvider; @@ -9,15 +7,12 @@ import net.osdn.gokigen.a01d.camera.ptpip.wrapper.command.IPtpIpCommunication; class CanonCameraDisconnectSequence implements Runnable { - private final String TAG = this.toString(); - private final Activity activity; private final IPtpIpCommunication command; private final IPtpIpCommunication async; private final IPtpIpCommunication liveview; - CanonCameraDisconnectSequence(Activity activity, @NonNull IPtpIpInterfaceProvider interfaceProvider) + CanonCameraDisconnectSequence(@NonNull IPtpIpInterfaceProvider interfaceProvider) { - this.activity = activity; this.command = interfaceProvider.getCommandCommunication(); this.async = interfaceProvider.getAsyncEventCommunication(); this.liveview = interfaceProvider.getLiveviewCommunication(); diff --git a/app/src/main/java/net/osdn/gokigen/a01d/camera/canon/wrapper/connection/CanonConnection.java b/app/src/main/java/net/osdn/gokigen/a01d/camera/canon/wrapper/connection/CanonConnection.java index d903dba..28f4e69 100644 --- a/app/src/main/java/net/osdn/gokigen/a01d/camera/canon/wrapper/connection/CanonConnection.java +++ b/app/src/main/java/net/osdn/gokigen/a01d/camera/canon/wrapper/connection/CanonConnection.java @@ -6,6 +6,7 @@ import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.IntentFilter; +import android.content.SharedPreferences; import android.net.ConnectivityManager; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; @@ -14,12 +15,14 @@ import android.util.Log; import androidx.annotation.NonNull; import androidx.appcompat.app.AlertDialog; +import androidx.preference.PreferenceManager; import net.osdn.gokigen.a01d.R; import net.osdn.gokigen.a01d.camera.ICameraConnection; import net.osdn.gokigen.a01d.camera.ICameraStatusReceiver; import net.osdn.gokigen.a01d.camera.ptpip.IPtpIpInterfaceProvider; import net.osdn.gokigen.a01d.camera.canon.wrapper.status.CanonStatusChecker; +import net.osdn.gokigen.a01d.preference.IPreferencePropertyAccessor; import java.util.concurrent.Executor; import java.util.concurrent.Executors; @@ -211,10 +214,10 @@ public class CanonConnection implements ICameraConnection */ private void disconnectFromCamera(final boolean powerOff) { - Log.v(TAG, " disconnectFromCamera()"); + Log.v(TAG, " disconnectFromCamera() : " + powerOff); try { - cameraExecutor.execute(new CanonCameraDisconnectSequence(context, interfaceProvider)); + cameraExecutor.execute(new CanonCameraDisconnectSequence(interfaceProvider)); } catch (Exception e) { @@ -231,7 +234,14 @@ public class CanonConnection implements ICameraConnection connectionStatus = CameraConnectionStatus.CONNECTING; try { - cameraExecutor.execute(new CanonCameraConnectSequence(context, statusReceiver, this, interfaceProvider, statusChecker)); + if (getConnectSequenceType() == 0) + { + cameraExecutor.execute(new CanonCameraConnectSequence(context, statusReceiver, this, interfaceProvider, statusChecker)); + } + else + { + cameraExecutor.execute(new CanonCameraConnectSequenceType1(context, statusReceiver, this, interfaceProvider, statusChecker)); + } } catch (Exception e) { @@ -239,4 +249,24 @@ public class CanonConnection implements ICameraConnection e.printStackTrace(); } } + + private int getConnectSequenceType() + { + int sequenceType = 0; + try + { + SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context); + String sequenceTypeStr = preferences.getString(IPreferencePropertyAccessor.CANON_CONNECTION_SEQUENCE, IPreferencePropertyAccessor.CANON_CONNECTION_SEQUENCE_DEFAULT_VALUE); + if (sequenceTypeStr != null) + { + sequenceType = Integer.parseInt(sequenceTypeStr); + } + Log.v(TAG, " Canon ConnectionSequence [" + sequenceType + "] " + sequenceTypeStr); + } + catch (Exception e) + { + e.printStackTrace(); + } + return (sequenceType); + } } diff --git a/app/src/main/java/net/osdn/gokigen/a01d/camera/canon/wrapper/liveview/CanonLiveViewControl.java b/app/src/main/java/net/osdn/gokigen/a01d/camera/canon/wrapper/liveview/CanonLiveViewControl.java index 8f2c441..d849167 100644 --- a/app/src/main/java/net/osdn/gokigen/a01d/camera/canon/wrapper/liveview/CanonLiveViewControl.java +++ b/app/src/main/java/net/osdn/gokigen/a01d/camera/canon/wrapper/liveview/CanonLiveViewControl.java @@ -24,18 +24,21 @@ public class CanonLiveViewControl implements ILiveViewControl, ILiveViewListener private final String TAG = this.toString(); private final IPtpIpCommandPublisher commandIssuer; private final int delayMs; - //private CanonLiveViewImageReceiver imageReceiver; + private final boolean isDumpLog = false; + private final boolean isSearchJpegHeader; + private final int retryCount = 1500; private final CanonLiveViewImageReceiver imageReceiver; private IImageDataReceiver dataReceiver = null; private boolean liveViewIsReceiving = false; private boolean commandIssued = false; - public CanonLiveViewControl(@NonNull Activity context, @NonNull IPtpIpInterfaceProvider interfaceProvider, int delayMs) + public CanonLiveViewControl(@NonNull Activity context, @NonNull IPtpIpInterfaceProvider interfaceProvider, int delayMs, boolean isSearchJpegHeader) { this.commandIssuer = interfaceProvider.getCommandPublisher(); + this.isSearchJpegHeader = isSearchJpegHeader; this.delayMs = delayMs; //this.imageReceiver = new CanonLiveViewImageReceiver(this); - this.imageReceiver = new CanonLiveViewImageReceiver(this); + this.imageReceiver = new CanonLiveViewImageReceiver(context,this); Log.v(TAG, " -=-=-=-=-=- CanonLiveViewControl : delay " + delayMs + " ms"); } @@ -67,8 +70,12 @@ public class CanonLiveViewControl implements ILiveViewControl, ILiveViewListener { if (!commandIssued) { + if (isDumpLog) + { + Log.v(TAG, " enqueueCommand() "); + } commandIssued = true; - commandIssuer.enqueueCommand(new PtpIpCommandGenericWithRetry(imageReceiver, SEQ_GET_VIEWFRAME, delayMs, 2000, false, false, 0, 0x9153, 12, 0x00200000, 0x01, 0x00, 0x00)); + commandIssuer.enqueueCommand(new PtpIpCommandGenericWithRetry(imageReceiver, SEQ_GET_VIEWFRAME, delayMs, retryCount, false, false, 0, 0x9153, 12, 0x00200000, 0x01, 0x00, 0x00)); } try { @@ -155,11 +162,14 @@ public class CanonLiveViewControl implements ILiveViewControl, ILiveViewListener { if ((dataReceiver != null)&&(data != null)) { - Log.v(TAG, " ---+++--- RECEIVED LV IMAGE ---+++--- : " + data.length + " bytes."); - //dataReceiver.setImageData(data, metadata); - if (data.length > 8) + if (isDumpLog) { - dataReceiver.setImageData(Arrays.copyOfRange(data, 8, data.length), metadata); // ヘッダ部分を切り取って送る + Log.v(TAG, " ---+++--- RECEIVED LV IMAGE ---+++--- : " + data.length + " bytes."); + } + int headerSize = searchJpegHeader(data); + if (headerSize >= 0) + { + dataReceiver.setImageData(Arrays.copyOfRange(data, headerSize, data.length), metadata); // ヘッダ部分を切り取って送る } } } @@ -170,6 +180,39 @@ public class CanonLiveViewControl implements ILiveViewControl, ILiveViewListener commandIssued = false; } + private int searchJpegHeader(byte[] data) + { + if (data.length <= 8) + { + return (-1); + } + if (!isSearchJpegHeader) + { + // JPEG ヘッダを探さない場合は、8バイト固定とする + return (8); + } + try + { + int size = data.length - 1; + int index = 0; + while (index < size) + { + if ((data[index] == (byte) 0xff)&&(data[index + 1] == (byte) 0xd8)) + { + return (index); + } + index++; + } + } + catch (Exception e) + { + e.printStackTrace(); + } + + // 見つからなかったときは 8 を返す + return (8); + } + @Override public void onErrorOccurred(Exception e) { diff --git a/app/src/main/java/net/osdn/gokigen/a01d/camera/canon/wrapper/liveview/CanonLiveViewImageReceiver.kt b/app/src/main/java/net/osdn/gokigen/a01d/camera/canon/wrapper/liveview/CanonLiveViewImageReceiver.kt index cf00b22..0fca70a 100644 --- a/app/src/main/java/net/osdn/gokigen/a01d/camera/canon/wrapper/liveview/CanonLiveViewImageReceiver.kt +++ b/app/src/main/java/net/osdn/gokigen/a01d/camera/canon/wrapper/liveview/CanonLiveViewImageReceiver.kt @@ -1,5 +1,6 @@ package net.osdn.gokigen.a01d.camera.canon.wrapper.liveview +import android.app.Activity import android.util.Log import net.osdn.gokigen.a01d.camera.ptpip.wrapper.command.IPtpIpCommandCallback import net.osdn.gokigen.a01d.camera.ptpip.wrapper.liveview.IPtpIpLiveViewImageCallback @@ -7,7 +8,7 @@ import net.osdn.gokigen.a01d.camera.utils.SimpleLogDumper import java.io.ByteArrayOutputStream import java.util.* -class CanonLiveViewImageReceiver(val callback: IPtpIpLiveViewImageCallback) : IPtpIpCommandCallback +class CanonLiveViewImageReceiver(val activity: Activity, val callback: IPtpIpLiveViewImageCallback) : IPtpIpCommandCallback { private val isDumpLog = false private val byteStream = ByteArrayOutputStream() @@ -15,6 +16,7 @@ class CanonLiveViewImageReceiver(val callback: IPtpIpLiveViewImageCallback) : IP private var receivedTotalBytes = 0 private var receivedRemainBytes = 0 private var receivedFirstData = false + private var dumpImageSize = -1 // 値をゼロにするとisDumpLogがtrueのときに受信データをファイルに出力する override fun receivedMessage(id: Int, rx_body: ByteArray?) { @@ -133,12 +135,18 @@ class CanonLiveViewImageReceiver(val callback: IPtpIpLiveViewImageCallback) : IP { val thumbNail = byteStream.toByteArray() var dumpLength = thumbNail.size - if (dumpLength > 256) + if (dumpLength > 96) { - dumpLength = 256 + dumpLength = 96 } SimpleLogDumper.dump_bytes(" [--ID:$id(>)--]", Arrays.copyOfRange(thumbNail, 0, dumpLength)) SimpleLogDumper.dump_bytes(" [-ID:$id(<)-]", Arrays.copyOfRange(thumbNail, thumbNail.size - dumpLength, thumbNail.size)) + Log.v(TAG, " RECEIVED LENGTH : $thumbNail.size") + if ((dumpImageSize > 0)&&(dumpImageSize < 30)) + { + SimpleLogDumper.binaryOutputToFile(activity, "CANON-${dumpImageSize}_", byteStream.toByteArray()) + dumpImageSize++ + } } callback.onCompleted(byteStream.toByteArray(), null) receivedFirstData = false @@ -153,8 +161,6 @@ class CanonLiveViewImageReceiver(val callback: IPtpIpLiveViewImageCallback) : IP } } - - override fun isReceiveMulti(): Boolean { return (true) diff --git a/app/src/main/java/net/osdn/gokigen/a01d/preference/IPreferencePropertyAccessor.java b/app/src/main/java/net/osdn/gokigen/a01d/preference/IPreferencePropertyAccessor.java index d20d2dd..c789131 100644 --- a/app/src/main/java/net/osdn/gokigen/a01d/preference/IPreferencePropertyAccessor.java +++ b/app/src/main/java/net/osdn/gokigen/a01d/preference/IPreferencePropertyAccessor.java @@ -123,6 +123,9 @@ public interface IPreferencePropertyAccessor String CANON_LIVEVIEW_WAIT = "canon_liveview_wait"; String CANON_LIVEVIEW_WAIT_DEFAULT_VALUE = "25"; + String CANON_CONNECTION_SEQUENCE = "canon_connection_mode"; + String CANON_CONNECTION_SEQUENCE_DEFAULT_VALUE = "0"; + /* int CHOICE_SPLASH_SCREEN = 10; diff --git a/app/src/main/java/net/osdn/gokigen/a01d/preference/canon/CanonPreferenceFragment.java b/app/src/main/java/net/osdn/gokigen/a01d/preference/canon/CanonPreferenceFragment.java index 90d93a8..4492739 100644 --- a/app/src/main/java/net/osdn/gokigen/a01d/preference/canon/CanonPreferenceFragment.java +++ b/app/src/main/java/net/osdn/gokigen/a01d/preference/canon/CanonPreferenceFragment.java @@ -139,6 +139,9 @@ public class CanonPreferenceFragment extends PreferenceFragmentCompat implements if (!items.containsKey(IPreferencePropertyAccessor.CANON_LIVEVIEW_WAIT)) { editor.putString(IPreferencePropertyAccessor.CANON_LIVEVIEW_WAIT, IPreferencePropertyAccessor.CANON_LIVEVIEW_WAIT_DEFAULT_VALUE); } + if (!items.containsKey(IPreferencePropertyAccessor.CANON_CONNECTION_SEQUENCE)) { + editor.putString(IPreferencePropertyAccessor.CANON_CONNECTION_SEQUENCE, IPreferencePropertyAccessor.CANON_CONNECTION_SEQUENCE_DEFAULT_VALUE); + } editor.apply(); } catch (Exception e) diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index fd49387..b783d04 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -346,4 +346,7 @@ LV画像受信待ち間隔(default: 25) ライブビュー画像受信間隔を指定します + 接続シーケンス + 通常、変更は不要です (初期値: TYPE0) + diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index 60dd56c..52010d0 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -151,4 +151,16 @@ AUTO + + TYPE0 + TYPE1 + TYPE2 + + + + 0 + 1 + 2 + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 03c2cfe..ea8a17f 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -351,4 +351,7 @@ Liveview receive wait (default: 25) + Connection Sequence + default: TYPE0 + diff --git a/app/src/main/res/xml/preferences_canon.xml b/app/src/main/res/xml/preferences_canon.xml index 5ef8b9e..e4cb72a 100644 --- a/app/src/main/res/xml/preferences_canon.xml +++ b/app/src/main/res/xml/preferences_canon.xml @@ -60,6 +60,14 @@ android:defaultValue="25" android:summary="@string/pref_summary_canon_liveview_wait" /> + +