From 4752be794b0f363a449dcec77b2950f3900aa218 Mon Sep 17 00:00:00 2001 From: MRSa Date: Sun, 25 Oct 2020 23:23:43 +0900 Subject: [PATCH] =?utf8?q?=E6=9A=AB=E5=AE=9A=E3=81=A7=E8=A8=98=E9=8C=B2?= =?utf8?q?=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- .../specific/NikonLiveViewRequestMessage.java | 8 +- .../specific/NikonStatusRequestMessage.java | 88 +++++++++++++ .../nikon/wrapper/liveview/NikonLiveViewControl.kt | 6 +- .../wrapper/liveview/NikonLiveViewImageReceiver.kt | 10 +- .../liveview/NikonLiveViewStatusReceiver.kt | 50 ++++++++ .../ptpip/wrapper/command/IPtpIpCommand.java | 3 + .../ptpip/wrapper/command/IPtpIpMessages.java | 1 + .../ptpip/wrapper/command/PtpIpCommandPublisher.kt | 142 ++++++++++++++------- .../wrapper/command/messages/PtpIpCommandBase.java | 6 + 9 files changed, 266 insertions(+), 48 deletions(-) create mode 100644 app/src/main/java/net/osdn/gokigen/a01d/camera/nikon/wrapper/command/messages/specific/NikonStatusRequestMessage.java create mode 100644 app/src/main/java/net/osdn/gokigen/a01d/camera/nikon/wrapper/liveview/NikonLiveViewStatusReceiver.kt diff --git a/app/src/main/java/net/osdn/gokigen/a01d/camera/nikon/wrapper/command/messages/specific/NikonLiveViewRequestMessage.java b/app/src/main/java/net/osdn/gokigen/a01d/camera/nikon/wrapper/command/messages/specific/NikonLiveViewRequestMessage.java index cb07f3a..d994ffd 100644 --- a/app/src/main/java/net/osdn/gokigen/a01d/camera/nikon/wrapper/command/messages/specific/NikonLiveViewRequestMessage.java +++ b/app/src/main/java/net/osdn/gokigen/a01d/camera/nikon/wrapper/command/messages/specific/NikonLiveViewRequestMessage.java @@ -68,9 +68,15 @@ public class NikonLiveViewRequestMessage extends PtpIpCommandBase } @Override + public boolean isLastReceiveRetry() + { + return (true); + } + + @Override public int maxRetryCount() { - return (3); + return (300); } @Override diff --git a/app/src/main/java/net/osdn/gokigen/a01d/camera/nikon/wrapper/command/messages/specific/NikonStatusRequestMessage.java b/app/src/main/java/net/osdn/gokigen/a01d/camera/nikon/wrapper/command/messages/specific/NikonStatusRequestMessage.java new file mode 100644 index 0000000..cddfd84 --- /dev/null +++ b/app/src/main/java/net/osdn/gokigen/a01d/camera/nikon/wrapper/command/messages/specific/NikonStatusRequestMessage.java @@ -0,0 +1,88 @@ +package net.osdn.gokigen.a01d.camera.nikon.wrapper.command.messages.specific; + +import androidx.annotation.NonNull; + +import net.osdn.gokigen.a01d.camera.ptpip.wrapper.command.IPtpIpCommandCallback; +import net.osdn.gokigen.a01d.camera.ptpip.wrapper.command.messages.PtpIpCommandBase; + +public class NikonStatusRequestMessage extends PtpIpCommandBase +{ + private final IPtpIpCommandCallback callback; + private final boolean isDumpLog; + private final int delayMs; + + public NikonStatusRequestMessage(@NonNull IPtpIpCommandCallback callback,int delayMs, boolean isDumpLog) + { + this.callback = callback; + this.delayMs = delayMs; + this.isDumpLog = isDumpLog; + } + + @Override + public IPtpIpCommandCallback responseCallback() + { + return (callback); + } + + @Override + public int getId() + { + return (SEQ_GET_CAMERASTATUS); + } + + @Override + public byte[] commandBody() + { + return (new byte[]{ + + // packet type + (byte) 0x06, (byte) 0x00, (byte) 0x00, (byte) 0x00, + + // data phase info + (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00, + + // operation code + (byte) 0xc2, (byte) 0x90, + + // sequence number + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + }); + } + + @Override + public boolean dumpLog() + { + return (isDumpLog); + } + + @Override + public int receiveDelayMs() + { + return (delayMs); + } + + @Override + public boolean isRetrySend() + { + return (false); + } + + @Override + public boolean isLastReceiveRetry() + { + return (true); + } + + @Override + public int maxRetryCount() + { + return (3); + } + + @Override + public boolean isIncrementSequenceNumberToRetry() + { + return (true); + } + +} diff --git a/app/src/main/java/net/osdn/gokigen/a01d/camera/nikon/wrapper/liveview/NikonLiveViewControl.kt b/app/src/main/java/net/osdn/gokigen/a01d/camera/nikon/wrapper/liveview/NikonLiveViewControl.kt index 610bd57..ef1508b 100644 --- a/app/src/main/java/net/osdn/gokigen/a01d/camera/nikon/wrapper/liveview/NikonLiveViewControl.kt +++ b/app/src/main/java/net/osdn/gokigen/a01d/camera/nikon/wrapper/liveview/NikonLiveViewControl.kt @@ -4,6 +4,7 @@ import android.util.Log import androidx.appcompat.app.AppCompatActivity import net.osdn.gokigen.a01d.camera.ILiveViewControl import net.osdn.gokigen.a01d.camera.nikon.wrapper.command.messages.specific.NikonLiveViewRequestMessage +import net.osdn.gokigen.a01d.camera.nikon.wrapper.command.messages.specific.NikonStatusRequestMessage import net.osdn.gokigen.a01d.camera.ptpip.IPtpIpInterfaceProvider import net.osdn.gokigen.a01d.camera.ptpip.wrapper.command.* import net.osdn.gokigen.a01d.camera.ptpip.wrapper.command.messages.PtpIpCommandGeneric @@ -14,9 +15,10 @@ import java.util.* class NikonLiveViewControl(private val context: AppCompatActivity, interfaceProvider: IPtpIpInterfaceProvider, private val delayMs: Int) : ILiveViewControl, ILiveViewListener, IPtpIpCommunication, IPtpIpLiveViewImageCallback, IPtpIpCommandCallback { + private val isDumpLog = false private val commandIssuer = interfaceProvider.commandPublisher private val imageReceiver = NikonLiveViewImageReceiver(this) - private val isDumpLog = false + private val statusReceiver = NikonLiveViewStatusReceiver(true) private var dataReceiver: IImageDataReceiver? = null private var liveViewIsReceiving = false @@ -121,6 +123,8 @@ class NikonLiveViewControl(private val context: AppCompatActivity, interfaceProv { try { + //Thread.sleep(delayMs.toLong()) + //commandIssuer.enqueueCommand(NikonStatusRequestMessage(statusReceiver, delayMs, isDumpLog)) Thread.sleep(delayMs.toLong()) commandIssuer.enqueueCommand(NikonLiveViewRequestMessage(imageReceiver, delayMs, isDumpLog)) } diff --git a/app/src/main/java/net/osdn/gokigen/a01d/camera/nikon/wrapper/liveview/NikonLiveViewImageReceiver.kt b/app/src/main/java/net/osdn/gokigen/a01d/camera/nikon/wrapper/liveview/NikonLiveViewImageReceiver.kt index 128b80a..fab9046 100644 --- a/app/src/main/java/net/osdn/gokigen/a01d/camera/nikon/wrapper/liveview/NikonLiveViewImageReceiver.kt +++ b/app/src/main/java/net/osdn/gokigen/a01d/camera/nikon/wrapper/liveview/NikonLiveViewImageReceiver.kt @@ -5,11 +5,10 @@ import net.osdn.gokigen.a01d.camera.ptpip.wrapper.command.IPtpIpCommandCallback import net.osdn.gokigen.a01d.camera.ptpip.wrapper.liveview.IPtpIpLiveViewImageCallback import net.osdn.gokigen.a01d.camera.utils.SimpleLogDumper import java.io.ByteArrayOutputStream -import java.util.* class NikonLiveViewImageReceiver(private var callback: IPtpIpLiveViewImageCallback) : IPtpIpCommandCallback { - private val isDumpLog = false + private val isDumpLog = true private var receivedTotalBytes = 0 private var receivedRemainBytes = 0 private var receivedFirstData = false @@ -41,6 +40,11 @@ class NikonLiveViewImageReceiver(private var callback: IPtpIpLiveViewImageCallba return } Log.v(TAG, " onReceiveProgress() $currentBytes/$totalBytes LENGTH: ${rx_body.size} bytes.") + if ((currentBytes > totalBytes)&&((currentBytes - totalBytes) < (32 + 14))) + { + // Operation Response Packet を受信していないとき... + Log.v(TAG, " ===== DO NOT RECEIVE RESPONSE MESSAGE YET. =====") + } // 受信したデータから、通信のヘッダ部分を削除する cutHeader(rx_body) @@ -95,7 +99,7 @@ class NikonLiveViewImageReceiver(private var callback: IPtpIpLiveViewImageCallba if (isDumpLog) { Log.v(TAG, " FIRST DATA POS. : $dataPosition len: $length "); - SimpleLogDumper.dump_bytes(" [sXXs]", rx_body.copyOfRange(0, (32))) + SimpleLogDumper.dump_bytes(" [1stData]", rx_body.copyOfRange(0, (32))) } } else diff --git a/app/src/main/java/net/osdn/gokigen/a01d/camera/nikon/wrapper/liveview/NikonLiveViewStatusReceiver.kt b/app/src/main/java/net/osdn/gokigen/a01d/camera/nikon/wrapper/liveview/NikonLiveViewStatusReceiver.kt new file mode 100644 index 0000000..2f4d707 --- /dev/null +++ b/app/src/main/java/net/osdn/gokigen/a01d/camera/nikon/wrapper/liveview/NikonLiveViewStatusReceiver.kt @@ -0,0 +1,50 @@ +package net.osdn.gokigen.a01d.camera.nikon.wrapper.liveview + +import android.util.Log +import net.osdn.gokigen.a01d.camera.ptpip.wrapper.command.IPtpIpCommandCallback +import net.osdn.gokigen.a01d.camera.utils.SimpleLogDumper + +class NikonLiveViewStatusReceiver(private val isDumpLog: Boolean = false) : IPtpIpCommandCallback +{ + override fun receivedMessage(id: Int, rx_body: ByteArray?) + { + if (rx_body == null) + { + Log.v(TAG, " receivedMessage $id is NULL.") + return + } + + if (isDumpLog) + { + Log.v(TAG, " receivedMessage() [$id] : ${rx_body.size} bytes. "); + val logDumpSize = if (rx_body.size > 64) 64 else rx_body.size + SimpleLogDumper.dump_bytes(" [rcv]", rx_body.copyOfRange(0, logDumpSize)) + } + } + + override fun onReceiveProgress(currentBytes: Int, totalBytes: Int, rx_body: ByteArray?) + { + if (rx_body == null) + { + Log.v(TAG, " onReceiveProgress() : $currentBytes/$totalBytes is NULL") + return + } + if (isDumpLog) + { + Log.v(TAG, " receivedMessage() [$currentBytes/$totalBytes] : ${rx_body.size} bytes. "); + val logDumpSize = if (rx_body.size > 64) 64 else rx_body.size + SimpleLogDumper.dump_bytes(" [rcv-m]", rx_body.copyOfRange(0, logDumpSize)) + } + } + + override fun isReceiveMulti(): Boolean + { + Log.v(TAG, " isReceiveMulti() : false") + return (false) + } + + companion object + { + private val TAG = "NikonLiveViewImageReceiver" + } +} diff --git a/app/src/main/java/net/osdn/gokigen/a01d/camera/ptpip/wrapper/command/IPtpIpCommand.java b/app/src/main/java/net/osdn/gokigen/a01d/camera/ptpip/wrapper/command/IPtpIpCommand.java index 787b589..825e7a5 100644 --- a/app/src/main/java/net/osdn/gokigen/a01d/camera/ptpip/wrapper/command/IPtpIpCommand.java +++ b/app/src/main/java/net/osdn/gokigen/a01d/camera/ptpip/wrapper/command/IPtpIpCommand.java @@ -56,6 +56,9 @@ public interface IPtpIpCommand // リトライオーバー発生時、コマンドを再送するか? boolean isRetrySend(); + // 最後に1回余計に受信をするか? + boolean isLastReceiveRetry(); + // 受信待ち再試行回数 int maxRetryCount(); diff --git a/app/src/main/java/net/osdn/gokigen/a01d/camera/ptpip/wrapper/command/IPtpIpMessages.java b/app/src/main/java/net/osdn/gokigen/a01d/camera/ptpip/wrapper/command/IPtpIpMessages.java index 1e670bf..866c086 100644 --- a/app/src/main/java/net/osdn/gokigen/a01d/camera/ptpip/wrapper/command/IPtpIpMessages.java +++ b/app/src/main/java/net/osdn/gokigen/a01d/camera/ptpip/wrapper/command/IPtpIpMessages.java @@ -28,6 +28,7 @@ public interface IPtpIpMessages int SEQ_CHECK_EVENT = 23; int SEQ_GET_DEVICE_PROP1 = 24; int SEQ_GET_DEVICE_PROP2 = 25; + int SEQ_GET_CAMERASTATUS = 26; int GET_STORAGE_ID = 101; int GET_STORAGE_INFO = 102; diff --git a/app/src/main/java/net/osdn/gokigen/a01d/camera/ptpip/wrapper/command/PtpIpCommandPublisher.kt b/app/src/main/java/net/osdn/gokigen/a01d/camera/ptpip/wrapper/command/PtpIpCommandPublisher.kt index 53a5450..40702d1 100644 --- a/app/src/main/java/net/osdn/gokigen/a01d/camera/ptpip/wrapper/command/PtpIpCommandPublisher.kt +++ b/app/src/main/java/net/osdn/gokigen/a01d/camera/ptpip/wrapper/command/PtpIpCommandPublisher.kt @@ -338,12 +338,12 @@ class PtpIpCommandPublisher(private val ipAddress : String, private val portNumb return (if (callback != null && callback.isReceiveMulti) { // 受信したら逐次「受信したよ」と応答するパターン - Log.v(TAG, " receiveMulti() : $delayMs [id:${command.id}]") + Log.v(TAG, " receiveMulti() : $delayMs [id:${command.id}] SEQ: $sequenceNumber") receiveMulti(command, delayMs) } else { - Log.v(TAG, " receiveSingle() : $delayMs [id:${command.id}]") + Log.v(TAG, " receiveSingle() : $delayMs [id:${command.id}] SEQ: $sequenceNumber") receiveSingle(command, delayMs) }) // 受信した後、すべてをまとめて「受信したよ」と応答するパターン @@ -381,6 +381,7 @@ class PtpIpCommandPublisher(private val ipAddress : String, private val portNumb } // 受信したデータをバッファに突っ込む + var receivedLength = 0 val byteStream = ByteArrayOutputStream() while (readBytes > 0) { @@ -392,10 +393,20 @@ class PtpIpCommandPublisher(private val ipAddress : String, private val portNumb } byteStream.write(byteArray, 0, readBytes) sleep(delayMs) + receivedLength += readBytes readBytes = inputStream.available() } - val outputStream = cutHeader(byteStream) - receivedAllMessage(isDumpReceiveLog, id, outputStream.toByteArray(), callback) + + Log.v(TAG, " receivedLength : $receivedLength") + if (receivedLength >= 4) + { + val outputStream = cutHeader(byteStream) + receivedAllMessage(isDumpReceiveLog, id, outputStream.toByteArray(), callback) + } + else + { + receivedAllMessage(isDumpReceiveLog, id, byteStream.toByteArray(), callback) + } System.gc() } catch (e: Throwable) @@ -440,7 +451,7 @@ class PtpIpCommandPublisher(private val ipAddress : String, private val portNumb if (readBytes < 0) { // リトライオーバー... - Log.v(TAG, " RECEIVE : RETRY OVER...... : " + delayMs + "ms x " + command.maxRetryCount()) + Log.v(TAG, " RECEIVE : RETRY OVER...... : " + delayMs + "ms x " + command.maxRetryCount() + " SEQ: $sequenceNumber") if (command.isRetrySend) { // 要求を再送する場合、、、ダメな場合は受信待ちとする @@ -450,79 +461,116 @@ class PtpIpCommandPublisher(private val ipAddress : String, private val portNumb callback?.receivedMessage(id, null) return (false) } - var targetLength: Int - var receivedLength: Int - run { - - // 初回データの読み込み... - readBytes = inputStream.read(byteArray, 0, receiveMessageBufferSize) + // 初回データの読み込み... + var targetLength = parseDataLength(byteArray, readBytes) + readBytes = inputStream.read(byteArray, 0, receiveMessageBufferSize) + var receivedLength = readBytes + if (targetLength <= 0) + { + // もう一回データを読み直す... targetLength = parseDataLength(byteArray, readBytes) - receivedLength = readBytes - if (targetLength <= 0) + } + + if ((targetLength <= 0)||(readBytes <= 0)) + { + // 受信サイズ異常の場合... + if (isDumpLog) { - // 受信サイズ異常の場合... - if (isDumpLog) + if (receivedLength > 0) { - if (receivedLength > 0) - { - SimpleLogDumper.dump_bytes("WRONG DATA : ", byteArray.copyOfRange(0, Math.min(receivedLength, 64))) - } - Log.v(TAG, " WRONG LENGTH. : $targetLength READ : $receivedLength bytes.") + SimpleLogDumper.dump_bytes("WRONG DATA : ", byteArray.copyOfRange(0, Math.min(receivedLength, 64))) } - callback?.receivedMessage(id, null) - - // データが不足しているので、もう一度受信待ち - return (true) + Log.v(TAG, " WRONG LENGTH. : $targetLength READ : $receivedLength bytes.") } + callback?.receivedMessage(id, null) + + // 受信したデータが不足しているので、もう一度受信待ち + Log.v(TAG, " 1st receive : AGAIN. [$readBytes][$targetLength]") + return (true) } + // 初回データの受信を報告する。 if (isDumpLog) { Log.v(TAG, " -=-=-=- 1st CALL : read_bytes : " + readBytes + "(" + receivedLength + ") : target_length : " + targetLength + " buffer SIZE : " + byteArray.size) } callback?.onReceiveProgress(receivedLength, targetLength, byteArray.copyOfRange(fromIndex = 0, toIndex = receivedLength)) - run { + var isWaitLogging = true + while ((maxRetryCount > 0)&&(readBytes >= 0)&&(receivedLength < targetLength)) + { sleep(delayMs) readBytes = inputStream.available() - if (readBytes == 0) + if (readBytes <= 0) { + if (isWaitLogging) + { + Log.v(TAG, " WAIT is.available() ... [length: $receivedLength, target: $targetLength] $readBytes bytes, retry : $maxRetryCount SEQ: $sequenceNumber") + isWaitLogging = false + } maxRetryCount-- + continue } - } - while (readBytes >= 0 && receivedLength < targetLength) - { + if (!isWaitLogging) + { + Log.v(TAG, " WAIT FOR RECEIVE COUNT: $maxRetryCount (SEQ: $sequenceNumber)") + } + readBytes = inputStream.read(byteArray, 0, receiveMessageBufferSize) if (readBytes <= 0) { if (isDumpLog) { - Log.v(TAG, " RECEIVED MESSAGE FINISHED ($readBytes)") + Log.v(TAG, " RECEIVED MESSAGE FINISHED ($readBytes) [receivedLength: $receivedLength, targetLength: $targetLength]") } break } receivedLength += readBytes callback?.onReceiveProgress(receivedLength, targetLength, byteArray.copyOfRange(0, readBytes)) maxRetryCount = command.maxRetryCount() + } - run { - sleep(delayMs) - readBytes = inputStream.available() - if (readBytes == 0) + // 最後のデータを受信した後にもう一度受信が必要な場合の処理... + if (command.isLastReceiveRetry) + { + var responseReceive = true + try + { + while (responseReceive) { - Log.v(TAG, " WAIT is.available() ... [length: $receivedLength, target: $targetLength] $readBytes bytes, retry : $maxRetryCount") - maxRetryCount-- + Log.v(TAG, " --- isLastReceiveRetry is true --- SEQ: $sequenceNumber") + sleep(delayMs) + if (inputStream.available() > 0) + { + readBytes = inputStream.read(byteArray, 0, receiveMessageBufferSize) + if (readBytes > 0) + { + receivedLength += readBytes + callback?.onReceiveProgress(receivedLength, targetLength, byteArray.copyOfRange(0, readBytes)) + Log.v(TAG, " --- isLastReceiveRetry: onReceiveProgress() $readBytes bytes. --- SEQ: $sequenceNumber ") + } + responseReceive = false + } + else + { + Log.v(TAG, " --- inputStream.available() is <= 0 --- : ${inputStream.available()} SEQ: $sequenceNumber") + responseReceive = false + } } } + catch (ex: Exception) + { + ex.printStackTrace() + } } // 終了報告... if (isDumpLog) { - Log.v(TAG, " --- receive_multi : $id ($readBytes) [$maxRetryCount] $receiveMessageBufferSize ($receivedLength) ") + Log.v(TAG, " --- receive_multi : $id ($readBytes) [$maxRetryCount] $receiveMessageBufferSize ($receivedLength) SEQ: $sequenceNumber") } - callback?.receivedMessage(id, Arrays.copyOfRange(byteArray, 0, receivedLength)) + callback?.receivedMessage(id, byteArray.copyOfRange(0, receivedLength)) } catch (e: Throwable) { @@ -610,7 +658,7 @@ class PtpIpCommandPublisher(private val ipAddress : String, private val portNumb var readBytes = 0 try { - while (readBytes <= 0) + while ((retryCount >= 0) && (readBytes <= 0)) { sleep(delayMs) readBytes = inputStream.available() @@ -618,16 +666,24 @@ class PtpIpCommandPublisher(private val ipAddress : String, private val portNumb { if (isLogOutput) { - Log.v(TAG, "waitForReceive:: is.available() WAIT... : $delayMs ms (Count : $retryCnt) ") + Log.v(TAG, "waitForReceive:: is.available() WAIT... : $delayMs ms (Count : $retryCount/$retryCnt) SEQ: $sequenceNumber") isLogOutput = false } - retryCount-- - if ((!waitForever)&&(retryCount < 0)) + if (!waitForever) { - return (-1) + retryCount-- + } + else + { + Log.v(TAG, "waitForReceive: wait forever ") + isLogOutput = false } } } + if (!isLogOutput) + { + Log.v(TAG, " --- waitForReceive : $readBytes bytes. (RetryCount : $retryCount/$retryCnt)") + } } catch (e: Exception) { diff --git a/app/src/main/java/net/osdn/gokigen/a01d/camera/ptpip/wrapper/command/messages/PtpIpCommandBase.java b/app/src/main/java/net/osdn/gokigen/a01d/camera/ptpip/wrapper/command/messages/PtpIpCommandBase.java index 1790bb2..b7c2686 100644 --- a/app/src/main/java/net/osdn/gokigen/a01d/camera/ptpip/wrapper/command/messages/PtpIpCommandBase.java +++ b/app/src/main/java/net/osdn/gokigen/a01d/camera/ptpip/wrapper/command/messages/PtpIpCommandBase.java @@ -115,6 +115,12 @@ public class PtpIpCommandBase implements IPtpIpCommand, IPtpIpMessages } @Override + public boolean isLastReceiveRetry() + { + return (false); + } + + @Override public int maxRetryCount() { return (20); -- 2.11.0