OSDN Git Service

ステータスの更新を実施。
[gokigen/A01d.git] / app / src / main / java / net / osdn / gokigen / a01d / camera / fujix / wrapper / command / FujiXCommandIssuer.java
1 package net.osdn.gokigen.a01d.camera.fujix.wrapper.command;
2
3 import android.util.Log;
4
5 import androidx.annotation.NonNull;
6
7 import java.io.BufferedReader;
8 import java.io.DataOutputStream;
9 import java.io.InputStream;
10 import java.net.Socket;
11 import java.util.ArrayDeque;
12 import java.util.Arrays;
13 import java.util.Queue;
14
15 public class FujiXCommandIssuer implements IFujiXCommandIssuer, IFujiXCommunication
16 {
17     private final String TAG = toString();
18
19     private static final int SEQUENCE_START_NUMBER = 1;
20     private static final int BUFFER_SIZE = 1024 * 1024 + 8;
21     private static final int COMMAND_SEND_RECEIVE_DURATION_MS = 50;
22     private static final int COMMAND_SEND_RECEIVE_DURATION_MAX = 1000;
23     private static final int COMMAND_POLL_QUEUE_MS = 150;
24
25     private final String ipAddress;
26     private final int portNumber;
27
28     private boolean isStart = false;
29     private Socket socket = null;
30     private DataOutputStream dos = null;
31     private BufferedReader bufferedReader = null;
32     private int sequenceNumber = SEQUENCE_START_NUMBER;
33     private Queue<IFujiXCommand> commandQueue;
34
35
36     public FujiXCommandIssuer(@NonNull String ip, int portNumber)
37     {
38         this.ipAddress = ip;
39         this.portNumber = portNumber;
40         this.commandQueue = new ArrayDeque<>();
41         commandQueue.clear();
42     }
43
44     @Override
45     public boolean isConnected()
46     {
47         return (socket != null);
48     }
49
50     @Override
51     public boolean connect()
52     {
53         try
54         {
55             socket = new Socket(ipAddress, portNumber);
56             return (true);
57         }
58         catch (Exception e)
59         {
60             e.printStackTrace();
61             socket = null;
62         }
63         return (false);
64     }
65
66     @Override
67     public void disconnect()
68     {
69         // ストリームを全部閉じる
70         try
71         {
72             dos.close();
73         }
74         catch (Exception e)
75         {
76             e.printStackTrace();
77         }
78         dos = null;
79
80         try
81         {
82             bufferedReader.close();
83         }
84         catch (Exception e)
85         {
86             e.printStackTrace();
87         }
88         bufferedReader = null;
89
90         try
91         {
92             socket.close();
93         }
94         catch (Exception e)
95         {
96             e.printStackTrace();
97         }
98         socket = null;
99         sequenceNumber = SEQUENCE_START_NUMBER;
100         System.gc();
101     }
102
103     @Override
104     public void start()
105     {
106         if (isStart)
107         {
108             // すでにコマンドのスレッド動作中なので抜ける
109             return;
110         }
111         isStart = true;
112         Thread thread = new Thread(new Runnable()
113         {
114             @Override
115             public void run()
116             {
117                 try
118                 {
119                     while (isStart)
120                     {
121                         try
122                         {
123                             IFujiXCommand command = commandQueue.poll();
124                             if (command != null)
125                             {
126                                 issueCommand(command);
127                             }
128                             Thread.sleep(COMMAND_POLL_QUEUE_MS);
129                         }
130                         catch (Exception e)
131                         {
132                             e.printStackTrace();
133                         }
134                     }
135                 }
136                 catch (Exception e)
137                 {
138                     Log.v(TAG, "<<<<< IP : " + ipAddress + " port : " + portNumber + " >>>>>");
139                     e.printStackTrace();
140                 }
141             }
142         });
143         try
144         {
145             thread.start();
146         }
147         catch (Exception e)
148         {
149             e.printStackTrace();
150         }
151     }
152
153     @Override
154     public void stop()
155     {
156         isStart = false;
157         commandQueue.clear();
158     }
159
160     @Override
161     public boolean enqueueCommand(@NonNull IFujiXCommand command)
162     {
163         try
164         {
165             //Log.v(TAG, "Enqueue : "  + command.getId());
166             return (commandQueue.offer(command));
167         }
168         catch (Exception e)
169         {
170             e.printStackTrace();
171         }
172         return (false);
173     }
174
175     private void issueCommand(@NonNull IFujiXCommand command)
176     {
177         try
178         {
179             //Log.v(TAG, "issueCommand : " + command.getId());
180             byte[] commandBody = command.commandBody();
181             if (commandBody != null)
182             {
183                 // コマンドボディが入っていた場合には、コマンド送信(入っていない場合は受信待ち)
184                 send_to_camera(command.dumpLog(), commandBody, command.useSequenceNumber());
185                 byte[] commandBody2 = command.commandBody2();
186                 if (commandBody2 != null)
187                 {
188                     // コマンドボディの2つめが入っていた場合には、コマンドを連続送信する
189                     send_to_camera(command.dumpLog(), commandBody2, command.useSequenceNumber());
190                 }
191                 if (command.isIncrementSeqNumber())
192                 {
193                     // シーケンス番号を更新する
194                     sequenceNumber++;
195                 }
196             }
197             int delayMs = command.receiveDelayMs();
198             if ((delayMs < 0)||(delayMs > COMMAND_SEND_RECEIVE_DURATION_MAX))
199             {
200                 delayMs = COMMAND_SEND_RECEIVE_DURATION_MS;
201             }
202             receive_from_camera(command.dumpLog(), command.getId(), command.responseCallback(), command.receiveAgainShortLengthMessage(), delayMs);
203         }
204         catch (Exception e)
205         {
206             e.printStackTrace();
207         }
208     }
209
210     /**
211      *    カメラにコマンドを送信する(メイン部分)
212      *
213      */
214     private void send_to_camera(boolean isDumpReceiveLog, byte[] byte_array, boolean useSequenceNumber)
215     {
216         try
217         {
218             dos = new DataOutputStream(socket.getOutputStream());
219
220             // メッセージボディを加工: 最初に4バイトのレングス長をつける
221             byte[] sendData = new byte[byte_array.length + 4];
222
223             sendData[0] = (byte) (byte_array.length + 4);
224             sendData[1] = 0x00;
225             sendData[2] = 0x00;
226             sendData[3] = 0x00;
227             System.arraycopy(byte_array,0,sendData,4, byte_array.length);
228
229             if (useSequenceNumber)
230             {
231                 // Sequence Number を反映させる
232                 sendData[8] = (byte) ((0x000000ff & sequenceNumber));
233                 sendData[9] = (byte) (((0x0000ff00 & sequenceNumber) >>> 8) & 0x000000ff);
234                 sendData[10] = (byte) (((0x00ff0000 & sequenceNumber) >>> 16) & 0x000000ff);
235                 sendData[11] = (byte) (((0xff000000 & sequenceNumber) >>> 24) & 0x000000ff);
236                 if (isDumpReceiveLog)
237                 {
238                     Log.v(TAG, "SEQ No. : " + sequenceNumber);
239                 }
240             }
241
242             // ログに送信メッセージを出力する
243             dump_bytes(isDumpReceiveLog,"SEND[" + sendData.length + "] ", sendData);
244
245             // (データを)送信
246             dos.write(sendData);
247             dos.flush();
248         }
249         catch (Exception e)
250         {
251             e.printStackTrace();
252         }
253     }
254
255     private void sleep(int delayMs)
256     {
257         try
258         {
259             Thread.sleep(delayMs);
260         }
261         catch (Exception e)
262         {
263             e.printStackTrace();
264         }
265     }
266
267     /**
268      *    カメラからにコマンドの結果を受信する(メイン部分)
269      *
270      */
271     private void receive_from_camera(boolean isDumpReceiveLog, int id, IFujiXCommandCallback callback, boolean receiveAgain, int delayMs)
272     {
273         try
274         {
275             sleep(delayMs);
276             byte[] byte_array = new byte[BUFFER_SIZE];
277             InputStream is = socket.getInputStream();
278             if (is != null)
279             {
280                 int read_bytes = is.read(byte_array, 0, BUFFER_SIZE);
281                 byte[] receive_body;
282                 if (read_bytes > 4)
283                 {
284                     if (receiveAgain)
285                     {
286                         int length = ((((int) byte_array[3]) & 0xff) << 24) + ((((int) byte_array[2]) & 0xff) << 16) + ((((int) byte_array[1]) & 0xff) << 8) + (((int) byte_array[0]) & 0xff);
287                         if ((length > read_bytes)||((length == read_bytes)&&((int) byte_array[4] == 0x02)))
288                         {
289                             // データについて、もう一回受信が必要な場合...
290                             Log.v(TAG, "--- RECEIVE AGAIN --- [" + length + "(" + read_bytes + ") " + byte_array[4]+ "] ");
291                             sleep(delayMs);
292                             int read_bytes2 = is.read(byte_array, read_bytes, BUFFER_SIZE - read_bytes);
293                             if (read_bytes2 > 0)
294                             {
295                                 read_bytes = read_bytes + read_bytes2;
296                             }
297                         }
298                     }
299                     receive_body = Arrays.copyOfRange(byte_array, 0, read_bytes);
300                 }
301                 else
302                 {
303                     receive_body = new byte[1];
304                 }
305                 if (isDumpReceiveLog)
306                 {
307                     // ログに受信メッセージを出力する
308                     Log.v(TAG, "receive_from_camera() : " + read_bytes + " bytes.");
309                     dump_bytes(isDumpReceiveLog, "RECV[" + receive_body.length + "] ", receive_body);
310                 }
311                if (callback != null)
312                 {
313                     callback.receivedMessage(id, receive_body);
314                 }
315             }
316         }
317         catch (Exception e)
318         {
319             e.printStackTrace();
320         }
321     }
322
323     /**
324      *   デバッグ用:ログにバイト列を出力する
325      *
326      */
327     private void dump_bytes(boolean isDumpReceiveLog, String header, byte[] data)
328     {
329         if (!isDumpReceiveLog)
330         {
331             // 受信ログを出さない
332             return;
333         }
334
335         int index = 0;
336         StringBuffer message;
337         message = new StringBuffer();
338         for (byte item : data)
339         {
340             index++;
341             message.append(String.format("%02x ", item));
342             if (index >= 8)
343             {
344                 Log.v(TAG, header + " " + message);
345                 index = 0;
346                 message = new StringBuffer();
347             }
348         }
349         if (index != 0)
350         {
351             Log.v(TAG, header + " " + message);
352         }
353         System.gc();
354     }
355 }