package org.droidplanner.services.android.impl.core.drone.autopilot.apm.solo;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.RemoteException;
import android.text.TextUtils;
import android.util.Pair;
import android.util.SparseArray;
import com.o3dr.android.client.BuildConfig;
import com.o3dr.services.android.lib.drone.attribute.AttributeEvent;
import com.o3dr.services.android.lib.drone.attribute.error.CommandExecutionError;
import com.o3dr.services.android.lib.drone.companion.solo.SoloEventExtras;
import com.o3dr.services.android.lib.drone.companion.solo.SoloEvents;
import com.o3dr.services.android.lib.drone.companion.solo.button.ButtonPacket;
import com.o3dr.services.android.lib.drone.companion.solo.button.ButtonTypes;
import com.o3dr.services.android.lib.drone.companion.solo.controller.SoloControllerMode;
import com.o3dr.services.android.lib.drone.companion.solo.controller.SoloControllerUnits;
import com.o3dr.services.android.lib.drone.companion.solo.tlv.SoloButtonSetting;
import com.o3dr.services.android.lib.drone.companion.solo.tlv.SoloButtonSettingSetter;
import com.o3dr.services.android.lib.drone.companion.solo.tlv.SoloGoproState;
import com.o3dr.services.android.lib.drone.companion.solo.tlv.SoloGoproStateV2;
import com.o3dr.services.android.lib.drone.companion.solo.tlv.SoloMessageLocation;
import com.o3dr.services.android.lib.drone.companion.solo.tlv.TLVMessageTypes;
import com.o3dr.services.android.lib.drone.companion.solo.tlv.TLVPacket;
import com.o3dr.services.android.lib.model.ICommandListener;
import org.droidplanner.services.android.impl.communication.model.DataLink;
import org.droidplanner.services.android.impl.core.drone.autopilot.apm.solo.controller.ControllerLinkListener;
import org.droidplanner.services.android.impl.core.drone.autopilot.apm.solo.controller.ControllerLinkManager;
import org.droidplanner.services.android.impl.core.drone.autopilot.apm.solo.sololink.SoloLinkListener;
import org.droidplanner.services.android.impl.core.drone.autopilot.apm.solo.sololink.SoloLinkManager;
import org.droidplanner.services.android.impl.utils.NetworkUtils;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import timber.log.Timber;
/**
* Sololink companion computer implementation
* Created by Fredia Huya-Kouadio on 7/9/15.
*/
public class SoloComp implements SoloLinkListener, ControllerLinkListener {
public interface SoloCompListener {
void onConnected();
void onDisconnected();
void onTlvPacketReceived(TLVPacket packet);
void onPresetButtonLoaded(int buttonType, SoloButtonSetting buttonSettings);
void onWifiInfoUpdated(String wifiName, String wifiPassword);
void onButtonPacketReceived(ButtonPacket packet);
void onTxPowerComplianceCountryUpdated(String compliantCountry);
void onVersionsUpdated();
void onControllerEvent(String event, Bundle eventInfo);
}
public static final String SOLO_LINK_WIFI_PREFIX = "SoloLink_";
public static final String SSH_USERNAME = "root";
public static final String SSH_PASSWORD = "TjSDBkAu";
private final ControllerLinkManager controllerLinkManager;
private final SoloLinkManager soloLinkMgr;
private final Context context;
private final Handler handler;
private final ExecutorService asyncExecutor;
private SoloCompListener compListener;
private SoloGoproState goproState;
private SoloGoproStateV2 goproStateV2;
/**
* Solo companion computer implementation
*
* @param context Application context
*/
public SoloComp(Context context, Handler handler, DataLink.DataLinkProvider mavClient) {
this.context = context;
this.handler = handler;
asyncExecutor = Executors.newCachedThreadPool();
this.controllerLinkManager = new ControllerLinkManager(context, handler, asyncExecutor, mavClient);
this.soloLinkMgr = new SoloLinkManager(context, handler, asyncExecutor, mavClient);
}
public SoloGoproState getGoproState() {
return goproState;
}
public SoloGoproStateV2 getGoproStateV2(){
return goproStateV2;
}
public boolean hasStreamingPermission(){
if(BuildConfig.SITL_DEBUG)
return true;
return controllerLinkManager.hasStreamingPermission();
}
public void setListener(SoloCompListener listener) {
this.compListener = listener;
}
public static boolean isAvailable(Context context) {
return NetworkUtils.isOnSololinkNetwork(context);
}
public void start() {
if (!isAvailable(context)) {
return;
}
if(!BuildConfig.SITL_DEBUG) {
controllerLinkManager.start(this);
}
soloLinkMgr.start(this);
}
public void stop() {
soloLinkMgr.stop();
if(!BuildConfig.SITL_DEBUG) {
controllerLinkManager.stop();
}
}
public void refreshState() {
soloLinkMgr.refreshState();
if(!BuildConfig.SITL_DEBUG)
controllerLinkManager.refreshState();
}
/**
* Terminates and releases resources used by this companion computer instance. The instance should no longer be used after calling this method.
*/
public void destroy() {
stop();
asyncExecutor.shutdownNow();
}
@Override
public void onTlvPacketReceived(TLVPacket packet) {
if (packet == null)
return;
switch (packet.getMessageType()) {
case TLVMessageTypes.TYPE_SOLO_GOPRO_STATE:
goproState = (SoloGoproState) packet;
Timber.d("Updated gopro state.");
break;
case TLVMessageTypes.TYPE_SOLO_GOPRO_STATE_V2:
goproStateV2 = (SoloGoproStateV2) packet;
Timber.i("Updated gopro state.");
break;
}
if (compListener != null)
compListener.onTlvPacketReceived(packet);
}
@Override
public void onWifiInfoUpdated(String wifiName, String wifiPassword) {
if (compListener != null)
compListener.onWifiInfoUpdated(wifiName, wifiPassword);
}
@Override
public void onButtonPacketReceived(ButtonPacket packet) {
if (compListener != null)
compListener.onButtonPacketReceived(packet);
}
@Override
public void onTxPowerComplianceCountryUpdated(String compliantCountry) {
if (compListener != null)
compListener.onTxPowerComplianceCountryUpdated(compliantCountry);
}
@Override
public void onControllerModeUpdated() {
if (compListener != null) {
final Bundle eventInfo = new Bundle();
eventInfo.putInt(SoloEventExtras.EXTRA_SOLO_CONTROLLER_MODE, getControllerMode());
compListener.onControllerEvent(SoloEvents.SOLO_CONTROLLER_MODE_UPDATED, eventInfo);
}
}
@Override
public void onControllerUnitUpdated(String trimmedResponse) {
if (compListener != null) {
final Bundle eventInfo = new Bundle();
eventInfo.putString(SoloEventExtras.EXTRA_SOLO_CONTROLLER_UNIT, trimmedResponse);
compListener.onControllerEvent(SoloEvents.SOLO_CONTROLLER_UNIT_UPDATED, eventInfo);
}
}
@Override
public void onPresetButtonLoaded(int buttonType, SoloButtonSetting buttonSettings) {
if (compListener != null)
compListener.onPresetButtonLoaded(buttonType, buttonSettings);
}
@Override
public void onLinkConnected() {
if (isConnected()) {
if (compListener != null)
compListener.onConnected();
} else {
if (!controllerLinkManager.isLinkConnected() && !BuildConfig.SITL_DEBUG)
controllerLinkManager.start(this);
if (!soloLinkMgr.isLinkConnected())
soloLinkMgr.start(this);
}
}
@Override
public void onLinkDisconnected() {
if (compListener != null)
compListener.onDisconnected();
soloLinkMgr.stop();
if(!BuildConfig.SITL_DEBUG) {
controllerLinkManager.stop();
}
}
@Override
public void onVersionsUpdated() {
if (compListener != null)
compListener.onVersionsUpdated();
}
@Override
public void onMacAddressUpdated() {
final String soloMacAddress = soloLinkMgr.getMacAddress();
final String artooMacAddress = controllerLinkManager.getMacAddress();
if (!TextUtils.isEmpty(soloMacAddress) && !TextUtils.isEmpty(artooMacAddress) && compListener != null) {
compListener.onControllerEvent(AttributeEvent.STATE_VEHICLE_UID, null);
}
}
public boolean isConnected() {
if(BuildConfig.SITL_DEBUG)
return soloLinkMgr.isLinkConnected();
return controllerLinkManager.isLinkConnected() && soloLinkMgr.isLinkConnected();
}
public Pair<String, String> getWifiSettings() {
return controllerLinkManager.getSoloLinkWifiInfo();
}
public String getTxPowerCompliantCountry() {
return controllerLinkManager.getTxPowerCompliantCountry();
}
public void refreshSoloVersions() {
soloLinkMgr.refreshSoloLinkVersions();
if(!BuildConfig.SITL_DEBUG)
controllerLinkManager.refreshControllerVersions();
}
public String getControllerVersion() {
return controllerLinkManager.getArtooVersion();
}
public String getControllerFirmwareVersion() {
return controllerLinkManager.getStm32Version();
}
public String getVehicleVersion() {
return soloLinkMgr.getVehicleVersion();
}
@SoloControllerMode.ControllerMode
public int getControllerMode() {
return controllerLinkManager.getControllerMode();
}
@SoloControllerUnits.ControllerUnit
public String getControllerUnit() {
return controllerLinkManager.getControllerUnit();
}
public String getSoloMacAddress() {
return soloLinkMgr.getMacAddress();
}
public String getControllerMacAddress() {
return controllerLinkManager.getMacAddress();
}
public String getAutopilotVersion() {
return soloLinkMgr.getPixhawkVersion();
}
public String getGimbalVersion() {
return soloLinkMgr.getGimbalVersion();
}
public SoloButtonSetting getButtonSetting(int buttonType) {
return soloLinkMgr.getLoadedPresetButton(buttonType);
}
public SparseArray<SoloButtonSetting> getButtonSettings() {
final SparseArray<SoloButtonSetting> buttonSettings = new SparseArray<>(2);
buttonSettings.append(ButtonTypes.BUTTON_A, soloLinkMgr.getLoadedPresetButton(ButtonTypes.BUTTON_A));
buttonSettings.append(ButtonTypes.BUTTON_B, soloLinkMgr.getLoadedPresetButton(ButtonTypes.BUTTON_B));
return buttonSettings;
}
public void sendSoloLinkMessage(TLVPacket message, ICommandListener listener) {
soloLinkMgr.sendTLVPacket(message, listener);
}
public void updateWifiSettings(final String wifiSsid, final String wifiPassword,
final ICommandListener listener) {
postAsyncTask(new Runnable() {
@Override
public void run() {
if (soloLinkMgr.updateSololinkWifi(wifiSsid, wifiPassword)
&& controllerLinkManager.updateSololinkWifi(wifiSsid, wifiPassword)) {
Timber.d("Sololink wifi update successful.");
if (listener != null) {
postSuccessEvent(listener);
}
} else {
Timber.d("Sololink wifi update failed.");
if (listener != null) {
postErrorEvent(CommandExecutionError.COMMAND_FAILED, listener);
}
}
}
});
}
public void pushButtonSettings(SoloButtonSettingSetter buttonSettings, ICommandListener listener) {
soloLinkMgr.pushPresetButtonSettings(buttonSettings, listener);
}
public void updateControllerMode(@SoloControllerMode.ControllerMode final int selectedMode, ICommandListener listener) {
controllerLinkManager.updateControllerMode(selectedMode, listener);
}
public void updateControllerUnit(@SoloControllerUnits.ControllerUnit final String selectedUnit, ICommandListener listener) {
controllerLinkManager.updateControllerUnit(selectedUnit, listener);
}
public void updateTxPowerComplianceCountry(String compliantCountry, ICommandListener listener) {
controllerLinkManager.setTxPowerComplianceCountry(compliantCountry, listener);
}
protected void postAsyncTask(Runnable task) {
if (asyncExecutor != null && !asyncExecutor.isShutdown()) {
asyncExecutor.execute(task);
}
}
protected void postSuccessEvent(final ICommandListener listener) {
if (handler != null && listener != null) {
handler.post(new Runnable() {
@Override
public void run() {
try {
listener.onSuccess();
} catch (RemoteException e) {
Timber.e(e, e.getMessage());
}
}
});
}
}
protected void postTimeoutEvent(final ICommandListener listener) {
if (handler != null && listener != null) {
handler.post(new Runnable() {
@Override
public void run() {
try {
listener.onTimeout();
} catch (RemoteException e) {
Timber.e(e, e.getMessage());
}
}
});
}
}
protected void postErrorEvent(final int error, final ICommandListener listener) {
if (handler != null && listener != null) {
handler.post(new Runnable() {
@Override
public void run() {
try {
listener.onError(error);
} catch (RemoteException e) {
Timber.e(e, e.getMessage());
}
}
});
}
}
public void enableFollowDataConnection() {
soloLinkMgr.enableFollowDataConnection();
}
public void disableFollowDataConnection() {
soloLinkMgr.disableFollowDataConnection();
}
public void updateFollowCenter(SoloMessageLocation location) {
soloLinkMgr.sendTLVPacket(location, true, null);
}
}