Skip to content

Commit

Permalink
handle when the node is already in short/fast
Browse files Browse the repository at this point in the history
  • Loading branch information
niccellular committed Jun 5, 2024
1 parent 3af3c45 commit 1cd9b8a
Show file tree
Hide file tree
Showing 3 changed files with 199 additions and 105 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,91 +33,128 @@ public void onMissionPackageTaskComplete(MissionPackageBaseTask missionPackageBa
File file = new File(missionPackageManifest.getPath());
Log.d(TAG, file.getAbsolutePath());

SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(MapView.getMapView().getContext());
SharedPreferences.Editor editor = prefs.edit();

if (FileSystemUtils.isFile(file)) {
// check file size
if (FileSystemUtils.getFileSize(file) > 1024 * 56) {
Toast.makeText(MapView.getMapView().getContext(), "File is too large to send, 56KB Max", Toast.LENGTH_LONG).show();
return;
} else {
Log.d(TAG, "File is small enough to send: " + FileSystemUtils.getFileSize(file));
Toast.makeText(MapView.getMapView().getContext(), "Switching to Short/Fast for file transfer", Toast.LENGTH_LONG).show();
Log.d(TAG, "Broadcasting switch command");
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(MapView.getMapView().getContext());
SharedPreferences.Editor editor = prefs.edit();

// flag to indicate we are in a file transfer mode
editor.putBoolean("plugin_meshtastic_file_transfer", true);
editor.putBoolean("plugin_meshtastic_switch_ACK", true);
int channel = prefs.getInt("plugin_meshtastic_channel", 0);
int messageId = ThreadLocalRandom.current().nextInt(0x10000000, 0x7fffff00);
Log.d(TAG, "Message ID: " + messageId);
editor.putInt("plugin_meshtastic_message_id", messageId);
editor.apply();

DataPacket dp = new DataPacket(DataPacket.ID_BROADCAST, new byte[]{'S', 'W', 'T'}, Portnums.PortNum.ATAK_FORWARDER_VALUE, DataPacket.ID_LOCAL, System.currentTimeMillis(), messageId, MessageStatus.UNKNOWN, 3, channel);
MeshtasticMapComponent.sendToMesh(dp);
// capture node's config
byte[] config = MeshtasticMapComponent.getConfig();
Log.d(TAG, "Config Size: " + config.length);
LocalOnlyProtos.LocalConfig c;
try {
c = LocalOnlyProtos.LocalConfig.parseFrom(config);
} catch (InvalidProtocolBufferException e) {
throw new RuntimeException(e);
}
Log.d(TAG, "Config: " + c.toString());
ConfigProtos.Config.LoRaConfig lc = c.getLora();

// retain old modem preset
int oldModemPreset = lc.getModemPreset().getNumber();

// configure short/fast mode
ConfigProtos.Config.Builder configBuilder = ConfigProtos.Config.newBuilder();
AtomicReference<ConfigProtos.Config.LoRaConfig.Builder> loRaConfigBuilder = new AtomicReference<>(lc.toBuilder());
AtomicReference<ConfigProtos.Config.LoRaConfig.ModemPreset> modemPreset = new AtomicReference<>(ConfigProtos.Config.LoRaConfig.ModemPreset.forNumber(ConfigProtos.Config.LoRaConfig.ModemPreset.SHORT_FAST_VALUE));
loRaConfigBuilder.get().setModemPreset(modemPreset.get());
configBuilder.setLora(loRaConfigBuilder.get());
boolean needReboot;

// if not already in short/fast mode, switch to it
if (oldModemPreset != ConfigProtos.Config.LoRaConfig.ModemPreset.SHORT_FAST_VALUE) {
Toast.makeText(MapView.getMapView().getContext(), "Rebooting to Short/Fast for file transfer", Toast.LENGTH_LONG).show();
needReboot = true;
} else {
needReboot = false;
}

new Thread(() -> {
try {
while (prefs.getBoolean("plugin_meshtastic_switch_ACK", false)) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}

// give the remote node time to reboot
Thread.sleep(2000);
// send out file transfer command
int channel = prefs.getInt("plugin_meshtastic_channel", 0);
int messageId = ThreadLocalRandom.current().nextInt(0x10000000, 0x7fffff00);
Log.d(TAG, "Switch Message ID: " + messageId);
editor.putInt("plugin_meshtastic_switch_id", messageId);

// flag to indicate we are waiting for remote nodes to ACK our SWT command
editor.putBoolean("plugin_meshtastic_switch_ACK", true);
editor.apply();

//capture local config
byte[] config = MeshtasticMapComponent.getConfig();
Log.d(TAG, "Config Size: " + config.length);
LocalOnlyProtos.LocalConfig c = LocalOnlyProtos.LocalConfig.parseFrom(config);
Log.d(TAG, "Config: " + c.toString());
ConfigProtos.Config.LoRaConfig lc = c.getLora();
Log.d(TAG, "Broadcasting switch command");
DataPacket dp = new DataPacket(DataPacket.ID_BROADCAST, new byte[]{'S', 'W', 'T'}, Portnums.PortNum.ATAK_FORWARDER_VALUE, DataPacket.ID_LOCAL, System.currentTimeMillis(), messageId, MessageStatus.UNKNOWN, 3, channel);
MeshtasticMapComponent.sendToMesh(dp);

int oldModemPreset = lc.getModemPreset().getNumber();
// wait for the remote nodes to ACK our switch command
while (prefs.getBoolean("plugin_meshtastic_switch_ACK", false)) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}

// set short/fast for file transfer
ConfigProtos.Config.Builder configBuilder = ConfigProtos.Config.newBuilder();
AtomicReference<ConfigProtos.Config.LoRaConfig.Builder> loRaConfigBuilder = new AtomicReference<>(lc.toBuilder());
AtomicReference<ConfigProtos.Config.LoRaConfig.ModemPreset> modemPreset = new AtomicReference<>(ConfigProtos.Config.LoRaConfig.ModemPreset.forNumber(ConfigProtos.Config.LoRaConfig.ModemPreset.SHORT_FAST_VALUE));
loRaConfigBuilder.get().setModemPreset(modemPreset.get());
configBuilder.setLora(loRaConfigBuilder.get());
MeshtasticMapComponent.setConfig(configBuilder.build().toByteArray());
// we gotta reboot to short/fast
if (needReboot) {
// give the remote nodes a little extra time to reboot
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}

editor.putBoolean("plugin_meshtastic_shortfast", true);
editor.apply();
try {
// flag to indicate we are waiting for a reboot into short/fast
editor.putBoolean("plugin_meshtastic_shortfast", true);
editor.apply();

// wait for ourselves to switch to short/fast
while(prefs.getBoolean("plugin_meshtastic_shortfast", false))
Thread.sleep(1000);
MeshtasticMapComponent.setConfig(configBuilder.build().toByteArray());

// the device has rebooted, send the file
// wait for ourselves to switch to short/fast
while (prefs.getBoolean("plugin_meshtastic_shortfast", false))
Thread.sleep(1000);

} catch (InterruptedException e) {
e.printStackTrace();
}
}

try {
// ready to send file
if (MeshtasticMapComponent.sendFile(file)) {
Log.d(TAG, "File sent successfully");

// wait for at least one ACK from a recipient
while(prefs.getBoolean("plugin_meshtastic_file_transfer", false))
Thread.sleep(1000);
while (prefs.getBoolean("plugin_meshtastic_file_transfer", false))
Thread.sleep(1000);
} else {
Log.d(TAG, "File send failed");
}

// restore config
Log.d(TAG, "Restoring previous modem preset");
loRaConfigBuilder.set(lc.toBuilder());
modemPreset.set(ConfigProtos.Config.LoRaConfig.ModemPreset.forNumber(oldModemPreset));
loRaConfigBuilder.get().setModemPreset(modemPreset.get());
configBuilder.setLora(loRaConfigBuilder.get());
MeshtasticMapComponent.setConfig(configBuilder.build().toByteArray());
if (needReboot) {
// restore config
Log.d(TAG, "Restoring previous modem preset");
loRaConfigBuilder.set(lc.toBuilder());
modemPreset.set(ConfigProtos.Config.LoRaConfig.ModemPreset.forNumber(oldModemPreset));
loRaConfigBuilder.get().setModemPreset(modemPreset.get());
configBuilder.setLora(loRaConfigBuilder.get());
MeshtasticMapComponent.setConfig(configBuilder.build().toByteArray());
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (InvalidProtocolBufferException e) {
e.printStackTrace();
}
}).start();

}

} else {
Log.d(TAG, "Invalid file");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.ThreadLocalRandom;
Expand Down Expand Up @@ -110,7 +111,7 @@ public enum ServiceConnectionState {
private static NotificationManager mNotifyManager;
private static NotificationCompat.Builder mBuilder;
private static NotificationChannel mChannel;
private static int id = 42069;
private static int NotificationId = 42069;

public static void sendToMesh(DataPacket dp) {
try {
Expand Down Expand Up @@ -159,6 +160,8 @@ public static boolean sendFile(File f) {
byte[] chunk_hdr = String.format(Locale.US, "CHK_%d_", fileBytes.length).getBytes();
int i = 0;

HashMap<String, byte[]> chunkMap = new HashMap<>();
OUTER:
for (byte[] c : chunkList) {
byte[] combined = new byte[chunk_hdr.length + c.length];
try {
Expand All @@ -173,19 +176,34 @@ public static boolean sendFile(File f) {
DataPacket dp;
i = ThreadLocalRandom.current().nextInt(0x10000000, 0x7fffff00);
Log.d(TAG, "Chunk ID: " + i);
chunkMap.put(String.valueOf(i), combined);
SharedPreferences.Editor editor = prefs.edit();
editor.putInt("plugin_meshtastic_chunk_id", i);
editor.putBoolean("plugin_meshtastic_chunk_ACK", true);
editor.apply();
String nodeID = "";
String id = "";
INNER:
for (int j=0; j<1; j++) {
dp = new DataPacket(DataPacket.ID_BROADCAST, combined, Portnums.PortNum.ATAK_FORWARDER_VALUE, DataPacket.ID_LOCAL, System.currentTimeMillis(), i, MessageStatus.UNKNOWN, 3, prefs.getInt("meshtastic_channel", 0));
if (nodeID.isEmpty()) {
// no errors yet
dp = new DataPacket(DataPacket.ID_BROADCAST, combined, Portnums.PortNum.ATAK_FORWARDER_VALUE, DataPacket.ID_LOCAL, System.currentTimeMillis(), i, MessageStatus.UNKNOWN, 3, prefs.getInt("meshtastic_channel", 0));
} else {
// nodeID had an error, retransmit
dp = new DataPacket(nodeID, chunkMap.get(Integer.valueOf(id)), Portnums.PortNum.ATAK_FORWARDER_VALUE, DataPacket.ID_LOCAL, System.currentTimeMillis(), i, MessageStatus.UNKNOWN, 3, prefs.getInt("meshtastic_channel", 0));
nodeID = "";
editor.putString("plugin_meshtastic_node_ERR", nodeID);
}
mMeshService.send(dp);
while (prefs.getBoolean("plugin_meshtastic_chunk_ACK", false)) {
try {
Thread.sleep(500);
if (prefs.getBoolean("plugin_meshtastic_chunk_ERR", false)) {
Log.d(TAG, "Chunk ERR received, retransmitting:" + i);
/*
nodeID = prefs.getString("plugin_meshtastic_node_ERR", "").split(",")[0];
id = prefs.getString("plugin_meshtastic_node_ERR", "").split(",")[1];
Log.d(TAG, "Chunk ERR received, retransmitting:" + i + " to node: " + nodeID);
*/
j=0;
break INNER;
}
Expand All @@ -198,7 +216,7 @@ public static boolean sendFile(File f) {
// caclulate progress
//zi = (xi – min(x)) / (max(x) – min(x)) * 100
mBuilder.setProgress(100, (int) Math.floor((++progress - 1) / (chunkList.size() - 1) * 100), false);
mNotifyManager.notify(id, mBuilder.build());
mNotifyManager.notify(NotificationId, mBuilder.build());
} catch (RemoteException e) {
e.printStackTrace();
return false;
Expand All @@ -208,7 +226,7 @@ public static boolean sendFile(File f) {
mBuilder.setContentText("Transfer complete")
// Removes the progress bar
.setProgress(0,0,false);
mNotifyManager.notify(id, mBuilder.build());
mNotifyManager.notify(NotificationId, mBuilder.build());

try {
// We're done chunking
Expand Down
Loading

0 comments on commit 1cd9b8a

Please sign in to comment.