applicationId "net.osdn.gokigen.a01d"
minSdkVersion 14
targetSdkVersion 29
- versionCode 10500
- versionName "1.5.0"
+ versionCode 10600
+ versionName "1.6.0"
}
buildTypes {
release {
--- /dev/null
+package net.osdn.gokigen.a01d;
+
+public interface IInformationReceiver
+{
+ void updateMessage(final String message, final boolean isBold, final boolean isColor, final int color);
+}
import androidx.annotation.NonNull;
+import net.osdn.gokigen.a01d.IInformationReceiver;
import net.osdn.gokigen.a01d.camera.ICameraConnection;
import net.osdn.gokigen.a01d.camera.ICameraInformation;
import net.osdn.gokigen.a01d.camera.ICameraStatus;
import net.osdn.gokigen.a01d.camera.IFocusingControl;
import net.osdn.gokigen.a01d.camera.ILiveViewControl;
import net.osdn.gokigen.a01d.camera.IZoomLensControl;
-import net.osdn.gokigen.a01d.camera.ptpip.command.IPtpIpCommandCallback;
+import net.osdn.gokigen.a01d.camera.ptpip.wrapper.command.IPtpIpCommandCallback;
+import net.osdn.gokigen.a01d.camera.ptpip.wrapper.command.IPtpIpCommandPublisher;
+import net.osdn.gokigen.a01d.camera.ptpip.wrapper.command.IPtpIpCommunication;
+import net.osdn.gokigen.a01d.camera.ptpip.wrapper.status.IPtpIpRunModeHolder;
import net.osdn.gokigen.a01d.liveview.ICameraStatusUpdateNotify;
import net.osdn.gokigen.a01d.liveview.liveviewlistener.ILiveViewListener;
ICaptureControl getCaptureControl();
IDisplayInjector getDisplayInjector();
- /*
- IFujiXRunModeHolder getRunModeHolder();
- IFujiXCommandCallback getStatusHolder();
- IFujiXCommandPublisher getCommandPublisher();
- IFujiXCommunication getLiveviewCommunication();
- IFujiXCommunication getAsyncEventCommunication();
- IFujiXCommunication getCommandCommunication();
- */
-
+ IPtpIpRunModeHolder getRunModeHolder();
+ IPtpIpCommandCallback getStatusHolder();
+ IPtpIpCommandPublisher getCommandPublisher();
+ IPtpIpCommunication getLiveviewCommunication();
+ IPtpIpCommunication getAsyncEventCommunication();
+ IPtpIpCommunication getCommandCommunication();
+ IInformationReceiver getInformationReceiver();
ICameraStatusWatcher getStatusWatcher();
ICameraStatusUpdateNotify getStatusListener();
--- /dev/null
+package net.osdn.gokigen.a01d.camera.canon.wrapper.command.messages;
+
+import androidx.annotation.NonNull;
+
+import net.osdn.gokigen.a01d.camera.ptpip.wrapper.command.IPtpIpCommandCallback;
+import net.osdn.gokigen.a01d.camera.ptpip.wrapper.command.messages.PtpIpCommandBase;
+
+public class PtpIpCommandCanonGetPartialObject extends PtpIpCommandBase
+{
+ private final IPtpIpCommandCallback callback;
+ private final boolean isDumpLog;
+ private final int id;
+ private final int holdId;
+ private final int estimatedObjectSize;
+
+ private final byte data0;
+ private final byte data1;
+ private final byte data2;
+ private final byte data3;
+
+ private final byte data4;
+ private final byte data5;
+ private final byte data6;
+ private final byte data7;
+
+ private final byte data8;
+ private final byte data9;
+ private final byte dataA;
+ private final byte dataB;
+
+ public PtpIpCommandCanonGetPartialObject(@NonNull IPtpIpCommandCallback callback, int id, boolean isDumpLog, int holdId, int value, int value2, int value3, int estimatedObjectSize)
+ {
+ this.callback = callback;
+ this.isDumpLog = isDumpLog;
+ this.estimatedObjectSize = estimatedObjectSize;
+
+ this.id = id;
+ this.holdId = holdId;
+
+ data0 = ((byte) (0x000000ff & value));
+ data1 = ((byte)((0x0000ff00 & value) >> 8));
+ data2 = ((byte)((0x00ff0000 & value) >> 16));
+ data3 = ((byte)((0xff000000 & value) >> 24));
+
+ data4 = ((byte) (0x000000ff & value2));
+ data5 = ((byte)((0x0000ff00 & value2) >> 8));
+ data6 = ((byte)((0x00ff0000 & value2) >> 16));
+ data7 = ((byte)((0xff000000 & value2) >> 24));
+
+ data8 = ((byte) (0x000000ff & value3));
+ data9 = ((byte)((0x0000ff00 & value3) >> 8));
+ dataA = ((byte)((0x00ff0000 & value3) >> 16));
+ dataB = ((byte)((0xff000000 & value3) >> 24));
+ }
+
+ @Override
+ public IPtpIpCommandCallback responseCallback()
+ {
+ return (callback);
+ }
+
+ @Override
+ public int estimatedReceiveDataSize()
+ {
+ return (estimatedObjectSize);
+ }
+
+ @Override
+ public int getId()
+ {
+ return (id);
+ }
+
+ @Override
+ public int receiveDelayMs()
+ {
+ return (20);
+ }
+
+ @Override
+ public byte[] commandBody()
+ {
+ return (new byte[]{
+ // packet type
+ (byte) 0x06, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+
+ // data phase info
+ (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+
+ // operation code
+ (byte) 0x07, (byte) 0x91,
+
+ // sequence number
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+
+ // data ...
+ data0, data1, data2, data3,
+ data4, data5, data6, data7,
+ data8, data9, dataA, dataB,
+ });
+ }
+
+ @Override
+ public int getHoldId()
+ {
+ return (holdId);
+ }
+
+ @Override
+ public boolean dumpLog()
+ {
+ return (isDumpLog);
+ }
+
+}
--- /dev/null
+package net.osdn.gokigen.a01d.camera.canon.wrapper.command.messages.specific;
+
+
+import androidx.annotation.NonNull;
+
+import net.osdn.gokigen.a01d.camera.ptpip.wrapper.command.IPtpIpCommandCallback;
+import net.osdn.gokigen.a01d.camera.ptpip.wrapper.command.messages.PtpIpCommandBase;
+
+public class CanonGetPartialObject extends PtpIpCommandBase
+{
+ private final IPtpIpCommandCallback callback;
+ private final boolean isDumpLog;
+ private final int id;
+ private final int holdId;
+
+ private final byte data00;
+ private final byte data01;
+ private final byte data02;
+ private final byte data03;
+
+ private final byte data10;
+ private final byte data11;
+ private final byte data12;
+ private final byte data13;
+
+ public CanonGetPartialObject(@NonNull IPtpIpCommandCallback callback, int id, boolean isDumpLog, int holdId, int startPosition, int dataSize)
+ {
+ this.callback = callback;
+ this.isDumpLog = isDumpLog;
+ this.id = id;
+ this.holdId = holdId;
+
+ data00 = ((byte) (0x000000ff & startPosition));
+ data01 = ((byte)((0x0000ff00 & startPosition) >> 8));
+ data02 = ((byte)((0x00ff0000 & startPosition) >> 16));
+ data03 = ((byte)((0xff000000 & startPosition) >> 24));
+
+ data10 = ((byte) (0x000000ff & dataSize));
+ data11 = ((byte)((0x0000ff00 & dataSize) >> 8));
+ data12 = ((byte)((0x00ff0000 & dataSize) >> 16));
+ data13 = ((byte)((0xff000000 & dataSize) >> 24));
+ }
+
+ @Override
+ public IPtpIpCommandCallback responseCallback()
+ {
+ return (callback);
+ }
+
+ @Override
+ public int getId()
+ {
+ return (id);
+ }
+
+ @Override
+ public boolean dumpLog()
+ {
+ return (isDumpLog);
+ }
+
+ @Override
+ public int receiveDelayMs()
+ {
+ return (35);
+ }
+
+ @Override
+ public byte[] commandBody()
+ {
+ return (new byte[]{
+ // packet type
+ (byte) 0x06, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+
+ // data phase info
+ (byte) 0x02, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+
+ // operation code
+ (byte) 0x07, (byte) 0x91,
+
+ // sequence number
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+
+ // ??? (0x01)
+ (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+
+ // data size
+ data00, data01, data02, data03,
+
+ // data size
+ data10, data11, data12, data13,
+ });
+ }
+
+ @Override
+ public int getHoldId()
+ {
+ return (holdId);
+ }
+
+ @Override
+ public boolean isHold()
+ {
+ return (true);
+ }
+
+ @Override
+ public boolean isRelease()
+ {
+ return (false);
+ }
+
+}
--- /dev/null
+package net.osdn.gokigen.a01d.camera.canon.wrapper.command.messages.specific;
+
+import androidx.annotation.NonNull;
+
+import net.osdn.gokigen.a01d.camera.ptpip.wrapper.command.IPtpIpCommandCallback;
+import net.osdn.gokigen.a01d.camera.ptpip.wrapper.command.messages.PtpIpCommandBase;
+
+public class CanonInitEventRequest extends PtpIpCommandBase
+{
+ private final IPtpIpCommandCallback callback;
+ private final int connectionNumber;
+
+ public CanonInitEventRequest(@NonNull IPtpIpCommandCallback callback, int connectionNumber)
+ {
+ this.callback = callback;
+ this.connectionNumber = connectionNumber;
+ }
+
+ @Override
+ public IPtpIpCommandCallback responseCallback()
+ {
+ return (callback);
+ }
+
+ @Override
+ public int getId()
+ {
+ return (SEQ_EVENT_INITIALIZE);
+ }
+
+ @Override
+ public int receiveDelayMs()
+ {
+ return (100);
+ }
+
+ @Override
+ public boolean receiveAgainShortLengthMessage()
+ {
+ return (false);
+ }
+
+ @Override
+ public boolean useSequenceNumber()
+ {
+ return (false);
+ }
+
+ @Override
+ public boolean isIncrementSeqNumber()
+ {
+ return (false);
+ }
+
+ @Override
+ public byte[] commandBody()
+ {
+ byte data0 = ((byte) (0x000000ff & connectionNumber));
+ byte data1 = ((byte)((0x0000ff00 & connectionNumber) >> 8));
+ byte data2 = ((byte)((0x00ff0000 & connectionNumber) >> 16));
+ byte data3 = ((byte)((0xff000000 & connectionNumber) >> 24));
+
+ return (new byte[] {
+ // packet type
+ (byte)0x03, (byte)0x00, (byte)0x00, (byte)0x00, data0, data1, data2, data3,
+ });
+ }
+}
--- /dev/null
+package net.osdn.gokigen.a01d.camera.canon.wrapper.command.messages.specific;
+
+
+import androidx.annotation.NonNull;
+
+import net.osdn.gokigen.a01d.camera.ptpip.wrapper.command.IPtpIpCommandCallback;
+import net.osdn.gokigen.a01d.camera.ptpip.wrapper.command.messages.PtpIpCommandBase;
+
+import java.nio.ByteBuffer;
+import java.util.UUID;
+
+public class CanonRegistrationMessage extends PtpIpCommandBase
+{
+ private final IPtpIpCommandCallback callback;
+
+ public CanonRegistrationMessage(@NonNull IPtpIpCommandCallback callback)
+ {
+ this.callback = callback;
+ }
+
+ @Override
+ public IPtpIpCommandCallback responseCallback()
+ {
+ return (callback);
+ }
+
+ @Override
+ public int getId()
+ {
+ return (SEQ_REGISTRATION);
+ }
+
+ @Override
+ public boolean receiveAgainShortLengthMessage()
+ {
+ return (false);
+ }
+
+ @Override
+ public boolean useSequenceNumber()
+ {
+ return (false);
+ }
+
+ @Override
+ public boolean isIncrementSeqNumber()
+ {
+ return (false);
+ }
+
+ @Override
+ public byte[] commandBody()
+ {
+ int uuid = UUID.randomUUID().hashCode();
+
+ byte[] typeArray = {
+ (byte)0x01, (byte)0x00, (byte)0x00, (byte)0x00,
+ };
+
+ byte[] uuidArray = {
+ (byte)0xad, (byte)0xa5, (byte)0x48, (byte)0x5d, (byte)0x87, (byte)0xb2, (byte)0x7f, (byte)0x0b,
+ (byte)0xd3, (byte)0xd5, (byte)0xde, (byte)0xd0, (byte)0x12, (byte)0x44, (byte)0x99, (byte)0x32,
+ };
+
+ byte[] deviceNameArray = {
+ // device_name 'GOKIGEN_a01'
+ (byte)0x47, (byte)0x00, (byte)0x4f, (byte)0x00, (byte)0x4b, (byte)0x00, (byte)0x49, (byte)0x00,
+ (byte)0x47, (byte)0x00, (byte)0x45, (byte)0x00, (byte)0x4e, (byte)0x00, (byte)0x5f, (byte)0x00,
+ (byte)0x61, (byte)0x00, (byte)0x30, (byte)0x00, (byte)0x31, (byte)0x00, (byte)0x00, (byte)0x00,
+ };
+ byte[] versionArray = {
+ //
+ (byte)0x00, (byte)0x00, (byte)0x01, (byte)0x00,
+ };
+
+ ByteBuffer byteBuffer = ByteBuffer.allocate(4 + 16 + 24 + 4);
+ byteBuffer.put(typeArray);
+ byteBuffer.put(uuidArray);
+ byteBuffer.put(deviceNameArray);
+ byteBuffer.put(versionArray);
+
+ return (byteBuffer.array());
+ }
+}
--- /dev/null
+package net.osdn.gokigen.a01d.camera.canon.wrapper.command.messages.specific;
+
+import androidx.annotation.NonNull;
+
+import net.osdn.gokigen.a01d.camera.ptpip.wrapper.command.IPtpIpCommandCallback;
+import net.osdn.gokigen.a01d.camera.ptpip.wrapper.command.messages.PtpIpCommandBase;
+
+public class CanonRequestInnerDevelopEnd extends PtpIpCommandBase
+{
+ private final IPtpIpCommandCallback callback;
+ private final boolean isDumpLog;
+ private final int id;
+ private final int holdId;
+
+ public CanonRequestInnerDevelopEnd(@NonNull IPtpIpCommandCallback callback, int id, boolean isDumpLog, int holdId)
+ {
+ this.callback = callback;
+ this.isDumpLog = isDumpLog;
+ this.id = id;
+ this.holdId = holdId;
+ }
+
+ @Override
+ public IPtpIpCommandCallback responseCallback()
+ {
+ return (callback);
+ }
+
+ @Override
+ public int getId()
+ {
+ return (id);
+ }
+
+ @Override
+ public boolean dumpLog()
+ {
+ return (isDumpLog);
+ }
+
+ @Override
+ public byte[] commandBody()
+ {
+ return (new byte[]{
+ // packet type
+ (byte) 0x06, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+
+ // data phase info
+ (byte) 0x02, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+
+ // operation code
+ (byte) 0x43, (byte) 0x91,
+
+ // sequence number
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+
+ // ???
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ });
+ }
+
+ @Override
+ public byte[] commandBody2()
+ {
+ return (new byte[]{
+
+ // packet type
+ (byte) 0x09, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+
+ // sequence number
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+
+ // データサイズ
+ (byte) 0x04, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ });
+ }
+
+ @Override
+ public byte[] commandBody3()
+ {
+ return (new byte[]{
+
+ // packet type
+ (byte) 0x0c, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+
+ // sequence number
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+
+ // ????
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ });
+ }
+ @Override
+ public int getHoldId()
+ {
+ return (holdId);
+ }
+
+ @Override
+ public boolean isHold()
+ {
+ return (false);
+ }
+
+ @Override
+ public boolean isRelease()
+ {
+ return (true);
+ }
+
+}
--- /dev/null
+package net.osdn.gokigen.a01d.camera.canon.wrapper.command.messages.specific;
+
+
+import androidx.annotation.NonNull;
+
+import net.osdn.gokigen.a01d.camera.ptpip.wrapper.command.IPtpIpCommandCallback;
+import net.osdn.gokigen.a01d.camera.ptpip.wrapper.command.messages.PtpIpCommandBase;
+
+public class CanonRequestInnerDevelopStart extends PtpIpCommandBase
+{
+ private final IPtpIpCommandCallback callback;
+ private final boolean isDumpLog;
+ private final int id;
+ private final int holdId;
+
+ private final byte data0;
+ private final byte data1;
+ private final byte data2;
+ private final byte data3;
+
+ public CanonRequestInnerDevelopStart(@NonNull IPtpIpCommandCallback callback, int id, boolean isDumpLog, int holdId, int objectId)
+ {
+ this.callback = callback;
+ this.isDumpLog = isDumpLog;
+ this.id = id;
+ this.holdId = holdId;
+
+ data0 = ((byte) (0x000000ff & objectId));
+ data1 = ((byte)((0x0000ff00 & objectId) >> 8));
+ data2 = ((byte)((0x00ff0000 & objectId) >> 16));
+ data3 = ((byte)((0xff000000 & objectId) >> 24));
+ }
+
+ @Override
+ public IPtpIpCommandCallback responseCallback()
+ {
+ return (callback);
+ }
+
+ @Override
+ public int getId()
+ {
+ return (id);
+ }
+
+ @Override
+ public boolean dumpLog()
+ {
+ return (isDumpLog);
+ }
+
+ @Override
+ public byte[] commandBody()
+ {
+ return (new byte[]{
+ // packet type
+ (byte) 0x06, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+
+ // data phase info
+ (byte) 0x02, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+
+ // operation code
+ (byte) 0x41, (byte) 0x91,
+
+ // sequence number
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+
+ // object id
+ data0, data1, data2, data3,
+
+ // ???
+ (byte) 0x04, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ });
+ }
+
+ @Override
+ public byte[] commandBody2()
+ {
+ return (new byte[]{
+
+ // packet type
+ (byte) 0x09, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+
+ // sequence number
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+
+ // データサイズ
+ (byte) 0x08, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ });
+ }
+
+ @Override
+ public byte[] commandBody3()
+ {
+ return (new byte[]{
+
+ // packet type
+ (byte) 0x0c, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+
+ // sequence number
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+
+ // data
+ (byte) 0x0f, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x02, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ });
+ }
+
+ @Override
+ public int getHoldId()
+ {
+ return (holdId);
+ }
+
+ @Override
+ public boolean isHold()
+ {
+ return (true);
+ }
+
+ @Override
+ public boolean isRelease()
+ {
+ return (false);
+ }
+
+
+}
--- /dev/null
+package net.osdn.gokigen.a01d.camera.canon.wrapper.connection;
+
+
+import android.app.Activity;
+import android.graphics.Color;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+
+import net.osdn.gokigen.a01d.R;
+import net.osdn.gokigen.a01d.camera.ICameraConnection;
+import net.osdn.gokigen.a01d.camera.ICameraStatusReceiver;
+import net.osdn.gokigen.a01d.camera.canon.ICanonInterfaceProvider;
+import net.osdn.gokigen.a01d.camera.canon.wrapper.command.messages.specific.CanonRegistrationMessage;
+import net.osdn.gokigen.a01d.camera.ptpip.wrapper.command.IPtpIpCommandCallback;
+import net.osdn.gokigen.a01d.camera.ptpip.wrapper.command.IPtpIpCommandPublisher;
+import net.osdn.gokigen.a01d.camera.ptpip.wrapper.command.IPtpIpMessages;
+import net.osdn.gokigen.a01d.camera.ptpip.wrapper.command.messages.PtpIpCommandGeneric;
+import net.osdn.gokigen.a01d.camera.ptpip.wrapper.status.PtpIpStatusChecker;
+
+public class CanonCameraConnectSequence implements Runnable, IPtpIpCommandCallback, IPtpIpMessages
+{
+ private final String TAG = this.toString();
+
+ private final Activity context;
+ private final ICameraConnection cameraConnection;
+ private final ICameraStatusReceiver cameraStatusReceiver;
+ private final ICanonInterfaceProvider interfaceProvider;
+ private final IPtpIpCommandPublisher commandIssuer;
+ private final PtpIpStatusChecker statusChecker;
+ private boolean isDumpLog = false;
+
+ CanonCameraConnectSequence(@NonNull Activity context, @NonNull ICameraStatusReceiver statusReceiver, @NonNull final ICameraConnection cameraConnection, @NonNull ICanonInterfaceProvider interfaceProvider, @NonNull PtpIpStatusChecker statusChecker)
+ {
+ Log.v(TAG, " CanonCameraConnectSequenceForPlayback");
+ this.context = context;
+ this.cameraConnection = cameraConnection;
+ this.cameraStatusReceiver = statusReceiver;
+ this.interfaceProvider = interfaceProvider;
+ this.commandIssuer = interfaceProvider.getCommandPublisher();
+ this.statusChecker = statusChecker;
+ }
+
+ @Override
+ public void run()
+ {
+ try
+ {
+ // カメラとTCP接続
+ IPtpIpCommandPublisher issuer = interfaceProvider.getCommandPublisher();
+ if (!issuer.isConnected())
+ {
+ if (!interfaceProvider.getCommandCommunication().connect())
+ {
+ // 接続失敗...
+ interfaceProvider.getInformationReceiver().updateMessage(context.getString(R.string.dialog_title_connect_failed_canon), false, true, Color.RED);
+ onConnectError(context.getString(R.string.dialog_title_connect_failed_canon));
+ return;
+ }
+ }
+ else
+ {
+ Log.v(TAG, "SOCKET IS ALREADY CONNECTED...");
+ }
+ // コマンドタスクの実行開始
+ issuer.start();
+
+ // 接続シーケンスの開始
+ sendRegistrationMessage();
+
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ interfaceProvider.getInformationReceiver().updateMessage(context.getString(R.string.dialog_title_connect_failed_canon), false, true, Color.RED);
+ onConnectError(e.getLocalizedMessage());
+ }
+ }
+
+ private void onConnectError(String reason)
+ {
+ cameraConnection.alertConnectingFailed(reason);
+ }
+
+ @Override
+ public void onReceiveProgress(int currentBytes, int totalBytes, byte[] body)
+ {
+ Log.v(TAG, " " + currentBytes + "/" + totalBytes);
+ }
+
+ @Override
+ public boolean isReceiveMulti()
+ {
+ return (false);
+ }
+
+ @Override
+ public void receivedMessage(int id, byte[] rx_body)
+ {
+ switch (id)
+ {
+ case SEQ_REGISTRATION:
+ if (checkRegistrationMessage(rx_body))
+ {
+ sendInitEventRequest(rx_body);
+ }
+ else
+ {
+ onConnectError(context.getString(R.string.connect_error_message));
+ }
+ break;
+
+ case SEQ_EVENT_INITIALIZE:
+ 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, isDumpLog, 0, 0x1002, 4, 0x41));
+ }
+ else
+ {
+ onConnectError(context.getString(R.string.connect_error_message));
+ }
+ break;
+
+ case SEQ_OPEN_SESSION:
+ interfaceProvider.getInformationReceiver().updateMessage(context.getString(R.string.canon_connect_connecting2), false, false, 0);
+ commandIssuer.enqueueCommand(new PtpIpCommandGeneric(this, SEQ_INIT_SESSION, isDumpLog, 0, 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, isDumpLog, 0, 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, isDumpLog, 0, 0x902f, 4, 0x02));
+ break;
+
+ case SEQ_SET_EVENT_MODE:
+ interfaceProvider.getInformationReceiver().updateMessage(context.getString(R.string.canon_connect_connecting5), false, false, 0);
+ interfaceProvider.getInformationReceiver().updateMessage(context.getString(R.string.connect_connect_finished), false, false, 0);
+ connectFinished();
+ Log.v(TAG, "CHANGED PLAYBACK MODE : DONE.");
+ break;
+
+ default:
+ Log.v(TAG, "RECEIVED UNKNOWN ID : " + id);
+ onConnectError(context.getString(R.string.connect_receive_unknown_message));
+ break;
+ }
+ }
+
+ private void sendRegistrationMessage()
+ {
+ interfaceProvider.getInformationReceiver().updateMessage(context.getString(R.string.connect_start), false, false, 0);
+ cameraStatusReceiver.onStatusNotify(context.getString(R.string.connect_start));
+ commandIssuer.enqueueCommand(new CanonRegistrationMessage(this));
+ }
+
+ private void sendInitEventRequest(byte[] receiveData)
+ {
+ interfaceProvider.getInformationReceiver().updateMessage(context.getString(R.string.connect_start_2), false, false, 0);
+ cameraStatusReceiver.onStatusNotify(context.getString(R.string.connect_start_2));
+ try
+ {
+ 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, isDumpLog, 0, 0x1002, 4, 0x41));
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ private boolean checkRegistrationMessage(byte[] receiveData)
+ {
+ // データ(Connection Number)がないときにはエラーと判断する
+ return (!((receiveData == null)||(receiveData.length < 12)));
+ }
+
+ private boolean checkEventInitialize(byte[] receiveData)
+ {
+ Log.v(TAG, "checkEventInitialize() ");
+ return (!(receiveData == null));
+ }
+
+ private void connectFinished()
+ {
+ try
+ {
+ // 接続成功のメッセージを出す
+ interfaceProvider.getInformationReceiver().updateMessage(context.getString(R.string.connect_connected), false, false, 0);
+
+ // ちょっと待つ
+ Thread.sleep(1000);
+
+ //interfaceProvider.getAsyncEventCommunication().connect();
+ //interfaceProvider.getCameraStatusWatcher().startStatusWatch(interfaceProvider.getStatusListener()); ステータスの定期確認は実施しない
+
+ // 接続成功!のメッセージを出す
+ interfaceProvider.getInformationReceiver().updateMessage(context.getString(R.string.connect_connected), false, false, 0);
+
+ onConnectNotify();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ private void onConnectNotify()
+ {
+ try
+ {
+ final Thread thread = new Thread(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ // カメラとの接続確立を通知する
+ cameraStatusReceiver.onStatusNotify(context.getString(R.string.connect_connected));
+ cameraStatusReceiver.onCameraConnected();
+ Log.v(TAG, " onConnectNotify()");
+ }
+ });
+ thread.start();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+}
--- /dev/null
+package net.osdn.gokigen.a01d.camera.canon.wrapper.connection;
+
+import android.app.Activity;
+
+import androidx.annotation.NonNull;
+
+import net.osdn.gokigen.a01d.camera.canon.ICanonInterfaceProvider;
+import net.osdn.gokigen.a01d.camera.ptpip.wrapper.command.IPtpIpCommunication;
+
+class CanonCameraDisconnectSequence implements Runnable
+{
+ private final String TAG = this.toString();
+ private final Activity activity;
+ private final IPtpIpCommunication command;
+ private final IPtpIpCommunication async;
+ private final IPtpIpCommunication liveview;
+
+ CanonCameraDisconnectSequence(Activity activity, @NonNull ICanonInterfaceProvider interfaceProvider)
+ {
+ this.activity = activity;
+ this.command = interfaceProvider.getCommandCommunication();
+ this.async = interfaceProvider.getAsyncEventCommunication();
+ this.liveview = interfaceProvider.getLiveviewCommunication();
+ }
+
+ @Override
+ public void run()
+ {
+ try
+ {
+ liveview.disconnect();
+ async.disconnect();
+ command.disconnect();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+}
--- /dev/null
+package net.osdn.gokigen.a01d.camera.canon.wrapper.connection;
+
+import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.ConnectivityManager;
+import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiManager;
+import android.provider.Settings;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.appcompat.app.AlertDialog;
+
+import net.osdn.gokigen.a01d.R;
+import net.osdn.gokigen.a01d.camera.ICameraConnection;
+import net.osdn.gokigen.a01d.camera.ICameraStatusReceiver;
+import net.osdn.gokigen.a01d.camera.canon.ICanonInterfaceProvider;
+import net.osdn.gokigen.a01d.camera.ptpip.wrapper.status.PtpIpStatusChecker;
+
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+
+public class CanonConnection implements ICameraConnection
+{
+ private final String TAG = toString();
+ private final Activity context;
+ private final ICameraStatusReceiver statusReceiver;
+ private final ICanonInterfaceProvider 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 ICanonInterfaceProvider interfaceProvider, @NonNull PtpIpStatusChecker statusChecker)
+ {
+ Log.v(TAG, "CanonConnection()");
+ this.context = context;
+ this.statusReceiver = statusReceiver;
+ this.interfaceProvider = interfaceProvider;
+ this.statusChecker = statusChecker;
+ connectionReceiver = new BroadcastReceiver()
+ {
+ @Override
+ public void onReceive(Context context, Intent intent)
+ {
+ onReceiveBroadcastOfConnection(context, intent);
+ }
+ };
+ }
+
+ /**
+ *
+ *
+ */
+ private void onReceiveBroadcastOfConnection(Context context, Intent intent)
+ {
+ interfaceProvider.getInformationReceiver().updateMessage(context.getString(R.string.connect_check_wifi), false, false, 0);
+ statusReceiver.onStatusNotify(context.getString(R.string.connect_check_wifi));
+
+ Log.v(TAG, context.getString(R.string.connect_check_wifi));
+
+ String action = intent.getAction();
+ if (action == null)
+ {
+ Log.v(TAG, "intent.getAction() : null");
+ return;
+ }
+
+ try
+ {
+ if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION))
+ {
+ Log.v(TAG, "onReceiveBroadcastOfConnection() : CONNECTIVITY_ACTION");
+
+ WifiManager wifiManager = (WifiManager) context.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
+ if (wifiManager != null) {
+ WifiInfo info = wifiManager.getConnectionInfo();
+ if (wifiManager.isWifiEnabled() && info != null) {
+ if (info.getNetworkId() != -1) {
+ Log.v(TAG, "Network ID is -1, there is no currently connected network.");
+ }
+ // 自動接続が指示されていた場合は、カメラとの接続処理を行う
+ connectToCamera();
+ } else {
+ if (info == null) {
+ Log.v(TAG, "NETWORK INFO IS NULL.");
+ } else {
+ Log.v(TAG, "isWifiEnabled : " + wifiManager.isWifiEnabled() + " NetworkId : " + info.getNetworkId());
+ }
+ }
+ }
+ }
+ } catch (Exception e) {
+ Log.w(TAG, "onReceiveBroadcastOfConnection() EXCEPTION" + e.getMessage());
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void startWatchWifiStatus(Context context)
+ {
+ Log.v(TAG, "startWatchWifiStatus()");
+ interfaceProvider.getInformationReceiver().updateMessage(context.getString(R.string.connect_prepare), false, false, 0);
+ statusReceiver.onStatusNotify("prepare");
+
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
+ filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
+ context.registerReceiver(connectionReceiver, filter);
+ }
+
+ @Override
+ public void stopWatchWifiStatus(Context context)
+ {
+ Log.v(TAG, "stopWatchWifiStatus()");
+ context.unregisterReceiver(connectionReceiver);
+ disconnect(false);
+ }
+
+ @Override
+ public void disconnect(boolean powerOff)
+ {
+ Log.v(TAG, "disconnect()");
+ disconnectFromCamera(powerOff);
+ connectionStatus = CameraConnectionStatus.DISCONNECTED;
+ statusReceiver.onCameraDisconnected();
+ }
+
+ @Override
+ public void connect()
+ {
+ Log.v(TAG, "connect()");
+ connectToCamera();
+ }
+
+ @Override
+ public void alertConnectingFailed(String message)
+ {
+ Log.v(TAG, "alertConnectingFailed() : " + message);
+ final AlertDialog.Builder builder = new AlertDialog.Builder(context)
+ .setTitle(context.getString(R.string.dialog_title_connect_failed_canon))
+ .setMessage(message)
+ .setPositiveButton(context.getString(R.string.dialog_title_button_retry), new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which)
+ {
+ disconnect(false);
+ connect();
+ }
+ })
+ .setNeutralButton(R.string.dialog_title_button_network_settings, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which)
+ {
+ try
+ {
+ // Wifi 設定画面を表示する
+ context.startActivity(new Intent(Settings.ACTION_WIFI_SETTINGS));
+ }
+ catch (android.content.ActivityNotFoundException ex)
+ {
+ // Activity が存在しなかった...設定画面が起動できなかった
+ Log.v(TAG, "android.content.ActivityNotFoundException...");
+
+ // この場合は、再試行と等価な動きとする
+ connect();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+ });
+ context.runOnUiThread(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ builder.show();
+ }
+ });
+ }
+
+ @Override
+ public CameraConnectionStatus getConnectionStatus()
+ {
+ Log.v(TAG, " getConnectionStatus()");
+ return (connectionStatus);
+ }
+
+ @Override
+ public void forceUpdateConnectionStatus(CameraConnectionStatus status)
+ {
+ Log.v(TAG, " forceUpdateConnectionStatus()");
+ connectionStatus = status;
+ }
+
+ /**
+ * カメラとの切断処理
+ */
+ private void disconnectFromCamera(final boolean powerOff)
+ {
+ Log.v(TAG, " disconnectFromCamera()");
+ try
+ {
+ cameraExecutor.execute(new CanonCameraDisconnectSequence(context, interfaceProvider));
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * カメラとの接続処理
+ */
+ private void connectToCamera()
+ {
+ Log.v(TAG, " connectToCamera()");
+ connectionStatus = CameraConnectionStatus.CONNECTING;
+ try
+ {
+ cameraExecutor.execute(new CanonCameraConnectSequence(context, statusReceiver, this, interfaceProvider, statusChecker));
+ }
+ catch (Exception e)
+ {
+ Log.v(TAG, " connectToCamera() EXCEPTION : " + e.getMessage());
+ e.printStackTrace();
+ }
+ }
+}
package net.osdn.gokigen.a01d.camera.nikon;
-
import androidx.annotation.NonNull;
+import net.osdn.gokigen.a01d.IInformationReceiver;
import net.osdn.gokigen.a01d.camera.ICameraConnection;
import net.osdn.gokigen.a01d.camera.ICameraInformation;
import net.osdn.gokigen.a01d.camera.ICameraStatus;
import net.osdn.gokigen.a01d.camera.IFocusingControl;
import net.osdn.gokigen.a01d.camera.ILiveViewControl;
import net.osdn.gokigen.a01d.camera.IZoomLensControl;
-import net.osdn.gokigen.a01d.camera.ptpip.command.IPtpIpCommandCallback;
+import net.osdn.gokigen.a01d.camera.ptpip.wrapper.command.IPtpIpCommandCallback;
+import net.osdn.gokigen.a01d.camera.ptpip.wrapper.command.IPtpIpCommandPublisher;
+import net.osdn.gokigen.a01d.camera.ptpip.wrapper.command.IPtpIpCommunication;
+import net.osdn.gokigen.a01d.camera.ptpip.wrapper.status.IPtpIpRunModeHolder;
import net.osdn.gokigen.a01d.liveview.ICameraStatusUpdateNotify;
import net.osdn.gokigen.a01d.liveview.liveviewlistener.ILiveViewListener;
ICaptureControl getCaptureControl();
IDisplayInjector getDisplayInjector();
- /*
- IFujiXRunModeHolder getRunModeHolder();
- IFujiXCommandCallback getStatusHolder();
- IFujiXCommandPublisher getCommandPublisher();
- IFujiXCommunication getLiveviewCommunication();
- IFujiXCommunication getAsyncEventCommunication();
- IFujiXCommunication getCommandCommunication();
- */
+ IPtpIpRunModeHolder getRunModeHolder();
+ IPtpIpCommandCallback getStatusHolder();
+ IPtpIpCommandPublisher getCommandPublisher();
+ IPtpIpCommunication getLiveviewCommunication();
+ IPtpIpCommunication getAsyncEventCommunication();
+ IPtpIpCommunication getCommandCommunication();
+ IInformationReceiver getInformationReceiver();
ICameraStatusWatcher getStatusWatcher();
--- /dev/null
+package net.osdn.gokigen.a01d.camera.nikon.wrapper.command.messages.specific;
+
+import androidx.annotation.NonNull;
+
+import net.osdn.gokigen.a01d.camera.ptpip.wrapper.command.IPtpIpCommandCallback;
+import net.osdn.gokigen.a01d.camera.ptpip.wrapper.command.messages.PtpIpCommandBase;
+
+import java.nio.ByteBuffer;
+import java.util.UUID;
+
+public class NikonRegistrationMessage extends PtpIpCommandBase
+{
+ private final IPtpIpCommandCallback callback;
+
+ public NikonRegistrationMessage(@NonNull IPtpIpCommandCallback callback)
+ {
+ this.callback = callback;
+ }
+
+ @Override
+ public IPtpIpCommandCallback responseCallback()
+ {
+ return (callback);
+ }
+
+ @Override
+ public int getId()
+ {
+ return (SEQ_REGISTRATION);
+ }
+
+ @Override
+ public boolean receiveAgainShortLengthMessage()
+ {
+ return (false);
+ }
+
+ @Override
+ public boolean useSequenceNumber()
+ {
+ return (false);
+ }
+
+ @Override
+ public boolean isIncrementSeqNumber()
+ {
+ return (false);
+ }
+
+ @Override
+ public int receiveDelayMs()
+ {
+ return (80);
+ }
+
+ @Override
+ public byte[] commandBody()
+ {
+ int uuid = UUID.randomUUID().hashCode();
+
+ byte[] typeArray = {
+ (byte)0x01, (byte)0x00, (byte)0x00, (byte)0x00,
+ };
+
+ byte[] uuidArray = {
+ (byte)0xad, (byte)0xa5, (byte)0x48, (byte)0x5d, (byte)0x87, (byte)0xb2, (byte)0x7f, (byte)0x0b,
+ (byte)0xd3, (byte)0xd5, (byte)0xde, (byte)0xd0, (byte)0x12, (byte)0x44, (byte)0x99, (byte)0x32,
+ };
+
+ byte[] deviceNameArray = {
+ // device_name 'GOKIGEN_a01'
+ (byte)0x47, (byte)0x00, (byte)0x4f, (byte)0x00, (byte)0x4b, (byte)0x00, (byte)0x49, (byte)0x00,
+ (byte)0x47, (byte)0x00, (byte)0x45, (byte)0x00, (byte)0x4e, (byte)0x00, (byte)0x5f, (byte)0x00,
+ (byte)0x61, (byte)0x00, (byte)0x30, (byte)0x00, (byte)0x31, (byte)0x00, (byte)0x00, (byte)0x00,
+ };
+ byte[] versionArray = {
+ //
+ (byte)0x00, (byte)0x00, (byte)0x01, (byte)0x00,
+ };
+
+ ByteBuffer byteBuffer = ByteBuffer.allocate(4 + 16 + 24 + 4);
+ byteBuffer.put(typeArray);
+ byteBuffer.put(uuidArray);
+ byteBuffer.put(deviceNameArray);
+ byteBuffer.put(versionArray);
+
+ return (byteBuffer.array());
+ }
+}
--- /dev/null
+package net.osdn.gokigen.a01d.camera.nikon.wrapper.connection;
+
+import android.app.Activity;
+import android.graphics.Color;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+
+import net.osdn.gokigen.a01d.R;
+import net.osdn.gokigen.a01d.camera.ICameraConnection;
+import net.osdn.gokigen.a01d.camera.ICameraStatusReceiver;
+import net.osdn.gokigen.a01d.camera.nikon.INikonInterfaceProvider;
+import net.osdn.gokigen.a01d.camera.nikon.wrapper.command.messages.specific.NikonRegistrationMessage;
+import net.osdn.gokigen.a01d.camera.nikon.wrapper.status.NikonStatusChecker;
+import net.osdn.gokigen.a01d.camera.ptpip.wrapper.command.IPtpIpCommandCallback;
+import net.osdn.gokigen.a01d.camera.ptpip.wrapper.command.IPtpIpCommandPublisher;
+import net.osdn.gokigen.a01d.camera.ptpip.wrapper.command.IPtpIpMessages;
+import net.osdn.gokigen.a01d.camera.ptpip.wrapper.command.messages.PtpIpCommandGeneric;
+
+public class NikonCameraConnectSequence implements Runnable, IPtpIpCommandCallback, IPtpIpMessages
+{
+ private final String TAG = this.toString();
+
+ private final Activity context;
+ private final ICameraConnection cameraConnection;
+ private final ICameraStatusReceiver cameraStatusReceiver;
+ private final INikonInterfaceProvider interfaceProvider;
+ private final IPtpIpCommandPublisher commandIssuer;
+ private final NikonStatusChecker statusChecker;
+ private boolean isDumpLog = false;
+
+ NikonCameraConnectSequence(@NonNull Activity context, @NonNull ICameraStatusReceiver statusReceiver, @NonNull final ICameraConnection cameraConnection, @NonNull INikonInterfaceProvider interfaceProvider, @NonNull NikonStatusChecker statusChecker)
+ {
+ Log.v(TAG, " NikonCameraConnectSequenceForPlayback");
+ this.context = context;
+ this.cameraConnection = cameraConnection;
+ this.cameraStatusReceiver = statusReceiver;
+ this.interfaceProvider = interfaceProvider;
+ this.commandIssuer = interfaceProvider.getCommandPublisher();
+ this.statusChecker = statusChecker;
+ }
+
+ @Override
+ public void run()
+ {
+ try
+ {
+ // カメラとTCP接続
+ IPtpIpCommandPublisher issuer = interfaceProvider.getCommandPublisher();
+ if (!issuer.isConnected())
+ {
+ if (!interfaceProvider.getCommandCommunication().connect())
+ {
+ // 接続失敗...
+ interfaceProvider.getInformationReceiver().updateMessage(context.getString(R.string.dialog_title_connect_failed_nikon), false, true, Color.RED);
+ onConnectError(context.getString(R.string.dialog_title_connect_failed_nikon));
+ return;
+ }
+ }
+ else
+ {
+ Log.v(TAG, "SOCKET IS ALREADY CONNECTED...");
+ }
+ // コマンドタスクの実行開始
+ issuer.start();
+
+ // 接続シーケンスの開始
+ sendRegistrationMessage();
+
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ interfaceProvider.getInformationReceiver().updateMessage(context.getString(R.string.dialog_title_connect_failed_nikon), false, true, Color.RED);
+ onConnectError(e.getLocalizedMessage());
+ }
+ }
+
+ private void onConnectError(String reason)
+ {
+ cameraConnection.alertConnectingFailed(reason);
+ }
+
+ @Override
+ public void onReceiveProgress(int currentBytes, int totalBytes, byte[] body)
+ {
+ Log.v(TAG, " " + currentBytes + "/" + totalBytes);
+ }
+
+ @Override
+ public boolean isReceiveMulti()
+ {
+ return (false);
+ }
+
+ @Override
+ public void receivedMessage(int id, byte[] rx_body)
+ {
+ switch (id)
+ {
+ case SEQ_REGISTRATION:
+ if (checkRegistrationMessage(rx_body))
+ {
+ sendInitEventRequest(rx_body);
+ }
+ else
+ {
+ onConnectError(context.getString(R.string.connect_error_message));
+ }
+ break;
+
+ case SEQ_EVENT_INITIALIZE:
+ 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, 50, isDumpLog, 0, 0x1002, 4, 0x41, 0, 0, 0)); // OpenSession
+ }
+ else
+ {
+ onConnectError(context.getString(R.string.connect_error_message));
+ }
+ break;
+
+ case SEQ_OPEN_SESSION:
+ interfaceProvider.getInformationReceiver().updateMessage(context.getString(R.string.canon_connect_connecting2), false, false, 0);
+ commandIssuer.enqueueCommand(new PtpIpCommandGeneric(this, SEQ_INIT_SESSION, 50, isDumpLog, 0, 0x1001, 0, 0, 0, 0, 0)); // GetDeviceInfo
+ break;
+
+ case SEQ_INIT_SESSION:
+ case SEQ_CHANGE_REMOTE:
+ case SEQ_SET_EVENT_MODE:
+ interfaceProvider.getInformationReceiver().updateMessage(context.getString(R.string.canon_connect_connecting3), false, false, 0);
+ interfaceProvider.getInformationReceiver().updateMessage(context.getString(R.string.canon_connect_connecting4), false, false, 0);
+ interfaceProvider.getInformationReceiver().updateMessage(context.getString(R.string.canon_connect_connecting5), false, false, 0);
+ interfaceProvider.getInformationReceiver().updateMessage(context.getString(R.string.connect_connect_finished), false, false, 0);
+ connectFinished();
+ Log.v(TAG, "CHANGED PLAYBACK MODE : DONE.");
+ break;
+
+ default:
+ Log.v(TAG, "RECEIVED UNKNOWN ID : " + id);
+ onConnectError(context.getString(R.string.connect_receive_unknown_message));
+ break;
+ }
+ }
+
+ private void sendRegistrationMessage()
+ {
+ interfaceProvider.getInformationReceiver().updateMessage(context.getString(R.string.connect_start), false, false, 0);
+ cameraStatusReceiver.onStatusNotify(context.getString(R.string.connect_start));
+ commandIssuer.enqueueCommand(new NikonRegistrationMessage(this));
+ }
+
+ private void sendInitEventRequest(byte[] receiveData)
+ {
+ interfaceProvider.getInformationReceiver().updateMessage(context.getString(R.string.connect_start_2), false, false, 0);
+ cameraStatusReceiver.onStatusNotify(context.getString(R.string.connect_start_2));
+ try
+ {
+ 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, 50, isDumpLog, 0, 0x1002, 4, 0x41, 0, 0, 0));
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ private boolean checkRegistrationMessage(byte[] receiveData)
+ {
+ // データ(Connection Number)がないときにはエラーと判断する
+ return (!((receiveData == null)||(receiveData.length < 12)));
+ }
+
+ private boolean checkEventInitialize(byte[] receiveData)
+ {
+ Log.v(TAG, "checkEventInitialize() ");
+ return (!(receiveData == null));
+ }
+
+ private void connectFinished()
+ {
+ try
+ {
+ // 接続成功のメッセージを出す
+ interfaceProvider.getInformationReceiver().updateMessage(context.getString(R.string.connect_connected), false, false, 0);
+
+ // ちょっと待つ
+ Thread.sleep(1000);
+
+ //interfaceProvider.getAsyncEventCommunication().connect();
+ //interfaceProvider.getCameraStatusWatcher().startStatusWatch(interfaceProvider.getStatusListener()); ステータスの定期確認は実施しない
+
+ // 接続成功!のメッセージを出す
+ interfaceProvider.getInformationReceiver().updateMessage(context.getString(R.string.connect_connected), false, false, 0);
+
+ onConnectNotify();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ private void onConnectNotify()
+ {
+ try
+ {
+ final Thread thread = new Thread(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ // カメラとの接続確立を通知する
+ cameraStatusReceiver.onStatusNotify(context.getString(R.string.connect_connected));
+ cameraStatusReceiver.onCameraConnected();
+ Log.v(TAG, " onConnectNotify()");
+ }
+ });
+ thread.start();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+}
--- /dev/null
+package net.osdn.gokigen.a01d.camera.nikon.wrapper.connection;
+
+import android.app.Activity;
+
+import androidx.annotation.NonNull;
+
+import net.osdn.gokigen.a01d.camera.nikon.INikonInterfaceProvider;
+import net.osdn.gokigen.a01d.camera.nikon.wrapper.status.NikonStatusChecker;
+import net.osdn.gokigen.a01d.camera.ptpip.wrapper.command.IPtpIpCommunication;
+
+class NikonCameraDisconnectSequence implements Runnable
+{
+ private final String TAG = this.toString();
+ private final Activity activity;
+ private final IPtpIpCommunication command;
+ private final IPtpIpCommunication async;
+ private final IPtpIpCommunication liveview;
+ private final NikonStatusChecker statusChecker;
+
+ NikonCameraDisconnectSequence(Activity activity, @NonNull INikonInterfaceProvider interfaceProvider, @NonNull NikonStatusChecker statusChecker)
+ {
+ this.activity = activity;
+ this.command = interfaceProvider.getCommandCommunication();
+ this.async = interfaceProvider.getAsyncEventCommunication();
+ this.liveview = interfaceProvider.getLiveviewCommunication();
+ this.statusChecker = statusChecker;
+ }
+
+ @Override
+ public void run()
+ {
+ try
+ {
+ statusChecker.stopStatusWatch();
+ liveview.disconnect();
+ async.disconnect();
+ command.disconnect();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+}
--- /dev/null
+package net.osdn.gokigen.a01d.camera.nikon.wrapper.connection;
+
+
+import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.ConnectivityManager;
+import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiManager;
+import android.provider.Settings;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.appcompat.app.AlertDialog;
+
+import net.osdn.gokigen.a01d.R;
+import net.osdn.gokigen.a01d.camera.ICameraConnection;
+import net.osdn.gokigen.a01d.camera.ICameraStatusReceiver;
+import net.osdn.gokigen.a01d.camera.nikon.INikonInterfaceProvider;
+import net.osdn.gokigen.a01d.camera.nikon.wrapper.status.NikonStatusChecker;
+
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+
+public class NikonConnection implements ICameraConnection
+{
+ private final String TAG = toString();
+ private final Activity context;
+ private final ICameraStatusReceiver statusReceiver;
+ private final INikonInterfaceProvider interfaceProvider;
+ private final BroadcastReceiver connectionReceiver;
+ private final Executor cameraExecutor = Executors.newFixedThreadPool(1);
+
+ private ICameraConnection.CameraConnectionStatus connectionStatus = CameraConnectionStatus.UNKNOWN;
+
+ private final NikonCameraConnectSequence connectSequence;
+ private final NikonCameraDisconnectSequence disconnectSequence;
+
+ public NikonConnection(@NonNull final Activity context, @NonNull final ICameraStatusReceiver statusReceiver, @NonNull INikonInterfaceProvider interfaceProvider, @NonNull NikonStatusChecker statusChecker)
+ {
+ Log.v(TAG, "NikonConnection()");
+ this.context = context;
+ this.statusReceiver = statusReceiver;
+ this.interfaceProvider = interfaceProvider;
+ connectionReceiver = new BroadcastReceiver()
+ {
+ @Override
+ public void onReceive(Context context, Intent intent)
+ {
+ onReceiveBroadcastOfConnection(context, intent);
+ }
+ };
+ connectSequence = new NikonCameraConnectSequence(context, statusReceiver, this, interfaceProvider, statusChecker);
+ disconnectSequence = new NikonCameraDisconnectSequence(context, interfaceProvider, statusChecker);
+ }
+
+ /**
+ *
+ *
+ */
+ private void onReceiveBroadcastOfConnection(Context context, Intent intent)
+ {
+ interfaceProvider.getInformationReceiver().updateMessage(context.getString(R.string.connect_check_wifi), false, false, 0);
+ statusReceiver.onStatusNotify(context.getString(R.string.connect_check_wifi));
+
+ Log.v(TAG, context.getString(R.string.connect_check_wifi));
+
+ String action = intent.getAction();
+ if (action == null)
+ {
+ Log.v(TAG, "intent.getAction() : null");
+ return;
+ }
+
+ try
+ {
+ if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION))
+ {
+ Log.v(TAG, "onReceiveBroadcastOfConnection() : CONNECTIVITY_ACTION");
+
+ WifiManager wifiManager = (WifiManager) context.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
+ if (wifiManager != null) {
+ WifiInfo info = wifiManager.getConnectionInfo();
+ if (wifiManager.isWifiEnabled() && info != null) {
+ if (info.getNetworkId() != -1) {
+ Log.v(TAG, "Network ID is -1, there is no currently connected network.");
+ }
+ // 自動接続が指示されていた場合は、カメラとの接続処理を行う
+ connectToCamera();
+ } else {
+ if (info == null) {
+ Log.v(TAG, "NETWORK INFO IS NULL.");
+ } else {
+ Log.v(TAG, "isWifiEnabled : " + wifiManager.isWifiEnabled() + " NetworkId : " + info.getNetworkId());
+ }
+ }
+ }
+ }
+ } catch (Exception e) {
+ Log.w(TAG, "onReceiveBroadcastOfConnection() EXCEPTION" + e.getMessage());
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void startWatchWifiStatus(Context context)
+ {
+ Log.v(TAG, "startWatchWifiStatus()");
+ interfaceProvider.getInformationReceiver().updateMessage(context.getString(R.string.connect_prepare), false, false, 0);
+ statusReceiver.onStatusNotify("prepare");
+
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
+ filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
+ context.registerReceiver(connectionReceiver, filter);
+ }
+
+ @Override
+ public void stopWatchWifiStatus(Context context)
+ {
+ Log.v(TAG, "stopWatchWifiStatus()");
+ context.unregisterReceiver(connectionReceiver);
+ disconnect(false);
+ }
+
+ @Override
+ public void disconnect(boolean powerOff)
+ {
+ Log.v(TAG, "disconnect()");
+ disconnectFromCamera(powerOff);
+ connectionStatus = CameraConnectionStatus.DISCONNECTED;
+ statusReceiver.onCameraDisconnected();
+ }
+
+ @Override
+ public void connect()
+ {
+ Log.v(TAG, "connect()");
+ connectToCamera();
+ }
+
+ @Override
+ public void alertConnectingFailed(String message)
+ {
+ Log.v(TAG, "alertConnectingFailed() : " + message);
+ final AlertDialog.Builder builder = new AlertDialog.Builder(context)
+ .setTitle(context.getString(R.string.dialog_title_connect_failed_nikon))
+ .setMessage(message)
+ .setPositiveButton(context.getString(R.string.dialog_title_button_retry), new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which)
+ {
+ disconnect(false);
+ connect();
+ }
+ })
+ .setNeutralButton(R.string.dialog_title_button_network_settings, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which)
+ {
+ try
+ {
+ // Wifi 設定画面を表示する
+ context.startActivity(new Intent(Settings.ACTION_WIFI_SETTINGS));
+ }
+ catch (android.content.ActivityNotFoundException ex)
+ {
+ // Activity が存在しなかった...設定画面が起動できなかった
+ Log.v(TAG, "android.content.ActivityNotFoundException...");
+
+ // この場合は、再試行と等価な動きとする
+ connect();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+ });
+ context.runOnUiThread(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ builder.show();
+ }
+ });
+ }
+
+ @Override
+ public CameraConnectionStatus getConnectionStatus()
+ {
+ Log.v(TAG, " getConnectionStatus()");
+ return (connectionStatus);
+ }
+
+ @Override
+ public void forceUpdateConnectionStatus(CameraConnectionStatus status)
+ {
+ Log.v(TAG, " forceUpdateConnectionStatus()");
+ connectionStatus = status;
+ }
+
+ /**
+ * カメラとの切断処理
+ */
+ private void disconnectFromCamera(final boolean powerOff)
+ {
+ Log.v(TAG, " disconnectFromCamera()");
+ try
+ {
+ cameraExecutor.execute(disconnectSequence);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * カメラとの接続処理
+ */
+ private void connectToCamera()
+ {
+ Log.v(TAG, " connectToCamera()");
+ connectionStatus = CameraConnectionStatus.CONNECTING;
+ try
+ {
+ cameraExecutor.execute(connectSequence);
+ }
+ catch (Exception e)
+ {
+ Log.v(TAG, " connectToCamera() EXCEPTION : " + e.getMessage());
+ e.printStackTrace();
+ }
+ }
+}
--- /dev/null
+package net.osdn.gokigen.a01d.camera.nikon.wrapper.status;
+
+import android.app.Activity;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+
+import net.osdn.gokigen.a01d.camera.ICameraStatus;
+import net.osdn.gokigen.a01d.camera.ICameraStatusWatcher;
+import net.osdn.gokigen.a01d.camera.ptpip.wrapper.command.IPtpIpCommand;
+import net.osdn.gokigen.a01d.camera.ptpip.wrapper.command.IPtpIpCommandCallback;
+import net.osdn.gokigen.a01d.camera.ptpip.wrapper.command.IPtpIpCommandPublisher;
+import net.osdn.gokigen.a01d.camera.ptpip.wrapper.command.IPtpIpMessages;
+import net.osdn.gokigen.a01d.camera.ptpip.wrapper.status.IPtpIpInitEventRequest;
+import net.osdn.gokigen.a01d.liveview.ICameraStatusUpdateNotify;
+
+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.a01d.camera.utils.SimpleLogDumper.dump_bytes;
+
+public class NikonStatusChecker 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 ICameraStatusUpdateNotify notifier = null;
+ private NikonStatusHolder statusHolder;
+ private boolean whileFetching = false;
+ private boolean logcat = false;
+ private final String ipAddress;
+ private final int portNumber;
+ private final IPtpIpInitEventRequest eventRequest;
+
+ private Socket socket = null;
+ private DataOutputStream dos = null;
+ private BufferedReader bufferedReader = null;
+ private int eventConnectionNumber = 0;
+
+ public NikonStatusChecker(@NonNull Activity activity, @NonNull IPtpIpCommandPublisher issuer, @NonNull String ip, int portNumber, @NonNull IPtpIpInitEventRequest eventRequest)
+ {
+ this.issuer = issuer;
+ this.statusHolder = new NikonStatusHolder();
+ this.ipAddress = ip;
+ this.portNumber = portNumber;
+ this.eventRequest = eventRequest;
+ Log.v(TAG, "POLLING WAIT : " + sleepMs);
+ }
+
+ @Override
+ public void onReceiveProgress(int currentBytes, int totalBytes, byte[] body)
+ {
+ Log.v(TAG, " " + currentBytes + "/" + totalBytes);
+ }
+
+ @Override
+ public boolean isReceiveMulti()
+ {
+ return (false);
+ }
+
+ @Override
+ public void receivedMessage(int id, byte[] data)
+ {
+ 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.)");
+ return;
+ }
+
+ int nofStatus = (data[13] * 256) + data[12];
+ int statusCount = 0;
+ int index = STATUS_MESSAGE_HEADER_SIZE;
+ while ((statusCount < nofStatus)&&(index < data.length))
+ {
+ int dataId = ((((int)data[index + 1]) & 0xff) * 256) + (((int) data[index]) & 0xff);
+ statusHolder.updateValue(notifier, dataId, data[index + 2], data[index + 3], data[index +4], data[index + 5]);
+ index = index + 6;
+ statusCount++;
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public List<String> getStatusList(String key)
+ {
+ try
+ {
+ if (statusHolder == null)
+ {
+ return (new ArrayList<>());
+ }
+ return (statusHolder.getAvailableItemList(key));
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ return (new ArrayList<>());
+ }
+
+ @Override
+ public String getStatus(String key)
+ {
+ try
+ {
+ if (statusHolder == null)
+ {
+ return ("");
+ }
+ return (statusHolder.getItemStatus(key));
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ return ("");
+ }
+
+ @Override
+ public void setStatus(String key, String value)
+ {
+ try
+ {
+ if (logcat)
+ {
+ Log.v(TAG, "setStatus(" + key + ", " + value + ")");
+ }
+
+ // ここで設定を行う。
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void startStatusWatch(@NonNull ICameraStatusUpdateNotify notifier)
+ {
+ if (whileFetching)
+ {
+ Log.v(TAG, "startStatusWatch() already starting.");
+ return;
+ }
+ try
+ {
+ final IPtpIpCommandCallback callback = this;
+ this.notifier = notifier;
+ whileFetching = true;
+
+ // セッションをオープンする
+ boolean isConnect = connect();
+ if (!isConnect)
+ {
+ Log.v(TAG, " CONNECT FAIL...(EVENT) : " + ipAddress + " " + portNumber);
+ }
+ issueCommand(eventRequest.getInitEventRequest(this, eventConnectionNumber));
+
+/*
+ Thread thread = new Thread(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ logcat("Start status watch. : " + sleepMs + "ms");
+ while (whileFetching)
+ {
+ try
+ {
+ issuer.enqueueCommand(new StatusRequestMessage(callback));
+ Thread.sleep(sleepMs);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+ logcat("STATUS WATCH STOPPED.");
+ }
+ });
+ thread.start();
+
+ // 切断する
+ disconnect();
+*/
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void stopStatusWatch()
+ {
+ Log.v(TAG, "stoptStatusWatch()");
+ whileFetching = false;
+ this.notifier = null;
+ }
+
+ private void logcat(String message)
+ {
+ if (logcat)
+ {
+ 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);
+
+ 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.");
+ 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();
+ }
+ }
+}
--- /dev/null
+package net.osdn.gokigen.a01d.camera.nikon.wrapper.status;
+
+import android.util.Log;
+import android.util.SparseIntArray;
+
+import androidx.annotation.NonNull;
+import androidx.collection.SparseArrayCompat;
+
+import net.osdn.gokigen.a01d.liveview.ICameraStatusUpdateNotify;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+
+//class NikonStatusHolder implements IPtpIpCameraProperties
+class NikonStatusHolder
+{
+ private final String TAG = toString();
+ private SparseIntArray statusHolder;
+ private SparseArrayCompat<String> statusNameArray;
+
+ NikonStatusHolder()
+ {
+ statusHolder = new SparseIntArray();
+ statusHolder.clear();
+
+ statusNameArray = new SparseArrayCompat<>();
+ prepareStatusNameArray();
+ }
+
+ private void prepareStatusNameArray()
+ {
+/*
+ statusNameArray.clear();
+ statusNameArray.append(BATTERY_LEVEL, BATTERY_LEVEL_STR);
+ statusNameArray.append(WHITE_BALANCE, WHITE_BALANCE_STR);
+ statusNameArray.append(APERTURE, APERTURE_STR);
+ statusNameArray.append(FOCUS_MODE, FOCUS_MODE_STR);
+ statusNameArray.append(SHOOTING_MODE, SHOOTING_MODE_STR);
+ statusNameArray.append(FLASH, FLASH_STR);
+ statusNameArray.append(EXPOSURE_COMPENSATION, EXPOSURE_COMPENSATION_STR);
+ statusNameArray.append(SELF_TIMER, SELF_TIMER_STR);
+ statusNameArray.append(FILM_SIMULATION, FILM_SIMULATION_STR);
+ statusNameArray.append(IMAGE_FORMAT, IMAGE_FORMAT_STR);
+ statusNameArray.append(RECMODE_ENABLE, RECMODE_ENABLE_STR);
+ statusNameArray.append(F_SS_CONTROL, F_SS_CONTROL_STR);
+ statusNameArray.append(ISO, ISO_STR);
+ statusNameArray.append(MOVIE_ISO, MOVIE_ISO_STR);
+ statusNameArray.append(FOCUS_POINT, FOCUS_POINT_STR);
+ statusNameArray.append(DEVICE_ERROR, DEVICE_ERROR_STR);
+ statusNameArray.append(IMAGE_FILE_COUNT, IMAGE_FILE_COUNT_STR);
+ statusNameArray.append(SDCARD_REMAIN_SIZE, SDCARD_REMAIN_SIZE_STR);
+ statusNameArray.append(FOCUS_LOCK, FOCUS_LOCK_STR);
+ statusNameArray.append(MOVIE_REMAINING_TIME, MOVIE_REMAINING_TIME_STR);
+ statusNameArray.append(SHUTTER_SPEED, SHUTTER_SPEED_STR);
+ statusNameArray.append(IMAGE_ASPECT,IMAGE_ASPECT_STR);
+ statusNameArray.append(BATTERY_LEVEL_2, BATTERY_LEVEL_2_STR);
+
+ statusNameArray.append(UNKNOWN_DF00, UNKNOWN_DF00_STR);
+ statusNameArray.append(PICTURE_JPEG_COUNT, PICTURE_JPEG_COUNT_STR);
+ statusNameArray.append(UNKNOWN_D400, UNKNOWN_D400_STR);
+ statusNameArray.append(UNKNOWN_D401, UNKNOWN_D401_STR);
+ statusNameArray.append(UNKNOWN_D52F, UNKNOWN_D52F_STR);
+*/
+ }
+
+
+ void updateValue(ICameraStatusUpdateNotify notifier, int id, byte data0, byte data1, byte data2, byte data3)
+ {
+ try
+ {
+ int value = ((((int) data3) & 0xff) << 24) + ((((int) data2) & 0xff) << 16) + ((((int) data1) & 0xff) << 8) + (((int) data0) & 0xff);
+ int currentValue = statusHolder.get(id, -1);
+ Log.v(TAG, "STATUS ID: " + id + " value : " + value + " (" + currentValue + ")");
+ statusHolder.put(id, value);
+ if (currentValue != value)
+ {
+ //Log.v(TAG, "STATUS ID: " + id + " value : " + currentValue + " -> " + value);
+ if (notifier != null)
+ {
+ updateDetected(notifier, id, currentValue, value);
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ private void updateDetected(@NonNull ICameraStatusUpdateNotify notifier, int id, int previous, int current)
+ {
+ try
+ {
+ String idName = statusNameArray.get(id, "Unknown");
+ Log.v(TAG, String.format(Locale.US,"<< UPDATE STATUS >> id: 0x%04x[%s] 0x%08x(%d) -> 0x%08x(%d)", id, idName, previous, previous, current, current));
+ //Log.v(TAG, "updateDetected(ID: " + id + " [" + idName + "] " + previous + " -> " + current + " )");
+/*
+ if (id == FOCUS_LOCK)
+ {
+ if (current == 1)
+ {
+ // focus Lock
+ notifier.updateFocusedStatus(true, true);
+ }
+ else
+ {
+ // focus unlock
+ notifier.updateFocusedStatus(false, false);
+ }
+ }
+*/
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * 認識したカメラのステータス名称のリストを応答する
+ *
+ */
+ private List<String> getAvailableStatusNameList()
+ {
+ ArrayList<String> selection = new ArrayList<>();
+ try
+ {
+ for (int index = 0; index < statusHolder.size(); index++)
+ {
+ int key = statusHolder.keyAt(index);
+ selection.add(statusNameArray.get(key, String.format(Locale.US, "0x%04x", key)));
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ return (selection);
+
+ }
+
+ List<String> getAvailableItemList(String listKey)
+ {
+ if (listKey == null)
+ {
+ // アイテム名の一覧を応答する
+ return (getAvailableStatusNameList());
+ }
+
+ ///// 選択可能なステータスの一覧を取得する : でも以下はアイテム名の一覧... /////
+ ArrayList<String> selection = new ArrayList<>();
+ try
+ {
+ for (int index = 0; index < statusHolder.size(); index++)
+ {
+ int key = statusHolder.keyAt(index);
+ selection.add(statusNameArray.get(key));
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ return (selection);
+ }
+
+ String getItemStatus(String key)
+ {
+ try
+ {
+ int strIndex = key.indexOf("x");
+ Log.v(TAG, "getItemStatus() : " + key + " [" + strIndex + "]");
+ if (strIndex >= 1)
+ {
+ key = key.substring(strIndex + 1);
+ try
+ {
+ int id = Integer.parseInt(key, 16);
+ int value = statusHolder.get(id);
+ Log.v(TAG, "getItemStatus() value : " + value);
+ return (value + "");
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ for (int index = 0; index < statusNameArray.size(); index++)
+ {
+ int id = statusNameArray.keyAt(index);
+ String strKey = statusNameArray.valueAt(index);
+ if (key.contentEquals(strKey))
+ {
+ int value = statusHolder.get(id);
+ return (value + "");
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ return ("? [" + key + "]");
+ }
+}
-package net.osdn.gokigen.a01d.camera.ptpip.command;
+package net.osdn.gokigen.a01d.camera.ptpip.wrapper.command;
public interface IPtpIpCommand
{
-package net.osdn.gokigen.a01d.camera.ptpip.command;
+package net.osdn.gokigen.a01d.camera.ptpip.wrapper.command;
public interface IPtpIpCommandCallback
{
-package net.osdn.gokigen.a01d.camera.ptpip.command;
+package net.osdn.gokigen.a01d.camera.ptpip.wrapper.command;
import androidx.annotation.NonNull;
--- /dev/null
+package net.osdn.gokigen.a01d.camera.ptpip.wrapper.command;
+
+public interface IPtpIpCommunication
+{
+ boolean connect();
+ void disconnect();
+}
--- /dev/null
+package net.osdn.gokigen.a01d.camera.ptpip.wrapper.command;
+
+public interface IPtpIpMessages
+{
+ int SEQ_DUMMY = 0;
+ 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;
+
+ int GET_STORAGE_ID = 101;
+ int GET_STORAGE_INFO = 102;
+ int GET_OBJECT_INFO_EX = 103;
+ int GET_OBJECT_INFO_EX_2 = 104;
+ int GET_OBJECT_INFO_EX_3 = 105;
+
+ int GET_STORAGE_HANDLE1 = 110;
+ int GET_STORAGE_HANDLE2 = 111;
+ int GET_STORAGE_HANDLE3 = 112;
+ int GET_PARTIAL_OBJECT= 113;
+
+/*
+ int SEQ_REGISTRATION = 1;
+ int SEQ_START = 2;
+ int SEQ_START_2ND = 3;
+ int SEQ_START_2ND_READ = 10;
+ int SEQ_START_2ND_RECEIVE = 4;
+ int SEQ_START_3RD = 5;
+ int SEQ_START_4TH = 6;
+ int SEQ_CAMERA_REMOTE = 7;
+ int SEQ_START_5TH = 8;
+ int SEQ_STATUS_REQUEST = 9;
+ int SEQ_QUERY_CAMERA_CAPABILITIES = 11;
+
+ int SEQ_CHANGE_TO_PLAYBACK_1ST = 12;
+ int SEQ_CHANGE_TO_PLAYBACK_2ND = 13;
+ int SEQ_CHANGE_TO_PLAYBACK_3RD = 14;
+ int SEQ_CHANGE_TO_PLAYBACK_4TH = 15;
+
+ int SEQ_CHANGE_TO_LIVEVIEW_1ST = 16;
+ int SEQ_CHANGE_TO_LIVEVIEW_2ND = 17;
+ int SEQ_CHANGE_TO_LIVEVIEW_3RD = 18;
+ int SEQ_CHANGE_TO_LIVEVIEW_4TH = 19;
+ int SEQ_CHANGE_TO_LIVEVIEW_5TH = 20;
+
+ int SEQ_SET_PROPERTY_VALUE = 21;
+ int SEQ_FOCUS_LOCK = 22;
+ int SEQ_FOCUS_UNLOCK = 23;
+ int SEQ_CAPTURE = 24;
+
+ int SEQ_IMAGE_INFO = 25;
+ int SEQ_THUMBNAIL = 26;
+ int SEQ_FULL_IMAGE = 27;
+*/
+}
--- /dev/null
+package net.osdn.gokigen.a01d.camera.ptpip.wrapper.command;
+
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+
+import java.io.InputStream;
+import java.net.Socket;
+
+public class PtpIpAsyncResponseReceiver implements IPtpIpCommunication
+{
+ private final String TAG = toString();
+ private final String ipAddress;
+ private final int portNumber;
+ private static final int BUFFER_SIZE = 1280 + 8;
+ private static final int WAIT_MS = 250; // 250ms
+ private static final int ERROR_LIMIT = 30;
+ private IPtpIpCommandCallback receiver = null;
+ private boolean isStart = false;
+
+ public PtpIpAsyncResponseReceiver(@NonNull String ip, int portNumber)
+ {
+ this.ipAddress = ip;
+ this.portNumber = portNumber;
+ }
+
+ public void setEventSubscriber(@NonNull IPtpIpCommandCallback receiver)
+ {
+ this.receiver = receiver;
+ }
+
+ @Override
+ public boolean connect()
+ {
+ start();
+ return (true);
+ }
+
+ @Override
+ public void disconnect()
+ {
+ isStart = false;
+ }
+
+ public void start()
+ {
+ if (isStart)
+ {
+ // すでに受信スレッド動作中なので抜ける
+ return;
+ }
+ isStart = true;
+ Thread thread = new Thread(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ try
+ {
+ Socket socket = new Socket(ipAddress, portNumber);
+ startReceive(socket);
+ }
+ catch (Exception e)
+ {
+ Log.v(TAG, " IP : " + ipAddress + " port : " + portNumber);
+ e.printStackTrace();
+ }
+ }
+ });
+ try
+ {
+ thread.start();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ public void stop()
+ {
+ isStart = false;
+ }
+
+ private void startReceive(Socket socket)
+ {
+ int errorCount = 0;
+ InputStream isr;
+ byte[] byte_array;
+ try
+ {
+ isr = socket.getInputStream();
+ byte_array = new byte[BUFFER_SIZE];
+
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ Log.v(TAG, "===== startReceive() aborted.");
+ return;
+ }
+ Log.v(TAG, "startReceive() start.");
+ while (isStart)
+ {
+ try
+ {
+ int read_bytes = isr.read(byte_array, 0, BUFFER_SIZE);
+ Log.v(TAG, "RECEIVE ASYNC : " + read_bytes + " bytes.");
+ if (receiver != null)
+ {
+ try
+ {
+ receiver.receivedMessage(0, byte_array);
+ }
+ catch (Exception ee)
+ {
+ ee.printStackTrace();
+ }
+ }
+ Thread.sleep(WAIT_MS);
+ errorCount = 0;
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ errorCount++;
+ }
+ if (errorCount > ERROR_LIMIT)
+ {
+ // エラーが連続でたくさん出たらループをストップさせる
+ isStart = false;
+ }
+ }
+ try
+ {
+ isr.close();
+ socket.close();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ Log.v(TAG, "startReceive() end.");
+ }
+}
--- /dev/null
+package net.osdn.gokigen.a01d.camera.ptpip.wrapper.command;
+
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.InputStream;
+import java.net.Socket;
+import java.util.ArrayDeque;
+import java.util.Arrays;
+import java.util.Queue;
+
+import static net.osdn.gokigen.a01d.camera.utils.SimpleLogDumper.dump_bytes;
+
+public class PtpIpCommandPublisher implements IPtpIpCommandPublisher, IPtpIpCommunication
+{
+ private static final String TAG = PtpIpCommandPublisher.class.getSimpleName();
+
+ private static final int SEQUENCE_START_NUMBER = 1;
+ private static final int BUFFER_SIZE = 1024 * 1024 + 16; // 受信バッファは 256kB
+ private static final int COMMAND_SEND_RECEIVE_DURATION_MS = 5;
+ private static final int COMMAND_SEND_RECEIVE_DURATION_MAX = 1000;
+ private static final int COMMAND_POLL_QUEUE_MS = 5;
+
+ private final String ipAddress;
+ private final int portNumber;
+
+ private boolean isStart = false;
+ private boolean isHold = false;
+ private int holdId = 0;
+ private Socket socket = null;
+ private DataOutputStream dos = null;
+ private BufferedReader bufferedReader = null;
+ private int sequenceNumber = SEQUENCE_START_NUMBER;
+ private Queue<IPtpIpCommand> commandQueue;
+ private Queue<IPtpIpCommand> holdCommandQueue;
+
+ public PtpIpCommandPublisher(@NonNull String ip, int portNumber)
+ {
+ this.ipAddress = ip;
+ this.portNumber = portNumber;
+ this.commandQueue = new ArrayDeque<>();
+ this.holdCommandQueue = new ArrayDeque<>();
+ commandQueue.clear();
+ holdCommandQueue.clear();
+ }
+
+ @Override
+ public boolean isConnected()
+ {
+ return (socket != null);
+ }
+
+ @Override
+ public boolean connect()
+ {
+ try
+ {
+ socket = new Socket(ipAddress, portNumber);
+ return (true);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ socket = null;
+ }
+ return (false);
+ }
+
+ @Override
+ public 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;
+ sequenceNumber = SEQUENCE_START_NUMBER;
+ isStart = false;
+ commandQueue.clear();
+ System.gc();
+ }
+
+ @Override
+ public void start()
+ {
+ if (isStart)
+ {
+ // すでにコマンドのスレッド動作中なので抜ける
+ return;
+ }
+ isStart = true;
+
+ Thread thread = new Thread(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ try
+ {
+ dos = new DataOutputStream(socket.getOutputStream());
+ while (isStart)
+ {
+ try
+ {
+ IPtpIpCommand command = commandQueue.poll();
+ if (command != null)
+ {
+ issueCommand(command);
+ }
+ Thread.sleep(COMMAND_POLL_QUEUE_MS);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ Log.v(TAG, "<<<<< IP : " + ipAddress + " port : " + portNumber + " >>>>>");
+ e.printStackTrace();
+ }
+ }
+ });
+ try
+ {
+ thread.start();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void stop()
+ {
+ isStart = false;
+ commandQueue.clear();
+ }
+
+ @Override
+ public boolean enqueueCommand(@NonNull IPtpIpCommand command)
+ {
+ try
+ {
+ if (isHold) {
+ if (holdId == command.getHoldId()) {
+ if (command.isRelease()) {
+ // コマンドをキューに積んだ後、リリースする
+ boolean ret = commandQueue.offer(command);
+ isHold = false;
+
+ // 溜まっているキューを積みなおす
+ while (holdCommandQueue.size() != 0) {
+ IPtpIpCommand queuedCommand = holdCommandQueue.poll();
+ commandQueue.offer(queuedCommand);
+ if ((queuedCommand != null)&&(queuedCommand.isHold()))
+ {
+ // 特定シーケンスに入った場合は、そこで積みなおすのをやめる
+ isHold = true;
+ holdId = queuedCommand.getHoldId();
+ break;
+ }
+ }
+ return (ret);
+ }
+ return (commandQueue.offer(command));
+ } else {
+ // 特定シーケンスではなかったので HOLD
+ return (holdCommandQueue.offer(command));
+ }
+ }
+ if (command.isHold())
+ {
+ isHold = true;
+ holdId = command.getHoldId();
+ }
+ //Log.v(TAG, "Enqueue : " + command.getId());
+ return (commandQueue.offer(command));
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ return (false);
+ }
+
+ @Override
+ public boolean flushHoldQueue()
+ {
+ Log.v(TAG, " flushHoldQueue()");
+ holdCommandQueue.clear();
+ System.gc();
+ return (true);
+ }
+
+ private void issueCommand(@NonNull IPtpIpCommand command)
+ {
+ try
+ {
+ boolean retry_over = true;
+ while (retry_over)
+ {
+ //Log.v(TAG, "issueCommand : " + command.getId());
+ byte[] commandBody = command.commandBody();
+ if (commandBody != null)
+ {
+ // コマンドボディが入っていた場合には、コマンド送信(入っていない場合は受信待ち)
+ send_to_camera(command.dumpLog(), commandBody, command.useSequenceNumber(), command.embeddedSequenceNumberIndex());
+ byte[] commandBody2 = command.commandBody2();
+ if (commandBody2 != null)
+ {
+ // コマンドボディの2つめが入っていた場合には、コマンドを連続送信する
+ send_to_camera(command.dumpLog(), commandBody2, command.useSequenceNumber(), command.embeddedSequenceNumberIndex2());
+ }
+ byte[] commandBody3 = command.commandBody3();
+ if (commandBody3 != null)
+ {
+ // コマンドボディの3つめが入っていた場合には、コマンドを連続送信する
+ send_to_camera(command.dumpLog(), commandBody3, command.useSequenceNumber(), command.embeddedSequenceNumberIndex3());
+ }
+ if (command.isIncrementSeqNumber())
+ {
+ // シーケンス番号を更新する
+ sequenceNumber++;
+ }
+ }
+ retry_over = receive_from_camera(command);
+ if ((retry_over)&&(commandBody != null))
+ {
+ // 再送信...のために、シーケンス番号を戻す...
+ sequenceNumber--;
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * カメラにコマンドを送信する(メイン部分)
+ *
+ */
+ private void send_to_camera(boolean isDumpReceiveLog, byte[] byte_array, boolean useSequenceNumber, int embeddedSequenceIndex)
+ {
+ try
+ {
+ if (dos == null)
+ {
+ Log.v(TAG, " DataOutputStream is null.");
+ return;
+ }
+
+ //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 (useSequenceNumber)
+ {
+ // Sequence Number を反映させる
+ sendData[embeddedSequenceIndex] = (byte) ((0x000000ff & sequenceNumber));
+ sendData[embeddedSequenceIndex + 1] = (byte) (((0x0000ff00 & sequenceNumber) >>> 8) & 0x000000ff);
+ sendData[embeddedSequenceIndex + 2] = (byte) (((0x00ff0000 & sequenceNumber) >>> 16) & 0x000000ff);
+ sendData[embeddedSequenceIndex + 3] = (byte) (((0xff000000 & sequenceNumber) >>> 24) & 0x000000ff);
+ if (isDumpReceiveLog)
+ {
+ Log.v(TAG, "----- SEQ No. : " + sequenceNumber + " -----");
+ }
+ }
+
+ if (isDumpReceiveLog)
+ {
+ // ログに送信メッセージを出力する
+ dump_bytes("SEND[" + sendData.length + "] ", sendData);
+ }
+
+ // (データを)送信
+ dos.write(sendData);
+ dos.flush();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ private void sleep(int delayMs)
+ {
+ try
+ {
+ Thread.sleep(delayMs);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+
+ /**
+ * カメラからにコマンドの結果を受信する(メイン部分)
+ *
+ */
+ private boolean receive_from_camera(@NonNull IPtpIpCommand command)
+ {
+ IPtpIpCommandCallback callback = command.responseCallback();
+ int delayMs = command.receiveDelayMs();
+ if ((delayMs < 0)||(delayMs > COMMAND_SEND_RECEIVE_DURATION_MAX))
+ {
+ delayMs = COMMAND_SEND_RECEIVE_DURATION_MS;
+ }
+ if ((callback != null)&&(callback.isReceiveMulti()))
+ {
+ // 受信したら逐次「受信したよ」と応答するパターン
+ return (receive_multi(command, delayMs));
+ }
+ // 受信した後、すべてをまとめて「受信したよ」と応答するパターン
+ return (receive_single(command, delayMs));
+ }
+
+ private boolean receive_single(@NonNull IPtpIpCommand command, int delayMs)
+ {
+ boolean isDumpReceiveLog = command.dumpLog();
+ int id = command.getId();
+ IPtpIpCommandCallback callback = command.responseCallback();
+ try
+ {
+ int receive_message_buffer_size = BUFFER_SIZE;
+ byte[] byte_array = new byte[receive_message_buffer_size];
+ InputStream is = socket.getInputStream();
+ if (is == null)
+ {
+ Log.v(TAG, " InputStream is NULL... RECEIVE ABORTED.");
+ return (false);
+ }
+
+ // 初回データが受信バッファにデータが溜まるまで待つ...
+ int read_bytes = waitForReceive(is, delayMs);
+ if (read_bytes < 0)
+ {
+ // リトライオーバー...
+ Log.v(TAG, " RECEIVE : RETRY OVER...");
+ return (true);
+ }
+
+ // 受信したデータをバッファに突っ込む
+ ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
+ while (read_bytes > 0)
+ {
+ read_bytes = is.read(byte_array, 0, receive_message_buffer_size);
+ if (read_bytes <= 0)
+ {
+ Log.v(TAG, " RECEIVED MESSAGE FINISHED (" + read_bytes + ")");
+ break;
+ }
+ byteStream.write(byte_array, 0, read_bytes);
+ sleep(delayMs);
+ read_bytes = is.available();
+ }
+ ByteArrayOutputStream outputStream = cutHeader(byteStream);
+ receivedAllMessage(isDumpReceiveLog, id, outputStream.toByteArray(), callback);
+ System.gc();
+ }
+ catch (Throwable e)
+ {
+ e.printStackTrace();
+ System.gc();
+ }
+ return (false);
+ }
+
+ private void receivedAllMessage(boolean isDumpReceiveLog, int id, byte[] body, IPtpIpCommandCallback callback)
+ {
+ Log.v(TAG, "receivedAllMessage() : " + ((body == null) ? 0 : body.length) + " bytes.");
+ if ((isDumpReceiveLog)&&(body != null))
+ {
+ // ログに受信メッセージを出力する
+ dump_bytes("RECV[" + body.length + "] ", body);
+ }
+ if (callback != null)
+ {
+ callback.receivedMessage(id, body);
+ }
+ }
+
+ private boolean receive_multi(@NonNull IPtpIpCommand command, int delayMs)
+ {
+ int estimatedSize = command.estimatedReceiveDataSize();
+ int id = command.getId();
+ IPtpIpCommandCallback callback = command.responseCallback();
+
+ try
+ {
+ Log.v(TAG, " ===== receive_multi() =====");
+ int receive_message_buffer_size = BUFFER_SIZE;
+ byte[] byte_array = new byte[receive_message_buffer_size];
+ InputStream is = socket.getInputStream();
+ if (is == null)
+ {
+ Log.v(TAG, " InputStream is NULL... RECEIVE ABORTED.");
+ return (false);
+ }
+
+ // 初回データが受信バッファにデータが溜まるまで待つ...
+ int read_bytes = waitForReceive(is, delayMs);
+ if (read_bytes < 0)
+ {
+ // リトライオーバー...
+ Log.v(TAG, " RECEIVE : RETRY OVER......");
+ return (true);
+ }
+
+ // 初回データの読み込み
+ read_bytes = is.read(byte_array, 0, receive_message_buffer_size);
+ int target_length = parseDataLength(byte_array, read_bytes);
+ int received_length = read_bytes;
+
+ // 一時的な処理
+ if (callback != null)
+ {
+ Log.v(TAG, " --- 1st CALL : read_bytes : "+ read_bytes + "(" + received_length + ") : total_length : " + target_length + " buffer SIZE : " + byte_array.length);
+ callback.onReceiveProgress(received_length, target_length, Arrays.copyOfRange(byte_array, 0, received_length));
+ }
+
+ do
+ {
+ sleep(delayMs);
+ read_bytes = is.available();
+ if (read_bytes == 0)
+ {
+ Log.v(TAG, " WAIT is.available() ... " + received_length + " < " + estimatedSize);
+ }
+ } while ((read_bytes == 0)&&(estimatedSize > 0)&&(received_length < estimatedSize));
+ while (read_bytes > 0)
+ {
+ read_bytes = is.read(byte_array, 0, receive_message_buffer_size);
+ if (read_bytes <= 0)
+ {
+ Log.v(TAG, " RECEIVED MESSAGE FINISHED (" + read_bytes + ")");
+ break;
+ }
+ received_length = received_length + read_bytes;
+
+ // 一時的な処理
+ if (callback != null)
+ {
+ //Log.v(TAG, " --- CALL : read_bytes : "+ read_bytes + " total_read : " + received_length + " : total_length : " + target_length + " buffer SIZE : " + byte_array.length);
+ callback.onReceiveProgress(received_length, target_length, Arrays.copyOfRange(byte_array, 0, read_bytes));
+ }
+ //byteStream.write(byte_array, 0, read_bytes);
+
+ do
+ {
+ sleep(delayMs);
+ read_bytes = is.available();
+ //Log.v(TAG, " is.available() read_bytes : " + read_bytes + " " + received_length + " < " + estimatedSize);
+ } while ((read_bytes == 0)&&(estimatedSize > 0)&&(received_length < estimatedSize));
+ }
+ //ByteArrayOutputStream outputStream = cutHeader(byteStream);
+ //receivedMessage(isDumpReceiveLog, id, outputStream.toByteArray(), callback);
+
+ // 終了報告...一時的?
+ if (callback != null)
+ {
+ Log.v(TAG, " --- receive_multi : receivedMessage() : " + id + " (" + read_bytes + ") [" + estimatedSize + "] " + receive_message_buffer_size + " (" + received_length + ")");
+ callback.receivedMessage(id, null);
+ }
+ System.gc();
+ }
+ catch (Throwable e)
+ {
+ e.printStackTrace();
+ System.gc();
+ }
+ return (false);
+ }
+
+ private int parseDataLength(byte[] byte_array, int read_bytes)
+ {
+ int lenlen = 0;
+ int packetType = 0;
+ try
+ {
+ if ((read_bytes > 20)&&((int) byte_array[4] == 0x09))
+ {
+ lenlen = ((((int) byte_array[15]) & 0xff) << 24) + ((((int) byte_array[14]) & 0xff) << 16) + ((((int) byte_array[13]) & 0xff) << 8) + (((int) byte_array[12]) & 0xff);
+ packetType = (((int)byte_array[16]) & 0xff);
+ }
+ Log.v(TAG, " --- parseDataLength() length: " + lenlen + " TYPE: " + packetType + " read_bytes: " + read_bytes);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ return (lenlen);
+ }
+
+ private ByteArrayOutputStream cutHeader(ByteArrayOutputStream receivedBuffer)
+ {
+ try
+ {
+ byte[] byte_array = receivedBuffer.toByteArray();
+ int limit = byte_array.length;
+ int lenlen = 0;
+ 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);
+ int packetType = (((int) byte_array[4]) & 0xff);
+ if ((limit == len)||(limit < 16384))
+ {
+ // 応答は1つしか入っていない。もしくは受信データサイズが16kBの場合は、そのまま返す。
+ return (receivedBuffer);
+ }
+ if (packetType == 0x09)
+ {
+ lenlen = ((((int) byte_array[15]) & 0xff) << 24) + ((((int) byte_array[14]) & 0xff) << 16) + ((((int) byte_array[13]) & 0xff) << 8) + (((int) byte_array[12]) & 0xff);
+ packetType = (((int) byte_array[16]) & 0xff);
+ }
+ Log.v(TAG, " --- RECEIVED MESSAGE : " + len + " bytes (BUFFER: " + byte_array.length + " bytes)" + " length : " + lenlen + " TYPE : " + packetType + " --- ");
+ if (lenlen == 0)
+ {
+ // データとしては変なので、なにもしない
+ return (receivedBuffer);
+ }
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ //outputStream.write(byte_array, 0, 20); //
+ int position = 20; // ヘッダ込の先頭
+ while (position < limit)
+ {
+ 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);
+ packetType = (((int) byte_array[position + 4]) & 0xff);
+ if (packetType != 0x0a)
+ {
+ Log.v(TAG, " <><><> PACKET TYPE : " + packetType + " LENGTH : " + lenlen);
+ }
+ int copyByte = ((lenlen - 12) > (limit - (position + 12))) ? (limit - (position + 12)) : (lenlen - 12);
+ outputStream.write(byte_array, (position + 12), copyByte);
+ position = position + lenlen;
+ }
+ return (outputStream);
+ }
+ catch (Throwable e)
+ {
+ e.printStackTrace();
+ System.gc();
+ }
+ return (receivedBuffer);
+ }
+
+ private int waitForReceive(InputStream is, int delayMs)
+ {
+ int retry_count = 50;
+ int read_bytes = 0;
+ try
+ {
+ while (read_bytes <= 0)
+ {
+ sleep(delayMs);
+ read_bytes = is.available();
+ if (read_bytes == 0)
+ {
+ Log.v(TAG, " is.available() WAIT... ");
+ retry_count--;
+ if (retry_count < 0)
+ {
+ return (-1);
+ }
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ return (read_bytes);
+ }
+}
--- /dev/null
+package net.osdn.gokigen.a01d.camera.ptpip.wrapper.command.messages;
+
+import net.osdn.gokigen.a01d.camera.ptpip.wrapper.command.IPtpIpCommand;
+import net.osdn.gokigen.a01d.camera.ptpip.wrapper.command.IPtpIpCommandCallback;
+import net.osdn.gokigen.a01d.camera.ptpip.wrapper.command.IPtpIpMessages;
+
+public class PtpIpCommandBase implements IPtpIpCommand, IPtpIpMessages
+{
+ @Override
+ public int getId()
+ {
+ return (SEQ_DUMMY);
+ }
+
+ @Override
+ public boolean receiveAgainShortLengthMessage()
+ {
+ return (true);
+ }
+
+ @Override
+ public boolean useSequenceNumber()
+ {
+ return (true);
+ }
+
+ @Override
+ public boolean isIncrementSeqNumber()
+ {
+ return (true);
+ }
+
+ @Override
+ public int receiveDelayMs()
+ {
+ return (15);
+ }
+
+ @Override
+ public int embeddedSequenceNumberIndex()
+ {
+ return (14);
+ }
+
+ @Override
+ public int embeddedSequenceNumberIndex2()
+ {
+ return (8);
+ }
+
+ @Override
+ public int embeddedSequenceNumberIndex3()
+ {
+ return (8);
+ }
+
+ @Override
+ public int estimatedReceiveDataSize()
+ {
+ return (-1);
+ }
+
+ @Override
+ public byte[] commandBody()
+ {
+ return (new byte[12]);
+ }
+
+ @Override
+ public byte[] commandBody2()
+ {
+ return (null);
+ }
+
+ @Override
+ public byte[] commandBody3()
+ {
+ return (null);
+ }
+
+ @Override
+ public IPtpIpCommandCallback responseCallback()
+ {
+ return (null);
+ }
+
+ @Override
+ public int getHoldId()
+ {
+ return (0);
+ }
+
+ @Override
+ public boolean isHold()
+ {
+ return (false);
+ }
+
+ @Override
+ public boolean isRelease()
+ {
+ return (false);
+ }
+
+ @Override
+ public boolean dumpLog()
+ {
+ return (true);
+ }
+}
--- /dev/null
+package net.osdn.gokigen.a01d.camera.ptpip.wrapper.command.messages;
+
+import androidx.annotation.NonNull;
+
+import net.osdn.gokigen.a01d.camera.ptpip.wrapper.command.IPtpIpCommandCallback;
+
+public class PtpIpCommandGeneric extends PtpIpCommandBase
+{
+ private final IPtpIpCommandCallback callback;
+ private final boolean isDumpLog;
+ private final int bodySize;
+ private final int id;
+ private final int holdId;
+ private final int estimatedObjectSize;
+
+ private final int delayMs;
+
+ private final byte opCode0;
+ private final byte opCode1;
+
+ private final byte data0;
+ private final byte data1;
+ private final byte data2;
+ private final byte data3;
+
+ private final byte data4;
+ private final byte data5;
+ private final byte data6;
+ private final byte data7;
+
+ private final byte data8;
+ private final byte data9;
+ private final byte dataA;
+ private final byte dataB;
+
+ private final byte dataC;
+ private final byte dataD;
+ private final byte dataE;
+ private final byte dataF;
+
+ public PtpIpCommandGeneric(@NonNull IPtpIpCommandCallback callback, int id, boolean isDumpLog, int holdId, int opcode)
+ {
+ this.callback = callback;
+ this.bodySize = 0;
+ this.isDumpLog = isDumpLog;
+ this.estimatedObjectSize = -1;
+ this.delayMs = 15;
+
+ this.id = id;
+ this.holdId = holdId;
+ opCode0 = ((byte) (0x000000ff & opcode));
+ opCode1 = ((byte)((0x0000ff00 & opcode) >> 8));
+
+ data0 = 0;
+ data1 = 0;
+ data2 = 0;
+ data3 = 0;
+
+ data4 = 0;
+ data5 = 0;
+ data6 = 0;
+ data7 = 0;
+
+ data8 = 0; // ((byte) (0x000000ff & value3));
+ data9 = 0; // ((byte)((0x0000ff00 & value3) >> 8));
+ dataA = 0; // ((byte)((0x00ff0000 & value3) >> 16));
+ dataB = 0; // ((byte)((0xff000000 & value3) >> 24));
+
+ dataC = 0; // ((byte) (0x000000ff & value4));
+ dataD = 0; // ((byte)((0x0000ff00 & value4) >> 8));
+ dataE = 0; // ((byte)((0x00ff0000 & value4) >> 16));
+ dataF = 0; // ((byte)((0xff000000 & value4) >> 24));
+ }
+
+ public PtpIpCommandGeneric(@NonNull IPtpIpCommandCallback callback, int id, boolean isDumpLog, int holdId, int opcode, int bodySize, int value)
+ {
+ this.callback = callback;
+ this.bodySize = bodySize;
+ this.isDumpLog = isDumpLog;
+ this.estimatedObjectSize = -1;
+ this.delayMs = 15;
+
+ this.id = id;
+ this.holdId = holdId;
+ opCode0 = ((byte) (0x000000ff & opcode));
+ opCode1 = ((byte)((0x0000ff00 & opcode) >> 8));
+
+ data0 = ((byte) (0x000000ff & value));
+ data1 = ((byte)((0x0000ff00 & value) >> 8));
+ data2 = ((byte)((0x00ff0000 & value) >> 16));
+ data3 = ((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));
+ dataA = 0; // ((byte)((0x00ff0000 & value3) >> 16));
+ dataB = 0; // ((byte)((0xff000000 & value3) >> 24));
+
+ dataC = 0; // ((byte) (0x000000ff & value4));
+ dataD = 0; // ((byte)((0x0000ff00 & value4) >> 8));
+ dataE = 0; // ((byte)((0x00ff0000 & value4) >> 16));
+ dataF = 0; // ((byte)((0xff000000 & value4) >> 24));
+ }
+
+ public PtpIpCommandGeneric(@NonNull IPtpIpCommandCallback callback, int id, boolean isDumpLog, int holdId, int opcode, int bodySize, int value, int value2)
+ {
+ this.callback = callback;
+ this.bodySize = bodySize;
+ this.isDumpLog = isDumpLog;
+ this.estimatedObjectSize = -1;
+ this.delayMs = 15;
+
+ this.id = id;
+ this.holdId = holdId;
+ opCode0 = ((byte) (0x000000ff & opcode));
+ opCode1 = ((byte)((0x0000ff00 & opcode) >> 8));
+
+ data0 = ((byte) (0x000000ff & value));
+ data1 = ((byte)((0x0000ff00 & value) >> 8));
+ data2 = ((byte)((0x00ff0000 & value) >> 16));
+ data3 = ((byte)((0xff000000 & value) >> 24));
+
+ data4 = ((byte) (0x000000ff & value2));
+ data5 = ((byte)((0x0000ff00 & value2) >> 8));
+ data6 = ((byte)((0x00ff0000 & value2) >> 16));
+ data7 = ((byte)((0xff000000 & value2) >> 24));
+
+ data8 = 0; // ((byte) (0x000000ff & value3));
+ data9 = 0; // ((byte)((0x0000ff00 & value3) >> 8));
+ dataA = 0; // ((byte)((0x00ff0000 & value3) >> 16));
+ dataB = 0; // ((byte)((0xff000000 & value3) >> 24));
+
+ dataC = 0; // ((byte) (0x000000ff & value4));
+ dataD = 0; // ((byte)((0x0000ff00 & value4) >> 8));
+ dataE = 0; // ((byte)((0x00ff0000 & value4) >> 16));
+ dataF = 0; // ((byte)((0xff000000 & value4) >> 24));
+ }
+
+ public PtpIpCommandGeneric(@NonNull IPtpIpCommandCallback callback, int id, boolean isDumpLog, int holdId, int opcode, int bodySize, int value, int value2, int value3)
+ {
+ this.callback = callback;
+ this.bodySize = bodySize;
+ this.isDumpLog = isDumpLog;
+ this.estimatedObjectSize = -1;
+ this.delayMs = 15;
+
+ this.id = id;
+ this.holdId = holdId;
+ opCode0 = ((byte) (0x000000ff & opcode));
+ opCode1 = ((byte)((0x0000ff00 & opcode) >> 8));
+
+ data0 = ((byte) (0x000000ff & value));
+ data1 = ((byte)((0x0000ff00 & value) >> 8));
+ data2 = ((byte)((0x00ff0000 & value) >> 16));
+ data3 = ((byte)((0xff000000 & value) >> 24));
+
+ data4 = ((byte) (0x000000ff & value2));
+ data5 = ((byte)((0x0000ff00 & value2) >> 8));
+ data6 = ((byte)((0x00ff0000 & value2) >> 16));
+ data7 = ((byte)((0xff000000 & value2) >> 24));
+
+ data8 = ((byte) (0x000000ff & value3));
+ data9 = ((byte)((0x0000ff00 & value3) >> 8));
+ dataA = ((byte)((0x00ff0000 & value3) >> 16));
+ dataB = ((byte)((0xff000000 & value3) >> 24));
+
+ dataC = 0; // ((byte) (0x000000ff & value4));
+ dataD = 0; // ((byte)((0x0000ff00 & value4) >> 8));
+ dataE = 0; // ((byte)((0x00ff0000 & value4) >> 16));
+ dataF = 0; // ((byte)((0xff000000 & value4) >> 24));
+
+ }
+
+ public PtpIpCommandGeneric(@NonNull IPtpIpCommandCallback callback, int id, boolean isDumpLog, int holdId, int opcode, int bodySize, int value, int value2, int value3, int value4)
+ {
+ this.callback = callback;
+ this.bodySize = bodySize;
+ this.isDumpLog = isDumpLog;
+ this.estimatedObjectSize = -1;
+ this.delayMs = 15;
+
+ this.id = id;
+ this.holdId = holdId;
+ opCode0 = ((byte) (0x000000ff & opcode));
+ opCode1 = ((byte)((0x0000ff00 & opcode) >> 8));
+
+ data0 = ((byte) (0x000000ff & value));
+ data1 = ((byte)((0x0000ff00 & value) >> 8));
+ data2 = ((byte)((0x00ff0000 & value) >> 16));
+ data3 = ((byte)((0xff000000 & value) >> 24));
+
+ data4 = ((byte) (0x000000ff & value2));
+ data5 = ((byte)((0x0000ff00 & value2) >> 8));
+ data6 = ((byte)((0x00ff0000 & value2) >> 16));
+ data7 = ((byte)((0xff000000 & value2) >> 24));
+
+ data8 = ((byte) (0x000000ff & value3));
+ data9 = ((byte)((0x0000ff00 & value3) >> 8));
+ dataA = ((byte)((0x00ff0000 & value3) >> 16));
+ dataB = ((byte)((0xff000000 & value3) >> 24));
+
+ dataC = ((byte) (0x000000ff & value4));
+ dataD = ((byte)((0x0000ff00 & value4) >> 8));
+ dataE = ((byte)((0x00ff0000 & value4) >> 16));
+ dataF = ((byte)((0xff000000 & value4) >> 24));
+ }
+
+ public PtpIpCommandGeneric(@NonNull IPtpIpCommandCallback callback, int id, int delayMs, boolean isDumpLog, int holdId, int opcode, int bodySize, int value, int value2, int value3, int value4)
+ {
+ this.callback = callback;
+ this.bodySize = bodySize;
+ this.isDumpLog = isDumpLog;
+ this.estimatedObjectSize = -1;
+ this.delayMs = delayMs;
+
+ this.id = id;
+ this.holdId = holdId;
+ opCode0 = ((byte) (0x000000ff & opcode));
+ opCode1 = ((byte)((0x0000ff00 & opcode) >> 8));
+
+ data0 = ((byte) (0x000000ff & value));
+ data1 = ((byte)((0x0000ff00 & value) >> 8));
+ data2 = ((byte)((0x00ff0000 & value) >> 16));
+ data3 = ((byte)((0xff000000 & value) >> 24));
+
+ data4 = ((byte) (0x000000ff & value2));
+ data5 = ((byte)((0x0000ff00 & value2) >> 8));
+ data6 = ((byte)((0x00ff0000 & value2) >> 16));
+ data7 = ((byte)((0xff000000 & value2) >> 24));
+
+ data8 = ((byte) (0x000000ff & value3));
+ data9 = ((byte)((0x0000ff00 & value3) >> 8));
+ dataA = ((byte)((0x00ff0000 & value3) >> 16));
+ dataB = ((byte)((0xff000000 & value3) >> 24));
+
+ dataC = ((byte) (0x000000ff & value4));
+ dataD = ((byte)((0x0000ff00 & value4) >> 8));
+ dataE = ((byte)((0x00ff0000 & value4) >> 16));
+ dataF = ((byte)((0xff000000 & value4) >> 24));
+ }
+
+ @Override
+ public IPtpIpCommandCallback responseCallback()
+ {
+ return (callback);
+ }
+
+ @Override
+ public int getId()
+ {
+ return (id);
+ }
+
+ @Override
+ public int estimatedReceiveDataSize()
+ {
+ return (estimatedObjectSize);
+ }
+
+ @Override
+ public byte[] commandBody()
+ {
+ if (bodySize == 2)
+ {
+ return (new byte[]{
+
+ // packet type
+ (byte) 0x06, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+
+ // data phase info
+ (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+
+ // operation code
+ opCode0, opCode1,
+
+ // sequence number
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+
+ // data ...
+ data0, data1,
+ });
+ }
+ else if (bodySize == 4)
+ {
+ return (new byte[]{
+
+ // packet type
+ (byte) 0x06, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+
+ // data phase info
+ (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+
+ // operation code
+ opCode0, opCode1,
+
+ // sequence number
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+
+ // data ...
+ data0, data1, data2, data3,
+ });
+ }
+ else if (bodySize == 8)
+ {
+ return (new byte[]{
+
+ // packet type
+ (byte) 0x06, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+
+ // data phase info
+ (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+
+ // operation code
+ opCode0, opCode1,
+
+ // sequence number
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+
+ // data ...
+ data0, data1, data2, data3,
+ data4, data5, data6, data7,
+ });
+ }
+ else if (bodySize == 12)
+ {
+ return (new byte[]{
+
+ // packet type
+ (byte) 0x06, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+
+ // data phase info
+ (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+
+ // operation code
+ opCode0, opCode1,
+
+ // sequence number
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+
+ // data ...
+ data0, data1, data2, data3,
+ data4, data5, data6, data7,
+ data8, data9, dataA, dataB,
+ });
+ }
+ else if (bodySize == 16)
+ {
+ return (new byte[]{
+
+ // packet type
+ (byte) 0x06, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+
+ // data phase info
+ (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+
+ // operation code
+ opCode0, opCode1,
+
+ // sequence number
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+
+ // data ...
+ data0, data1, data2, data3,
+ data4, data5, data6, data7,
+ data8, data9, dataA, dataB,
+ dataC, dataD, dataE, dataF,
+ });
+ }
+ else // ボディ長が 2, 4, 8, 12 以外の場合... (ボディなし)
+ {
+ return (new byte[]{
+
+ // packet type
+ (byte) 0x06, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+
+ // data phase info
+ (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+
+ // operation code
+ opCode0, opCode1,
+
+ // sequence number
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ });
+ }
+ }
+
+ @Override
+ public int receiveDelayMs()
+ {
+ return (delayMs);
+ }
+
+ @Override
+ public int getHoldId()
+ {
+ return (holdId);
+ }
+
+ @Override
+ public boolean dumpLog()
+ {
+ return (isDumpLog);
+ }
+}
--- /dev/null
+package net.osdn.gokigen.a01d.camera.ptpip.wrapper.command.messages;
+
+import androidx.annotation.NonNull;
+
+import net.osdn.gokigen.a01d.camera.ptpip.wrapper.command.IPtpIpCommandCallback;
+
+public class PtpIpReceiveOnly extends PtpIpCommandBase
+{
+ private final IPtpIpCommandCallback callback;
+ private final int id;
+
+ public PtpIpReceiveOnly(int id, @NonNull IPtpIpCommandCallback callback)
+ {
+ this.callback = callback;
+ this.id = id;
+ }
+
+ @Override
+ public IPtpIpCommandCallback responseCallback()
+ {
+ return (callback);
+ }
+
+ @Override
+ public int getId()
+ {
+ return (id);
+ }
+
+ @Override
+ public byte[] commandBody()
+ {
+ return (null);
+ }
+}
--- /dev/null
+package net.osdn.gokigen.a01d.camera.ptpip.wrapper.command.messages.specific;
+
+import androidx.annotation.NonNull;
+
+import net.osdn.gokigen.a01d.camera.ptpip.wrapper.command.IPtpIpCommandCallback;
+import net.osdn.gokigen.a01d.camera.ptpip.wrapper.command.messages.PtpIpCommandBase;
+
+public class StatusRequestMessage extends PtpIpCommandBase
+{
+ private final IPtpIpCommandCallback callback;
+
+ public StatusRequestMessage(@NonNull IPtpIpCommandCallback callback)
+ {
+ this.callback = callback;
+ }
+
+ @Override
+ public IPtpIpCommandCallback responseCallback()
+ {
+ return (callback);
+ }
+
+ @Override
+ public int getId()
+ {
+ return (SEQ_STATUS_REQUEST);
+ }
+
+ @Override
+ public byte[] commandBody()
+ {
+ return (new byte[] {
+
+ // message_header.index : uint16 (0: terminate, 2: two_part_message, 1: other)
+ (byte)0x01, (byte)0x00,
+
+ // message_header.type : single_part (0x1015) : 0xd212 (status_request)
+ (byte)0x15, (byte)0x10,
+
+ // sequence number
+ (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+
+ // data ...
+ (byte)0x12, (byte)0xd2, (byte)0x00, (byte)0x00,
+ });
+ }
+
+ @Override
+ public boolean dumpLog()
+ {
+ return (false);
+ }
+}
--- /dev/null
+package net.osdn.gokigen.a01d.camera.ptpip.wrapper.status;
+
+public interface IPtpIpCameraProperties
+{
+ int BATTERY_LEVEL = 0x5001;
+ int WHITE_BALANCE = 0x5005;
+ int APERTURE = 0x5007;
+ int FOCUS_MODE = 0x500a;
+ int SHOOTING_MODE = 0x500e;
+ int FLASH = 0x500c;
+ int EXPOSURE_COMPENSATION = 0x5010;
+ int SELF_TIMER = 0x5012;
+ int FILM_SIMULATION = 0xd001;
+ int IMAGE_FORMAT = 0xd018;
+ int RECMODE_ENABLE = 0xd019;
+ int F_SS_CONTROL = 0xd028;
+ int ISO = 0xd02a;
+ int MOVIE_ISO = 0xd02b;
+ int FOCUS_POINT = 0xd17c;
+ int FOCUS_LOCK = 0xd209;
+ int DEVICE_ERROR = 0xd21b;
+ int IMAGE_FILE_COUNT = 0xd222;
+ int SDCARD_REMAIN_SIZE = 0xd229;
+ int MOVIE_REMAINING_TIME = 0xd22a;
+ int SHUTTER_SPEED = 0xd240;
+ int IMAGE_ASPECT = 0xd241;
+ int BATTERY_LEVEL_2 = 0xd242;
+ int UNKNOWN_DF00 = 0xdf00;
+ int PICTURE_JPEG_COUNT = 0xd220;
+ int UNKNOWN_D400 = 0xd400;
+ int UNKNOWN_D401 = 0xd401;
+ int UNKNOWN_D52F = 0xd52f;
+
+
+
+ String BATTERY_LEVEL_STR = "Battery";
+ String WHITE_BALANCE_STR = "WhiteBalance";
+ String APERTURE_STR = "Aperture";
+ String FOCUS_MODE_STR = "FocusMode";
+ String SHOOTING_MODE_STR = "ShootingMode";
+ String FLASH_STR = "FlashMode";
+ String EXPOSURE_COMPENSATION_STR = "ExposureCompensation";
+ String SELF_TIMER_STR = "SelfTimer";
+ String FILM_SIMULATION_STR = "FilmSimulation";
+ String IMAGE_FORMAT_STR = "ImageFormat";
+ String RECMODE_ENABLE_STR = "RecModeEnable";
+ String F_SS_CONTROL_STR = "F_SS_Control";
+ String ISO_STR = "Iso";
+ String MOVIE_ISO_STR = "MovieIso";
+ String FOCUS_POINT_STR = "FocusPoint";
+ String FOCUS_LOCK_STR = "FocusLock";
+ String DEVICE_ERROR_STR = "DeviceError";
+ String IMAGE_FILE_COUNT_STR = "ImageFileCount";
+ String SDCARD_REMAIN_SIZE_STR = "ImageRemainCount";
+ String MOVIE_REMAINING_TIME_STR = "MovieRemainTime";
+ String SHUTTER_SPEED_STR = "ShutterSpeed";
+ String IMAGE_ASPECT_STR = "ImageAspect";
+ String BATTERY_LEVEL_2_STR = "BatteryLevel";
+
+ String UNKNOWN_DF00_STR = "0xdf00";
+ String PICTURE_JPEG_COUNT_STR = "PictureCount";
+ String UNKNOWN_D400_STR = "0xd400";
+ String UNKNOWN_D401_STR = "0xd401";
+ String UNKNOWN_D52F_STR = "0xd52f";
+
+
+ String BATTERY_LEVEL_STR_ID = "0x5001";
+ String WHITE_BALANCE_STR_ID = "0x5005";
+ String APERTURE_STR_ID = "0x5007";
+ String FOCUS_MODE_STR_ID = "0x500a";
+ String SHOOTING_MODE_STR_ID = "0x500e";
+ String FLASH_STR_ID = "0x500c";
+ String EXPOSURE_COMPENSATION_STR_ID = "0x5010";
+ String SELF_TIMER_STR_ID = "0x5012";
+ String FILM_SIMULATION_STR_ID = "0xd001";
+ String IMAGE_FORMAT_STR_ID = "0xd018";
+ String RECMODE_ENABLE_STR_ID = "0xd019";
+ String F_SS_CONTROL_STR_ID = "0xd028";
+ String ISO_STR_ID = "0xd02a";
+ String MOVIE_ISO_STR_ID = "0xd02b";
+ String FOCUS_POINT_STR_ID = "0xd17c";
+ String FOCUS_LOCK_STR_ID = "0xd209";
+ String DEVICE_ERROR_STR_ID = "0xd21b";
+ String IMAGE_FILE_COUNT_STR_ID = "0xd222";
+ String SDCARD_REMAIN_SIZE_STR_ID = "0xd229";
+ String MOVIE_REMAINING_TIME_STR_ID = "0xd22a";
+ String SHUTTER_SPEED_STR_ID = "0xd240";
+ String IMAGE_ASPECT_STR_ID = "0xd241";
+ String BATTERY_LEVEL_2_STR_ID = "0xd242";
+
+ String UNKNOWN_DF00_STR_ID = "0xdf00";
+ String PICTURE_JPEG_COUNT_STR_ID = "0xd220";
+ String UNKNOWN_D400_STR_ID = "0xd400";
+ String UNKNOWN_D401_STR_ID = "0xd401";
+ String UNKNOWN_D52F_STR_ID = "0xd52f";
+
+}
--- /dev/null
+package net.osdn.gokigen.a01d.camera.ptpip.wrapper.status;
+
+import net.osdn.gokigen.a01d.camera.ptpip.wrapper.command.IPtpIpCommand;
+import net.osdn.gokigen.a01d.camera.ptpip.wrapper.command.IPtpIpCommandCallback;
+
+public interface IPtpIpInitEventRequest
+{
+ IPtpIpCommand getInitEventRequest(IPtpIpCommandCallback callback, int connectionNumber);
+}
--- /dev/null
+package net.osdn.gokigen.a01d.camera.ptpip.wrapper.status;
+
+public interface IPtpIpRunModeHolder
+{
+ void transitToRecordingMode(boolean isFinished);
+ void transitToPlaybackMode(boolean isFinished);
+}
--- /dev/null
+package net.osdn.gokigen.a01d.camera.ptpip.wrapper.status;
+
+import android.app.Activity;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+
+import net.osdn.gokigen.a01d.camera.ICameraStatus;
+import net.osdn.gokigen.a01d.camera.ICameraStatusWatcher;
+import net.osdn.gokigen.a01d.camera.ptpip.wrapper.command.IPtpIpCommand;
+import net.osdn.gokigen.a01d.camera.ptpip.wrapper.command.IPtpIpCommandCallback;
+import net.osdn.gokigen.a01d.camera.ptpip.wrapper.command.IPtpIpCommandPublisher;
+import net.osdn.gokigen.a01d.camera.ptpip.wrapper.command.IPtpIpMessages;
+import net.osdn.gokigen.a01d.liveview.ICameraStatusUpdateNotify;
+
+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.a01d.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 ICameraStatusUpdateNotify notifier = null;
+ private PtpIpStatusHolder statusHolder;
+ private boolean whileFetching = false;
+ private boolean logcat = false;
+ private final String ipAddress;
+ private final int portNumber;
+ private final IPtpIpInitEventRequest eventRequest;
+
+ private Socket socket = null;
+ private DataOutputStream dos = null;
+ private BufferedReader bufferedReader = null;
+ private int eventConnectionNumber = 0;
+
+ public PtpIpStatusChecker(@NonNull Activity activity, @NonNull IPtpIpCommandPublisher issuer, @NonNull String ip, int portNumber, @NonNull IPtpIpInitEventRequest eventRequest)
+ {
+ this.issuer = issuer;
+ this.statusHolder = new PtpIpStatusHolder();
+ this.ipAddress = ip;
+ this.portNumber = portNumber;
+ this.eventRequest = eventRequest;
+ Log.v(TAG, "POLLING WAIT : " + sleepMs);
+ }
+
+ @Override
+ public void onReceiveProgress(int currentBytes, int totalBytes, byte[] body)
+ {
+ Log.v(TAG, " " + currentBytes + "/" + totalBytes);
+ }
+
+ @Override
+ public boolean isReceiveMulti()
+ {
+ return (false);
+ }
+
+ @Override
+ public void receivedMessage(int id, byte[] data)
+ {
+ 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.)");
+ return;
+ }
+
+ int nofStatus = (data[13] * 256) + data[12];
+ int statusCount = 0;
+ int index = STATUS_MESSAGE_HEADER_SIZE;
+ while ((statusCount < nofStatus)&&(index < data.length))
+ {
+ int dataId = ((((int)data[index + 1]) & 0xff) * 256) + (((int) data[index]) & 0xff);
+ statusHolder.updateValue(notifier, dataId, data[index + 2], data[index + 3], data[index +4], data[index + 5]);
+ index = index + 6;
+ statusCount++;
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public List<String> getStatusList(String key)
+ {
+ try
+ {
+ if (statusHolder == null)
+ {
+ return (new ArrayList<>());
+ }
+ return (statusHolder.getAvailableItemList(key));
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ return (new ArrayList<>());
+ }
+
+ @Override
+ public String getStatus(String key)
+ {
+ try
+ {
+ if (statusHolder == null)
+ {
+ return ("");
+ }
+ return (statusHolder.getItemStatus(key));
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ return ("");
+ }
+
+ @Override
+ public void setStatus(String key, String value)
+ {
+ try
+ {
+ if (logcat)
+ {
+ Log.v(TAG, "setStatus(" + key + ", " + value + ")");
+ }
+
+ // ここで設定を行う。
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void startStatusWatch(@NonNull ICameraStatusUpdateNotify notifier)
+ {
+ if (whileFetching)
+ {
+ Log.v(TAG, "startStatusWatch() already starting.");
+ return;
+ }
+ try
+ {
+ this.notifier = notifier;
+ whileFetching = true;
+
+ // セッションをオープンする
+ boolean isConnect = connect();
+ if (!isConnect)
+ {
+ Log.v(TAG, " CONNECT FAIL...(EVENT) : " + ipAddress + " " + portNumber);
+ }
+ issueCommand(eventRequest.getInitEventRequest(this, eventConnectionNumber));
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void stopStatusWatch()
+ {
+ Log.v(TAG, "stoptStatusWatch()");
+ whileFetching = false;
+ this.notifier = null;
+ }
+
+ private void logcat(String message)
+ {
+ if (logcat)
+ {
+ 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);
+
+ 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.");
+ 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();
+ }
+ }
+
+}
--- /dev/null
+package net.osdn.gokigen.a01d.camera.ptpip.wrapper.status;
+
+import android.util.Log;
+import android.util.SparseIntArray;
+
+import androidx.annotation.NonNull;
+import androidx.collection.SparseArrayCompat;
+
+import net.osdn.gokigen.a01d.liveview.ICameraStatusUpdateNotify;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+
+class PtpIpStatusHolder implements IPtpIpCameraProperties
+{
+ private final String TAG = toString();
+ private SparseIntArray statusHolder;
+ private SparseArrayCompat<String> statusNameArray;
+
+ PtpIpStatusHolder()
+ {
+ statusHolder = new SparseIntArray();
+ statusHolder.clear();
+
+ statusNameArray = new SparseArrayCompat<>();
+ prepareStatusNameArray();
+ }
+
+ private void prepareStatusNameArray()
+ {
+ statusNameArray.clear();
+ statusNameArray.append(BATTERY_LEVEL, BATTERY_LEVEL_STR);
+ statusNameArray.append(WHITE_BALANCE, WHITE_BALANCE_STR);
+ statusNameArray.append(APERTURE, APERTURE_STR);
+ statusNameArray.append(FOCUS_MODE, FOCUS_MODE_STR);
+ statusNameArray.append(SHOOTING_MODE, SHOOTING_MODE_STR);
+ statusNameArray.append(FLASH, FLASH_STR);
+ statusNameArray.append(EXPOSURE_COMPENSATION, EXPOSURE_COMPENSATION_STR);
+ statusNameArray.append(SELF_TIMER, SELF_TIMER_STR);
+ statusNameArray.append(FILM_SIMULATION, FILM_SIMULATION_STR);
+ statusNameArray.append(IMAGE_FORMAT, IMAGE_FORMAT_STR);
+ statusNameArray.append(RECMODE_ENABLE, RECMODE_ENABLE_STR);
+ statusNameArray.append(F_SS_CONTROL, F_SS_CONTROL_STR);
+ statusNameArray.append(ISO, ISO_STR);
+ statusNameArray.append(MOVIE_ISO, MOVIE_ISO_STR);
+ statusNameArray.append(FOCUS_POINT, FOCUS_POINT_STR);
+ statusNameArray.append(DEVICE_ERROR, DEVICE_ERROR_STR);
+ statusNameArray.append(IMAGE_FILE_COUNT, IMAGE_FILE_COUNT_STR);
+ statusNameArray.append(SDCARD_REMAIN_SIZE, SDCARD_REMAIN_SIZE_STR);
+ statusNameArray.append(FOCUS_LOCK, FOCUS_LOCK_STR);
+ statusNameArray.append(MOVIE_REMAINING_TIME, MOVIE_REMAINING_TIME_STR);
+ statusNameArray.append(SHUTTER_SPEED, SHUTTER_SPEED_STR);
+ statusNameArray.append(IMAGE_ASPECT,IMAGE_ASPECT_STR);
+ statusNameArray.append(BATTERY_LEVEL_2, BATTERY_LEVEL_2_STR);
+
+ statusNameArray.append(UNKNOWN_DF00, UNKNOWN_DF00_STR);
+ statusNameArray.append(PICTURE_JPEG_COUNT, PICTURE_JPEG_COUNT_STR);
+ statusNameArray.append(UNKNOWN_D400, UNKNOWN_D400_STR);
+ statusNameArray.append(UNKNOWN_D401, UNKNOWN_D401_STR);
+ statusNameArray.append(UNKNOWN_D52F, UNKNOWN_D52F_STR);
+
+ }
+
+
+ void updateValue(ICameraStatusUpdateNotify notifier, int id, byte data0, byte data1, byte data2, byte data3)
+ {
+ try
+ {
+ int value = ((((int) data3) & 0xff) << 24) + ((((int) data2) & 0xff) << 16) + ((((int) data1) & 0xff) << 8) + (((int) data0) & 0xff);
+ int currentValue = statusHolder.get(id, -1);
+ Log.v(TAG, "STATUS ID: " + id + " value : " + value + " (" + currentValue + ")");
+ statusHolder.put(id, value);
+ if (currentValue != value)
+ {
+ //Log.v(TAG, "STATUS ID: " + id + " value : " + currentValue + " -> " + value);
+ if (notifier != null)
+ {
+ updateDetected(notifier, id, currentValue, value);
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ private void updateDetected(@NonNull ICameraStatusUpdateNotify notifier, int id, int previous, int current)
+ {
+ try
+ {
+ String idName = statusNameArray.get(id, "Unknown");
+ Log.v(TAG, String.format(Locale.US,"<< UPDATE STATUS >> id: 0x%04x[%s] 0x%08x(%d) -> 0x%08x(%d)", id, idName, previous, previous, current, current));
+ //Log.v(TAG, "updateDetected(ID: " + id + " [" + idName + "] " + previous + " -> " + current + " )");
+
+ if (id == FOCUS_LOCK)
+ {
+ if (current == 1)
+ {
+ // focus Lock
+ notifier.updateFocusedStatus(true, true);
+ }
+ else
+ {
+ // focus unlock
+ notifier.updateFocusedStatus(false, false);
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * 認識したカメラのステータス名称のリストを応答する
+ *
+ */
+ private List<String> getAvailableStatusNameList()
+ {
+ ArrayList<String> selection = new ArrayList<>();
+ try
+ {
+ for (int index = 0; index < statusHolder.size(); index++)
+ {
+ int key = statusHolder.keyAt(index);
+ selection.add(statusNameArray.get(key, String.format(Locale.US, "0x%04x", key)));
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ return (selection);
+
+ }
+
+ List<String> getAvailableItemList(String listKey)
+ {
+ if (listKey == null)
+ {
+ // アイテム名の一覧を応答する
+ return (getAvailableStatusNameList());
+ }
+
+ ///// 選択可能なステータスの一覧を取得する : でも以下はアイテム名の一覧... /////
+ ArrayList<String> selection = new ArrayList<>();
+ try
+ {
+ for (int index = 0; index < statusHolder.size(); index++)
+ {
+ int key = statusHolder.keyAt(index);
+ selection.add(statusNameArray.get(key));
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ return (selection);
+ }
+
+ String getItemStatus(String key)
+ {
+ try
+ {
+ int strIndex = key.indexOf("x");
+ Log.v(TAG, "getItemStatus() : " + key + " [" + strIndex + "]");
+ if (strIndex >= 1)
+ {
+ key = key.substring(strIndex + 1);
+ try
+ {
+ int id = Integer.parseInt(key, 16);
+ int value = statusHolder.get(id);
+ Log.v(TAG, "getItemStatus() value : " + value);
+ return (value + "");
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ for (int index = 0; index < statusNameArray.size(); index++)
+ {
+ int id = statusNameArray.keyAt(index);
+ String strKey = statusNameArray.valueAt(index);
+ if (key.contentEquals(strKey))
+ {
+ int value = statusHolder.get(id);
+ return (value + "");
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ return ("? [" + key + "]");
+ }
+}
<string name="dialog_title_connect_failed_sony">接続失敗(SONY)</string>
<string name="dialog_title_connect_failed_fuji">接続失敗(FUJI)</string>
<string name="dialog_title_connect_failed_theta">接続失敗(THETA)</string>
+ <string name="dialog_title_connect_failed_nikon">接続失敗(NIKON)</string>
+ <string name="dialog_title_connect_failed_canon">接続失敗(CANON)</string>
<string name="fatal_cannot_use_camera">Olympus Camera Kitが動作しないモードのため、カメラのリセットが必要です。電源ボタンを8秒以上長押しして、カメラをリセットしてください。</string>
<string name="network_connection_timeout">接続タイムアウト</string>
<string name="restored_my_props">設定を展開しました。 : </string>
<string name="connect_connecting12">接続中…(12/12)</string>
<string name="connect_connect_finished">カメラと接続</string>
+ <string name="connect_start_2">準備中…</string>
+ <string name="canon_connect_connecting1">接続中…(1/5)</string>
+ <string name="canon_connect_connecting2">接続中…(2/5)</string>
+ <string name="canon_connect_connecting3">接続中…(3/5)</string>
+ <string name="canon_connect_connecting4">接続中…(4/5)</string>
+ <string name="canon_connect_connecting5">接続中…(5/5)</string>
+
+ <string name="connect_error_message">接続失敗</string>
+
<string name="connect_error_message_olympus">接続失敗 (OLYMPUS)</string>
<string name="connect_error_message_fuji">接続失敗 (FUJI)</string>
<string name="dialog_title_connect_failed_sony">Connect failed (SONY)</string>
<string name="dialog_title_connect_failed_fuji">Connect failed (FUJI)</string>
<string name="dialog_title_connect_failed_theta">Connect failed (THETA)</string>
+ <string name="dialog_title_connect_failed_nikon">Connect failed (NIKON)</string>
+ <string name="dialog_title_connect_failed_canon">Connect failed (CANON)</string>
<string name="dialog_title_button_retry">Retry</string>
<string name="dialog_title_button_network_settings">WiFi Settings</string>
<string name="connect_connecting12">Connecting…(12/12)</string>
<string name="connect_connect_finished">Connect Finished.</string>
+ <string name="connect_start_2">Preparing…</string>
+ <string name="canon_connect_connecting1">Connecting…(1/5)</string>
+ <string name="canon_connect_connecting2">Connecting…(2/5)</string>
+ <string name="canon_connect_connecting3">Connecting…(3/5)</string>
+ <string name="canon_connect_connecting4">Connecting…(4/5)</string>
+ <string name="canon_connect_connecting5">Connecting…(5/5)</string>
+
+ <string name="connect_error_message">CONNECTION ERROR</string>
+
<string name="connect_error_message_olympus">CONNECTION ERROR (OLYMPUS)</string>
<string name="connect_error_message_fuji">CONNECTION ERROR (FUJI)</string>