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);
149 // Log.v(TAG, " QUEUE SIZE : " + commandQueue.size());
159 Log.v(TAG, "<<<<< IP : " + ipAddress + " port : " + portNumber + " >>>>>");
178 commandQueue.clear();
182 public boolean enqueueCommand(@NonNull IPtpIpCommand command)
187 if (holdId == command.getHoldId()) {
188 if (command.isRelease()) {
189 // コマンドをキューに積んだ後、リリースする
190 boolean ret = commandQueue.offer(command);
194 while (holdCommandQueue.size() != 0) {
195 IPtpIpCommand queuedCommand = holdCommandQueue.poll();
196 commandQueue.offer(queuedCommand);
197 if ((queuedCommand != null)&&(queuedCommand.isHold()))
199 // 特定シーケンスに入った場合は、そこで積みなおすのをやめる
201 holdId = queuedCommand.getHoldId();
207 return (commandQueue.offer(command));
209 // 特定シーケンスではなかったので HOLD
210 return (holdCommandQueue.offer(command));
213 if (command.isHold())
216 holdId = command.getHoldId();
218 //Log.v(TAG, "Enqueue : " + command.getId());
219 return (commandQueue.offer(command));
229 public boolean flushHoldQueue()
231 Log.v(TAG, " flushHoldQueue()");
232 holdCommandQueue.clear();
237 private void issueCommand(@NonNull IPtpIpCommand command)
241 boolean retry_over = true;
244 //Log.v(TAG, "issueCommand : " + command.getId());
245 byte[] commandBody = command.commandBody();
246 if (commandBody != null)
248 // コマンドボディが入っていた場合には、コマンド送信(入っていない場合は受信待ち)
249 send_to_camera(command.dumpLog(), commandBody, command.useSequenceNumber(), command.embeddedSequenceNumberIndex());
250 byte[] commandBody2 = command.commandBody2();
251 if (commandBody2 != null)
253 // コマンドボディの2つめが入っていた場合には、コマンドを連続送信する
254 send_to_camera(command.dumpLog(), commandBody2, command.useSequenceNumber(), command.embeddedSequenceNumberIndex2());
256 byte[] commandBody3 = command.commandBody3();
257 if (commandBody3 != null)
259 // コマンドボディの3つめが入っていた場合には、コマンドを連続送信する
260 send_to_camera(command.dumpLog(), commandBody3, command.useSequenceNumber(), command.embeddedSequenceNumberIndex3());
262 if (command.isIncrementSeqNumber())
268 retry_over = receive_from_camera(command);
269 if ((retry_over)&&(commandBody != null))
271 if (!command.isRetrySend())
273 // コマンドを再送信しない場合はここで抜ける
276 // 再送信...のために、シーケンス番号を戻す...
288 * カメラにコマンドを送信する(メイン部分)
291 private void send_to_camera(boolean isDumpReceiveLog, byte[] byte_array, boolean useSequenceNumber, int embeddedSequenceIndex)
297 Log.v(TAG, " DataOutputStream is null.");
301 //dos = new DataOutputStream(socket.getOutputStream()); // ここにいたらいけない?
303 // メッセージボディを加工: 最初に4バイトのレングス長をつける
304 byte[] sendData = new byte[byte_array.length + 4];
306 sendData[0] = (byte) (byte_array.length + 4);
310 System.arraycopy(byte_array,0,sendData,4, byte_array.length);
312 if (useSequenceNumber)
314 // Sequence Number を反映させる
315 sendData[embeddedSequenceIndex] = (byte) ((0x000000ff & sequenceNumber));
316 sendData[embeddedSequenceIndex + 1] = (byte) (((0x0000ff00 & sequenceNumber) >>> 8) & 0x000000ff);
317 sendData[embeddedSequenceIndex + 2] = (byte) (((0x00ff0000 & sequenceNumber) >>> 16) & 0x000000ff);
318 sendData[embeddedSequenceIndex + 3] = (byte) (((0xff000000 & sequenceNumber) >>> 24) & 0x000000ff);
319 if (isDumpReceiveLog)
321 Log.v(TAG, "----- SEQ No. : " + sequenceNumber + " -----");
325 if (isDumpReceiveLog)
328 dump_bytes("SEND[" + sendData.length + "] ", sendData);
341 private void sleep(int delayMs)
345 Thread.sleep(delayMs);
355 * カメラからにコマンドの結果を受信する(メイン部分)
358 private boolean receive_from_camera(@NonNull IPtpIpCommand command)
360 IPtpIpCommandCallback callback = command.responseCallback();
361 int delayMs = command.receiveDelayMs();
362 if ((delayMs < 0)||(delayMs > COMMAND_SEND_RECEIVE_DURATION_MAX))
364 delayMs = COMMAND_SEND_RECEIVE_DURATION_MS;
366 if ((callback != null)&&(callback.isReceiveMulti()))
368 // 受信したら逐次「受信したよ」と応答するパターン
369 return (receive_multi(command, delayMs));
371 // 受信した後、すべてをまとめて「受信したよ」と応答するパターン
372 return (receive_single(command, delayMs));
375 private boolean receive_single(@NonNull IPtpIpCommand command, int delayMs)
377 boolean isDumpReceiveLog = command.dumpLog();
378 int id = command.getId();
379 IPtpIpCommandCallback callback = command.responseCallback();
382 int receive_message_buffer_size = BUFFER_SIZE;
383 byte[] byte_array = new byte[receive_message_buffer_size];
384 InputStream is = socket.getInputStream();
387 Log.v(TAG, " InputStream is NULL... RECEIVE ABORTED.");
391 // 初回データが受信バッファにデータが溜まるまで待つ...
392 int read_bytes = waitForReceive(is, delayMs);
396 Log.v(TAG, " RECEIVE : RETRY OVER...");
401 ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
402 while (read_bytes > 0)
404 read_bytes = is.read(byte_array, 0, receive_message_buffer_size);
407 Log.v(TAG, " RECEIVED MESSAGE FINISHED (" + read_bytes + ")");
410 byteStream.write(byte_array, 0, read_bytes);
412 read_bytes = is.available();
414 ByteArrayOutputStream outputStream = cutHeader(byteStream);
415 receivedAllMessage(isDumpReceiveLog, id, outputStream.toByteArray(), callback);
426 private void receivedAllMessage(boolean isDumpReceiveLog, int id, byte[] body, IPtpIpCommandCallback callback)
428 Log.v(TAG, "receivedAllMessage() : " + ((body == null) ? 0 : body.length) + " bytes.");
429 if ((isDumpReceiveLog)&&(body != null))
432 dump_bytes("RECV[" + body.length + "] ", body);
434 if (callback != null)
436 callback.receivedMessage(id, body);
440 private boolean receive_multi(@NonNull IPtpIpCommand command, int delayMs)
442 int estimatedSize = command.estimatedReceiveDataSize();
443 int id = command.getId();
444 IPtpIpCommandCallback callback = command.responseCallback();
448 Log.v(TAG, " ===== receive_multi() =====");
449 int receive_message_buffer_size = BUFFER_SIZE;
450 byte[] byte_array = new byte[receive_message_buffer_size];
451 InputStream is = socket.getInputStream();
454 Log.v(TAG, " InputStream is NULL... RECEIVE ABORTED.");
458 // 初回データが受信バッファにデータが溜まるまで待つ...
459 int read_bytes = waitForReceive(is, delayMs);
463 Log.v(TAG, " RECEIVE : RETRY OVER......");
468 read_bytes = is.read(byte_array, 0, receive_message_buffer_size);
469 int target_length = parseDataLength(byte_array, read_bytes);
470 int received_length = read_bytes;
473 if (callback != null)
475 Log.v(TAG, " --- 1st CALL : read_bytes : "+ read_bytes + "(" + received_length + ") : total_length : " + target_length + " buffer SIZE : " + byte_array.length);
476 callback.onReceiveProgress(received_length, target_length, Arrays.copyOfRange(byte_array, 0, received_length));
482 read_bytes = is.available();
485 Log.v(TAG, " WAIT is.available() ... " + received_length + " < " + estimatedSize);
487 } while ((read_bytes == 0)&&(estimatedSize > 0)&&(received_length < estimatedSize));
488 while (read_bytes > 0)
490 read_bytes = is.read(byte_array, 0, receive_message_buffer_size);
493 Log.v(TAG, " RECEIVED MESSAGE FINISHED (" + read_bytes + ")");
496 received_length = received_length + read_bytes;
499 if (callback != null)
501 //Log.v(TAG, " --- CALL : read_bytes : "+ read_bytes + " total_read : " + received_length + " : total_length : " + target_length + " buffer SIZE : " + byte_array.length);
502 callback.onReceiveProgress(received_length, target_length, Arrays.copyOfRange(byte_array, 0, read_bytes));
504 //byteStream.write(byte_array, 0, read_bytes);
509 read_bytes = is.available();
510 //Log.v(TAG, " is.available() read_bytes : " + read_bytes + " " + received_length + " < " + estimatedSize);
511 } while ((read_bytes == 0)&&(estimatedSize > 0)&&(received_length < estimatedSize));
513 //ByteArrayOutputStream outputStream = cutHeader(byteStream);
514 //receivedMessage(isDumpReceiveLog, id, outputStream.toByteArray(), callback);
517 if (callback != null)
519 Log.v(TAG, " --- receive_multi : receivedMessage() : " + id + " (" + read_bytes + ") [" + estimatedSize + "] " + receive_message_buffer_size + " (" + received_length + ")");
520 callback.receivedMessage(id, null);
532 private int parseDataLength(byte[] byte_array, int read_bytes)
538 if ((read_bytes > 20)&&((int) byte_array[4] == 0x09))
540 lenlen = ((((int) byte_array[15]) & 0xff) << 24) + ((((int) byte_array[14]) & 0xff) << 16) + ((((int) byte_array[13]) & 0xff) << 8) + (((int) byte_array[12]) & 0xff);
541 packetType = (((int)byte_array[16]) & 0xff);
543 Log.v(TAG, " --- parseDataLength() length: " + lenlen + " TYPE: " + packetType + " read_bytes: " + read_bytes);
552 private ByteArrayOutputStream cutHeader(ByteArrayOutputStream receivedBuffer)
556 byte[] byte_array = receivedBuffer.toByteArray();
557 int limit = byte_array.length;
559 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);
560 int packetType = (((int) byte_array[4]) & 0xff);
561 if ((limit == len)||(limit < 16384))
563 // 応答は1つしか入っていない。もしくは受信データサイズが16kBの場合は、そのまま返す。
564 return (receivedBuffer);
566 if (packetType == 0x09)
568 lenlen = ((((int) byte_array[15]) & 0xff) << 24) + ((((int) byte_array[14]) & 0xff) << 16) + ((((int) byte_array[13]) & 0xff) << 8) + (((int) byte_array[12]) & 0xff);
569 packetType = (((int) byte_array[16]) & 0xff);
571 Log.v(TAG, " --- RECEIVED MESSAGE : " + len + " bytes (BUFFER: " + byte_array.length + " bytes)" + " length : " + lenlen + " TYPE : " + packetType + " --- ");
574 // データとしては変なので、なにもしない
575 return (receivedBuffer);
577 ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
578 //outputStream.write(byte_array, 0, 20); //
579 int position = 20; // ヘッダ込の先頭
580 while (position < limit)
582 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);
583 packetType = (((int) byte_array[position + 4]) & 0xff);
585 if (packetType != 0x0a)
587 Log.v(TAG, " <><><> PACKET TYPE : " + packetType + " LENGTH : " + lenlen);
590 int copyByte = ((lenlen - 12) > (limit - (position + 12))) ? (limit - (position + 12)) : (lenlen - 12);
591 outputStream.write(byte_array, (position + 12), copyByte);
592 position = position + lenlen;
594 return (outputStream);
601 return (receivedBuffer);
604 private int waitForReceive(InputStream is, int delayMs)
606 boolean isLogOutput = true;
607 int retry_count = 50;
611 while (read_bytes <= 0)
614 read_bytes = is.available();
619 Log.v(TAG, " is.available() WAIT... ");