1 package net.osdn.gokigen.a01d.camera.ptpip.wrapper.command;
3 import android.util.Log;
5 import androidx.annotation.NonNull;
7 import java.io.BufferedReader;
8 import java.io.ByteArrayOutputStream;
9 import java.io.DataOutputStream;
10 import java.io.InputStream;
11 import java.net.Socket;
12 import java.util.ArrayDeque;
13 import java.util.Arrays;
14 import java.util.Queue;
16 import static net.osdn.gokigen.a01d.camera.utils.SimpleLogDumper.dump_bytes;
18 public class PtpIpCommandPublisher implements IPtpIpCommandPublisher, IPtpIpCommunication
20 private static final String TAG = PtpIpCommandPublisher.class.getSimpleName();
22 private static final int SEQUENCE_START_NUMBER = 1;
23 private static final int BUFFER_SIZE = 1024 * 1024 + 16; // 受信バッファは 256kB
24 private static final int COMMAND_SEND_RECEIVE_DURATION_MS = 5;
25 private static final int COMMAND_SEND_RECEIVE_DURATION_MAX = 3000;
26 private static final int COMMAND_POLL_QUEUE_MS = 5;
28 private final String ipAddress;
29 private final int portNumber;
31 private boolean isStart = false;
32 private boolean isHold = false;
33 private int holdId = 0;
34 private Socket socket = null;
35 private DataOutputStream dos = null;
36 private BufferedReader bufferedReader = null;
37 private int sequenceNumber = SEQUENCE_START_NUMBER;
38 private Queue<IPtpIpCommand> commandQueue;
39 private Queue<IPtpIpCommand> holdCommandQueue;
41 public PtpIpCommandPublisher(@NonNull String ip, int portNumber)
44 this.portNumber = portNumber;
45 this.commandQueue = new ArrayDeque<>();
46 this.holdCommandQueue = new ArrayDeque<>();
48 holdCommandQueue.clear();
52 public boolean isConnected()
54 return (socket != null);
58 public boolean connect()
62 socket = new Socket(ipAddress, portNumber);
74 public void disconnect()
92 if (bufferedReader != null)
94 bufferedReader.close();
101 bufferedReader = null;
115 sequenceNumber = SEQUENCE_START_NUMBER;
117 commandQueue.clear();
126 // すでにコマンドのスレッド動作中なので抜ける
131 Thread thread = new Thread(new Runnable()
138 dos = new DataOutputStream(socket.getOutputStream());
143 IPtpIpCommand command = commandQueue.poll();
146 issueCommand(command);
148 Thread.sleep(COMMAND_POLL_QUEUE_MS);
158 Log.v(TAG, "<<<<< IP : " + ipAddress + " port : " + portNumber + " >>>>>");
177 commandQueue.clear();
181 public boolean enqueueCommand(@NonNull IPtpIpCommand command)
186 if (holdId == command.getHoldId()) {
187 if (command.isRelease()) {
188 // コマンドをキューに積んだ後、リリースする
189 boolean ret = commandQueue.offer(command);
193 while (holdCommandQueue.size() != 0) {
194 IPtpIpCommand queuedCommand = holdCommandQueue.poll();
195 commandQueue.offer(queuedCommand);
196 if ((queuedCommand != null)&&(queuedCommand.isHold()))
198 // 特定シーケンスに入った場合は、そこで積みなおすのをやめる
200 holdId = queuedCommand.getHoldId();
206 return (commandQueue.offer(command));
208 // 特定シーケンスではなかったので HOLD
209 return (holdCommandQueue.offer(command));
212 if (command.isHold())
215 holdId = command.getHoldId();
217 //Log.v(TAG, "Enqueue : " + command.getId());
218 return (commandQueue.offer(command));
228 public boolean flushHoldQueue()
230 Log.v(TAG, " flushHoldQueue()");
231 holdCommandQueue.clear();
236 private void issueCommand(@NonNull IPtpIpCommand command)
240 boolean retry_over = true;
243 //Log.v(TAG, "issueCommand : " + command.getId());
244 byte[] commandBody = command.commandBody();
245 if (commandBody != null)
247 // コマンドボディが入っていた場合には、コマンド送信(入っていない場合は受信待ち)
248 send_to_camera(command.dumpLog(), commandBody, command.useSequenceNumber(), command.embeddedSequenceNumberIndex());
249 byte[] commandBody2 = command.commandBody2();
250 if (commandBody2 != null)
252 // コマンドボディの2つめが入っていた場合には、コマンドを連続送信する
253 send_to_camera(command.dumpLog(), commandBody2, command.useSequenceNumber(), command.embeddedSequenceNumberIndex2());
255 byte[] commandBody3 = command.commandBody3();
256 if (commandBody3 != null)
258 // コマンドボディの3つめが入っていた場合には、コマンドを連続送信する
259 send_to_camera(command.dumpLog(), commandBody3, command.useSequenceNumber(), command.embeddedSequenceNumberIndex3());
261 if (command.isIncrementSeqNumber())
267 retry_over = receive_from_camera(command);
268 if ((retry_over)&&(commandBody != null))
270 if (!command.isRetrySend())
272 // コマンドを再送信しない場合はここで抜ける
275 // 再送信...のために、シーケンス番号を戻す...
287 * カメラにコマンドを送信する(メイン部分)
290 private void send_to_camera(boolean isDumpReceiveLog, byte[] byte_array, boolean useSequenceNumber, int embeddedSequenceIndex)
296 Log.v(TAG, " DataOutputStream is null.");
300 //dos = new DataOutputStream(socket.getOutputStream()); // ここにいたらいけない?
302 // メッセージボディを加工: 最初に4バイトのレングス長をつける
303 byte[] sendData = new byte[byte_array.length + 4];
305 sendData[0] = (byte) (byte_array.length + 4);
309 System.arraycopy(byte_array,0,sendData,4, byte_array.length);
311 if (useSequenceNumber)
313 // Sequence Number を反映させる
314 sendData[embeddedSequenceIndex] = (byte) ((0x000000ff & sequenceNumber));
315 sendData[embeddedSequenceIndex + 1] = (byte) (((0x0000ff00 & sequenceNumber) >>> 8) & 0x000000ff);
316 sendData[embeddedSequenceIndex + 2] = (byte) (((0x00ff0000 & sequenceNumber) >>> 16) & 0x000000ff);
317 sendData[embeddedSequenceIndex + 3] = (byte) (((0xff000000 & sequenceNumber) >>> 24) & 0x000000ff);
318 if (isDumpReceiveLog)
320 Log.v(TAG, "----- SEQ No. : " + sequenceNumber + " -----");
324 if (isDumpReceiveLog)
327 dump_bytes("SEND[" + sendData.length + "] ", sendData);
340 private void sleep(int delayMs)
344 Thread.sleep(delayMs);
354 * カメラからにコマンドの結果を受信する(メイン部分)
357 private boolean receive_from_camera(@NonNull IPtpIpCommand command)
359 IPtpIpCommandCallback callback = command.responseCallback();
360 int delayMs = command.receiveDelayMs();
361 if ((delayMs < 0)||(delayMs > COMMAND_SEND_RECEIVE_DURATION_MAX))
363 delayMs = COMMAND_SEND_RECEIVE_DURATION_MS;
365 if ((callback != null)&&(callback.isReceiveMulti()))
367 // 受信したら逐次「受信したよ」と応答するパターン
368 return (receive_multi(command, delayMs));
370 // 受信した後、すべてをまとめて「受信したよ」と応答するパターン
371 return (receive_single(command, delayMs));
374 private boolean receive_single(@NonNull IPtpIpCommand command, int delayMs)
376 boolean isDumpReceiveLog = command.dumpLog();
377 int id = command.getId();
378 IPtpIpCommandCallback callback = command.responseCallback();
381 int receive_message_buffer_size = BUFFER_SIZE;
382 byte[] byte_array = new byte[receive_message_buffer_size];
383 InputStream is = socket.getInputStream();
386 Log.v(TAG, " InputStream is NULL... RECEIVE ABORTED.");
390 // 初回データが受信バッファにデータが溜まるまで待つ...
391 int read_bytes = waitForReceive(is, delayMs);
395 Log.v(TAG, " RECEIVE : RETRY OVER...");
400 ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
401 while (read_bytes > 0)
403 read_bytes = is.read(byte_array, 0, receive_message_buffer_size);
406 Log.v(TAG, " RECEIVED MESSAGE FINISHED (" + read_bytes + ")");
409 byteStream.write(byte_array, 0, read_bytes);
411 read_bytes = is.available();
413 ByteArrayOutputStream outputStream = cutHeader(byteStream);
414 receivedAllMessage(isDumpReceiveLog, id, outputStream.toByteArray(), callback);
425 private void receivedAllMessage(boolean isDumpReceiveLog, int id, byte[] body, IPtpIpCommandCallback callback)
427 Log.v(TAG, "receivedAllMessage() : " + ((body == null) ? 0 : body.length) + " bytes.");
428 if ((isDumpReceiveLog)&&(body != null))
431 dump_bytes("RECV[" + body.length + "] ", body);
433 if (callback != null)
435 callback.receivedMessage(id, body);
439 private boolean receive_multi(@NonNull IPtpIpCommand command, int delayMs)
441 int estimatedSize = command.estimatedReceiveDataSize();
442 int id = command.getId();
443 IPtpIpCommandCallback callback = command.responseCallback();
447 Log.v(TAG, " ===== receive_multi() =====");
448 int receive_message_buffer_size = BUFFER_SIZE;
449 byte[] byte_array = new byte[receive_message_buffer_size];
450 InputStream is = socket.getInputStream();
453 Log.v(TAG, " InputStream is NULL... RECEIVE ABORTED.");
457 // 初回データが受信バッファにデータが溜まるまで待つ...
458 int read_bytes = waitForReceive(is, delayMs);
462 Log.v(TAG, " RECEIVE : RETRY OVER......");
467 read_bytes = is.read(byte_array, 0, receive_message_buffer_size);
468 int target_length = parseDataLength(byte_array, read_bytes);
469 int received_length = read_bytes;
472 if (callback != null)
474 Log.v(TAG, " --- 1st CALL : read_bytes : "+ read_bytes + "(" + received_length + ") : total_length : " + target_length + " buffer SIZE : " + byte_array.length);
475 callback.onReceiveProgress(received_length, target_length, Arrays.copyOfRange(byte_array, 0, received_length));
481 read_bytes = is.available();
484 Log.v(TAG, " WAIT is.available() ... " + received_length + " < " + estimatedSize);
486 } while ((read_bytes == 0)&&(estimatedSize > 0)&&(received_length < estimatedSize));
487 while (read_bytes > 0)
489 read_bytes = is.read(byte_array, 0, receive_message_buffer_size);
492 Log.v(TAG, " RECEIVED MESSAGE FINISHED (" + read_bytes + ")");
495 received_length = received_length + read_bytes;
498 if (callback != null)
500 //Log.v(TAG, " --- CALL : read_bytes : "+ read_bytes + " total_read : " + received_length + " : total_length : " + target_length + " buffer SIZE : " + byte_array.length);
501 callback.onReceiveProgress(received_length, target_length, Arrays.copyOfRange(byte_array, 0, read_bytes));
503 //byteStream.write(byte_array, 0, read_bytes);
508 read_bytes = is.available();
509 //Log.v(TAG, " is.available() read_bytes : " + read_bytes + " " + received_length + " < " + estimatedSize);
510 } while ((read_bytes == 0)&&(estimatedSize > 0)&&(received_length < estimatedSize));
512 //ByteArrayOutputStream outputStream = cutHeader(byteStream);
513 //receivedMessage(isDumpReceiveLog, id, outputStream.toByteArray(), callback);
516 if (callback != null)
518 Log.v(TAG, " --- receive_multi : receivedMessage() : " + id + " (" + read_bytes + ") [" + estimatedSize + "] " + receive_message_buffer_size + " (" + received_length + ")");
519 callback.receivedMessage(id, null);
531 private int parseDataLength(byte[] byte_array, int read_bytes)
537 if ((read_bytes > 20)&&((int) byte_array[4] == 0x09))
539 lenlen = ((((int) byte_array[15]) & 0xff) << 24) + ((((int) byte_array[14]) & 0xff) << 16) + ((((int) byte_array[13]) & 0xff) << 8) + (((int) byte_array[12]) & 0xff);
540 packetType = (((int)byte_array[16]) & 0xff);
542 Log.v(TAG, " --- parseDataLength() length: " + lenlen + " TYPE: " + packetType + " read_bytes: " + read_bytes);
551 private ByteArrayOutputStream cutHeader(ByteArrayOutputStream receivedBuffer)
555 byte[] byte_array = receivedBuffer.toByteArray();
556 int limit = byte_array.length;
558 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);
559 int packetType = (((int) byte_array[4]) & 0xff);
560 if ((limit == len)||(limit < 16384))
562 // 応答は1つしか入っていない。もしくは受信データサイズが16kBの場合は、そのまま返す。
563 return (receivedBuffer);
565 if (packetType == 0x09)
567 lenlen = ((((int) byte_array[15]) & 0xff) << 24) + ((((int) byte_array[14]) & 0xff) << 16) + ((((int) byte_array[13]) & 0xff) << 8) + (((int) byte_array[12]) & 0xff);
568 packetType = (((int) byte_array[16]) & 0xff);
570 Log.v(TAG, " --- RECEIVED MESSAGE : " + len + " bytes (BUFFER: " + byte_array.length + " bytes)" + " length : " + lenlen + " TYPE : " + packetType + " --- ");
573 // データとしては変なので、なにもしない
574 return (receivedBuffer);
576 ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
577 //outputStream.write(byte_array, 0, 20); //
578 int position = 20; // ヘッダ込の先頭
579 while (position < limit)
581 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);
582 packetType = (((int) byte_array[position + 4]) & 0xff);
583 if (packetType != 0x0a)
585 Log.v(TAG, " <><><> PACKET TYPE : " + packetType + " LENGTH : " + lenlen);
587 int copyByte = ((lenlen - 12) > (limit - (position + 12))) ? (limit - (position + 12)) : (lenlen - 12);
588 outputStream.write(byte_array, (position + 12), copyByte);
589 position = position + lenlen;
591 return (outputStream);
598 return (receivedBuffer);
601 private int waitForReceive(InputStream is, int delayMs)
603 boolean isLogOutput = true;
604 int retry_count = 50;
608 while (read_bytes <= 0)
611 read_bytes = is.available();
616 Log.v(TAG, " is.available() WAIT... ");