1 package net.osdn.gokigen.a01d.camera.ptpip.wrapper.command
3 import android.util.Log
4 import net.osdn.gokigen.a01d.camera.utils.SimpleLogDumper
5 import java.io.BufferedReader
6 import java.io.ByteArrayOutputStream
7 import java.io.DataOutputStream
8 import java.io.InputStream
9 import java.net.InetSocketAddress
10 import java.net.Socket
13 class PtpIpCommandPublisher(private val ipAddress : String, private val portNumber : Int, private val tcpNoDelay : Boolean, private val waitForever: Boolean) : IPtpIpCommandPublisher, IPtpIpCommunication
15 private var isConnected = false
16 private var isStart = false
17 private var isHold = false
18 private var holdId = 0
20 private var socket : Socket? = null
21 private var dos: DataOutputStream? = null
22 private var bufferedReader: BufferedReader? = null
24 private var sequenceNumber = SEQUENCE_START_NUMBER
25 private var commandQueue: Queue<IPtpIpCommand> = ArrayDeque()
26 private var holdCommandQueue: Queue<IPtpIpCommand> = ArrayDeque()
31 holdCommandQueue.clear()
34 override fun isConnected(): Boolean
39 override fun connect(): Boolean
43 Log.v(TAG, " connect()")
45 socket?.tcpNoDelay = tcpNoDelay
48 socket?.keepAlive = false
49 socket?.setPerformancePreferences(0, 2, 0)
50 socket?.oobInline = true
51 socket?.reuseAddress = false
52 socket?.trafficClass = 0x80
53 //socket?.setSoLinger(true, 3000);
54 //socket?.setReceiveBufferSize(2097152);
55 //socket?.setSendBufferSize(524288);
57 socket?.connect(InetSocketAddress(ipAddress, portNumber), 0)
69 override fun disconnect()
74 bufferedReader?.close()
84 sequenceNumber = SEQUENCE_START_NUMBER
96 // すでにコマンドのスレッド動作中なので抜ける
102 Log.v(TAG, " SOCKET IS NULL. (cannot start)")
107 Log.v(TAG, " start()")
108 val thread = Thread {
111 dos = DataOutputStream(socket?.getOutputStream())
116 val command = commandQueue.poll()
117 command?.let { issueCommand(it) }
118 Thread.sleep(COMMAND_POLL_QUEUE_MS.toLong())
128 Log.v(TAG, "<<<<< IP : $ipAddress port : $portNumber >>>>>")
148 override fun enqueueCommand(command: IPtpIpCommand): Boolean
154 return (if (holdId == command.holdId) {
155 if (command.isRelease)
157 // コマンドをキューに積んだ後、リリースする
158 val ret = commandQueue.offer(command)
162 while (holdCommandQueue.size != 0)
164 val queuedCommand = holdCommandQueue.poll()
165 commandQueue.offer(queuedCommand)
166 if (queuedCommand != null && queuedCommand.isHold)
168 // 特定シーケンスに入った場合は、そこで積みなおすのをやめる
170 holdId = queuedCommand.holdId
176 commandQueue.offer(command)
180 // 特定シーケンスではなかったので HOLD
181 holdCommandQueue.offer(command)
187 holdId = command.holdId
189 //Log.v(TAG, "Enqueue : " + command.getId());
190 return (commandQueue.offer(command))
199 override fun flushHoldQueue(): Boolean
201 Log.v(TAG, " flushHoldQueue()")
202 holdCommandQueue.clear()
207 private fun issueCommand(command: IPtpIpCommand)
214 //Log.v(TAG, "issueCommand : " + command.getId());
215 val commandBody = command.commandBody()
216 if (commandBody != null)
218 // コマンドボディが入っていた場合には、コマンド送信(入っていない場合は受信待ち)
219 sendToCamera(command.dumpLog(), commandBody, command.useSequenceNumber(), command.embeddedSequenceNumberIndex())
220 val commandBody2 = command.commandBody2()
221 if (commandBody2 != null)
223 // コマンドボディの2つめが入っていた場合には、コマンドを連続送信する
224 sendToCamera(command.dumpLog(), commandBody2, command.useSequenceNumber(), command.embeddedSequenceNumberIndex2())
226 val commandBody3 = command.commandBody3()
227 if (commandBody3 != null)
229 // コマンドボディの3つめが入っていた場合には、コマンドを連続送信する
230 sendToCamera(command.dumpLog(), commandBody3, command.useSequenceNumber(), command.embeddedSequenceNumberIndex3())
232 if (command.isIncrementSeqNumber)
238 retryOver = receiveFromCamera(command)
239 if ((retryOver)&&(commandBody != null))
241 if (!command.isRetrySend)
245 // コマンドを再送信しない場合はここで応答を待つ...
246 retryOver = receiveFromCamera(command)
250 if (!command.isIncrementSequenceNumberToRetry)
252 // 再送信...のために、シーケンス番号を戻す...
265 * カメラにコマンドを送信する(メイン部分)
268 private fun sendToCamera(isDumpReceiveLog: Boolean, byte_array: ByteArray, useSequenceNumber: Boolean, embeddedSequenceIndex: Int)
274 Log.v(TAG, " DataOutputStream is null.")
278 // メッセージボディを加工: 最初に4バイトのレングス長をつける
279 val sendData = ByteArray(byte_array.size + 4)
280 sendData[0] = (byte_array.size + 4).toByte()
284 System.arraycopy(byte_array, 0, sendData, 4, byte_array.size)
285 if (useSequenceNumber)
287 // Sequence Number を反映させる
288 sendData[embeddedSequenceIndex ] = (0x000000ff and sequenceNumber).toByte()
289 sendData[embeddedSequenceIndex + 1] = (0x0000ff00 and sequenceNumber ushr 8 and 0x000000ff).toByte()
290 sendData[embeddedSequenceIndex + 2] = (0x00ff0000 and sequenceNumber ushr 16 and 0x000000ff).toByte()
291 sendData[embeddedSequenceIndex + 3] = (-0x1000000 and sequenceNumber ushr 24 and 0x000000ff).toByte()
292 if (isDumpReceiveLog)
294 Log.v(TAG, "----- SEQ No. : $sequenceNumber -----")
297 if (isDumpReceiveLog)
300 SimpleLogDumper.dump_bytes("SEND[" + sendData.size + "] ", sendData)
313 private fun sleep(delayMs: Int)
317 Thread.sleep(delayMs.toLong())
326 * カメラからにコマンドの結果を受信する(メイン部分)
329 private fun receiveFromCamera(command: IPtpIpCommand): Boolean
331 val callback = command.responseCallback()
332 var delayMs = command.receiveDelayMs()
333 if (delayMs < 0 || delayMs > COMMAND_SEND_RECEIVE_DURATION_MAX)
335 delayMs = COMMAND_SEND_RECEIVE_DURATION_MS
338 return (if (callback != null && callback.isReceiveMulti)
340 // 受信したら逐次「受信したよ」と応答するパターン
341 Log.v(TAG, " receiveMulti() : $delayMs [id:${command.id}]")
342 receiveMulti(command, delayMs)
346 Log.v(TAG, " receiveSingle() : $delayMs [id:${command.id}]")
347 receiveSingle(command, delayMs)
349 // 受信した後、すべてをまとめて「受信したよ」と応答するパターン
352 private fun receiveSingle(command: IPtpIpCommand, delayMs: Int): Boolean
354 val isDumpReceiveLog = command.dumpLog()
356 val callback = command.responseCallback()
359 val receiveMessageBufferSize = BUFFER_SIZE
360 val byteArray = ByteArray(receiveMessageBufferSize)
361 val inputStream = socket?.getInputStream()
362 if (inputStream == null)
364 Log.v(TAG, " InputStream is NULL... RECEIVE ABORTED.")
365 receivedAllMessage(isDumpReceiveLog, id, null, callback)
369 // 初回データが受信バッファにデータが溜まるまで待つ...
370 var readBytes = waitForReceive(inputStream, delayMs, command.maxRetryCount())
374 Log.v(TAG, " RECEIVE : RETRY OVER...")
375 if (!command.isRetrySend)
377 // 再送しない場合には、応答がないことを通知する
378 receivedAllMessage(isDumpReceiveLog, id, null, callback)
384 val byteStream = ByteArrayOutputStream()
385 while (readBytes > 0)
387 readBytes = inputStream.read(byteArray, 0, receiveMessageBufferSize)
390 Log.v(TAG, " RECEIVED MESSAGE FINISHED ($readBytes)")
393 byteStream.write(byteArray, 0, readBytes)
395 readBytes = inputStream.available()
397 val outputStream = cutHeader(byteStream)
398 receivedAllMessage(isDumpReceiveLog, id, outputStream.toByteArray(), callback)
409 private fun receivedAllMessage(isDumpReceiveLog: Boolean, id: Int, body: ByteArray?, callback: IPtpIpCommandCallback?)
411 Log.v(TAG, "receivedAllMessage() : " + (body?.size ?: 0) + " bytes.")
412 if ((isDumpReceiveLog)&&(body != null))
415 SimpleLogDumper.dump_bytes("RECV[" + body.size + "] ", body)
417 callback?.receivedMessage(id, body)
420 private fun receiveMulti(command: IPtpIpCommand, delayMs: Int): Boolean
422 val isDumpLog = command.dumpLog()
423 var maxRetryCount = command.maxRetryCount()
425 val callback = command.responseCallback()
428 // Log.v(TAG, " ===== receive_multi() =====")
429 val receiveMessageBufferSize = BUFFER_SIZE
430 val byteArray = ByteArray(receiveMessageBufferSize)
431 val inputStream = socket?.getInputStream()
432 if (inputStream == null)
434 Log.v(TAG, " InputStream is NULL... RECEIVE ABORTED.")
438 // 初回データが受信バッファにデータが溜まるまで待つ...
439 var readBytes = waitForReceive(inputStream, delayMs, command.maxRetryCount())
443 Log.v(TAG, " RECEIVE : RETRY OVER...... : " + delayMs + "ms x " + command.maxRetryCount())
444 if (command.isRetrySend)
446 // 要求を再送する場合、、、ダメな場合は受信待ちとする
447 Log.v(TAG, " --- SEND RETRY ---")
450 callback?.receivedMessage(id, null)
453 var targetLength: Int
454 var receivedLength: Int
459 readBytes = inputStream.read(byteArray, 0, receiveMessageBufferSize)
460 targetLength = parseDataLength(byteArray, readBytes)
461 receivedLength = readBytes
462 if (targetLength <= 0)
467 if (receivedLength > 0)
469 SimpleLogDumper.dump_bytes("WRONG DATA : ", byteArray.copyOfRange(0, Math.min(receivedLength, 64)))
471 Log.v(TAG, " WRONG LENGTH. : $targetLength READ : $receivedLength bytes.")
473 callback?.receivedMessage(id, null)
475 // データが不足しているので、もう一度受信待ち
482 Log.v(TAG, " -=-=-=- 1st CALL : read_bytes : " + readBytes + "(" + receivedLength + ") : target_length : " + targetLength + " buffer SIZE : " + byteArray.size)
484 callback?.onReceiveProgress(receivedLength, targetLength, byteArray.copyOfRange(fromIndex = 0, toIndex = receivedLength))
488 readBytes = inputStream.available()
494 while (readBytes >= 0 && receivedLength < targetLength)
496 readBytes = inputStream.read(byteArray, 0, receiveMessageBufferSize)
501 Log.v(TAG, " RECEIVED MESSAGE FINISHED ($readBytes)")
505 receivedLength += readBytes
506 callback?.onReceiveProgress(receivedLength, targetLength, byteArray.copyOfRange(0, readBytes))
507 maxRetryCount = command.maxRetryCount()
511 readBytes = inputStream.available()
514 Log.v(TAG, " WAIT is.available() ... [length: $receivedLength, target: $targetLength] $readBytes bytes, retry : $maxRetryCount")
523 Log.v(TAG, " --- receive_multi : $id ($readBytes) [$maxRetryCount] $receiveMessageBufferSize ($receivedLength) ")
525 callback?.receivedMessage(id, Arrays.copyOfRange(byteArray, 0, receivedLength))
534 private fun parseDataLength(byte_array: ByteArray, read_bytes: Int): Int
542 if (byte_array[offset + 4].toUByte().toInt() == 0x07)
544 // 前の応答が入っていると考える... レングスバイト分読み飛ばす
545 offset = byte_array[offset].toUByte().toInt()
547 if (byte_array[offset + 4].toUByte().toInt() == 0x09)
550 lenlen = (byte_array[offset + 15].toUByte().toInt() and 0xff shl 24) + (byte_array[offset + 14].toUByte().toInt() and 0xff shl 16) + (byte_array[offset + 13].toUByte().toInt() and 0xff shl 8) + (byte_array[offset + 12].toUByte().toInt() and 0xff)
561 private fun cutHeader(receivedBuffer: ByteArrayOutputStream): ByteArrayOutputStream
565 val byteArray = receivedBuffer.toByteArray()
566 val limit = byteArray.size
568 val len = (byteArray[3].toUByte().toInt() and 0xff shl 24) + (byteArray[2].toUByte().toInt() and 0xff shl 16) + (byteArray[1].toUByte().toInt() and 0xff shl 8) + (byteArray[0].toUByte().toInt() and 0xff)
569 val packetType = byteArray[4].toUByte().toInt() and 0xff
570 if ((limit == len)||(limit < 16384))
572 // 応答は1つしか入っていない。もしくは受信データサイズが16kBの場合は、そのまま返す。
573 return (receivedBuffer)
576 if (packetType == 0x09)
578 lenlen = (byteArray[15].toUByte().toInt() and 0xff shl 24) + (byteArray[14].toUByte().toInt() and 0xff shl 16) + (byteArray[13].toUByte().toInt() and 0xff shl 8) + (byteArray[12].toUByte().toInt() and 0xff)
583 // データとしては変なので、なにもしない
584 return receivedBuffer
586 val outputStream = ByteArrayOutputStream()
587 var position = 20 // ヘッダ込の先頭
588 while (position < limit)
590 lenlen = (byteArray[position + 3].toUByte().toInt() and 0xff shl 24) + (byteArray[position + 2].toUByte().toInt() and 0xff shl 16) + (byteArray[position + 1].toUByte().toInt() and 0xff shl 8) + (byteArray[position].toUByte().toInt() and 0xff)
592 val copyByte = Math.min(limit - (position + 12), lenlen - 12)
593 outputStream.write(byteArray, position + 12, copyByte)
596 return (outputStream)
603 return (receivedBuffer)
606 private fun waitForReceive(inputStream : InputStream, delayMs: Int, retryCnt : Int): Int
608 var retryCount = retryCnt
609 var isLogOutput = true
613 while (readBytes <= 0)
616 readBytes = inputStream.available()
617 if (readBytes <= 0) // if (readBytes <= 0)
621 Log.v(TAG, "waitForReceive:: is.available() WAIT... : $delayMs ms (Count : $retryCnt) ")
625 if ((!waitForever)&&(retryCount < 0))
641 private val TAG = PtpIpCommandPublisher::class.java.simpleName
643 private const val SEQUENCE_START_NUMBER = 1
644 private const val BUFFER_SIZE = 1024 * 1024 + 16 // 受信バッファは 1MB
645 private const val COMMAND_SEND_RECEIVE_DURATION_MS = 5
646 private const val COMMAND_SEND_RECEIVE_DURATION_MAX = 3000
647 private const val COMMAND_POLL_QUEUE_MS = 5