--- /dev/null
+package net.osdn.gokigen.pkremote.camera.utils;
+
+import android.util.Log;
+
+import net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.command.PtpIpCommandPublisher;
+
+public class SimpleLogDumper
+{
+ private static final String TAG = SimpleLogDumper.class.getSimpleName();
+
+ /**
+ * デバッグ用:ログにバイト列を出力する
+ *
+ */
+ public static void dump_bytes(String header, byte[] data)
+ {
+ int index = 0;
+ StringBuffer message;
+ message = new StringBuffer();
+ for (byte item : data)
+ {
+ index++;
+ message.append(String.format("%02x ", item));
+ if (index >= 8)
+ {
+ Log.v(TAG, header + " " + message);
+ index = 0;
+ message = new StringBuffer();
+ }
+ }
+ if (index != 0)
+ {
+ Log.v(TAG, header + " " + message);
+ }
+ System.gc();
+ }
+
+}
private static final int STREAM_PORT = 15742; // ??
private static final int ASYNC_RESPONSE_PORT = 15741; // ??
private static final int CONTROL_PORT = 15740;
+ private static final int EVENT_PORT = 15740;
private static final String CAMERA_IP = "192.168.0.1";
private final Activity activity;
commandPublisher = new PtpIpCommandPublisher(CAMERA_IP, CONTROL_PORT);
liveViewControl = new PtpIpLiveViewControl(context, CAMERA_IP, STREAM_PORT);
asyncReceiver = new PtpIpAsyncResponseReceiver(CAMERA_IP, ASYNC_RESPONSE_PORT);
- canonConnection = new CanonConnection(context, provider, this);
+ statusChecker = new PtpIpStatusChecker(activity, commandPublisher, CAMERA_IP, EVENT_PORT);
+ canonConnection = new CanonConnection(context, provider, this, statusChecker);
zoomControl = new PtpIpZoomControl();
- statusChecker = new PtpIpStatusChecker(activity, commandPublisher);
this.statusListener = statusListener;
this.runmode = new PtpIpRunMode();
this.hardwareStatus = new PtpIpHardwareStatus();
int SEQ_REGISTRATION = 1;
int SEQ_EVENT_INITIALIZE = 2;
int SEQ_OPEN_SESSION = 3;
+ int SEQ_INIT_SESSION = 4;
+ int SEQ_CHANGE_REMOTE = 5;
+ int SEQ_SET_EVENT_MODE = 6;
int SEQ_STATUS_REQUEST = 9;
package net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.command;
-
import android.util.Log;
import androidx.annotation.NonNull;
import java.util.Arrays;
import java.util.Queue;
+import static net.osdn.gokigen.pkremote.camera.utils.SimpleLogDumper.dump_bytes;
+
public class PtpIpCommandPublisher implements IPtpIpCommandPublisher, IPtpIpCommunication
{
- private final String TAG = toString();
+ private static final String TAG = PtpIpCommandPublisher.class.getSimpleName();
private static final int SEQUENCE_START_NUMBER = 1;
private static final int BUFFER_SIZE = 1024 * 1024 + 8;
if (useSequenceNumber)
{
// Sequence Number を反映させる
- sendData[15] = (byte) ((0x000000ff & sequenceNumber));
- sendData[16] = (byte) (((0x0000ff00 & sequenceNumber) >>> 8) & 0x000000ff);
- sendData[17] = (byte) (((0x00ff0000 & sequenceNumber) >>> 16) & 0x000000ff);
- sendData[18] = (byte) (((0xff000000 & sequenceNumber) >>> 24) & 0x000000ff);
+ sendData[14] = (byte) ((0x000000ff & sequenceNumber));
+ sendData[15] = (byte) (((0x0000ff00 & sequenceNumber) >>> 8) & 0x000000ff);
+ sendData[16] = (byte) (((0x00ff0000 & sequenceNumber) >>> 16) & 0x000000ff);
+ sendData[17] = (byte) (((0xff000000 & sequenceNumber) >>> 24) & 0x000000ff);
if (isDumpReceiveLog)
{
Log.v(TAG, "SEQ No. : " + sequenceNumber);
// (データを)送信
dos.write(sendData);
dos.flush();
- //dos.close(); // ← これが必要?
- //dos = null; // ← これが必要?
}
catch (Exception e)
{
}
}
- /**
- * デバッグ用:ログにバイト列を出力する
- *
- */
- private void dump_bytes(String header, byte[] data)
- {
- int index = 0;
- StringBuffer message;
- message = new StringBuffer();
- for (byte item : data)
- {
- index++;
- message.append(String.format("%02x ", item));
- if (index >= 8)
- {
- Log.v(TAG, header + " " + message);
- index = 0;
- message = new StringBuffer();
- }
- }
- if (index != 0)
- {
- Log.v(TAG, header + " " + message);
- }
- System.gc();
- }
}
data2 = ((byte)((0x00ff0000 & value) >> 16));
data3 = ((byte)((0xff000000 & value) >> 24));
- data4 = ((byte) (0x000000ff & value));
- data5 = ((byte)((0x0000ff00 & value) >> 8));
- data6 = ((byte)((0x00ff0000 & value) >> 16));
- data7 = ((byte)((0xff000000 & value) >> 24));
+ data4 = 0; // ((byte) (0x000000ff & value));
+ data5 = 0; // ((byte)((0x0000ff00 & value) >> 8));
+ data6 = 0; // ((byte)((0x00ff0000 & value) >> 16));
+ data7 = 0; // ((byte)((0xff000000 & value) >> 24));
data8 = 0; // ((byte) (0x000000ff & value3));
data9 = 0; // ((byte)((0x0000ff00 & value3) >> 8));
package net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.connection;
import android.app.Activity;
-import android.content.SharedPreferences;
import android.graphics.Color;
import android.util.Log;
import androidx.annotation.NonNull;
-import androidx.preference.PreferenceManager;
import net.osdn.gokigen.pkremote.R;
import net.osdn.gokigen.pkremote.camera.interfaces.control.ICameraConnection;
import net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.command.IPtpIpCommandPublisher;
import net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.command.IPtpIpMessages;
import net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.command.messages.PtpIpCommandGeneric;
-import net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.command.messages.specific.CanonInitEventRequest;
import net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.command.messages.specific.CanonRegistrationMessage;
import net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.status.IPtpIpRunModeHolder;
-import net.osdn.gokigen.pkremote.preference.IPreferencePropertyAccessor;
+import net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.status.PtpIpStatusChecker;
public class CanonCameraConnectSequenceForPlayback implements Runnable, IPtpIpCommandCallback, IPtpIpMessages
private final ICameraStatusReceiver cameraStatusReceiver;
private final IPtpIpInterfaceProvider interfaceProvider;
private final IPtpIpCommandPublisher commandIssuer;
+ private final PtpIpStatusChecker statusChecker;
private boolean isBothLiveView = false;
- CanonCameraConnectSequenceForPlayback(@NonNull Activity context, @NonNull ICameraStatusReceiver statusReceiver, @NonNull final ICameraConnection cameraConnection, @NonNull IPtpIpInterfaceProvider interfaceProvider)
+ CanonCameraConnectSequenceForPlayback(@NonNull Activity context, @NonNull ICameraStatusReceiver statusReceiver, @NonNull final ICameraConnection cameraConnection, @NonNull IPtpIpInterfaceProvider interfaceProvider, @NonNull PtpIpStatusChecker statusChecker)
{
Log.v(TAG, " CanonCameraConnectSequenceForPlayback");
this.context = context;
this.cameraStatusReceiver = statusReceiver;
this.interfaceProvider = interfaceProvider;
this.commandIssuer = interfaceProvider.getCommandPublisher();
+ this.statusChecker = statusChecker;
}
@Override
if (checkEventInitialize(rx_body))
{
interfaceProvider.getInformationReceiver().updateMessage(context.getString(R.string.canon_connect_connecting1), false, false, 0);
- commandIssuer.enqueueCommand(new PtpIpCommandGeneric(this, SEQ_OPEN_SESSION, 0x1002));
+ commandIssuer.enqueueCommand(new PtpIpCommandGeneric(this, SEQ_OPEN_SESSION, 0x1002, 4, 0x41));
}
else
{
case SEQ_OPEN_SESSION:
interfaceProvider.getInformationReceiver().updateMessage(context.getString(R.string.canon_connect_connecting2), false, false, 0);
- //commandIssuer.enqueueCommand(new PtpIpCommandGeneric(this, SEQ_OPEN_SESSION));
+ commandIssuer.enqueueCommand(new PtpIpCommandGeneric(this, SEQ_INIT_SESSION, 0x902f));
break;
+ case SEQ_INIT_SESSION:
+ interfaceProvider.getInformationReceiver().updateMessage(context.getString(R.string.canon_connect_connecting3), false, false, 0);
+ commandIssuer.enqueueCommand(new PtpIpCommandGeneric(this, SEQ_CHANGE_REMOTE, 0x9114, 4, 0x15));
+ break;
+
+ case SEQ_CHANGE_REMOTE:
+ interfaceProvider.getInformationReceiver().updateMessage(context.getString(R.string.canon_connect_connecting4), false, false, 0);
+ commandIssuer.enqueueCommand(new PtpIpCommandGeneric(this, SEQ_SET_EVENT_MODE, 0x902f, 4, 0x02));
+ break;
+
+ case SEQ_SET_EVENT_MODE:
+ interfaceProvider.getInformationReceiver().updateMessage(context.getString(R.string.canon_connect_connecting5), false, false, 0);
+ break;
/*
case SEQ_START_2ND_READ:
interfaceProvider.getInformationReceiver().updateMessage(context.getString(R.string.connect_connecting2), false, false, 0);
{
interfaceProvider.getInformationReceiver().updateMessage(context.getString(R.string.connect_start_2), false, false, 0);
cameraStatusReceiver.onStatusNotify(context.getString(R.string.connect_start_2));
- int connectionNumber = 0;
try
{
- connectionNumber = (receiveData[8] & 0xff);
- connectionNumber = connectionNumber + ((receiveData[9] & 0xff) << 8);
- connectionNumber = connectionNumber + ((receiveData[10] & 0xff) << 16);
- connectionNumber = connectionNumber + ((receiveData[11] & 0xff) << 24);
+ int eventConnectionNumber = (receiveData[8] & 0xff);
+ eventConnectionNumber = eventConnectionNumber + ((receiveData[9] & 0xff) << 8);
+ eventConnectionNumber = eventConnectionNumber + ((receiveData[10] & 0xff) << 16);
+ eventConnectionNumber = eventConnectionNumber + ((receiveData[11] & 0xff) << 24);
+ statusChecker.setEventConnectionNumber(eventConnectionNumber);
+ interfaceProvider.getCameraStatusWatcher().startStatusWatch(null);
+
+ commandIssuer.enqueueCommand(new PtpIpCommandGeneric(this, SEQ_OPEN_SESSION, 0x1002, 4, 0x41));
}
catch (Exception e)
{
e.printStackTrace();
}
- commandIssuer.enqueueCommand(new CanonInitEventRequest(this, connectionNumber));
+ //commandIssuer.enqueueCommand(new CanonInitEventRequest(this, connectionNumber));
+ //commandIssuer.enqueueCommand(new PtpIpCommandGeneric(this, SEQ_OPEN_SESSION, 0x1002, 4, 0x41));
}
private boolean checkRegistrationMessage(byte[] receiveData)
import net.osdn.gokigen.pkremote.camera.interfaces.control.ICameraConnection;
import net.osdn.gokigen.pkremote.camera.interfaces.status.ICameraStatusReceiver;
import net.osdn.gokigen.pkremote.camera.vendor.ptpip.IPtpIpInterfaceProvider;
+import net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.status.PtpIpStatusChecker;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
private final IPtpIpInterfaceProvider interfaceProvider;
private final BroadcastReceiver connectionReceiver;
private final Executor cameraExecutor = Executors.newFixedThreadPool(1);
+ private final PtpIpStatusChecker statusChecker;
private CameraConnectionStatus connectionStatus = CameraConnectionStatus.UNKNOWN;
- public CanonConnection(@NonNull final Activity context, @NonNull final ICameraStatusReceiver statusReceiver, @NonNull IPtpIpInterfaceProvider interfaceProvider)
+ public CanonConnection(@NonNull final Activity context, @NonNull final ICameraStatusReceiver statusReceiver, @NonNull IPtpIpInterfaceProvider interfaceProvider, @NonNull PtpIpStatusChecker statusChecker)
{
Log.v(TAG, "CanonConnection()");
this.context = context;
this.statusReceiver = statusReceiver;
this.interfaceProvider = interfaceProvider;
+ this.statusChecker = statusChecker;
connectionReceiver = new BroadcastReceiver()
{
@Override
connectionStatus = CameraConnectionStatus.CONNECTING;
try
{
- cameraExecutor.execute(new CanonCameraConnectSequenceForPlayback(context, statusReceiver, this, interfaceProvider));
+ cameraExecutor.execute(new CanonCameraConnectSequenceForPlayback(context, statusReceiver, this, interfaceProvider, statusChecker));
}
catch (Exception e)
{
package net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.status;
import android.app.Activity;
-import android.content.SharedPreferences;
import android.util.Log;
import androidx.annotation.NonNull;
-import androidx.preference.PreferenceManager;
import net.osdn.gokigen.pkremote.camera.interfaces.liveview.ICameraStatusUpdateNotify;
import net.osdn.gokigen.pkremote.camera.interfaces.status.ICameraStatus;
import net.osdn.gokigen.pkremote.camera.interfaces.status.ICameraStatusWatcher;
+import net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.command.IPtpIpCommand;
import net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.command.IPtpIpCommandCallback;
import net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.command.IPtpIpCommandPublisher;
+import net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.command.IPtpIpMessages;
+import net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.command.messages.specific.CanonInitEventRequest;
import net.osdn.gokigen.pkremote.camera.vendor.ptpip.wrapper.command.messages.specific.StatusRequestMessage;
-import net.osdn.gokigen.pkremote.preference.IPreferencePropertyAccessor;
+import java.io.BufferedReader;
+import java.io.DataOutputStream;
+import java.io.InputStream;
+import java.net.Socket;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
+import static net.osdn.gokigen.pkremote.camera.utils.SimpleLogDumper.dump_bytes;
+
public class PtpIpStatusChecker implements IPtpIpCommandCallback, ICameraStatusWatcher, ICameraStatus
{
private final String TAG = toString();
+
+ private static final int BUFFER_SIZE = 1024 * 1024 + 8;
private static final int STATUS_MESSAGE_HEADER_SIZE = 14;
private int sleepMs;
private final IPtpIpCommandPublisher issuer;
private PtpIpStatusHolder statusHolder;
private boolean whileFetching = false;
private boolean logcat = false;
+ private final String ipAddress;
+ private final int portNumber;
+ private Socket socket = null;
+ private DataOutputStream dos = null;
+ private BufferedReader bufferedReader = null;
+ private int eventConnectionNumber = 0;
- public PtpIpStatusChecker(@NonNull Activity activity, @NonNull IPtpIpCommandPublisher issuer)
+ public PtpIpStatusChecker(@NonNull Activity activity, @NonNull IPtpIpCommandPublisher issuer, @NonNull String ip, int portNumber)
{
this.issuer = issuer;
this.statusHolder = new PtpIpStatusHolder();
+ this.ipAddress = ip;
+ this.portNumber = portNumber;
+
+/*
try
{
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(activity);
e.printStackTrace();
this.sleepMs = 400;
}
+*/
Log.v(TAG, "POLLING WAIT : " + sleepMs);
}
try
{
logcat("receivedMessage : " + id + ", length: " + data.length);
+ if (id == IPtpIpMessages.SEQ_EVENT_INITIALIZE)
+ {
+ // 終わる
+ Log.v(TAG, " ----- PTP-IP Connection is ESTABLISHED. -----");
+ return;
+ }
if (data.length < STATUS_MESSAGE_HEADER_SIZE)
{
Log.v(TAG, "received status length is short. (" + data.length + " bytes.)");
final IPtpIpCommandCallback callback = this;
this.notifier = notifier;
whileFetching = true;
+
+ // セッションをオープンする
+ boolean isConnect = connect();
+ if (!isConnect)
+ {
+ Log.v(TAG, " CONNECT FAIL...(EVENT) : " + ipAddress + " " + portNumber);
+ }
+ issueCommand(new CanonInitEventRequest(this, eventConnectionNumber));
+
+/*
Thread thread = new Thread(new Runnable()
{
@Override
}
});
thread.start();
+
+ // 切断する
+ disconnect();
+*/
}
catch (Exception e)
{
Log.v(TAG, message);
}
}
+
+ private boolean connect()
+ {
+ try
+ {
+ socket = new Socket(ipAddress, portNumber);
+ return (true);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ socket = null;
+ }
+ return (false);
+ }
+
+ private void disconnect()
+ {
+ // ストリームを全部閉じる
+ try
+ {
+ if (dos != null)
+ {
+ dos.close();
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ dos = null;
+
+ try
+ {
+ if (bufferedReader != null)
+ {
+ bufferedReader.close();
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ bufferedReader = null;
+
+ try
+ {
+ if (socket != null)
+ {
+ socket.close();
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ socket = null;
+ System.gc();
+ }
+
+
+ public void setEventConnectionNumber(int connectionNumber)
+ {
+ eventConnectionNumber = connectionNumber;
+ }
+
+ private void issueCommand(@NonNull IPtpIpCommand command)
+ {
+ try
+ {
+ //Log.v(TAG, "issueCommand : " + command.getId());
+ byte[] commandBody = command.commandBody();
+ if (commandBody != null)
+ {
+ // コマンドボディが入っていた場合には、コマンド送信(入っていない場合は受信待ち)
+ send_to_camera(command.dumpLog(), commandBody);
+ }
+ receive_from_camera(command.dumpLog(), command.getId(), command.responseCallback(), command.receiveAgainShortLengthMessage(), command.receiveDelayMs());
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * カメラにコマンドを送信する(メイン部分)
+ *
+ */
+ private void send_to_camera(boolean isDumpReceiveLog, byte[] byte_array)
+ {
+ try
+ {
+ dos = new DataOutputStream(socket.getOutputStream()); // ここにいたらいけない?
+
+ // メッセージボディを加工: 最初に4バイトのレングス長をつける
+ byte[] sendData = new byte[byte_array.length + 4];
+
+ sendData[0] = (byte) (byte_array.length + 4);
+ sendData[1] = 0x00;
+ sendData[2] = 0x00;
+ sendData[3] = 0x00;
+ System.arraycopy(byte_array,0,sendData,4, byte_array.length);
+
+ if (isDumpReceiveLog)
+ {
+ // ログに送信メッセージを出力する
+ dump_bytes("SEND[" + sendData.length + "] ", sendData);
+ }
+
+ // (データを)送信
+ dos.write(sendData);
+ dos.flush();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+
+ /**
+ * カメラからにコマンドの結果を受信する(メイン部分)
+ *
+ */
+ private void receive_from_camera(boolean isDumpReceiveLog, int id, IPtpIpCommandCallback callback, boolean receiveAgain, int delayMs) {
+ try {
+ sleep(delayMs);
+ Log.v(TAG, " ----- receive_from_camera() ----- : " + isDumpReceiveLog + " " + receiveAgain);
+ boolean isFirstTime = true;
+ int totalReadBytes;
+ int receive_message_buffer_size = BUFFER_SIZE;
+ byte[] byte_array = new byte[receive_message_buffer_size];
+ InputStream is = socket.getInputStream();
+ if (is != null) {
+ int read_bytes = is.read(byte_array, 0, receive_message_buffer_size);
+ byte[] receive_body;
+ if (read_bytes > 4) {
+ if (receiveAgain) {
+ 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);
+ if (length > receive_message_buffer_size) {
+ Log.v(TAG, "+++++ TOTAL RECEIVE MESSAGE SIZE IS " + length + " +++++");
+ }
+ totalReadBytes = read_bytes;
+ while ((length > totalReadBytes) || ((length == read_bytes) && ((int) byte_array[4] == 0x02))) {
+ // データについて、もう一回受信が必要な場合...
+ if (isDumpReceiveLog) {
+ Log.v(TAG, "--- RECEIVE AGAIN --- [" + length + "(" + read_bytes + ") " + byte_array[4] + "] ");
+ }
+ sleep(delayMs);
+ int read_bytes2 = is.read(byte_array, read_bytes, receive_message_buffer_size - read_bytes);
+ if (read_bytes2 > 0) {
+ read_bytes = read_bytes + read_bytes2;
+ totalReadBytes = totalReadBytes + read_bytes2;
+ } else {
+ // よみだし終了。
+ Log.v(TAG, "FINISHED RECEIVE... ");
+ break;
+ }
+ if (callback != null) {
+ if (callback.isReceiveMulti()) {
+ int offset = 0;
+ if (isFirstTime) {
+ // 先頭のヘッダ部分をカットして送る
+ offset = 12;
+ isFirstTime = false;
+ //Log.v(TAG, " FIRST TIME : " + read_bytes + " " + offset);
+ }
+ callback.onReceiveProgress(read_bytes - offset, length, Arrays.copyOfRange(byte_array, offset, read_bytes));
+ read_bytes = 0;
+ } else {
+ callback.onReceiveProgress(read_bytes, length, null);
+ }
+ }
+ }
+ }
+ receive_body = Arrays.copyOfRange(byte_array, 0, read_bytes);
+ } else {
+ receive_body = new byte[1];
+ }
+ if (isDumpReceiveLog) {
+ // ログに受信メッセージを出力する
+ Log.v(TAG, " receive_from_camera() : " + read_bytes + " bytes. [" + receive_message_buffer_size + "]");
+ dump_bytes("RECV[" + receive_body.length + "] ", receive_body);
+ }
+ if (callback != null) {
+ if (callback.isReceiveMulti()) {
+ callback.receivedMessage(id, null);
+ } else {
+ callback.receivedMessage(id, receive_body);
+ //callback.receivedMessage(id, Arrays.copyOfRange(receive_body, 0, receive_body.length));
+ }
+ }
+ }
+ } catch (Throwable e) {
+ e.printStackTrace();
+ }
+ }
+
+ private void sleep(int delayMs)
+ {
+ try
+ {
+ Thread.sleep(delayMs);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
}