1 package net.osdn.gokigen.a01d.camera.ptpip.wrapper.command;
3 import android.util.Log;
5 import androidx.annotation.NonNull;
7 import net.osdn.gokigen.a01d.camera.utils.SimpleLogDumper;
9 import java.io.BufferedReader;
10 import java.io.ByteArrayOutputStream;
11 import java.io.DataOutputStream;
12 import java.io.InputStream;
13 import java.net.Socket;
14 import java.util.ArrayDeque;
15 import java.util.Arrays;
16 import java.util.Queue;
18 import static net.osdn.gokigen.a01d.camera.utils.SimpleLogDumper.dump_bytes;
20 public class PtpIpCommandPublisher implements IPtpIpCommandPublisher, IPtpIpCommunication
22 private static final String TAG = PtpIpCommandPublisher.class.getSimpleName();
24 private static final int SEQUENCE_START_NUMBER = 1;
25 private static final int BUFFER_SIZE = 1024 * 1024 + 16; // 受信バッファは 1MB
26 private static final int COMMAND_SEND_RECEIVE_DURATION_MS = 5;
27 private static final int COMMAND_SEND_RECEIVE_DURATION_MAX = 3000;
28 private static final int COMMAND_POLL_QUEUE_MS = 5;
30 private final String ipAddress;
31 private final int portNumber;
33 private boolean isStart = false;
34 private boolean isHold = false;
35 private int holdId = 0;
36 private Socket socket = null;
37 private DataOutputStream dos = null;
38 private BufferedReader bufferedReader = null;
39 private int sequenceNumber = SEQUENCE_START_NUMBER;
40 private Queue<IPtpIpCommand> commandQueue;
41 private Queue<IPtpIpCommand> holdCommandQueue;
43 public PtpIpCommandPublisher(@NonNull String ip, int portNumber)
46 this.portNumber = portNumber;
47 this.commandQueue = new ArrayDeque<>();
48 this.holdCommandQueue = new ArrayDeque<>();
50 holdCommandQueue.clear();
54 public boolean isConnected()
56 return (socket != null);
60 public boolean connect()
64 socket = new Socket(ipAddress, portNumber);
76 public void disconnect()
94 if (bufferedReader != null)
96 bufferedReader.close();
103 bufferedReader = null;
117 sequenceNumber = SEQUENCE_START_NUMBER;
119 commandQueue.clear();
128 // すでにコマンドのスレッド動作中なので抜ける
133 Thread thread = new Thread(new Runnable()
140 dos = new DataOutputStream(socket.getOutputStream());
145 IPtpIpCommand command = commandQueue.poll();
148 issueCommand(command);
150 Thread.sleep(COMMAND_POLL_QUEUE_MS);
151 // Log.v(TAG, " QUEUE SIZE : " + commandQueue.size());
161 Log.v(TAG, "<<<<< IP : " + ipAddress + " port : " + portNumber + " >>>>>");
180 commandQueue.clear();
184 public boolean enqueueCommand(@NonNull IPtpIpCommand command)
189 if (holdId == command.getHoldId()) {
190 if (command.isRelease()) {
191 // コマンドをキューに積んだ後、リリースする
192 boolean ret = commandQueue.offer(command);
196 while (holdCommandQueue.size() != 0) {
197 IPtpIpCommand queuedCommand = holdCommandQueue.poll();
198 commandQueue.offer(queuedCommand);
199 if ((queuedCommand != null)&&(queuedCommand.isHold()))
201 // 特定シーケンスに入った場合は、そこで積みなおすのをやめる
203 holdId = queuedCommand.getHoldId();
209 return (commandQueue.offer(command));
211 // 特定シーケンスではなかったので HOLD
212 return (holdCommandQueue.offer(command));
215 if (command.isHold())
218 holdId = command.getHoldId();
220 //Log.v(TAG, "Enqueue : " + command.getId());
221 return (commandQueue.offer(command));
231 public boolean flushHoldQueue()
233 Log.v(TAG, " flushHoldQueue()");
234 holdCommandQueue.clear();
239 private void issueCommand(@NonNull IPtpIpCommand command)
243 boolean retry_over = true;
246 //Log.v(TAG, "issueCommand : " + command.getId());
247 byte[] commandBody = command.commandBody();
248 if (commandBody != null)
250 // コマンドボディが入っていた場合には、コマンド送信(入っていない場合は受信待ち)
251 send_to_camera(command.dumpLog(), commandBody, command.useSequenceNumber(), command.embeddedSequenceNumberIndex());
252 byte[] commandBody2 = command.commandBody2();
253 if (commandBody2 != null)
255 // コマンドボディの2つめが入っていた場合には、コマンドを連続送信する
256 send_to_camera(command.dumpLog(), commandBody2, command.useSequenceNumber(), command.embeddedSequenceNumberIndex2());
258 byte[] commandBody3 = command.commandBody3();
259 if (commandBody3 != null)
261 // コマンドボディの3つめが入っていた場合には、コマンドを連続送信する
262 send_to_camera(command.dumpLog(), commandBody3, command.useSequenceNumber(), command.embeddedSequenceNumberIndex3());
264 if (command.isIncrementSeqNumber())
270 retry_over = receive_from_camera(command);
271 if ((retry_over)&&(commandBody != null))
273 if (!command.isRetrySend())
275 // コマンドを再送信しない場合はここで抜ける
278 // 再送信...のために、シーケンス番号を戻す...
290 * カメラにコマンドを送信する(メイン部分)
293 private void send_to_camera(boolean isDumpReceiveLog, byte[] byte_array, boolean useSequenceNumber, int embeddedSequenceIndex)
299 Log.v(TAG, " DataOutputStream is null.");
303 //dos = new DataOutputStream(socket.getOutputStream()); // ここにいたらいけない?
305 // メッセージボディを加工: 最初に4バイトのレングス長をつける
306 byte[] sendData = new byte[byte_array.length + 4];
308 sendData[0] = (byte) (byte_array.length + 4);
312 System.arraycopy(byte_array,0,sendData,4, byte_array.length);
314 if (useSequenceNumber)
316 // Sequence Number を反映させる
317 sendData[embeddedSequenceIndex] = (byte) ((0x000000ff & sequenceNumber));
318 sendData[embeddedSequenceIndex + 1] = (byte) (((0x0000ff00 & sequenceNumber) >>> 8) & 0x000000ff);
319 sendData[embeddedSequenceIndex + 2] = (byte) (((0x00ff0000 & sequenceNumber) >>> 16) & 0x000000ff);
320 sendData[embeddedSequenceIndex + 3] = (byte) (((0xff000000 & sequenceNumber) >>> 24) & 0x000000ff);
321 if (isDumpReceiveLog)
323 Log.v(TAG, "----- SEQ No. : " + sequenceNumber + " -----");
327 if (isDumpReceiveLog)
330 dump_bytes("SEND[" + sendData.length + "] ", sendData);
343 private void sleep(int delayMs)
347 Thread.sleep(delayMs);
357 * カメラからにコマンドの結果を受信する(メイン部分)
360 private boolean receive_from_camera(@NonNull IPtpIpCommand command)
362 IPtpIpCommandCallback callback = command.responseCallback();
363 int delayMs = command.receiveDelayMs();
364 if ((delayMs < 0)||(delayMs > COMMAND_SEND_RECEIVE_DURATION_MAX))
366 delayMs = COMMAND_SEND_RECEIVE_DURATION_MS;
368 if ((callback != null)&&(callback.isReceiveMulti()))
370 // 受信したら逐次「受信したよ」と応答するパターン
371 return (receive_multi(command, delayMs));
373 // 受信した後、すべてをまとめて「受信したよ」と応答するパターン
374 return (receive_single(command, delayMs));
377 private boolean receive_single(@NonNull IPtpIpCommand command, int delayMs)
379 boolean isDumpReceiveLog = command.dumpLog();
380 int id = command.getId();
381 IPtpIpCommandCallback callback = command.responseCallback();
384 int receive_message_buffer_size = BUFFER_SIZE;
385 byte[] byte_array = new byte[receive_message_buffer_size];
386 InputStream is = socket.getInputStream();
389 Log.v(TAG, " InputStream is NULL... RECEIVE ABORTED.");
393 // 初回データが受信バッファにデータが溜まるまで待つ...
394 int read_bytes = waitForReceive(is, delayMs);
398 Log.v(TAG, " RECEIVE : RETRY OVER...");
403 ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
404 while (read_bytes > 0)
406 read_bytes = is.read(byte_array, 0, receive_message_buffer_size);
409 Log.v(TAG, " RECEIVED MESSAGE FINISHED (" + read_bytes + ")");
412 byteStream.write(byte_array, 0, read_bytes);
414 read_bytes = is.available();
416 ByteArrayOutputStream outputStream = cutHeader(byteStream);
417 receivedAllMessage(isDumpReceiveLog, id, outputStream.toByteArray(), callback);
428 private void receivedAllMessage(boolean isDumpReceiveLog, int id, byte[] body, IPtpIpCommandCallback callback)
430 Log.v(TAG, "receivedAllMessage() : " + ((body == null) ? 0 : body.length) + " bytes.");
431 if ((isDumpReceiveLog)&&(body != null))
434 dump_bytes("RECV[" + body.length + "] ", body);
436 if (callback != null)
438 callback.receivedMessage(id, body);
442 private boolean receive_multi(@NonNull IPtpIpCommand command, int delayMs)
444 //int estimatedSize = command.estimatedReceiveDataSize();
445 int maxRetryCount = 20;
446 int id = command.getId();
447 IPtpIpCommandCallback callback = command.responseCallback();
451 Log.v(TAG, " ===== receive_multi() =====");
452 int receive_message_buffer_size = BUFFER_SIZE;
453 byte[] byte_array = new byte[receive_message_buffer_size];
454 InputStream is = socket.getInputStream();
457 Log.v(TAG, " InputStream is NULL... RECEIVE ABORTED.");
461 // 初回データが受信バッファにデータが溜まるまで待つ...
462 int read_bytes = waitForReceive(is, delayMs);
466 Log.v(TAG, " RECEIVE : RETRY OVER......");
471 read_bytes = is.read(byte_array, 0, receive_message_buffer_size);
472 int target_length = parseDataLength(byte_array, read_bytes);
473 int received_length = read_bytes;
476 if (callback != null)
478 Log.v(TAG, " --- 1st CALL : read_bytes : "+ read_bytes + "(" + received_length + ") : target_length : " + target_length + " buffer SIZE : " + byte_array.length);
479 callback.onReceiveProgress(received_length, target_length, Arrays.copyOfRange(byte_array, 0, received_length));
485 read_bytes = is.available();
488 Log.v(TAG, " WAIT is.available() ... [" + received_length + ", " + target_length + "] retry : " + maxRetryCount);
491 } while ((read_bytes == 0)&&(maxRetryCount > 0)&&(received_length < target_length)); // ((read_bytes == 0)&&(estimatedSize > 0)&&(received_length < estimatedSize));
493 while ((read_bytes >= 0)&&(received_length < target_length))
495 read_bytes = is.read(byte_array, 0, receive_message_buffer_size);
498 Log.v(TAG, " RECEIVED MESSAGE FINISHED (" + read_bytes + ")");
501 received_length = received_length + read_bytes;
504 if (callback != null)
506 //Log.v(TAG, " --- CALL : read_bytes : "+ read_bytes + " total_read : " + received_length + " : total_length : " + target_length + " buffer SIZE : " + byte_array.length);
507 callback.onReceiveProgress(received_length, target_length, Arrays.copyOfRange(byte_array, 0, read_bytes));
509 //byteStream.write(byte_array, 0, read_bytes);
515 read_bytes = is.available();
516 //Log.v(TAG, " is.available() read_bytes : " + read_bytes + " " + received_length + " < " + estimatedSize);
519 Log.v(TAG, " WAIT is.available() ... [" + received_length + ", " + target_length + "] " + read_bytes + " retry : " + maxRetryCount);
522 } while ((read_bytes == 0)&&(maxRetryCount > 0)&&(received_length < target_length)); // while ((read_bytes == 0)&&(estimatedSize > 0)&&(received_length < estimatedSize));
524 //ByteArrayOutputStream outputStream = cutHeader(byteStream);
525 //receivedMessage(isDumpReceiveLog, id, outputStream.toByteArray(), callback);
528 if (callback != null)
530 Log.v(TAG, " --- receive_multi : " + id + " (" + read_bytes + ") [" + maxRetryCount + "] " + receive_message_buffer_size + " (" + received_length + ") ");
531 callback.receivedMessage(id, null);
543 private int parseDataLength(byte[] byte_array, int read_bytes)
549 if ((read_bytes > 20)&&((int) byte_array[4] == 0x09))
551 lenlen = ((((int) byte_array[15]) & 0xff) << 24) + ((((int) byte_array[14]) & 0xff) << 16) + ((((int) byte_array[13]) & 0xff) << 8) + (((int) byte_array[12]) & 0xff);
552 packetType = (((int)byte_array[16]) & 0xff);
554 Log.v(TAG, " --- parseDataLength() length: " + lenlen + " TYPE: " + packetType + " read_bytes: " + read_bytes);
563 private ByteArrayOutputStream cutHeader(ByteArrayOutputStream receivedBuffer)
567 byte[] byte_array = receivedBuffer.toByteArray();
568 int limit = byte_array.length;
570 int len = ((((int) byte_array[3]) & 0xff) << 24) + ((((int) byte_array[2]) & 0xff) << 16) + ((((int) byte_array[1]) & 0xff) << 8) + (((int) byte_array[0]) & 0xff);
571 int packetType = (((int) byte_array[4]) & 0xff);
572 if ((limit == len)||(limit < 16384))
574 // 応答は1つしか入っていない。もしくは受信データサイズが16kBの場合は、そのまま返す。
575 return (receivedBuffer);
577 if (packetType == 0x09)
579 lenlen = ((((int) byte_array[15]) & 0xff) << 24) + ((((int) byte_array[14]) & 0xff) << 16) + ((((int) byte_array[13]) & 0xff) << 8) + (((int) byte_array[12]) & 0xff);
580 packetType = (((int) byte_array[16]) & 0xff);
582 // Log.v(TAG, " --- RECEIVED MESSAGE : " + len + " bytes (BUFFER: " + byte_array.length + " bytes)" + " length : " + lenlen + " TYPE : " + packetType + " --- ");
585 // データとしては変なので、なにもしない
586 return (receivedBuffer);
588 ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
589 //outputStream.write(byte_array, 0, 20); //
590 int position = 20; // ヘッダ込の先頭
591 while (position < limit)
593 lenlen = ((((int) byte_array[position + 3]) & 0xff) << 24) + ((((int) byte_array[position + 2]) & 0xff) << 16) + ((((int) byte_array[position + 1]) & 0xff) << 8) + (((int) byte_array[position]) & 0xff);
594 packetType = (((int) byte_array[position + 4]) & 0xff);
596 if (packetType != 0x0a)
598 Log.v(TAG, " <><><> PACKET TYPE : " + packetType + " LENGTH : " + lenlen);
601 int copyByte = ((lenlen - 12) > (limit - (position + 12))) ? (limit - (position + 12)) : (lenlen - 12);
602 outputStream.write(byte_array, (position + 12), copyByte);
603 position = position + lenlen;
605 return (outputStream);
612 return (receivedBuffer);
615 private int waitForReceive(InputStream is, int delayMs)
617 boolean isLogOutput = true;
618 int retry_count = 50;
622 while (read_bytes <= 0)
625 read_bytes = is.available();
630 Log.v(TAG, " is.available() WAIT... ");