Skip to content

Commit

Permalink
Added options for different IP address connection modes
Browse files Browse the repository at this point in the history
  • Loading branch information
Gold872 committed Nov 18, 2023
1 parent 33fbff4 commit 7a267cd
Show file tree
Hide file tree
Showing 9 changed files with 205 additions and 110 deletions.
8 changes: 8 additions & 0 deletions lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import 'dart:ui';
import 'package:elastic_dashboard/pages/dashboard_page.dart';
import 'package:elastic_dashboard/services/field_images.dart';
import 'package:elastic_dashboard/services/globals.dart';
import 'package:elastic_dashboard/services/ip_address_util.dart';
import 'package:elastic_dashboard/services/nt4_connection.dart';
import 'package:flutter/material.dart';
import 'package:package_info_plus/package_info_plus.dart';
Expand Down Expand Up @@ -34,6 +35,9 @@ void main() async {

await windowManager.ensureInitialized();

Globals.ipAddressMode =
IPAddressMode.fromIndex(preferences.getInt(PrefKeys.ipAddressMode));

Globals.gridSize = preferences.getInt(PrefKeys.gridSize) ?? Globals.gridSize;
Globals.snapToGrid =
preferences.getBool(PrefKeys.snapToGrid) ?? Globals.snapToGrid;
Expand All @@ -45,6 +49,10 @@ void main() async {
.nt4Connect(preferences.getString(PrefKeys.ipAddress) ?? '127.0.0.1');

nt4Connection.dsClientConnect((ip) async {
if (Globals.ipAddressMode != IPAddressMode.driverStation) {
return;
}

if (preferences.getString(PrefKeys.ipAddress) != ip) {
await preferences.setString(PrefKeys.ipAddress, ip);
} else {
Expand Down
95 changes: 47 additions & 48 deletions lib/pages/dashboard_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -719,39 +719,57 @@ class _DashboardPageState extends State<DashboardPage> with WindowListener {

await _preferences.setInt(PrefKeys.teamNumber, newTeamNumber);

if (nt4Connection.isDSConnected) {
setState(() {});
return;
}

bool determineAddressFromTeamNumber =
_preferences.getBool(PrefKeys.useTeamNumberForIP) ?? true;

if (determineAddressFromTeamNumber) {
_updateIPAddress(newIPAddress: data);
switch (Globals.ipAddressMode) {
case IPAddressMode.roboRIOmDNS:
_updateIPAddress(
IPAddressUtil.teamNumberToRIOmDNS(newTeamNumber));
break;
case IPAddressMode.teamNumber:
_updateIPAddress(IPAddressUtil.teamNumberToIP(newTeamNumber));
break;
default:
setState(() {});
break;
}
},
onUseTeamNumberToggle: (value) async {
await _preferences.setBool(PrefKeys.useTeamNumberForIP, value);

if (nt4Connection.isDSConnected) {
return;
}

if (value) {
_updateIPAddress();
onIPAddressModeChanged: (mode) async {
await _preferences.setInt(PrefKeys.ipAddressMode, mode.index);

Globals.ipAddressMode = mode;

switch (mode) {
case IPAddressMode.driverStation:
String? lastAnnouncedIP = nt4Connection.dsClient.lastAnnouncedIP;

if (lastAnnouncedIP != null) {
_updateIPAddress(lastAnnouncedIP);
}
break;
case IPAddressMode.roboRIOmDNS:
_updateIPAddress(
IPAddressUtil.teamNumberToRIOmDNS(Globals.teamNumber));
break;
case IPAddressMode.teamNumber:
_updateIPAddress(
IPAddressUtil.teamNumberToIP(Globals.teamNumber));
break;
case IPAddressMode.roboRIODefault:
_updateIPAddress(Globals.roboRIODefaultIP);
break;
case IPAddressMode.localhost:
_updateIPAddress('localhost');
break;
default:
setState(() {});
break;
}
},
onIPAddressChanged: (String? data) async {
if (data == null) {
return;
}

if (nt4Connection.isDSConnected) {
return;
}

_updateIPAddress(newIPAddress: data);
_updateIPAddress(data);
},
onGridToggle: (value) async {
setState(() {
Expand Down Expand Up @@ -801,31 +819,12 @@ class _DashboardPageState extends State<DashboardPage> with WindowListener {
);
}

void _updateIPAddress({String? newIPAddress}) async {
String ipAddress =
_preferences.getString(PrefKeys.ipAddress) ?? '127.0.0.1';
void _updateIPAddress(String newIPAddress) async {
await _preferences.setString(PrefKeys.ipAddress, newIPAddress);

if (newIPAddress != null) {
bool isTeamNumber = IPAddressUtil.isTeamNumber(newIPAddress);

if (isTeamNumber) {
ipAddress = IPAddressUtil.teamNumberToIP(int.parse(newIPAddress));
} else {
ipAddress = newIPAddress;
}
} else {
int? teamNumber = _preferences.getInt(PrefKeys.teamNumber);

if (teamNumber != null) {
ipAddress = IPAddressUtil.teamNumberToIP(teamNumber);
}
}

await _preferences.setString(PrefKeys.ipAddress, ipAddress);

nt4Connection.changeIPAddress(ipAddress);

setState(() {});
setState(() {
nt4Connection.changeIPAddress(newIPAddress);
});
}

void showWindowCloseConfirmation(BuildContext context) {
Expand Down
8 changes: 7 additions & 1 deletion lib/services/globals.dart
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import 'package:elastic_dashboard/services/ip_address_util.dart';

class Globals {
static const String repositoryLink =
'https://github.com/Gold872/elastic-dashboard';
static const String releasesLink = '$repositoryLink/releases/latest';

static IPAddressMode ipAddressMode = IPAddressMode.driverStation;

static String ipAddress = '127.0.0.1';
static int teamNumber = 353;
static int gridSize = 128;
Expand All @@ -12,12 +16,14 @@ class Globals {

static const double defaultPeriod = 0.1;
static const double defaultGraphPeriod = 0.033;

static const String roboRIODefaultIP = '192.168.7.201';
}

class PrefKeys {
static String layout = 'layout';
static String ipAddress = 'ip_address';
static String useTeamNumberForIP = 'ip_from_team_number';
static String ipAddressMode = 'ip_address_mode';
static String teamNumber = 'team_number';
static String teamColor = 'team_color';
static String gridSize = 'grid_size';
Expand Down
35 changes: 34 additions & 1 deletion lib/services/ip_address_util.dart
Original file line number Diff line number Diff line change
@@ -1,15 +1,48 @@
import 'dart:io';
import 'dart:typed_data';

enum IPAddressMode {
driverStation('Driver Station'), // 0
roboRIOmDNS('RoboRIO mDNS (roboRIO-###-FRC.local)'), // 1
teamNumber('Team Number (10.TE.AM.2)'), // 2
roboRIODefault('RoboRIO Default (192.168.7.201)'), // 3
localhost('localhost (127.0.0.1)'), // 4
custom('Custom'); // 5

const IPAddressMode(this.displayName);

final String displayName;

@override
String toString() {
return displayName;
}

static IPAddressMode fromIndex(int? index) {
if (index == null || index >= values.length) {
return driverStation;
}

return values[index];
}
}

class IPAddressUtil {
static bool isTeamNumber(String ipAddress) {
return int.tryParse(ipAddress) != null;
}

static String teamNumberToIP(int teamNumber) {
static String teamNumberToRIOmDNS(int teamNumber) {
return 'roboRIO-$teamNumber-FRC.local';
}

static String teamNumberToIP(int teamNumber) {
String te = (teamNumber ~/ 100).toString();
String am = (teamNumber % 100).toString().padLeft(2, '0');

return '10.$te.$am.2';
}

static String getIpFromInt32Value(int value) =>
InternetAddress.fromRawAddress(
(ByteData(4)..setInt32(0, value)).buffer.asUint8List())
Expand Down
13 changes: 13 additions & 0 deletions lib/services/nt4_connection.dart
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,19 @@ class NT4Connection {
}
}

Stream<bool> dsConnectionStatus() async* {
yield _dsConnected;
bool lastYielded = _dsConnected;

while (true) {
if (_dsConnected != lastYielded) {
yield _dsConnected;
lastYielded = _dsConnected;
}
await Future.delayed(const Duration(seconds: 1));
}
}

void changeIPAddress(String ipAddress) {
if (_ntClient.serverBaseAddress == ipAddress) {
return;
Expand Down
70 changes: 43 additions & 27 deletions lib/widgets/settings_dialog.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import 'package:dot_cast/dot_cast.dart';
import 'package:elastic_dashboard/services/globals.dart';
import 'package:elastic_dashboard/services/ip_address_util.dart';
import 'package:elastic_dashboard/services/nt4_connection.dart';
import 'package:elastic_dashboard/widgets/dialog_widgets/dialog_color_picker.dart';
import 'package:elastic_dashboard/widgets/dialog_widgets/dialog_dropdown_chooser.dart';
import 'package:elastic_dashboard/widgets/dialog_widgets/dialog_text_input.dart';
import 'package:elastic_dashboard/widgets/dialog_widgets/dialog_toggle_switch.dart';
import 'package:flutter/material.dart';
Expand All @@ -11,7 +15,7 @@ class SettingsDialog extends StatefulWidget {

final Function(String? data)? onIPAddressChanged;
final Function(String? data)? onTeamNumberChanged;
final Function(bool value)? onUseTeamNumberToggle;
final Function(IPAddressMode mode)? onIPAddressModeChanged;
final Function(Color color)? onColorChanged;
final Function(bool value)? onGridToggle;
final Function(String? gridSize)? onGridSizeChanged;
Expand All @@ -21,7 +25,7 @@ class SettingsDialog extends StatefulWidget {
super.key,
required this.preferences,
this.onTeamNumberChanged,
this.onUseTeamNumberToggle,
this.onIPAddressModeChanged,
this.onIPAddressChanged,
this.onColorChanged,
this.onGridToggle,
Expand Down Expand Up @@ -74,28 +78,37 @@ class _SettingsDialogState extends State<SettingsDialog> {
),
],
),
const Divider(),
const Align(
alignment: Alignment.topLeft,
child: Text('IP Address Settings'),
),
const SizedBox(height: 5),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Flexible(
child: DialogToggleSwitch(
initialValue: widget.preferences
.getBool(PrefKeys.useTeamNumberForIP) ??
false,
label: 'Use Team # for IP',
onToggle: (value) {
setState(() {
widget.onUseTeamNumberToggle?.call(value);
});
},
),
),
Flexible(
child: DialogTextInput(
enabled: !(widget.preferences
.getBool(PrefKeys.useTeamNumberForIP) ??
false),
const Text('IP Address Mode'),
DialogDropdownChooser<IPAddressMode>(
onSelectionChanged: (mode) {
if (mode == null) {
return;
}

widget.onIPAddressModeChanged?.call(mode);

setState(() {});
},
choices: IPAddressMode.values,
initialValue: Globals.ipAddressMode,
),
const SizedBox(height: 5),
StreamBuilder(
stream: nt4Connection.dsConnectionStatus(),
initialData: nt4Connection.isDSConnected,
builder: (context, snapshot) {
bool dsConnected = tryCast(snapshot.data) ?? false;

return DialogTextInput(
enabled: Globals.ipAddressMode == IPAddressMode.custom ||
(Globals.ipAddressMode == IPAddressMode.driverStation &&
!dsConnected),
initialText:
widget.preferences.getString(PrefKeys.ipAddress),
label: 'IP Address',
Expand All @@ -104,11 +117,14 @@ class _SettingsDialogState extends State<SettingsDialog> {
widget.onIPAddressChanged?.call(data);
});
},
),
),
],
),
);
}),
const Divider(),
const Align(
alignment: Alignment.topLeft,
child: Text('Grid Settings'),
),
const SizedBox(height: 5),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Expand Down
19 changes: 13 additions & 6 deletions test/services/ip_address_util_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,19 @@ void main() {
expect(IPAddressUtil.isTeamNumber('353'), true);
expect(IPAddressUtil.isTeamNumber('10.03.53.2'), false);

expect(IPAddressUtil.teamNumberToIP(353), 'roboRIO-353-FRC.local');
expect(IPAddressUtil.teamNumberToIP(2601), 'roboRIO-2601-FRC.local');
expect(IPAddressUtil.teamNumberToIP(47), 'roboRIO-47-FRC.local');
expect(IPAddressUtil.teamNumberToIP(101), 'roboRIO-101-FRC.local');
expect(IPAddressUtil.teamNumberToIP(3015), 'roboRIO-3015-FRC.local');
expect(IPAddressUtil.teamNumberToIP(12053), 'roboRIO-12053-FRC.local');
expect(IPAddressUtil.teamNumberToRIOmDNS(353), 'roboRIO-353-FRC.local');
expect(IPAddressUtil.teamNumberToRIOmDNS(2601), 'roboRIO-2601-FRC.local');
expect(IPAddressUtil.teamNumberToRIOmDNS(47), 'roboRIO-47-FRC.local');
expect(IPAddressUtil.teamNumberToRIOmDNS(101), 'roboRIO-101-FRC.local');
expect(IPAddressUtil.teamNumberToRIOmDNS(3015), 'roboRIO-3015-FRC.local');
expect(IPAddressUtil.teamNumberToRIOmDNS(12053), 'roboRIO-12053-FRC.local');

expect(IPAddressUtil.teamNumberToIP(353), '10.3.53.2');
expect(IPAddressUtil.teamNumberToIP(2601), '10.26.01.2');
expect(IPAddressUtil.teamNumberToIP(47), '10.0.47.2');
expect(IPAddressUtil.teamNumberToIP(101), '10.1.01.2');
expect(IPAddressUtil.teamNumberToIP(3015), '10.30.15.2');
expect(IPAddressUtil.teamNumberToIP(12053), '10.120.53.2');

expect(IPAddressUtil.getIpFromInt32Value(2130706433), '127.0.0.1');
expect(IPAddressUtil.getIpFromInt32Value(167982338), '10.3.53.2');
Expand Down
6 changes: 6 additions & 0 deletions test/test_util.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ void setupMockOfflineNT4() {
when(mockNT4Connection.connectionStatus())
.thenAnswer((_) => Stream.value(false));

when(mockNT4Connection.dsConnectionStatus())
.thenAnswer((_) => Stream.value(false));

when(mockNT4Connection.getLastAnnouncedValue(any)).thenReturn(null);

when(mockNT4Connection.subscribe(any, any)).thenReturn(mockSubscription);
Expand Down Expand Up @@ -70,6 +73,9 @@ void setupMockOnlineNT4() {
when(mockNT4Connection.connectionStatus())
.thenAnswer((_) => Stream.value(true));

when(mockNT4Connection.dsConnectionStatus())
.thenAnswer((_) => Stream.value(true));

when(mockNT4Connection.getLastAnnouncedValue(any)).thenReturn(null);

when(mockNT4Connection.subscribe(any, any)).thenReturn(mockSubscription);
Expand Down
Loading

0 comments on commit 7a267cd

Please sign in to comment.