19
19
import android .os .RemoteException ;
20
20
import android .preference .PreferenceManager ;
21
21
import android .widget .Toast ;
22
- import android .app .NotificationChannel ;
23
22
24
23
import androidx .core .app .NotificationCompat ;
25
24
29
28
import com .atakmap .android .ipc .AtakBroadcast ;
30
29
import com .atakmap .android .maps .MapView ;
31
30
import com .atakmap .android .meshtastic .plugin .R ;
32
- import com .atakmap .android .util .NotificationUtil ;
33
31
import com .atakmap .app .preferences .ToolsPreferenceFragment ;
34
32
import com .atakmap .comms .CotServiceRemote ;
35
33
import com .atakmap .coremap .filesystem .FileSystemUtils ;
49
47
import com .geeksville .mesh .IMeshService ;
50
48
51
49
import com .google .protobuf .ByteString ;
52
- import com .paulmandal .atak .libcotshrink .pub .api .CotShrinker ;
53
- import com .paulmandal .atak .libcotshrink .pub .api .CotShrinkerFactory ;
50
+ import com .siemens .ct .exi .core .EXIFactory ;
51
+ import com .siemens .ct .exi .core .helpers .DefaultEXIFactory ;
52
+ import com .siemens .ct .exi .main .api .sax .EXIResult ;
54
53
54
+ import org .xml .sax .InputSource ;
55
+ import org .xml .sax .XMLReader ;
55
56
import org .xmlpull .v1 .XmlPullParser ;
56
57
import org .xmlpull .v1 .XmlPullParserException ;
57
58
import org .xmlpull .v1 .XmlPullParserFactory ;
58
59
60
+ import java .io .ByteArrayOutputStream ;
59
61
import java .io .File ;
60
62
import java .io .IOException ;
61
63
import java .io .StringReader ;
65
67
import java .util .HashMap ;
66
68
import java .util .List ;
67
69
import java .util .Locale ;
68
- import java .util .concurrent .ThreadLocalRandom ;
70
+ import java .util .concurrent .atomic .AtomicInteger ;
71
+
72
+ import javax .xml .parsers .SAXParser ;
73
+ import javax .xml .parsers .SAXParserFactory ;
69
74
70
75
71
76
public class MeshtasticMapComponent extends DropDownMapComponent
@@ -74,9 +79,6 @@ public class MeshtasticMapComponent extends DropDownMapComponent
74
79
CotServiceRemote .ConnectionListener {
75
80
private static final String TAG = "MeshtasticMapComponent" ;
76
81
private Context pluginContext ;
77
- public static CotShrinkerFactory cotShrinkerFactory = new CotShrinkerFactory ();
78
- public static CotShrinker cotShrinker = cotShrinkerFactory .createCotShrinker ();
79
-
80
82
@ Override
81
83
public void onCotServiceConnected (Bundle bundle ) {
82
84
@@ -189,7 +191,7 @@ public static boolean sendFile(File f) {
189
191
try {
190
192
// send out 1 chunk
191
193
DataPacket dp ;
192
- i = ThreadLocalRandom . current (). nextInt ( 0x10000000 , 0x7fffff00 );
194
+ i = mMeshService . getPacketId ( );
193
195
Log .d (TAG , "Chunk ID: " + i );
194
196
chunkMap .put (String .valueOf (i ), combined );
195
197
editor .putInt ("plugin_meshtastic_chunk_id" , i );
@@ -202,7 +204,7 @@ public static boolean sendFile(File f) {
202
204
mMeshService .send (dp );
203
205
while (prefs .getBoolean ("plugin_meshtastic_chunk_ACK" , false )) {
204
206
try {
205
- Thread .sleep (500 );
207
+ Thread .sleep (250 );
206
208
if (prefs .getBoolean ("plugin_meshtastic_chunk_ERR" , false )) {
207
209
Log .d (TAG , "Chunk ERR received, retransmitting message ID: " + i );
208
210
j =0 ;
@@ -342,7 +344,7 @@ public void processCotEvent(CotEvent cotEvent, String[] strings) {
342
344
return ;
343
345
}
344
346
345
- DataPacket dp ;
347
+ final DataPacket [] dp = new DataPacket [ 1 ] ;
346
348
347
349
int hopLimit = mr .getHopLimit ();
348
350
@@ -475,10 +477,10 @@ else if (xpp.getAttributeName(i).equalsIgnoreCase("speed"))
475
477
Log .d (TAG , "Total wire size for TAKPacket: " + tak_packet .build ().toByteArray ().length );
476
478
Log .d (TAG , "Sending: " + tak_packet .build ().toString ());
477
479
478
- dp = new DataPacket (DataPacket .ID_BROADCAST , tak_packet .build ().toByteArray (), Portnums .PortNum .ATAK_PLUGIN_VALUE , DataPacket .ID_LOCAL , System .currentTimeMillis (), 0 , MessageStatus .UNKNOWN , hopLimit , channel );
480
+ dp [ 0 ] = new DataPacket (DataPacket .ID_BROADCAST , tak_packet .build ().toByteArray (), Portnums .PortNum .ATAK_PLUGIN_VALUE , DataPacket .ID_LOCAL , System .currentTimeMillis (), 0 , MessageStatus .UNKNOWN , hopLimit , channel );
479
481
try {
480
482
if (mMeshService != null )
481
- mMeshService .send (dp );
483
+ mMeshService .send (dp [ 0 ] );
482
484
} catch (RemoteException e ) {
483
485
throw new RuntimeException (e );
484
486
}
@@ -545,10 +547,10 @@ else if (xpp.getAttributeName(i).equalsIgnoreCase("speed"))
545
547
Log .d (TAG , "Total wire size for TAKPacket: " + tak_packet .build ().toByteArray ().length );
546
548
Log .d (TAG , "Sending: " + tak_packet .build ().toString ());
547
549
548
- dp = new DataPacket (DataPacket .ID_BROADCAST , tak_packet .build ().toByteArray (), Portnums .PortNum .ATAK_PLUGIN_VALUE , DataPacket .ID_LOCAL , System .currentTimeMillis (), 0 , MessageStatus .UNKNOWN , hopLimit , channel );
550
+ dp [ 0 ] = new DataPacket (DataPacket .ID_BROADCAST , tak_packet .build ().toByteArray (), Portnums .PortNum .ATAK_PLUGIN_VALUE , DataPacket .ID_LOCAL , System .currentTimeMillis (), 0 , MessageStatus .UNKNOWN , hopLimit , channel );
549
551
try {
550
552
if (mMeshService != null )
551
- mMeshService .send (dp );
553
+ mMeshService .send (dp [ 0 ] );
552
554
} catch (RemoteException e ) {
553
555
throw new RuntimeException (e );
554
556
}
@@ -623,14 +625,14 @@ else if (xpp.getAttributeName(i).equalsIgnoreCase("speed"))
623
625
// if "to" starts with !, its probably a meshtastic ID, so don't send it to ^all but the actual ID
624
626
if (to .startsWith ("!" )) {
625
627
Log .d (TAG , "Sending to Meshtastic ID: " + to );
626
- dp = new DataPacket (to , MeshProtos .Data .newBuilder ().setPayload (ByteString .copyFrom (message .getBytes (StandardCharsets .UTF_8 ))).build ().toByteArray (),Portnums .PortNum .TEXT_MESSAGE_APP_VALUE , DataPacket .ID_LOCAL , System .currentTimeMillis (), 0 , MessageStatus .UNKNOWN , hopLimit , channel );
628
+ dp [ 0 ] = new DataPacket (to , MeshProtos .Data .newBuilder ().setPayload (ByteString .copyFrom (message .getBytes (StandardCharsets .UTF_8 ))).build ().toByteArray (),Portnums .PortNum .TEXT_MESSAGE_APP_VALUE , DataPacket .ID_LOCAL , System .currentTimeMillis (), 0 , MessageStatus .UNKNOWN , hopLimit , channel );
627
629
} else {
628
630
Log .d (TAG , "Sending to ^all" );
629
- dp = new DataPacket (DataPacket .ID_BROADCAST , tak_packet .build ().toByteArray (), Portnums .PortNum .ATAK_PLUGIN_VALUE , DataPacket .ID_LOCAL , System .currentTimeMillis (), 0 , MessageStatus .UNKNOWN , hopLimit , channel );
631
+ dp [ 0 ] = new DataPacket (DataPacket .ID_BROADCAST , tak_packet .build ().toByteArray (), Portnums .PortNum .ATAK_PLUGIN_VALUE , DataPacket .ID_LOCAL , System .currentTimeMillis (), 0 , MessageStatus .UNKNOWN , hopLimit , channel );
630
632
}
631
633
try {
632
634
if (mMeshService != null )
633
- mMeshService .send (dp );
635
+ mMeshService .send (dp [ 0 ] );
634
636
} catch (RemoteException e ) {
635
637
throw new RuntimeException (e );
636
638
}
@@ -640,62 +642,104 @@ else if (xpp.getAttributeName(i).equalsIgnoreCase("speed"))
640
642
Log .d (TAG , "PLI/Chat Only" );
641
643
return ;
642
644
}
645
+ new Thread (() -> {
646
+ Log .d (TAG , "Using libcotshrink" );
643
647
644
- Log .d (TAG , "Using libcotshrink" );
645
-
646
- byte [] cotAsBytes = cotShrinker .toByteArrayLossy (cotEvent );
647
-
648
- Log .d (TAG , "Size: " + cotAsBytes .length );
648
+ byte [] cotAsBytes ;
649
649
650
- if (cotAsBytes .length < 236 ) {
651
- Log .d (TAG , "Small send" );
652
- dp = new DataPacket (DataPacket .ID_BROADCAST , cotAsBytes , Portnums .PortNum .ATAK_FORWARDER_VALUE , DataPacket .ID_LOCAL , System .currentTimeMillis (), 0 , MessageStatus .UNKNOWN , hopLimit , channel );
653
650
try {
654
- if (mMeshService != null )
655
- mMeshService .send (dp );
656
- } catch (RemoteException e ) {
651
+ EXIFactory exiFactory = DefaultEXIFactory .newInstance ();
652
+ ByteArrayOutputStream osEXI = new ByteArrayOutputStream ();
653
+ EXIResult exiResult = new EXIResult (exiFactory );
654
+ exiResult .setOutputStream (osEXI );
655
+ SAXParserFactory saxParserFactory = SAXParserFactory .newInstance ();
656
+ SAXParser newSAXParser = saxParserFactory .newSAXParser ();
657
+ XMLReader xmlReader = newSAXParser .getXMLReader ();
658
+ xmlReader .setContentHandler (exiResult .getHandler ());
659
+ InputSource stream = new InputSource (new StringReader (cotEvent .toString ()));
660
+ xmlReader .parse (stream ); // parse XML input
661
+ cotAsBytes = osEXI .toByteArray ();
662
+ osEXI .close ();
663
+ } catch (Exception e ) {
657
664
e .printStackTrace ();
665
+ return ;
658
666
}
659
- return ;
660
- }
661
667
662
- List < byte []> chunkList = divideArray ( cotAsBytes , 200 );
668
+ Log . d ( TAG , "Size: " + cotAsBytes . length );
663
669
664
- int chunks = (int ) Math .floor (cotAsBytes .length / 200 );
665
- chunks ++;
666
- Log .d (TAG , "Sending " + chunks );
670
+ if (cotAsBytes .length < 236 ) {
671
+ Log .d (TAG , "Small send" );
672
+ dp [0 ] = new DataPacket (DataPacket .ID_BROADCAST , cotAsBytes , Portnums .PortNum .ATAK_FORWARDER_VALUE , DataPacket .ID_LOCAL , System .currentTimeMillis (), 0 , MessageStatus .UNKNOWN , hopLimit , channel );
673
+ try {
674
+ if (mMeshService != null )
675
+ mMeshService .send (dp [0 ]);
676
+ } catch (RemoteException e ) {
677
+ e .printStackTrace ();
678
+ }
679
+ return ;
680
+ }
667
681
668
- byte [] chunk_hdr = String .format (Locale .US , "CHK_%d_" , cotAsBytes .length ).getBytes ();
682
+ int chunkSize = 220 ;
683
+ List <byte []> chunkList = divideArray (cotAsBytes , chunkSize );
684
+ final AtomicInteger [] i = {new AtomicInteger ()};
685
+ int chunks = (int ) Math .floor (cotAsBytes .length / chunkSize );
686
+ chunks ++;
687
+ Log .d (TAG , "Sending " + chunks );
688
+
689
+ byte [] chunk_hdr = String .format (Locale .US , "CHK_%d_" , cotAsBytes .length ).getBytes ();
690
+ HashMap <String , byte []> chunkMap = new HashMap <>();
691
+
692
+ for (byte [] c : chunkList ) {
693
+ byte [] combined = new byte [chunk_hdr .length + c .length ];
694
+ try {
695
+ System .arraycopy (chunk_hdr , 0 , combined , 0 , chunk_hdr .length );
696
+ System .arraycopy (c , 0 , combined , chunk_hdr .length , c .length );
697
+ } catch (Exception e ) {
698
+ e .printStackTrace ();
699
+ return ;
700
+ }
669
701
670
- for (byte [] c : chunkList ) {
671
- byte [] combined = new byte [chunk_hdr .length + c .length ];
672
- try {
673
- System .arraycopy (chunk_hdr , 0 , combined , 0 , chunk_hdr .length );
674
- System .arraycopy (c , 0 , combined , chunk_hdr .length , c .length );
675
- } catch (Exception e ) {
676
- e .printStackTrace ();
677
- return ;
702
+ try {
703
+ // send out 1 chunk
704
+ i [0 ].set (mMeshService .getPacketId ());
705
+ Log .d (TAG , "Chunk ID: " + i [0 ]);
706
+ chunkMap .put (String .valueOf (i [0 ].get ()), combined );
707
+ editor .putInt ("plugin_meshtastic_chunk_id" , i [0 ].get ());
708
+ editor .putBoolean ("plugin_meshtastic_chunk_ACK" , true );
709
+ editor .apply ();
710
+
711
+ INNER :
712
+ for (int j = 0 ; j < 1 ; j ++) {
713
+ dp [0 ] = new DataPacket (DataPacket .ID_BROADCAST , combined , Portnums .PortNum .ATAK_FORWARDER_VALUE , DataPacket .ID_LOCAL , System .currentTimeMillis (), i [0 ].get (), MessageStatus .UNKNOWN , hopLimit , channel );
714
+ mMeshService .send (dp [0 ]);
715
+ while (prefs .getBoolean ("plugin_meshtastic_chunk_ACK" , false )) {
716
+ try {
717
+ Thread .sleep (500 );
718
+ if (prefs .getBoolean ("plugin_meshtastic_chunk_ERR" , false )) {
719
+ Log .d (TAG , "Chunk ERR received, retransmitting message ID: " + i [0 ]);
720
+ j = 0 ;
721
+ break INNER ;
722
+ }
723
+ } catch (Exception e ) {
724
+ e .printStackTrace ();
725
+ }
726
+ }
727
+ }
728
+ } catch (RemoteException e ) {
729
+ e .printStackTrace ();
730
+ return ;
731
+ }
678
732
}
679
- // send out 1 chunk
680
- dp = new DataPacket (DataPacket .ID_BROADCAST , combined , Portnums .PortNum .ATAK_FORWARDER_VALUE , DataPacket .ID_LOCAL , System .currentTimeMillis (), 0 , MessageStatus .UNKNOWN , hopLimit , channel );
681
- try {
682
- if ( mMeshService != null )
683
- mMeshService .send (dp );
684
- } catch (RemoteException e ) {
685
- e .printStackTrace ();
686
- return ;
733
+ // We're done chunking
734
+ dp [ 0 ] = new DataPacket (DataPacket .ID_BROADCAST , new byte []{ 'E' , 'N' , 'D' }, Portnums .PortNum .ATAK_FORWARDER_VALUE , DataPacket .ID_LOCAL , System .currentTimeMillis (), 0 , MessageStatus .UNKNOWN , 3 , prefs . getInt ( "meshtastic_channel" , 0 ) );
735
+ if ( mMeshService != null ) {
736
+ try {
737
+ mMeshService .send (dp [ 0 ] );
738
+ } catch (RemoteException e ) {
739
+ e .printStackTrace ();
740
+ }
687
741
}
688
- }
689
-
690
- // We're done chunking
691
- dp = new DataPacket (DataPacket .ID_BROADCAST , new byte []{'E' , 'N' , 'D' }, Portnums .PortNum .ATAK_FORWARDER_VALUE , DataPacket .ID_LOCAL , System .currentTimeMillis (), 0 , MessageStatus .UNKNOWN , hopLimit , channel );
692
- try {
693
- if (mMeshService != null )
694
- mMeshService .send (dp );
695
- } catch (RemoteException e ) {
696
- e .printStackTrace ();
697
- return ;
698
- }
742
+ }).start ();
699
743
}
700
744
}
701
745
public void onCreate (final Context context , Intent intent , MapView view ) {
0 commit comments