1 package net.osdn.gokigen.a01d.camera.kodak.wrapper.command;
3 import android.util.Log;
5 import androidx.annotation.NonNull;
6 import androidx.annotation.Nullable;
8 import net.osdn.gokigen.a01d.camera.kodak.wrapper.command.messages.KodakCommandReceiveOnly;
10 import java.io.BufferedReader;
11 import java.io.ByteArrayOutputStream;
12 import java.io.DataOutputStream;
13 import java.io.InputStream;
14 import java.net.InetSocketAddress;
15 import java.net.Socket;
16 import java.util.ArrayDeque;
17 import java.util.Queue;
19 import static net.osdn.gokigen.a01d.camera.kodak.wrapper.command.messages.IKodakMessages.SEQ_RECEIVE_ONLY;
20 import static net.osdn.gokigen.a01d.camera.utils.SimpleLogDumper.dump_bytes;
22 public class KodakCommandCommunicator implements IKodakCommandPublisher, IKodakCommunication
24 private static final String TAG = KodakCommandCommunicator.class.getSimpleName();
26 private static final int BUFFER_SIZE = 1024 * 1024 + 16; // 受信バッファは 1MB
27 private static final int COMMAND_SEND_RECEIVE_DURATION_MS = 5;
28 private static final int COMMAND_SEND_RECEIVE_DURATION_MAX = 3000;
29 private static final int COMMAND_POLL_QUEUE_MS = 5;
31 private final String ipAddress;
32 private final int portNumber;
34 private boolean isStart = false;
35 private boolean tcpNoDelay;
36 private boolean waitForever;
37 private Socket socket = null;
38 private DataOutputStream dos = null;
39 private BufferedReader bufferedReader = null;
40 private Queue<IKodakCommand> commandQueue;
42 public KodakCommandCommunicator(@NonNull String ip, int portNumber, boolean tcpNoDelay, boolean waitForever)
45 this.portNumber = portNumber;
46 this.tcpNoDelay = tcpNoDelay;
47 this.waitForever = waitForever;
48 this.commandQueue = new ArrayDeque<>();
53 public boolean isConnected()
55 return (socket != null);
59 public boolean connect()
63 Log.v(TAG, " connect()");
64 socket = new Socket();
65 socket.setTcpNoDelay(tcpNoDelay);
68 socket.setKeepAlive(false);
69 socket.setPerformancePreferences(0, 2, 0);
70 socket.setOOBInline(true);
71 socket.setReuseAddress(false);
72 socket.setTrafficClass(0x80);
74 socket.connect(new InetSocketAddress(ipAddress, portNumber), 0);
85 private void closeOutputStream()
101 private void closeBufferedReader()
105 if (bufferedReader != null)
107 bufferedReader.close();
114 bufferedReader = null;
117 private void closeSocket()
134 public void disconnect()
138 closeBufferedReader();
142 commandQueue.clear();
151 // すでにコマンドのスレッド動作中なので抜ける
155 Log.v(TAG, " start()");
157 Thread thread = new Thread(new Runnable()
164 InputStream is = socket.getInputStream();
165 dos = new DataOutputStream(socket.getOutputStream());
170 IKodakCommand command = commandQueue.poll();
173 issueCommand(command);
175 Thread.sleep(COMMAND_POLL_QUEUE_MS);
176 if ((is != null)&&(is.available() > 0))
178 Log.v(TAG, " --- RECV MSG --- ");
179 receive_from_camera(new KodakCommandReceiveOnly(SEQ_RECEIVE_ONLY, null));
190 Log.v(TAG, "<<<<< IP : " + ipAddress + " port : " + portNumber + " >>>>>");
209 commandQueue.clear();
213 public boolean enqueueCommand(@NonNull IKodakCommand command)
217 //Log.v(TAG, "Enqueue : " + command.getId());
218 return (commandQueue.offer(command));
227 private void issueCommand(@NonNull IKodakCommand command)
231 boolean retry_over = true;
234 //Log.v(TAG, "issueCommand : " + command.getId());
235 byte[] commandBody = command.commandBody();
236 if (commandBody != null)
238 // コマンドボディが入っていた場合には、コマンド送信(入っていない場合は受信待ち)
239 send_to_camera(command.dumpLog(), commandBody);
240 byte[] commandBody2 = command.commandBody2();
241 if (commandBody2 != null)
243 // コマンドボディの2つめが入っていた場合には、コマンドを連続送信する
244 send_to_camera(command.dumpLog(), commandBody2);
247 retry_over = receive_from_camera(command);
250 retry_over = command.sendRetry();
261 * カメラにコマンドを送信する(メイン部分)
264 private void send_to_camera(boolean isDumpReceiveLog, @NonNull byte[] byte_array)
270 Log.v(TAG, " DataOutputStream is null.");
274 if (byte_array.length <= 0)
277 Log.v(TAG, " SEND BODY IS NOTHING.");
281 if (isDumpReceiveLog)
284 dump_bytes("SEND[" + byte_array.length + "] ", byte_array);
288 dos.write(byte_array);
297 private void sleep(int delayMs)
301 Thread.sleep(delayMs);
310 * カメラからにコマンドの結果を受信する(メイン部分)
313 private boolean receive_from_camera(@NonNull IKodakCommand command)
315 int delayMs = command.receiveDelayMs();
316 if ((delayMs < 0)||(delayMs > COMMAND_SEND_RECEIVE_DURATION_MAX))
318 delayMs = COMMAND_SEND_RECEIVE_DURATION_MS;
321 // 受信した後、すべてをまとめて「受信したよ」と応答するパターン
322 return (receive_single(command, delayMs));
325 private boolean receive_single(@NonNull IKodakCommand command, int delayMs)
327 boolean isDumpReceiveLog = command.dumpLog();
328 int id = command.getId();
329 IKodakCommandCallback callback = command.responseCallback();
332 int receive_message_buffer_size = BUFFER_SIZE;
333 byte[] byte_array = new byte[receive_message_buffer_size];
334 InputStream is = socket.getInputStream();
337 Log.v(TAG, " InputStream is NULL... RECEIVE ABORTED.");
338 receivedAllMessage(isDumpReceiveLog, id, null, callback);
342 // 初回データが受信バッファにデータが溜まるまで待つ...
343 int read_bytes = waitForReceive(is, delayMs, command.maxRetryCount());
347 Log.v(TAG, " DETECT RETRY OVER...");
352 ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
353 while (read_bytes > 0)
355 read_bytes = is.read(byte_array, 0, receive_message_buffer_size);
358 Log.v(TAG, " RECEIVED MESSAGE FINISHED (" + read_bytes + ")");
361 byteStream.write(byte_array, 0, read_bytes);
363 read_bytes = is.available();
365 receivedAllMessage(isDumpReceiveLog, id, byteStream.toByteArray(), callback);
376 private void receivedAllMessage(boolean isDumpReceiveLog, int id, byte[] body, IKodakCommandCallback callback)
378 Log.v(TAG, "receivedAllMessage() : " + ((body == null) ? 0 : body.length) + " bytes.");
379 if ((isDumpReceiveLog)&&(body != null))
382 dump_bytes("RECV[" + body.length + "] ", body);
384 if (checkReceiveStatusMessage(body))
386 send_secondary_message(isDumpReceiveLog, body);
389 if (callback != null)
391 callback.receivedMessage(id, body);
395 private void send_secondary_message(boolean isDumpReceiveLog, @Nullable byte[] received_body)
397 if (received_body == null)
399 Log.v(TAG, "send_secondary_message : NULL ");
402 Log.v(TAG, "send_secondary_message : [" + received_body[8] + "] [" + received_body[9] + "] ");
404 byte[] message_to_send = null;
405 if ((received_body[8] == (byte) 0xd2) && (received_body[9] == (byte) 0xd2)) {
406 message_to_send = new byte[]{
407 (byte) 0x2e, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
408 (byte) 0xd2, (byte) 0x07, (byte) 0x00, (byte) 0x00, (byte) 0x01, (byte) 0x10, (byte) 0x00, (byte) 0x80,
409 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
410 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
411 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
412 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
413 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
414 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
415 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
419 if ((received_body[8] == (byte) 0xba) && (received_body[9] == (byte) 0x0b)) {
420 message_to_send = new byte[]
422 (byte) 0x2e, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
423 (byte) 0xba, (byte) 0x0b, (byte) 0x00, (byte) 0x00, (byte) 0x01, (byte) 0x10, (byte) 0x00, (byte) 0x80,
424 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
425 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
426 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
427 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
428 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
429 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
430 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
433 if ((received_body[8] == (byte) 0xbb) && (received_body[9] == (byte) 0x0b)) {
434 message_to_send = new byte[]
436 (byte) 0x2e, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
437 (byte) 0xbb, (byte) 0x0b, (byte) 0x00, (byte) 0x00, (byte) 0x01, (byte) 0x10, (byte) 0x00, (byte) 0x80,
438 (byte) 0x1f, (byte) 0x00, (byte) 0x00, (byte) 0x90, (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
439 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
440 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
441 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
442 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
443 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
444 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00
447 if ((isDumpReceiveLog)&&(message_to_send != null))
450 dump_bytes("SND2[" + message_to_send.length + "] ", message_to_send);
453 if ((dos != null)&&(message_to_send != null))
456 dos.write(message_to_send);
466 private boolean checkReceiveStatusMessage(@Nullable byte[] receive_body)
468 boolean isReceivedStatusMessage = false;
471 if (receive_body == null)
475 if (receive_body.length < 16)
477 Log.v(TAG, " BODY SIZE IS SMALL. : " + receive_body.length);
480 if (((receive_body[8] == (byte) 0xd2)&&(receive_body[9] == (byte) 0x07))||
481 ((receive_body[8] == (byte) 0xba)&&(receive_body[9] == (byte) 0x0b))||
482 ((receive_body[8] == (byte) 0xbb)&&(receive_body[9] == (byte) 0x0b)))
485 isReceivedStatusMessage = true;
486 Log.v(TAG, " >>> RECEIVED HOST PRIMARY MESSAGE. <<<");
493 return (isReceivedStatusMessage);
496 private int waitForReceive(InputStream is, int delayMs, int retry_count)
498 boolean isLogOutput = true;
502 while (read_bytes <= 0)
504 Log.v(TAG, " --- waitForReceive : " + retry_count + " delay : " + delayMs + "ms");
506 read_bytes = is.available();
511 Log.v(TAG, " waitForReceive:: is.available() WAIT... : " + delayMs + "ms");
515 if ((!waitForever)&&(retry_count < 0))