Initial radio implementation 74/29574/1
authorScott Murray <scott.murray@konsulko.com>
Sun, 31 Dec 2023 21:24:51 +0000 (16:24 -0500)
committerScott Murray <scott.murray@konsulko.com>
Wed, 3 Jan 2024 23:23:52 +0000 (18:23 -0500)
Notable changes:
- Add radio gRPC API protobuf definitation and generated files.
- Reworked existing single gRPC APIs library to split it into
  per-API libraries to avoid name collision issues.
- Add radio gRPC client class and associated radio state class
  and RiverPod providers.
- Split media controls and play list table classes into media
  player and radio specific versions to facilitate customization
  and wiring up their appropriate backends in a straightforward
  fashion.  Some potential rationalization of styling widgets
  may be done as a follow up to avoid some duplication.
- Added radio configuration and presets loading.  The presets
  will be populated with the contents of a radio-presets.yaml
  file from the configured location, the default location is
  the /etc/xdg/AGL/ics-homescreen directory.
- Implemented FM radio player against the radio gRPC API.
  For the sake of expediency, no attempt has been made to make
  the player able to handle AM band support.
- Reworked media page navigation state so that active player is
  restored when coming back to the page.  Logic has been added to
  start/stop the radio on navigating to or leaving the FM radio
  sub-page.  This will potentially be reworked before CES to work
  with the pause/stop button present on the other pages.
- Started pruning down global exports.dart a bit to remove files
  only used in a specific page/hierarchy, starting with media.

Bug-AGL: SPEC-5029

Change-Id: I1ae0aca4a7a8218e69e4286c863f01509a1cccb7
Signed-off-by: Scott Murray <scott.murray@konsulko.com>
45 files changed:
lib/data/data_providers/app_config_provider.dart
lib/data/data_providers/app_launcher.dart
lib/data/data_providers/app_provider.dart
lib/data/data_providers/audio_notifier.dart
lib/data/data_providers/radio_client.dart [new file with mode: 0644]
lib/data/data_providers/radio_notifier.dart [new file with mode: 0644]
lib/data/data_providers/radio_presets_provider.dart [new file with mode: 0644]
lib/data/data_providers/val_client.dart
lib/data/data_providers/vehicle_notifier.dart
lib/data/models/audio_state.dart [moved from lib/data/models/audio.dart with 79% similarity]
lib/data/models/radio_state.dart [new file with mode: 0644]
lib/export.dart
lib/presentation/common_widget/custom_bottom_bar.dart
lib/presentation/common_widget/volume_and_fan_control.dart
lib/presentation/router/routes/routes.dart
lib/presentation/screens/media/media.dart [moved from lib/presentation/screens/media_player/media_player.dart with 57% similarity]
lib/presentation/screens/media/media_nav_notifier.dart [new file with mode: 0644]
lib/presentation/screens/media/media_player.dart [moved from lib/presentation/screens/media_player/media_content.dart with 87% similarity]
lib/presentation/screens/media/media_player_controls.dart [new file with mode: 0644]
lib/presentation/screens/media/play_list_table.dart [moved from lib/presentation/screens/media_player/play_list_table.dart with 99% similarity]
lib/presentation/screens/media/player_navigation.dart [moved from lib/presentation/screens/media_player/player_navigation.dart with 76% similarity]
lib/presentation/screens/media/radio_player.dart [moved from lib/presentation/screens/media_player/fm_player.dart with 56% similarity]
lib/presentation/screens/media/radio_player_controls.dart [new file with mode: 0644]
lib/presentation/screens/media/radio_preset_table.dart [new file with mode: 0644]
lib/presentation/screens/media/segmented_buttons.dart [moved from lib/presentation/screens/media_player/segmented_buttons.dart with 100% similarity]
lib/presentation/screens/media/widgets/gradient_progress_indicator.dart [moved from lib/presentation/screens/media_player/widgets/gradient_progress_indicator.dart with 100% similarity]
lib/presentation/screens/media/widgets/media_volume_bar.dart [moved from lib/presentation/screens/media_player/widgets/media_volume_bar.dart with 75% similarity]
lib/presentation/screens/media_player/media_controls.dart [deleted file]
lib/presentation/screens/media_player/my_media.dart [deleted file]
lib/presentation/screens/settings/settings_screens/audio_settings/widget/slider_widgets.dart
lib/presentation/screens/splash/widget/splash_content.dart
protos/lib/agl-shell-api.dart [new file with mode: 0644]
protos/lib/applauncher-api.dart [new file with mode: 0644]
protos/lib/radio-api.dart [new file with mode: 0644]
protos/lib/src/generated/radio.pb.dart [new file with mode: 0644]
protos/lib/src/generated/radio.pbenum.dart [new file with mode: 0644]
protos/lib/src/generated/radio.pbgrpc.dart [new file with mode: 0644]
protos/lib/src/generated/radio.pbjson.dart [new file with mode: 0644]
protos/lib/src/generated/todo.pb.dart [deleted file]
protos/lib/src/generated/todo.pbenum.dart [deleted file]
protos/lib/src/generated/todo.pbgrpc.dart [deleted file]
protos/lib/src/generated/todo.pbjson.dart [deleted file]
protos/lib/val-api.dart [moved from protos/lib/protos.dart with 51% similarity]
protos/protos/radio.proto [new file with mode: 0644]
protos/protos/todo.proto [deleted file]

index 7e0ddc6..a60a462 100644 (file)
@@ -35,14 +35,40 @@ class KuksaConfig {
   }
 }
 
+class RadioConfig {
+  final String hostname;
+  final int port;
+  final String presets;
+
+  static String defaultHostname = 'localhost';
+  static int defaultPort = 50053;
+  static String defaultPresets =
+      '/etc/xdg/AGL/ics-homescreen/radio-presets.yaml';
+
+  RadioConfig(
+      {required this.hostname, required this.port, required this.presets});
+
+  static RadioConfig defaultConfig() {
+    return RadioConfig(
+        hostname: RadioConfig.defaultHostname,
+        port: RadioConfig.defaultPort,
+        presets: RadioConfig.defaultPresets);
+  }
+}
+
 class AppConfig {
   final bool disableBkgAnimation;
   final bool randomHybridAnimation;
   final KuksaConfig kuksaConfig;
+  final RadioConfig radioConfig;
 
   static String configFilePath = '/etc/xdg/AGL/ics-homescreen.yaml';
 
-  AppConfig({required this.disableBkgAnimation, required this.randomHybridAnimation, required this.kuksaConfig});
+  AppConfig(
+      {required this.disableBkgAnimation,
+      required this.randomHybridAnimation,
+      required this.kuksaConfig,
+      required this.radioConfig});
 
   static KuksaConfig parseKuksaConfig(YamlMap kuksaMap) {
     try {
@@ -64,7 +90,7 @@ class AppConfig {
             debugPrint("Reading authorization token $s");
             try {
               token = File(s).readAsStringSync();
-            } on Exception catch (_) {
+            } catch (_) {
               print("ERROR: Could not read authorization token file $token");
               token = "";
             }
@@ -89,7 +115,7 @@ class AppConfig {
       }
       try {
         ca_cert = File(ca_path).readAsBytesSync();
-      } on Exception catch (_) {
+      } catch (_) {
         print("ERROR: Could not read CA certificate file $ca_path");
         ca_cert = [];
       }
@@ -107,10 +133,33 @@ class AppConfig {
           use_tls: use_tls,
           ca_certificate: ca_cert,
           tls_server_name: tls_server_name);
-    } on Exception catch (_) {
+    } catch (_) {
       return KuksaConfig.defaultConfig();
     }
   }
+
+  static RadioConfig parseRadioConfig(YamlMap radioMap) {
+    try {
+      String hostname = RadioConfig.defaultHostname;
+      if (radioMap.containsKey('hostname')) {
+        hostname = radioMap['hostname'];
+      }
+
+      int port = RadioConfig.defaultPort;
+      if (radioMap.containsKey('port')) {
+        port = radioMap['port'];
+      }
+
+      String presets = RadioConfig.defaultPresets;
+      if (radioMap.containsKey('presets')) {
+        hostname = radioMap['presets'];
+      }
+
+      return RadioConfig(hostname: hostname, port: port, presets: presets);
+    } catch (_) {
+      return RadioConfig.defaultConfig();
+    }
+  }
 }
 
 final appConfigProvider = Provider((ref) {
@@ -133,6 +182,13 @@ final appConfigProvider = Provider((ref) {
           tls_server_name: "");
     }
 
+    RadioConfig radioConfig;
+    if (yamlMap.containsKey('radio')) {
+      radioConfig = AppConfig.parseRadioConfig(yamlMap['radio']);
+    } else {
+      radioConfig = RadioConfig.defaultConfig();
+    }
+
     bool disableBkgAnimation = disableBkgAnimationDefault;
     if (yamlMap.containsKey('disable-bg-animation')) {
       var value = yamlMap['disable-bg-animation'];
@@ -152,11 +208,13 @@ final appConfigProvider = Provider((ref) {
     return AppConfig(
         disableBkgAnimation: disableBkgAnimation,
         randomHybridAnimation: randomHybridAnimation,
-        kuksaConfig: kuksaConfig);
-  } on Exception catch (_) {
+        kuksaConfig: kuksaConfig,
+        radioConfig: radioConfig);
+  } catch (_) {
     return AppConfig(
         disableBkgAnimation: false,
         randomHybridAnimation: false,
-        kuksaConfig: KuksaConfig.defaultConfig());
+        kuksaConfig: KuksaConfig.defaultConfig(),
+        radioConfig: RadioConfig.defaultConfig());
   }
 });
index b0199d3..8762643 100644 (file)
@@ -1,5 +1,6 @@
 import 'package:flutter_ics_homescreen/export.dart';
-import 'package:protos/protos.dart';
+import 'package:protos/applauncher-api.dart';
+import 'package:protos/agl-shell-api.dart';
 
 class AppLauncher {
   final Ref ref;
@@ -9,20 +10,18 @@ class AppLauncher {
   late ClientChannel appLauncherChannel;
   late AppLauncherClient appLauncher;
 
-  List<String> appStack = [ 'homescreen' ];
+  List<String> appStack = ['homescreen'];
 
   AppLauncher({required this.ref}) {
-    aglShellChannel =
-      ClientChannel('localhost',
-                    port: 14005,
-                    options: ChannelOptions(credentials: ChannelCredentials.insecure()));
+    aglShellChannel = ClientChannel('localhost',
+        port: 14005,
+        options: ChannelOptions(credentials: ChannelCredentials.insecure()));
 
     aglShell = AglShellManagerServiceClient(aglShellChannel);
 
-    appLauncherChannel =
-      ClientChannel('localhost',
-                    port: 50052,
-                    options: ChannelOptions(credentials: ChannelCredentials.insecure()));
+    appLauncherChannel = ClientChannel('localhost',
+        port: 50052,
+        options: ChannelOptions(credentials: ChannelCredentials.insecure()));
     appLauncher = AppLauncherClient(appLauncherChannel);
   }
 
@@ -58,13 +57,23 @@ class AppLauncher {
         debugPrint("Got app:");
         debugPrint("$info");
         // Existing icons are currently not usable, so leave blank for now
-        apps.add(AppLauncherInfo(id: info.id, name: info.name, icon: "", internal: false));
+        apps.add(AppLauncherInfo(
+            id: info.id, name: info.name, icon: "", internal: false));
       }
       apps.sort((a, b) => a.name.compareTo(b.name));
 
       // Add built-in app widgets
-      apps.insert(0, AppLauncherInfo(id: "clock", name: "Clock", icon: "clock.svg", internal: true));
-      apps.insert(0, AppLauncherInfo(id: "weather", name: "Weather", icon: "weather.svg", internal: true));
+      apps.insert(
+          0,
+          AppLauncherInfo(
+              id: "clock", name: "Clock", icon: "clock.svg", internal: true));
+      apps.insert(
+          0,
+          AppLauncherInfo(
+              id: "weather",
+              name: "Weather",
+              icon: "weather.svg",
+              internal: true));
 
       ref.read(appLauncherListProvider.notifier).update(apps);
     } catch (e) {
@@ -104,5 +113,4 @@ class AppLauncher {
       }
     }
   }
-
 }
index 1670eba..ad3dd22 100644 (file)
@@ -4,8 +4,10 @@ import 'package:flutter_ics_homescreen/data/data_providers/time_notifier.dart';
 import 'package:flutter_ics_homescreen/data/data_providers/units_notifier.dart';
 import 'package:flutter_ics_homescreen/data/data_providers/audio_notifier.dart';
 import 'package:flutter_ics_homescreen/data/data_providers/users_notifier.dart';
+import 'package:flutter_ics_homescreen/data/data_providers/radio_notifier.dart';
 import 'package:flutter_ics_homescreen/data/data_providers/val_client.dart';
 import 'package:flutter_ics_homescreen/data/data_providers/app_launcher.dart';
+import 'package:flutter_ics_homescreen/data/data_providers/radio_client.dart';
 import 'package:flutter_ics_homescreen/export.dart';
 
 import '../models/users.dart';
@@ -16,7 +18,7 @@ enum AppState {
   dashboard,
   hvac,
   apps,
-  mediaPlayer,
+  media,
   settings,
   splash,
   dateTime,
@@ -48,7 +50,14 @@ final appLauncherProvider = Provider((ref) {
   return AppLauncher(ref: ref);
 });
 
-final appLauncherListProvider = NotifierProvider<AppLauncherList, List<AppLauncherInfo>>(AppLauncherList.new);
+final appLauncherListProvider =
+    NotifierProvider<AppLauncherList, List<AppLauncherInfo>>(
+        AppLauncherList.new);
+
+final radioClientProvider = Provider((ref) {
+  RadioConfig config = ref.watch(appConfigProvider).radioConfig;
+  return RadioClient(config: config, ref: ref);
+});
 
 final vehicleProvider =
     NotifierProvider<VehicleNotifier, Vehicle>(VehicleNotifier.new);
@@ -62,7 +71,10 @@ final unitStateProvider = StateNotifierProvider<UnitsNotifier, Units>((ref) {
 });
 
 final audioStateProvider =
-    NotifierProvider<AudioNotifier, Audio>(AudioNotifier.new);
+    NotifierProvider<AudioStateNotifier, AudioState>(AudioStateNotifier.new);
+
+final radioStateProvider =
+    NotifierProvider<RadioStateNotifier, RadioState>(RadioStateNotifier.new);
 
 final usersProvider = StateNotifierProvider<UsersNotifier, Users>((ref) {
   return UsersNotifier(Users.initial());
@@ -77,4 +89,3 @@ final currentTimeProvider =
     StateNotifierProvider<CurrentTimeNotifier, DateTime>((ref) {
   return CurrentTimeNotifier();
 });
-
index 32ab409..a601095 100644 (file)
@@ -1,10 +1,10 @@
 import 'package:flutter_ics_homescreen/export.dart';
-import 'package:protos/protos.dart';
+import 'package:protos/val-api.dart';
 
-class AudioNotifier extends Notifier<Audio> {
+class AudioStateNotifier extends Notifier<AudioState> {
   @override
-  Audio build() {
-    return Audio.initial();
+  AudioState build() {
+    return AudioState.initial();
   }
 
   void resetToDefaults() {
diff --git a/lib/data/data_providers/radio_client.dart b/lib/data/data_providers/radio_client.dart
new file mode 100644 (file)
index 0000000..2cde65e
--- /dev/null
@@ -0,0 +1,161 @@
+import 'package:flutter_ics_homescreen/export.dart';
+import 'package:protos/radio-api.dart' as api;
+
+class RadioClient {
+  final RadioConfig config;
+  final Ref ref;
+  late api.ClientChannel channel;
+  late api.RadioClient stub;
+
+  RadioClient({required this.config, required this.ref}) {
+    debugPrint(
+        "Connecting to radio service at ${config.hostname}:${config.port}");
+    api.ChannelCredentials creds = const api.ChannelCredentials.insecure();
+    channel = api.ClientChannel(config.hostname,
+        port: config.port, options: api.ChannelOptions(credentials: creds));
+    stub = api.RadioClient(channel);
+  }
+
+  void run() async {
+    getBandParameters();
+
+    try {
+      var responseStream = stub.getStatusEvents(api.StatusRequest());
+      await for (var event in responseStream) {
+        handleStatusEvent(event);
+      }
+    } catch (e) {
+      print(e);
+    }
+  }
+
+  void getBandParameters() async {
+    try {
+      var response = await stub.getBandParameters(
+          api.GetBandParametersRequest(band: api.Band.BAND_FM));
+      ref.read(radioStateProvider.notifier).updateBandParameters(
+          freqMin: response.min,
+          freqMax: response.max,
+          freqStep: response.step);
+
+      // Get initial frequency
+      var freqResponse = await stub.getFrequency(api.GetFrequencyRequest());
+      ref
+          .read(radioStateProvider.notifier)
+          .updateFrequency(freqResponse.frequency);
+    } catch (e) {
+      print(e);
+    }
+  }
+
+  void handleStatusEvent(api.StatusResponse response) {
+    switch (response.whichStatus()) {
+      case api.StatusResponse_Status.frequency:
+        var status = response.frequency;
+        ref.read(radioStateProvider.notifier).updateFrequency(status.frequency);
+        break;
+      case api.StatusResponse_Status.play:
+        var status = response.play;
+        ref.read(radioStateProvider.notifier).updatePlaying(status.playing);
+        break;
+      case api.StatusResponse_Status.scan:
+        var status = response.scan;
+        if (status.stationFound) {
+          ref.read(radioStateProvider.notifier).updateScanning(false);
+        }
+        break;
+      default:
+        break;
+    }
+  }
+
+  void start() async {
+    try {
+      var response = await stub.start(api.StartRequest());
+    } catch (e) {
+      print(e);
+    }
+  }
+
+  void stop() async {
+    try {
+      var response = await stub.stop(api.StopRequest());
+    } catch (e) {
+      print(e);
+    }
+  }
+
+  void setFrequency(int frequency) async {
+    var radioState = ref.read(radioStateProvider);
+    if ((frequency < radioState.freqMin) ||
+        (frequency > radioState.freqMax) ||
+        ((frequency - radioState.freqMin) % radioState.freqStep) != 0) {
+      debugPrint("setFrequency: invalid frequency $frequency!");
+      return;
+    }
+    try {
+      var response = await stub
+          .setFrequency(api.SetFrequencyRequest(frequency: frequency));
+    } catch (e) {
+      print(e);
+    }
+  }
+
+  void tuneForward() async {
+    var radioState = ref.read(radioStateProvider);
+    if (radioState.freqCurrent < radioState.freqMax) {
+      int frequency = radioState.freqCurrent + radioState.freqStep;
+      if (frequency > radioState.freqMax) {
+        frequency = radioState.freqMax;
+      }
+      try {
+        var response = await stub
+            .setFrequency(api.SetFrequencyRequest(frequency: frequency));
+      } catch (e) {
+        print(e);
+      }
+    }
+  }
+
+  void tuneBackward() async {
+    var radioState = ref.read(radioStateProvider);
+    if (radioState.freqCurrent > radioState.freqMin) {
+      int frequency = radioState.freqCurrent - radioState.freqStep;
+      if (frequency < radioState.freqMin) {
+        frequency = radioState.freqMin;
+      }
+      try {
+        var response = await stub
+            .setFrequency(api.SetFrequencyRequest(frequency: frequency));
+      } catch (e) {
+        print(e);
+      }
+    }
+  }
+
+  void scanForward() async {
+    try {
+      var response = await stub.scanStart(api.ScanStartRequest(
+          direction: api.ScanDirection.SCAN_DIRECTION_FORWARD));
+    } catch (e) {
+      print(e);
+    }
+  }
+
+  void scanBackward() async {
+    try {
+      var response = await stub.scanStart(api.ScanStartRequest(
+          direction: api.ScanDirection.SCAN_DIRECTION_BACKWARD));
+    } catch (e) {
+      print(e);
+    }
+  }
+
+  void scanStop() async {
+    try {
+      var response = await stub.scanStop(api.ScanStopRequest());
+    } catch (e) {
+      print(e);
+    }
+  }
+}
diff --git a/lib/data/data_providers/radio_notifier.dart b/lib/data/data_providers/radio_notifier.dart
new file mode 100644 (file)
index 0000000..90e0df5
--- /dev/null
@@ -0,0 +1,31 @@
+import 'package:flutter_ics_homescreen/export.dart';
+
+class RadioStateNotifier extends Notifier<RadioState> {
+  @override
+  RadioState build() {
+    return RadioState.initial();
+  }
+
+  void updateBandParameters(
+      {required int freqMin, required freqMax, required freqStep}) {
+    state =
+        state.copyWith(freqMin: freqMin, freqMax: freqMax, freqStep: freqStep);
+  }
+
+  void updateFrequency(int frequency) {
+    state = state.copyWith(freqCurrent: frequency);
+  }
+
+  void setFrequency(int frequency) {
+    state = state.copyWith(freqCurrent: frequency);
+    ref.read(radioClientProvider).setFrequency(frequency);
+  }
+
+  void updatePlaying(bool playing) {
+    state = state.copyWith(playing: playing);
+  }
+
+  void updateScanning(bool scanning) {
+    state = state.copyWith(scanning: scanning);
+  }
+}
diff --git a/lib/data/data_providers/radio_presets_provider.dart b/lib/data/data_providers/radio_presets_provider.dart
new file mode 100644 (file)
index 0000000..9ee68ac
--- /dev/null
@@ -0,0 +1,49 @@
+import 'dart:io';
+import 'package:flutter_ics_homescreen/export.dart';
+import 'package:yaml/yaml.dart';
+
+class RadioPreset {
+  final int frequency;
+  final String name;
+
+  RadioPreset({required this.frequency, required this.name});
+}
+
+class RadioPresets {
+  final List<RadioPreset> fmPresets;
+
+  RadioPresets({required this.fmPresets});
+}
+
+final radioPresetsProvider = Provider((ref) {
+  final presetsFilename = ref.read(appConfigProvider).radioConfig.presets;
+  if (presetsFilename.isEmpty) {
+    return RadioPresets(fmPresets: []);
+  }
+  try {
+    print("Reading radio presets $presetsFilename");
+    var presetsFile = File(presetsFilename);
+    String content = presetsFile.readAsStringSync();
+    final dynamic yamlMap = loadYaml(content);
+
+    List<RadioPreset> presets = [];
+    if (yamlMap.containsKey('fm')) {
+      dynamic list = yamlMap['fm'];
+      if (list is YamlList) {
+        for (var element in list) {
+          if ((element is YamlMap) &&
+              element.containsKey('frequency') &&
+              element.containsKey('name')) {
+            presets.add(RadioPreset(
+                frequency: element['frequency'].toInt(),
+                name: element['name'].toString()));
+          }
+        }
+      }
+    }
+    return RadioPresets(fmPresets: presets);
+  } catch (_) {
+    debugPrint("Exception reading presets!");
+    return RadioPresets(fmPresets: []);
+  }
+});
index 28bb480..db962ee 100644 (file)
@@ -1,5 +1,5 @@
 import 'package:flutter_ics_homescreen/export.dart';
-import 'package:protos/protos.dart';
+import 'package:protos/val-api.dart';
 
 class ValClient {
   final KuksaConfig config;
@@ -9,7 +9,7 @@ class ValClient {
   late String authorization;
 
   ValClient({required this.config, required this.ref}) {
-    debugPrint("Using ${config.hostname}:${config.port}");
+    debugPrint("Connecting to KUKSA.val at ${config.hostname}:${config.port}");
     ChannelCredentials creds;
     if (config.use_tls && config.ca_certificate.isNotEmpty) {
       print("Using TLS");
@@ -25,11 +25,10 @@ class ValClient {
     }
     channel = ClientChannel(config.hostname,
         port: config.port, options: ChannelOptions(credentials: creds));
-    debugPrint('Start Listen on port: ${config.port}');
     stub = VALClient(channel);
   }
 
-  void startListen() async {
+  void run() async {
     List<String> fewSignals = VSSPath().getSignalsList();
     var request = SubscribeRequest();
     Map<String, String> metadata = {};
index 78c5328..6fafb8c 100644 (file)
@@ -3,7 +3,7 @@
 import 'dart:async';
 
 import 'package:flutter_ics_homescreen/export.dart';
-import 'package:protos/protos.dart';
+import 'package:protos/val-api.dart';
 
 class VehicleNotifier extends Notifier<Vehicle> {
   @override
similarity index 79%
rename from lib/data/models/audio.dart
rename to lib/data/models/audio_state.dart
index 65490f9..cfa550b 100644 (file)
@@ -3,13 +3,13 @@ import 'dart:convert';
 import 'package:flutter_ics_homescreen/export.dart';
 
 @immutable
-class Audio {
+class AudioState {
   final double volume;
   final double balance;
   final double fade;
   final double treble;
   final double bass;
-  const Audio({
+  const AudioState({
     required this.volume,
     required this.balance,
     required this.fade,
@@ -17,22 +17,21 @@ class Audio {
     required this.bass,
   });
 
-  const Audio.initial()
+  const AudioState.initial()
       : volume = 5.0,
         balance = 5.0,
         fade = 5.0,
         treble = 5.0,
         bass = 5.0;
-  
 
-  Audio copyWith({
+  AudioState copyWith({
     double? volume,
     double? balance,
     double? fade,
     double? treble,
     double? bass,
   }) {
-    return Audio(
+    return AudioState(
       volume: volume ?? this.volume,
       balance: balance ?? this.balance,
       fade: fade ?? this.fade,
@@ -51,8 +50,8 @@ class Audio {
     };
   }
 
-  factory Audio.fromMap(Map<String, dynamic> map) {
-    return Audio(
+  factory AudioState.fromMap(Map<String, dynamic> map) {
+    return AudioState(
       volume: map['volume']?.toDouble() ?? 0.0,
       balance: map['balance']?.toDouble() ?? 0.0,
       fade: map['fade']?.toDouble() ?? 0.0,
@@ -63,18 +62,19 @@ class Audio {
 
   String toJson() => json.encode(toMap());
 
-  factory Audio.fromJson(String source) => Audio.fromMap(json.decode(source));
+  factory AudioState.fromJson(String source) =>
+      AudioState.fromMap(json.decode(source));
 
   @override
   String toString() {
-    return 'Audio(volume: $volume, balance: $balance, fade: $fade, treble: $treble, bass: $bass)';
+    return 'AudioState(volume: $volume, balance: $balance, fade: $fade, treble: $treble, bass: $bass)';
   }
 
   @override
   bool operator ==(Object other) {
     if (identical(this, other)) return true;
-  
-    return other is Audio &&
+
+    return other is AudioState &&
         other.volume == volume &&
         other.balance == balance &&
         other.fade == fade &&
diff --git a/lib/data/models/radio_state.dart b/lib/data/models/radio_state.dart
new file mode 100644 (file)
index 0000000..dd307d9
--- /dev/null
@@ -0,0 +1,100 @@
+import 'dart:convert';
+
+import 'package:flutter_ics_homescreen/export.dart';
+
+@immutable
+class RadioState {
+  final int freqMin;
+  final int freqMax;
+  final int freqStep;
+  final int freqCurrent;
+  final bool playing;
+  final bool scanning;
+  const RadioState(
+      {required this.freqMin,
+      required this.freqMax,
+      required this.freqStep,
+      required this.freqCurrent,
+      required this.playing,
+      required this.scanning});
+
+  const RadioState.initial()
+      : freqMin = 8790000,
+        freqMax = 1083000,
+        freqStep = 20000,
+        freqCurrent = 8790000,
+        playing = false,
+        scanning = false;
+
+  RadioState copyWith(
+      {int? freqMin,
+      int? freqMax,
+      int? freqStep,
+      int? freqCurrent,
+      bool? playing,
+      bool? scanning}) {
+    return RadioState(
+      freqMin: freqMin ?? this.freqMin,
+      freqMax: freqMax ?? this.freqMax,
+      freqStep: freqStep ?? this.freqStep,
+      freqCurrent: freqCurrent ?? this.freqCurrent,
+      playing: playing ?? this.playing,
+      scanning: scanning ?? this.scanning,
+    );
+  }
+
+  Map<String, dynamic> toMap() {
+    return {
+      'freqMin': freqMin,
+      'freqMax': freqMax,
+      'freqStep': freqStep,
+      'freqCurrent': freqCurrent,
+      'playing': playing,
+      'scanning': scanning,
+    };
+  }
+
+  factory RadioState.fromMap(Map<String, dynamic> map) {
+    return RadioState(
+      freqMin: map['freqMin']?.toInt().toUnsigned() ?? 0,
+      freqMax: map['freqMax']?.toInt().toUnsigned() ?? 0,
+      freqStep: map['freqStep']?.toInt().toUnsigned() ?? 0,
+      freqCurrent: map['freqCurrent']?.toInt().toUnsigned() ?? 0,
+      playing: map['playing']?.toBool() ?? false,
+      scanning: map['scanning']?.toBool() ?? false,
+    );
+  }
+
+  String toJson() => json.encode(toMap());
+
+  factory RadioState.fromJson(String source) =>
+      RadioState.fromMap(json.decode(source));
+
+  @override
+  String toString() {
+    return 'RadioState(freqMin: $freqMin, freqMax: $freqMax, freqStep: $freqStep, freqCurrent: $freqCurrent, playing: $playing, scanning: $scanning)';
+  }
+
+  @override
+  bool operator ==(Object other) {
+    if (identical(this, other)) return true;
+
+    return other is RadioState &&
+        other.freqMin == freqMin &&
+        other.freqMax == freqMax &&
+        other.freqStep == freqStep &&
+        other.freqCurrent == freqCurrent &&
+        other.playing == playing &&
+        other.scanning == scanning;
+  }
+
+  @override
+  int get hashCode {
+    return freqMin.hashCode ^
+        freqMax.hashCode ^
+        freqStep.hashCode ^
+        freqCurrent.hashCode ^
+        playing.hashCode ^
+        scanning.hashCode;
+  }
+}
index 1e07f3f..a5c5626 100644 (file)
@@ -8,7 +8,8 @@ export 'data/theme/theme.dart';
 //Models
 export 'data/models/vehicle.dart';
 export 'data/models/units.dart';
-export 'data/models/audio.dart';
+export 'data/models/audio_state.dart';
+export 'data/models/radio_state.dart';
 export 'data/models/connections_signals.dart';
 export 'data/models/hybrid.dart';
 
@@ -25,7 +26,7 @@ export 'presentation/screens/dashboard/widgets/child_lock.dart';
 export 'presentation/screens/dashboard/widgets/hybrid_mode.dart';
 export 'presentation/common_widget/custom_bottom_bar.dart';
 export 'presentation/common_widget/custom_top_bar.dart';
-export 'presentation/screens/media_player/media_player.dart';
+export 'presentation/screens/media/media.dart';
 export 'presentation/screens/hvac/hvac.dart';
 export 'presentation/screens/settings/settings.dart';
 export 'presentation/screens/settings/widgets/settings_list_tile.dart';
@@ -44,13 +45,7 @@ export 'package:flutter_ics_homescreen/presentation/screens/settings/settings_sc
 export 'presentation/screens/apps/apps.dart';
 export 'presentation/screens/splash/splash.dart';
 export 'presentation/screens/splash/widget/splash_content.dart';
-//export 'presentation/screens/apps/apps_content.dart';
 export 'presentation/screens/hvac/hvac_content.dart';
-export 'presentation/screens/media_player/media_controls.dart';
-export 'presentation/screens/media_player/play_list_table.dart';
-export 'presentation/screens/media_player/player_navigation.dart';
-export 'presentation/screens/media_player/segmented_buttons.dart';
-export 'presentation/screens/media_player/media_content.dart';
 export 'presentation/screens/hvac/widgets/climate_controls.dart';
 export 'presentation/screens/hvac/widgets/fan_focus.dart';
 export 'presentation/screens/hvac/widgets/fan_speed_controls.dart';
index 61a7e20..19c56b9 100644 (file)
@@ -35,7 +35,7 @@ class CustomBottomBarState extends ConsumerState<CustomBottomBar> {
       case "HVAC":
         status = AppState.hvac;
       case "Media":
-        status = AppState.mediaPlayer;
+        status = AppState.media;
       case "Settings":
         status = AppState.settings;
       case "Apps":
index 051e360..b38e303 100644 (file)
@@ -20,7 +20,7 @@ class VolumeFanControl extends ConsumerWidget {
         mainAxisAlignment: MainAxisAlignment.center,
         children: [
           Visibility.maintain(
-              visible: state == AppState.mediaPlayer ? false : true,
+              visible: state == AppState.media ? false : true,
               child: const VolumeBar()),
           SizedBox(
             height: gapSize,
index 57e50d2..45a1a14 100644 (file)
@@ -17,8 +17,8 @@ List<Page<dynamic>> onGenerateAppViewPages(
       return [HvacPage.page()];
     case AppState.apps:
       return [AppsPage.page()];
-    case AppState.mediaPlayer:
-      return [MediaPlayerPage.page()];
+    case AppState.media:
+      return [MediaPage.page()];
     case AppState.settings:
       return [SettingsPage.page()];
     case AppState.splash:
@@ -1,13 +1,14 @@
-import 'package:flutter_ics_homescreen/presentation/screens/media_player/fm_player.dart';
-
-import '/export.dart';
+import 'package:flutter_ics_homescreen/export.dart';
+import 'package:flutter_ics_homescreen/presentation/screens/media/media_player.dart';
+import 'package:flutter_ics_homescreen/presentation/screens/media/radio_player.dart';
 import 'widgets/media_volume_bar.dart';
+import 'media_nav_notifier.dart';
+import 'player_navigation.dart';
 
-class MediaPlayerPage extends StatelessWidget {
-  const MediaPlayerPage({super.key});
+class MediaPage extends StatelessWidget {
+  const MediaPage({super.key});
 
-  static Page<void> page() =>
-      const MaterialPage<void>(child: MediaPlayerPage());
+  static Page<void> page() => const MaterialPage<void>(child: MediaPage());
   @override
   Widget build(BuildContext context) {
     Size size = MediaQuery.sizeOf(context);
@@ -21,7 +22,7 @@ class MediaPlayerPage extends StatelessWidget {
         //   // decoration:
         //   //   BoxDecoration(gradient: AGLDemoColors.gradientBackgroundColor),
         //   child: SvgPicture.asset(
-        //     'assets/MediaPlayerBackground.svg',
+        //     'assets/Media.svg',
         //     alignment: Alignment.center,
         //     fit: BoxFit.cover,
         //     //width: 200,
@@ -42,31 +43,45 @@ class MediaPlayerPage extends StatelessWidget {
         ),
         const Padding(
           padding: EdgeInsets.symmetric(vertical: 50, horizontal: 50),
-          child: MediaPlayerBackground(),
+          child: Media(),
         )
-        //const MediaPlayer(),
       ],
     );
   }
 }
 
-class MediaPlayerBackground extends StatefulWidget {
-  const MediaPlayerBackground({super.key});
+class Media extends ConsumerStatefulWidget {
+  const Media({super.key});
 
   @override
-  State<MediaPlayerBackground> createState() => _MediaPlayerBackgroundState();
+  ConsumerState<Media> createState() => _MediaState();
 }
 
-class _MediaPlayerBackgroundState extends State<MediaPlayerBackground> {
-  String selectedNav = "My Media";
-  onPressed(type) {
+class _MediaState extends ConsumerState<Media> {
+  //late MediaNavState selectedNav;
+
+  //@override
+  //initState() {
+  //  selectedNav = ref.read(mediaNavStateProvider);
+  //  super.initState();
+  //}
+
+  onPressed(MediaNavState type) {
     setState(() {
-      selectedNav = type;
+      if (type == MediaNavState.fm) {
+        ref.read(mediaNavStateProvider.notifier).set(MediaNavState.fm);
+        ref.read(radioClientProvider).start();
+      } else if (type == MediaNavState.media) {
+        ref.read(mediaNavStateProvider.notifier).set(MediaNavState.media);
+        ref.read(radioClientProvider).stop();
+      }
     });
   }
 
   @override
   Widget build(BuildContext context) {
+    var navState = ref.watch(mediaNavStateProvider);
+
     return SingleChildScrollView(
       child: Column(
         children: [
@@ -81,14 +96,14 @@ class _MediaPlayerBackgroundState extends State<MediaPlayerBackground> {
           Padding(
             padding: const EdgeInsets.symmetric(horizontal: 80),
             child: SingleChildScrollView(
-              child: selectedNav == "My Media"
+              child: navState == MediaNavState.media
                   ? const MediaPlayer()
-                  : selectedNav == "FM"
-                      ? const FMPlayer()
+                  : navState == MediaNavState.fm
+                      ? const RadioPlayer()
                       : Container(),
             ),
           ),
-          if (selectedNav == "My Media" || selectedNav == "FM")
+          if (navState == MediaNavState.media || navState == MediaNavState.fm)
             const Padding(
               padding: EdgeInsets.symmetric(horizontal: 144, vertical: 23.5),
               child: CustomVolumeSlider(),
diff --git a/lib/presentation/screens/media/media_nav_notifier.dart b/lib/presentation/screens/media/media_nav_notifier.dart
new file mode 100644 (file)
index 0000000..6f93850
--- /dev/null
@@ -0,0 +1,18 @@
+import 'package:flutter_ics_homescreen/export.dart';
+
+enum MediaNavState { media, fm, am, xm }
+
+class MediaNavStateNotifier extends Notifier<MediaNavState> {
+  @override
+  MediaNavState build() {
+    return MediaNavState.media;
+  }
+
+  set(MediaNavState value) {
+    state = value;
+  }
+}
+
+final mediaNavStateProvider =
+    NotifierProvider<MediaNavStateNotifier, MediaNavState>(
+        MediaNavStateNotifier.new);
@@ -1,4 +1,7 @@
 import 'package:flutter_ics_homescreen/export.dart';
+import 'media_player_controls.dart';
+import 'play_list_table.dart';
+import 'segmented_buttons.dart';
 
 class MediaPlayer extends StatefulWidget {
   const MediaPlayer({super.key});
@@ -31,7 +34,7 @@ class _MediaPlayerState extends State<MediaPlayer> {
     return Column(
       crossAxisAlignment: CrossAxisAlignment.stretch,
       children: [
-        //    const PlayerNavigation(),
+        //const PlayerNavigation(),
         SegmentedButtons(
           navItems: navItems,
           selectedNav: selectedNav,
@@ -55,12 +58,10 @@ class _MediaPlayerState extends State<MediaPlayer> {
         Column(
           crossAxisAlignment: CrossAxisAlignment.stretch,
           children: [
-            MediaControls(
-              songName: songName,
-              songLengthStart: "-1:23",
-              songLengthStop: "5:03",
-              type: "media",
-            ),
+            MediaPlayerControls(
+                songName: songName,
+                songLengthStart: "-1:23",
+                songLengthStop: "5:03"),
             const SizedBox(
               height: 72,
             ),
diff --git a/lib/presentation/screens/media/media_player_controls.dart b/lib/presentation/screens/media/media_player_controls.dart
new file mode 100644 (file)
index 0000000..518b669
--- /dev/null
@@ -0,0 +1,235 @@
+import 'package:flutter_ics_homescreen/core/utils/helpers.dart';
+import 'package:flutter_ics_homescreen/export.dart';
+import 'package:flutter_ics_homescreen/presentation/screens/media/widgets/gradient_progress_indicator.dart';
+
+class MediaPlayerControls extends StatefulWidget {
+  const MediaPlayerControls(
+      {super.key,
+      required this.songName,
+      required this.songLengthStart,
+      required this.songLengthStop});
+
+  final String songName;
+  final String songLengthStart;
+  final String songLengthStop;
+
+  @override
+  State<MediaPlayerControls> createState() => _MediaPlayerControlsState();
+}
+
+class _MediaPlayerControlsState extends State<MediaPlayerControls> {
+  late String songName;
+  late String songLengthStart;
+  late String songLengthStop;
+  final String albumName = "Gorillaz";
+
+  int songProgress = 20;
+
+  @override
+  void initState() {
+    songName = widget.songName;
+    songLengthStart = widget.songLengthStart;
+    songLengthStop = widget.songLengthStop;
+    super.initState();
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return Material(
+      color: Colors.transparent,
+      child: Column(crossAxisAlignment: CrossAxisAlignment.stretch, children: [
+        Text(
+          songName,
+          style: TextStyle(
+              color: Colors.white,
+              fontWeight: FontWeight.w400,
+              shadows: [Helpers.dropShadowRegular],
+              fontSize: 44),
+        ),
+        MediaPlayerControlsubDetails(
+          albumName: albumName,
+        ),
+        Column(children: [
+          GradientProgressIndicator(
+            percent: songProgress,
+            type: "media",
+            gradient: LinearGradient(
+                begin: Alignment.centerLeft,
+                end: Alignment.centerRight,
+                colors: [
+                  AGLDemoColors.jordyBlueColor,
+                  AGLDemoColors.jordyBlueColor.withOpacity(0.8),
+                ]),
+            backgroundColor: AGLDemoColors.gradientBackgroundDarkColor,
+          ),
+          // const LinearProgressIndicator(
+          //   backgroundColor: AGLDemoColors.gradientBackgroundDarkColor,
+          //   color: Colors.white70,
+          //   minHeight: 8,
+          //   value: 0.7,
+          // ),
+          Padding(
+            padding: const EdgeInsets.symmetric(vertical: 5),
+            child: Row(
+              mainAxisAlignment: MainAxisAlignment.spaceBetween,
+              children: [
+                Text(
+                  songLengthStart,
+                  style: TextStyle(
+                      color: Colors.white,
+                      fontSize: 26,
+                      shadows: [Helpers.dropShadowRegular]),
+                ),
+                Text(
+                  songLengthStop,
+                  style: TextStyle(
+                      color: Colors.white,
+                      fontSize: 26,
+                      shadows: [Helpers.dropShadowRegular]),
+                )
+              ],
+            ),
+          ),
+        ]),
+        const MediaPlayerActions(),
+      ]),
+    );
+  }
+}
+
+class MediaPlayerControlsubDetails extends StatefulWidget {
+  const MediaPlayerControlsubDetails({super.key, required this.albumName});
+  final String albumName;
+
+  @override
+  State<MediaPlayerControlsubDetails> createState() =>
+      _MediaPlayerControlsubDetailsState();
+}
+
+class _MediaPlayerControlsubDetailsState
+    extends State<MediaPlayerControlsubDetails> {
+  bool isShuffleEnabled = false;
+  bool isRepeatEnabled = false;
+  @override
+  Widget build(BuildContext context) {
+    return Row(
+      mainAxisAlignment: MainAxisAlignment.spaceBetween,
+      children: [
+        Text(
+          widget.albumName,
+          style: TextStyle(
+              color: Colors.white,
+              fontWeight: FontWeight.w400,
+              fontSize: 40,
+              shadows: [Helpers.dropShadowRegular]),
+        ),
+        Row(
+          children: [
+            InkWell(
+                customBorder: const CircleBorder(),
+                onTap: () {
+                  setState(() {
+                    isShuffleEnabled = !isShuffleEnabled;
+                  });
+                },
+                child: Padding(
+                    padding: const EdgeInsets.all(8.0),
+                    child: SvgPicture.asset(
+                      "assets/${isShuffleEnabled ? "ShufflePressed.svg" : "Shuffle.svg"}",
+                      width: 48,
+                    ))),
+            InkWell(
+                customBorder: const CircleBorder(),
+                onTap: () {
+                  setState(() {
+                    isRepeatEnabled = !isRepeatEnabled;
+                  });
+                },
+                child: Padding(
+                    padding: const EdgeInsets.all(8.0),
+                    child: SvgPicture.asset(
+                      "assets/${isRepeatEnabled ? "RepeatPressed.svg" : "Repeat.svg"}",
+                      width: 48,
+                    ))),
+          ],
+        )
+      ],
+    );
+  }
+}
+
+class MediaPlayerActions extends StatefulWidget {
+  const MediaPlayerActions({super.key});
+
+  @override
+  State<MediaPlayerActions> createState() => _MediaPlayerActionsState();
+}
+
+class _MediaPlayerActionsState extends State<MediaPlayerActions> {
+  bool isPressed = false;
+  bool isPlaying = true;
+
+  @override
+  Widget build(BuildContext context) {
+    return Row(
+      mainAxisAlignment: MainAxisAlignment.center,
+      children: [
+        InkWell(
+            customBorder: const CircleBorder(),
+            onTap: () {},
+            child: Padding(
+              padding: const EdgeInsets.all(8.0),
+              child: SvgPicture.asset(
+                "assets/SkipPrevious.svg",
+                width: 48,
+              ),
+            )),
+        const SizedBox(
+          width: 120,
+        ),
+        InkWell(
+            customBorder: const CircleBorder(),
+            onTap: () {
+              setState(() {
+                isPlaying = !isPlaying;
+              });
+            },
+            onTapDown: (details) {
+              setState(() {
+                isPressed = true;
+              });
+            },
+            onTapUp: (details) {
+              isPressed = false;
+            },
+            child: Container(
+              width: 64,
+              height: 64,
+              decoration: BoxDecoration(
+                  shape: BoxShape.circle,
+                  color:
+                      isPressed ? Colors.white : AGLDemoColors.periwinkleColor,
+                  boxShadow: [Helpers.boxDropShadowRegular]),
+              child: Icon(
+                isPlaying ? Icons.pause : Icons.play_arrow,
+                color: AGLDemoColors.resolutionBlueColor,
+                size: 60,
+              ),
+            )),
+        const SizedBox(
+          width: 120,
+        ),
+        InkWell(
+            customBorder: const CircleBorder(),
+            onTap: () {},
+            child: Padding(
+              padding: const EdgeInsets.all(8.0),
+              child: SvgPicture.asset(
+                "assets/SkipNext.svg",
+                width: 48,
+              ),
+            )),
+      ],
+    );
+  }
+}
@@ -23,6 +23,7 @@ class _PlayListTableState extends State<PlayListTable> {
   late String tableName;
   late List<PlayListModel> playList;
   late String selectedPlayListSongName;
+
   @override
   void initState() {
     tableName = widget.tableName;
@@ -1,19 +1,30 @@
 import 'package:flutter_ics_homescreen/core/utils/helpers.dart';
 import 'package:flutter_ics_homescreen/export.dart';
+import 'media_nav_notifier.dart';
 
-class PlayerNavigation extends StatefulWidget {
+class PlayerNavigation extends ConsumerStatefulWidget {
   const PlayerNavigation({super.key, required this.onPressed});
   final Function onPressed;
 
   @override
-  State<PlayerNavigation> createState() => _PlayerNavigationState();
+  ConsumerState<PlayerNavigation> createState() => _PlayerNavigationState();
 }
 
-class _PlayerNavigationState extends State<PlayerNavigation> {
+class _PlayerNavigationState extends ConsumerState<PlayerNavigation> {
   List<String> navItems = ["My Media", "FM", "AM", "XM"];
-  String selectedNav = "My Media";
+  Map<MediaNavState, String> navStateMap = {
+    MediaNavState.media: "My Media",
+    MediaNavState.fm: "FM",
+    MediaNavState.am: "AM",
+    MediaNavState.xm: "XM"
+  };
+  //String selectedNav = "My Media";
+
   @override
   Widget build(BuildContext context) {
+    var navState = ref.watch(mediaNavStateProvider);
+    var selectedNav = navStateMap[navState];
+
     return Row(
         children: navItems
             .map((e) => Expanded(
@@ -35,9 +46,16 @@ class _PlayerNavigationState extends State<PlayerNavigation> {
                     child: InkWell(
                       onTap: () {
                         setState(() {
-                          selectedNav = e;
+                          if (e == "My Media" || e == "FM") {
+                            selectedNav = e;
+                          }
                         });
-                        widget.onPressed(selectedNav);
+                        if (e == "My Media" || e == "FM") {
+                          for (MapEntry<MediaNavState, String> me
+                              in navStateMap.entries) {
+                            if (me.value == e) widget.onPressed(me.key);
+                          }
+                        }
                       },
                       child: Container(
                         padding: const EdgeInsets.symmetric(vertical: 7),
@@ -1,25 +1,37 @@
+import 'package:flutter_ics_homescreen/data/data_providers/radio_presets_provider.dart';
 import 'package:flutter_ics_homescreen/export.dart';
+import 'radio_player_controls.dart';
+import 'radio_preset_table.dart';
+import 'segmented_buttons.dart';
 
-class FMPlayer extends StatefulWidget {
-  const FMPlayer({super.key});
+class RadioPlayer extends ConsumerStatefulWidget {
+  const RadioPlayer({super.key});
 
   @override
-  State<FMPlayer> createState() => _FMPlayerState();
+  ConsumerState<RadioPlayer> createState() => _RadioPlayerState();
 }
 
-class _FMPlayerState extends State<FMPlayer> {
+class _RadioPlayerState extends ConsumerState<RadioPlayer> {
   String selectedNav = "Standard";
   List<String> navItems = [
     "Standard",
     "HD",
   ];
   String tableName = "Presets";
-  List<PlayListModel> playList = [
-    PlayListModel(songName: "93.1 The Mountain", albumName: "93.1"),
-    PlayListModel(songName: "Mix 94.1", albumName: "94.1 MHz"),
-    PlayListModel(songName: "96.3 KKLZ", albumName: "96.3 MHz"),
-  ];
-  String selectedPlayListSongName = "93.1 The Mountain";
+  late List<RadioPreset> presets;
+  late String selectedPreset;
+
+  @override
+  void initState() {
+    presets = ref.read(radioPresetsProvider).fmPresets;
+    if (presets.isNotEmpty) {
+      selectedPreset = presets.first.name;
+    } else {
+      selectedPreset = "";
+    }
+    super.initState();
+  }
+
   @override
   Widget build(BuildContext context) {
     double fmSignalHeight = 460;
@@ -52,21 +64,14 @@ class _FMPlayerState extends State<FMPlayer> {
           ),
           Column(
             children: [
-              const MediaControls(
-                songName: "87.9",
-                songLengthStart: "87.9 MHz",
-                songLengthStop: "87.9 MHz",
-                type: "fm",
-              ),
+              const RadioPlayerControls(),
               const SizedBox(
                 height: 70,
               ),
-              PlayListTable(
-                playList: playList,
-                selectedPlayListSongName: selectedPlayListSongName,
-                tableName: tableName,
-                type: "fm",
-              ),
+              RadioPresetTable(
+                  presets: presets,
+                  selectedPreset: selectedPreset,
+                  tableName: tableName),
             ],
           )
         ],
diff --git a/lib/presentation/screens/media/radio_player_controls.dart b/lib/presentation/screens/media/radio_player_controls.dart
new file mode 100644 (file)
index 0000000..bfa8da6
--- /dev/null
@@ -0,0 +1,251 @@
+import 'package:flutter_ics_homescreen/core/utils/helpers.dart';
+import 'package:flutter_ics_homescreen/export.dart';
+import 'package:flutter_ics_homescreen/presentation/screens/settings/settings_screens/audio_settings/widget/slider_widgets.dart';
+
+class RadioPlayerControls extends ConsumerWidget {
+  const RadioPlayerControls({super.key});
+
+  @override
+  Widget build(BuildContext context, WidgetRef ref) {
+    var freqCurrent =
+        ref.watch(radioStateProvider.select((radio) => radio.freqCurrent));
+    String currentString = (freqCurrent / 1000000.0).toStringAsFixed(1);
+
+    return Material(
+      color: Colors.transparent,
+      child: Column(
+        crossAxisAlignment: CrossAxisAlignment.stretch,
+        children: [
+          Text(
+            currentString,
+            style: TextStyle(
+                color: Colors.white,
+                fontWeight: FontWeight.w400,
+                shadows: [Helpers.dropShadowRegular],
+                fontSize: 44),
+          ),
+          const RadioPlayerControlsSubDetails(),
+          const RadioPlayerControlsSlider(),
+        ],
+      ),
+    );
+  }
+}
+
+class RadioPlayerControlsSubDetails extends ConsumerWidget {
+  const RadioPlayerControlsSubDetails({super.key});
+
+  onPressed({required WidgetRef ref, required String type}) {
+    if (type == "tuneLeft") {
+      ref.read(radioClientProvider).tuneBackward();
+    } else if (type == "tuneRight") {
+      ref.read(radioClientProvider).tuneForward();
+    } else if (type == "scanLeft") {
+      bool playing =
+          ref.read(radioStateProvider.select((radio) => radio.playing));
+      if (playing) {
+        ref.read(radioClientProvider).scanBackward();
+      }
+    } else if (type == "scanRight") {
+      bool playing =
+          ref.read(radioStateProvider.select((radio) => radio.playing));
+      if (playing) {
+        ref.read(radioClientProvider).scanForward();
+      }
+    }
+  }
+
+  @override
+  Widget build(BuildContext context, WidgetRef ref) {
+    return Padding(
+      padding: const EdgeInsets.only(bottom: 5),
+      child: Row(
+        mainAxisAlignment: MainAxisAlignment.spaceBetween,
+        children: [
+          Row(
+            children: [
+              Text(
+                "Tune",
+                style: TextStyle(
+                    color: Colors.white,
+                    fontWeight: FontWeight.w400,
+                    fontSize: 40,
+                    shadows: [Helpers.dropShadowRegular]),
+              ),
+              const SizedBox(
+                width: 25,
+              ),
+              InkWell(
+                  customBorder: const CircleBorder(),
+                  onTap: () {
+                    onPressed(ref: ref, type: "tuneLeft");
+                  },
+                  child: const Padding(
+                      padding: EdgeInsets.all(8.0),
+                      child: Icon(
+                        Icons.arrow_back,
+                        size: 48,
+                        color: AGLDemoColors.periwinkleColor,
+                      ))),
+              const SizedBox(
+                width: 25,
+              ),
+              InkWell(
+                  customBorder: const CircleBorder(),
+                  onTap: () {
+                    onPressed(ref: ref, type: "tuneRight");
+                  },
+                  child: const Padding(
+                      padding: EdgeInsets.all(8.0),
+                      child: Icon(
+                        Icons.arrow_forward,
+                        color: AGLDemoColors.periwinkleColor,
+                        size: 48,
+                      ))),
+            ],
+          ),
+          Row(
+            children: [
+              Text(
+                "Scan",
+                style: TextStyle(
+                    color: Colors.white,
+                    fontWeight: FontWeight.w400,
+                    fontSize: 40,
+                    shadows: [Helpers.dropShadowRegular]),
+              ),
+              const SizedBox(
+                width: 25,
+              ),
+              InkWell(
+                  customBorder: const CircleBorder(),
+                  onTap: () {
+                    onPressed(ref: ref, type: "scanLeft");
+                  },
+                  child: const Padding(
+                      padding: EdgeInsets.all(8.0),
+                      child: Icon(
+                        Icons.arrow_back,
+                        color: AGLDemoColors.periwinkleColor,
+                        size: 48,
+                      ))),
+              const SizedBox(
+                width: 25,
+              ),
+              InkWell(
+                  customBorder: const CircleBorder(),
+                  onTap: () {
+                    onPressed(ref: ref, type: "scanRight");
+                  },
+                  child: const Padding(
+                      padding: EdgeInsets.all(8.0),
+                      child: Icon(
+                        Icons.arrow_forward,
+                        color: AGLDemoColors.periwinkleColor,
+                        size: 48,
+                      ))),
+            ],
+          )
+        ],
+      ),
+    );
+  }
+}
+
+class RadioPlayerControlsSlider extends ConsumerStatefulWidget {
+  const RadioPlayerControlsSlider({super.key});
+
+  @override
+  ConsumerState<RadioPlayerControlsSlider> createState() =>
+      RadioPlayerControlsSliderState();
+}
+
+class RadioPlayerControlsSliderState
+    extends ConsumerState<RadioPlayerControlsSlider> {
+  @override
+  Widget build(BuildContext context) {
+    var freqMin =
+        ref.watch(radioStateProvider.select((radio) => radio.freqMin));
+    var freqMax =
+        ref.watch(radioStateProvider.select((radio) => radio.freqMax));
+    var freqStep =
+        ref.watch(radioStateProvider.select((radio) => radio.freqStep));
+    var currentFreq =
+        ref.watch(radioStateProvider.select((radio) => radio.freqCurrent)) /
+            1000000.0;
+
+    String minString = (freqMin / 1000000.0).toStringAsFixed(1);
+    String maxString = (freqMax / 1000000.0).toStringAsFixed(1);
+
+    return Padding(
+        padding: const EdgeInsets.symmetric(horizontal: 64),
+        child: Container(
+          decoration: const ShapeDecoration(
+            color: AGLDemoColors.buttonFillEnabledColor,
+            shape: StadiumBorder(
+                side: BorderSide(
+              color: Color(0xFF5477D4),
+              width: 0.5,
+            )),
+          ),
+          height: 160,
+          child: Row(
+            children: [
+              Padding(
+                  padding: const EdgeInsets.symmetric(horizontal: 20),
+                  child: Text(
+                    minString,
+                    style: TextStyle(
+                        color: Colors.white,
+                        fontSize: 32,
+                        shadows: [Helpers.dropShadowRegular]),
+                  )),
+              Expanded(
+                child: SliderTheme(
+                  data: SliderThemeData(
+                    overlayShape: SliderComponentShape.noOverlay,
+                    valueIndicatorShape: SliderComponentShape.noOverlay,
+                    activeTickMarkColor: Colors.transparent,
+                    inactiveTickMarkColor: Colors.transparent,
+                    inactiveTrackColor: AGLDemoColors.backgroundInsetColor,
+                    thumbShape: const PolygonSliderThumb(
+                        sliderValue: 3, thumbRadius: 23),
+                    //trackHeight: 5,
+                  ),
+                  child: Slider(
+                    divisions: (freqMax - freqMin) ~/ freqStep,
+                    min: freqMin / 1000000.0,
+                    max: freqMax / 1000000.0,
+                    value: currentFreq,
+                    onChangeStart: (double value) {
+                      ref.read(radioClientProvider).scanStop();
+                    },
+                    onChanged: (double value) {
+                      setState(() {
+                        ref
+                            .read(radioStateProvider.notifier)
+                            .updateFrequency((value * 1000000.0).toInt());
+                      });
+                    },
+                    onChangeEnd: (double value) {
+                      ref
+                          .read(radioStateProvider.notifier)
+                          .setFrequency((value * 1000000.0).toInt());
+                    },
+                  ),
+                ),
+              ),
+              Padding(
+                  padding: const EdgeInsets.symmetric(horizontal: 20),
+                  child: Text(
+                    maxString,
+                    style: TextStyle(
+                        color: Colors.white,
+                        fontSize: 32,
+                        shadows: [Helpers.dropShadowRegular]),
+                  )),
+            ],
+          ),
+        ));
+  }
+}
diff --git a/lib/presentation/screens/media/radio_preset_table.dart b/lib/presentation/screens/media/radio_preset_table.dart
new file mode 100644 (file)
index 0000000..816bcb9
--- /dev/null
@@ -0,0 +1,151 @@
+import 'package:auto_size_text/auto_size_text.dart';
+import 'package:flutter_ics_homescreen/core/utils/helpers.dart';
+import 'package:flutter_ics_homescreen/export.dart';
+import 'package:flutter_ics_homescreen/data/data_providers/radio_presets_provider.dart';
+
+class RadioPresetTable extends ConsumerStatefulWidget {
+  const RadioPresetTable(
+      {super.key,
+      required this.tableName,
+      required this.presets,
+      required this.selectedPreset});
+
+  final String tableName;
+  final List<RadioPreset> presets;
+  final String selectedPreset;
+
+  @override
+  ConsumerState<RadioPresetTable> createState() => _RadioPresetTableState();
+}
+
+class _RadioPresetTableState extends ConsumerState<RadioPresetTable> {
+  bool isAudioSettingsEnabled = false;
+  late String tableName;
+  late List<RadioPreset> presets;
+  late String selectedPreset;
+
+  @override
+  void initState() {
+    tableName = widget.tableName;
+    presets = widget.presets;
+    selectedPreset = widget.selectedPreset;
+    super.initState();
+  }
+
+  String frequencyToString(int frequency) {
+    return "${(frequency / 1000000.0).toStringAsFixed(1)} MHz";
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return Material(
+        color: Colors.transparent,
+        child: Column(
+          crossAxisAlignment: CrossAxisAlignment.stretch,
+          children: [
+            Row(
+              mainAxisAlignment: MainAxisAlignment.spaceBetween,
+              children: [
+                Row(
+                  children: [
+                    Text(
+                      tableName,
+                      style: const TextStyle(
+                          color: Colors.white,
+                          fontWeight: FontWeight.w400,
+                          fontSize: 40),
+                    ),
+                  ],
+                ),
+                InkWell(
+                    customBorder: const CircleBorder(),
+                    onTap: () {
+                      setState(() {
+                        isAudioSettingsEnabled = !isAudioSettingsEnabled;
+                      });
+                    },
+                    child: Padding(
+                        padding: const EdgeInsets.all(8.0),
+                        child: SvgPicture.asset(
+                          "assets/${isAudioSettingsEnabled ? "AudioSettingsPressed.svg" : "AudioSettings.svg"}",
+                          width: 48,
+                        )))
+              ],
+            ),
+            SizedBox(
+              height: 325,
+              child: SingleChildScrollView(
+                child: Column(
+                    children: presets.map((index) {
+                  return Container(
+                    height: 100,
+                    margin: const EdgeInsets.symmetric(vertical: 4),
+                    decoration: BoxDecoration(
+                        border: Border(
+                            left: selectedPreset == index.name
+                                ? const BorderSide(
+                                    color: Colors.white, width: 4)
+                                : BorderSide.none),
+                        gradient: LinearGradient(
+                            colors: selectedPreset == index.name
+                                ? [
+                                    AGLDemoColors.neonBlueColor,
+                                    AGLDemoColors.neonBlueColor
+                                        .withOpacity(0.15)
+                                  ]
+                                : [
+                                    Colors.black,
+                                    Colors.black.withOpacity(0.20)
+                                  ])),
+                    child: InkWell(
+                      onTap: () {
+                        ref
+                            .read(radioClientProvider)
+                            .setFrequency(index.frequency);
+                        setState(() {
+                          selectedPreset = index.name;
+                        });
+                      },
+                      child: Padding(
+                        padding: const EdgeInsets.symmetric(
+                            vertical: 17, horizontal: 24),
+                        child: Row(
+                          children: [
+                            Expanded(
+                                flex: 6,
+                                child: AutoSizeText(
+                                  index.name,
+                                  maxLines: 1,
+                                  style: TextStyle(
+                                      color: Colors.white,
+                                      fontSize: 40,
+                                      shadows: [Helpers.dropShadowRegular]),
+                                )),
+                            Expanded(
+                                flex: 4,
+                                child: Text(
+                                  frequencyToString(index.frequency),
+                                  style: TextStyle(
+                                      color: Colors.white,
+                                      fontSize: 26,
+                                      shadows: [Helpers.dropShadowRegular]),
+                                ))
+                          ],
+                        ),
+                      ),
+                    ),
+                  );
+                }).toList()),
+              ),
+            ),
+          ],
+        ));
+  }
+}
+
+class PlayListModel {
+  final String songName;
+  final String albumName;
+
+  PlayListModel({required this.songName, required this.albumName});
+}
@@ -23,7 +23,7 @@ class CustomVolumeSliderState extends ConsumerState<CustomVolumeSlider> {
     });
   }
 
-  void _dercrease() {
+  void _decrease() {
     _currentVal -= 10;
     if (_currentVal < 0) {
       _currentVal = 0;
@@ -34,6 +34,7 @@ class CustomVolumeSliderState extends ConsumerState<CustomVolumeSlider> {
   }
 
   double _currentVal = 50;
+
   @override
   Widget build(BuildContext context) {
     final volumeValue =
@@ -61,7 +62,7 @@ class CustomVolumeSliderState extends ConsumerState<CustomVolumeSlider> {
                   child: InkWell(
                       customBorder: const CircleBorder(),
                       onTap: () {
-                        _dercrease();
+                        _decrease();
                       },
                       child: const Padding(
                           padding: EdgeInsets.all(8.0),
@@ -72,22 +73,6 @@ class CustomVolumeSliderState extends ConsumerState<CustomVolumeSlider> {
                           ))),
                 ),
               ),
-              // Padding(
-              //   padding: const EdgeInsets.only(left: 10.0),
-              //   child: SizedBox(
-              //     width: 50,
-              //     child: IconButton(
-              //         padding: EdgeInsets.zero,
-              //         onPressed: () {
-              //           _dercrease();
-              //         },
-              //         icon: const Icon(
-              //           CustomIcons.vol_min,
-              //           color: AGLDemoColors.periwinkleColor,
-              //           size: 48,
-              //         )),
-              //   ),
-              // ),
               Expanded(
                 child: SliderTheme(
                   data: SliderThemeData(
@@ -130,22 +115,6 @@ class CustomVolumeSliderState extends ConsumerState<CustomVolumeSlider> {
                           ))),
                 ),
               ),
-              // Padding(
-              //   padding: const EdgeInsets.only(right: 10.0),
-              //   child: SizedBox(
-              //     width: 60,
-              //     child: IconButton(
-              //         padding: EdgeInsets.zero,
-              //         onPressed: () {
-              //           _increase();
-              //         },
-              //         icon: const Icon(
-              //           CustomIcons.vol_max,
-              //           color: AGLDemoColors.periwinkleColor,
-              //           size: 48,
-              //         )),
-              //   ),
-              // ),
             ],
           ),
         ),
diff --git a/lib/presentation/screens/media_player/media_controls.dart b/lib/presentation/screens/media_player/media_controls.dart
deleted file mode 100644 (file)
index 0686187..0000000
+++ /dev/null
@@ -1,413 +0,0 @@
-import 'package:flutter_ics_homescreen/core/utils/helpers.dart';
-import 'package:flutter_ics_homescreen/export.dart';
-import 'package:flutter_ics_homescreen/presentation/screens/media_player/widgets/gradient_progress_indicator.dart';
-
-class MediaControls extends StatefulWidget {
-  const MediaControls(
-      {super.key,
-      required this.type,
-      required this.songName,
-      required this.songLengthStart,
-      required this.songLengthStop});
-
-  final String type;
-  final String songName;
-  final String songLengthStart;
-  final String songLengthStop;
-
-  @override
-  State<MediaControls> createState() => _MediaControlsState();
-}
-
-class _MediaControlsState extends State<MediaControls> {
-  late String songName;
-  late String songLengthStart;
-  late String songLengthStop;
-  final String albumName = "Gorillaz";
-
-  int songProgress = 20;
-
-  @override
-  void initState() {
-    songName = widget.songName;
-    songLengthStart = widget.songLengthStart;
-    songLengthStop = widget.songLengthStop;
-    super.initState();
-  }
-
-  @override
-  Widget build(BuildContext context) {
-    return Material(
-      color: Colors.transparent,
-      child: Column(
-        crossAxisAlignment: CrossAxisAlignment.stretch,
-        children: [
-          Text(
-            songName,
-            style: TextStyle(
-                color: Colors.white,
-                fontWeight: FontWeight.w400,
-                shadows: [Helpers.dropShadowRegular],
-                fontSize: 44),
-          ),
-          if (widget.type == "media")
-            MediaControlSubDetails(
-              albumName: albumName,
-            )
-          else if (widget.type == "fm")
-            const FMPlayerSubDetails(),
-          if (widget.type == "media")
-            Column(children: [
-              GradientProgressIndicator(
-                percent: songProgress,
-                type: "media",
-                gradient: LinearGradient(
-                    begin: Alignment.centerLeft,
-                    end: Alignment.centerRight,
-                    colors: [
-                      AGLDemoColors.jordyBlueColor,
-                      AGLDemoColors.jordyBlueColor.withOpacity(0.8),
-                    ]),
-                backgroundColor: AGLDemoColors.gradientBackgroundDarkColor,
-              ),
-              // const LinearProgressIndicator(
-              //   backgroundColor: AGLDemoColors.gradientBackgroundDarkColor,
-              //   color: Colors.white70,
-              //   minHeight: 8,
-              //   value: 0.7,
-              // ),
-              Padding(
-                padding: const EdgeInsets.symmetric(vertical: 5),
-                child: Row(
-                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
-                  children: [
-                    Text(
-                      songLengthStart,
-                      style: TextStyle(
-                          color: Colors.white,
-                          fontSize: 26,
-                          shadows: [Helpers.dropShadowRegular]),
-                    ),
-                    Text(
-                      songLengthStop,
-                      style: TextStyle(
-                          color: Colors.white,
-                          fontSize: 26,
-                          shadows: [Helpers.dropShadowRegular]),
-                    )
-                  ],
-                ),
-              ),
-            ])
-          else if (widget.type == "fm")
-            FMPlayerSlider(
-              minHertz: songLengthStart,
-              maxHertz: songLengthStop,
-              songProgress: songProgress,
-            ),
-          if (widget.type == "media") const MediaPlayerActions()
-        ],
-      ),
-    );
-  }
-}
-
-class MediaControlSubDetails extends StatefulWidget {
-  const MediaControlSubDetails({super.key, required this.albumName});
-  final String albumName;
-
-  @override
-  State<MediaControlSubDetails> createState() => _MediaControlSubDetailsState();
-}
-
-class _MediaControlSubDetailsState extends State<MediaControlSubDetails> {
-  bool isShuffleEnabled = false;
-  bool isRepeatEnabled = false;
-  @override
-  Widget build(BuildContext context) {
-    return Row(
-      mainAxisAlignment: MainAxisAlignment.spaceBetween,
-      children: [
-        Text(
-          widget.albumName,
-          style: TextStyle(
-              color: Colors.white,
-              fontWeight: FontWeight.w400,
-              fontSize: 40,
-              shadows: [Helpers.dropShadowRegular]),
-        ),
-        Row(
-          children: [
-            InkWell(
-                customBorder: const CircleBorder(),
-                onTap: () {
-                  setState(() {
-                    isShuffleEnabled = !isShuffleEnabled;
-                  });
-                },
-                child: Padding(
-                    padding: const EdgeInsets.all(8.0),
-                    child: SvgPicture.asset(
-                      "assets/${isShuffleEnabled ? "ShufflePressed.svg" : "Shuffle.svg"}",
-                      width: 48,
-                    ))),
-            InkWell(
-                customBorder: const CircleBorder(),
-                onTap: () {
-                  setState(() {
-                    isRepeatEnabled = !isRepeatEnabled;
-                  });
-                },
-                child: Padding(
-                    padding: const EdgeInsets.all(8.0),
-                    child: SvgPicture.asset(
-                      "assets/${isRepeatEnabled ? "RepeatPressed.svg" : "Repeat.svg"}",
-                      width: 48,
-                    ))),
-          ],
-        )
-      ],
-    );
-  }
-}
-
-class FMPlayerSubDetails extends StatefulWidget {
-  const FMPlayerSubDetails({
-    super.key,
-  });
-
-  @override
-  State<FMPlayerSubDetails> createState() => _FMPlayerSubDetailsState();
-}
-
-class _FMPlayerSubDetailsState extends State<FMPlayerSubDetails> {
-  onPressed({required String type}) {}
-  @override
-  Widget build(BuildContext context) {
-    return Padding(
-      padding: const EdgeInsets.only(bottom: 5),
-      child: Row(
-        mainAxisAlignment: MainAxisAlignment.spaceBetween,
-        children: [
-          Row(
-            children: [
-              Text(
-                "Tune",
-                style: TextStyle(
-                    color: Colors.white,
-                    fontWeight: FontWeight.w400,
-                    fontSize: 40,
-                    shadows: [Helpers.dropShadowRegular]),
-              ),
-              const SizedBox(
-                width: 25,
-              ),
-              InkWell(
-                  customBorder: const CircleBorder(),
-                  onTap: () {
-                    onPressed(type: "scanLeft");
-                  },
-                  child: const Padding(
-                      padding: EdgeInsets.all(8.0),
-                      child: Icon(
-                        Icons.arrow_back,
-                        size: 48,
-                        color: AGLDemoColors.periwinkleColor,
-                      ))),
-              const SizedBox(
-                width: 25,
-              ),
-              InkWell(
-                  customBorder: const CircleBorder(),
-                  onTap: () {
-                    onPressed(type: "scanRight");
-                  },
-                  child: const Padding(
-                      padding: EdgeInsets.all(8.0),
-                      child: Icon(
-                        Icons.arrow_forward,
-                        color: AGLDemoColors.periwinkleColor,
-                        size: 48,
-                      ))),
-            ],
-          ),
-          Row(
-            children: [
-              Text(
-                "Scan",
-                style: TextStyle(
-                    color: Colors.white,
-                    fontWeight: FontWeight.w400,
-                    fontSize: 40,
-                    shadows: [Helpers.dropShadowRegular]),
-              ),
-              const SizedBox(
-                width: 25,
-              ),
-              InkWell(
-                  customBorder: const CircleBorder(),
-                  onTap: () {
-                    onPressed(type: "scanLeft");
-                  },
-                  child: const Padding(
-                      padding: EdgeInsets.all(8.0),
-                      child: Icon(
-                        Icons.arrow_back,
-                        color: AGLDemoColors.periwinkleColor,
-                        size: 48,
-                      ))),
-              const SizedBox(
-                width: 25,
-              ),
-              InkWell(
-                  customBorder: const CircleBorder(),
-                  onTap: () {
-                    onPressed(type: "scanRight");
-                  },
-                  child: const Padding(
-                      padding: EdgeInsets.all(8.0),
-                      child: Icon(
-                        Icons.arrow_forward,
-                        color: AGLDemoColors.periwinkleColor,
-                        size: 48,
-                      ))),
-            ],
-          )
-        ],
-      ),
-    );
-  }
-}
-
-class MediaPlayerActions extends StatefulWidget {
-  const MediaPlayerActions({super.key});
-
-  @override
-  State<MediaPlayerActions> createState() => _MediaPlayerActionsState();
-}
-
-class _MediaPlayerActionsState extends State<MediaPlayerActions> {
-  bool isPressed = false;
-  bool isPlaying = true;
-
-  @override
-  Widget build(BuildContext context) {
-    return Row(
-      mainAxisAlignment: MainAxisAlignment.center,
-      children: [
-        InkWell(
-            customBorder: const CircleBorder(),
-            onTap: () {},
-            child: Padding(
-              padding: const EdgeInsets.all(8.0),
-              child: SvgPicture.asset(
-                "assets/SkipPrevious.svg",
-                width: 48,
-              ),
-            )),
-        const SizedBox(
-          width: 120,
-        ),
-        InkWell(
-            customBorder: const CircleBorder(),
-            onTap: () {
-              setState(() {
-                isPlaying = !isPlaying;
-              });
-            },
-            onTapDown: (details) {
-              setState(() {
-                isPressed = true;
-              });
-            },
-            onTapUp: (details) {
-              isPressed = false;
-
-            },
-            child: Container(
-              width: 64,
-              height: 64,
-              decoration: BoxDecoration(
-                  shape: BoxShape.circle,
-                  color:
-                      isPressed ? Colors.white : AGLDemoColors.periwinkleColor,
-                  boxShadow: [Helpers.boxDropShadowRegular]),
-              child: Icon(
-                isPlaying ? Icons.pause : Icons.play_arrow,
-                color: AGLDemoColors.resolutionBlueColor,
-                size: 60,
-              ),
-            )),
-        const SizedBox(
-          width: 120,
-        ),
-        InkWell(
-            customBorder: const CircleBorder(),
-            onTap: () {},
-            child: Padding(
-              padding: const EdgeInsets.all(8.0),
-              child: SvgPicture.asset(
-                "assets/SkipNext.svg",
-                width: 48,
-              ),
-            )),
-      ],
-    );
-  }
-}
-
-class FMPlayerSlider extends StatefulWidget {
-  const FMPlayerSlider(
-      {super.key,
-      required this.minHertz,
-      required this.maxHertz,
-      required this.songProgress});
-  final String minHertz;
-  final String maxHertz;
-  final int songProgress;
-
-  @override
-  State<FMPlayerSlider> createState() => _FMPlayerSliderState();
-}
-
-class _FMPlayerSliderState extends State<FMPlayerSlider> {
-  @override
-  Widget build(BuildContext context) {
-    return Row(
-      children: [
-        Text(
-          widget.minHertz,
-          style: TextStyle(
-              color: Colors.white,
-              fontSize: 26,
-              shadows: [Helpers.dropShadowRegular]),
-        ),
-        Expanded(
-          child: Padding(
-            padding: const EdgeInsets.symmetric(horizontal: 40),
-            child: GradientProgressIndicator(
-              percent: widget.songProgress,
-              height: 10,
-              type: "fm",
-              gradient: LinearGradient(
-                  begin: Alignment.centerLeft,
-                  end: Alignment.centerRight,
-                  colors: [
-                    AGLDemoColors.jordyBlueColor,
-                    AGLDemoColors.jordyBlueColor.withOpacity(0.8),
-                  ]),
-              backgroundColor: AGLDemoColors.gradientBackgroundDarkColor,
-            ),
-          ),
-        ),
-        Text(
-          widget.maxHertz,
-          style: TextStyle(
-              color: Colors.white,
-              fontSize: 26,
-              shadows: [Helpers.dropShadowRegular]),
-        )
-      ],
-    );
-  }
-}
diff --git a/lib/presentation/screens/media_player/my_media.dart b/lib/presentation/screens/media_player/my_media.dart
deleted file mode 100644 (file)
index e69de29..0000000
index fefd9ed..6988caa 100644 (file)
@@ -74,7 +74,7 @@ class CustomBalanceState extends ConsumerState<CustomBalanceSlider> {
                     onTap: () {
                       _decrease();
                     },
-                    child: Text(
+                    child: const Text(
                       'LEFT',
                       style: TextStyle(
                         fontSize: 18,
@@ -127,7 +127,7 @@ class CustomBalanceState extends ConsumerState<CustomBalanceSlider> {
                     onTap: () {
                       _increase();
                     },
-                    child: Text(
+                    child: const Text(
                       'RIGHT',
                       style: TextStyle(
                         fontSize: 18,
@@ -217,14 +217,14 @@ class CustomFaderState extends ConsumerState<CustomFaderSlider> {
                     onTap: () {
                       _decrease();
                     },
-                    child: Text(
+                    child: const Text(
                       'REAR',
                       style: TextStyle(
                         fontSize: 18,
                         fontWeight: FontWeight.bold,
                         color: AGLDemoColors.periwinkleColor,
                       ),
-                  )),
+                    )),
               ),
               SizedBox(
                 width: 584,
@@ -246,9 +246,7 @@ class CustomFaderState extends ConsumerState<CustomFaderSlider> {
                     max: 10,
                     value: faderValue,
                     onChanged: (newValue) {
-                      ref
-                          .read(audioStateProvider.notifier)
-                          .setFade(newValue);
+                      ref.read(audioStateProvider.notifier).setFade(newValue);
                       _currentVal = newValue;
                     },
                     onChangeEnd: (value) {
@@ -270,7 +268,7 @@ class CustomFaderState extends ConsumerState<CustomFaderSlider> {
                     onTap: () {
                       _increase();
                     },
-                    child: Text(
+                    child: const Text(
                       'FRONT',
                       style: TextStyle(
                         fontSize: 18,
index d93be4f..29d8d6c 100644 (file)
@@ -66,7 +66,8 @@ class SplashContentState extends ConsumerState<SplashContent>
 
   @override
   void didChangeDependencies() {
-    ref.read(valClientProvider).startListen();
+    ref.read(valClientProvider).run();
+    ref.read(radioClientProvider).run();
     super.didChangeDependencies();
   }
 
diff --git a/protos/lib/agl-shell-api.dart b/protos/lib/agl-shell-api.dart
new file mode 100644 (file)
index 0000000..af19dc6
--- /dev/null
@@ -0,0 +1,8 @@
+library agl_shell_api;
+
+export 'src/generated/agl_shell.pb.dart';
+export 'src/generated/agl_shell.pbenum.dart';
+export 'src/generated/agl_shell.pbgrpc.dart';
+export 'src/generated/agl_shell.pbjson.dart';
+
+export 'package:grpc/grpc.dart';
diff --git a/protos/lib/applauncher-api.dart b/protos/lib/applauncher-api.dart
new file mode 100644 (file)
index 0000000..fdb181e
--- /dev/null
@@ -0,0 +1,8 @@
+library applauncher_api;
+
+export 'src/generated/applauncher.pb.dart';
+export 'src/generated/applauncher.pbenum.dart';
+export 'src/generated/applauncher.pbgrpc.dart';
+export 'src/generated/applauncher.pbjson.dart';
+
+export 'package:grpc/grpc.dart';
diff --git a/protos/lib/radio-api.dart b/protos/lib/radio-api.dart
new file mode 100644 (file)
index 0000000..1b12e91
--- /dev/null
@@ -0,0 +1,8 @@
+library radio_api;
+
+export 'src/generated/radio.pb.dart';
+export 'src/generated/radio.pbenum.dart';
+export 'src/generated/radio.pbgrpc.dart';
+export 'src/generated/radio.pbjson.dart';
+
+export 'package:grpc/grpc.dart';
diff --git a/protos/lib/src/generated/radio.pb.dart b/protos/lib/src/generated/radio.pb.dart
new file mode 100644 (file)
index 0000000..da3d1a8
--- /dev/null
@@ -0,0 +1,1904 @@
+//
+//  Generated code. Do not modify.
+//  source: radio.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:core' as $core;
+
+import 'package:protobuf/protobuf.dart' as $pb;
+
+import 'radio.pbenum.dart';
+
+export 'radio.pbenum.dart';
+
+class GetFrequencyRequest extends $pb.GeneratedMessage {
+  factory GetFrequencyRequest() => create();
+  GetFrequencyRequest._() : super();
+  factory GetFrequencyRequest.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory GetFrequencyRequest.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'GetFrequencyRequest', package: const $pb.PackageName(_omitMessageNames ? '' : 'automotivegradelinux'), createEmptyInstance: create)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  GetFrequencyRequest clone() => GetFrequencyRequest()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  GetFrequencyRequest copyWith(void Function(GetFrequencyRequest) updates) => super.copyWith((message) => updates(message as GetFrequencyRequest)) as GetFrequencyRequest;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static GetFrequencyRequest create() => GetFrequencyRequest._();
+  GetFrequencyRequest createEmptyInstance() => create();
+  static $pb.PbList<GetFrequencyRequest> createRepeated() => $pb.PbList<GetFrequencyRequest>();
+  @$core.pragma('dart2js:noInline')
+  static GetFrequencyRequest getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<GetFrequencyRequest>(create);
+  static GetFrequencyRequest? _defaultInstance;
+}
+
+class GetFrequencyResponse extends $pb.GeneratedMessage {
+  factory GetFrequencyResponse({
+    $core.int? frequency,
+  }) {
+    final $result = create();
+    if (frequency != null) {
+      $result.frequency = frequency;
+    }
+    return $result;
+  }
+  GetFrequencyResponse._() : super();
+  factory GetFrequencyResponse.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory GetFrequencyResponse.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'GetFrequencyResponse', package: const $pb.PackageName(_omitMessageNames ? '' : 'automotivegradelinux'), createEmptyInstance: create)
+    ..a<$core.int>(1, _omitFieldNames ? '' : 'frequency', $pb.PbFieldType.OU3)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  GetFrequencyResponse clone() => GetFrequencyResponse()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  GetFrequencyResponse copyWith(void Function(GetFrequencyResponse) updates) => super.copyWith((message) => updates(message as GetFrequencyResponse)) as GetFrequencyResponse;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static GetFrequencyResponse create() => GetFrequencyResponse._();
+  GetFrequencyResponse createEmptyInstance() => create();
+  static $pb.PbList<GetFrequencyResponse> createRepeated() => $pb.PbList<GetFrequencyResponse>();
+  @$core.pragma('dart2js:noInline')
+  static GetFrequencyResponse getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<GetFrequencyResponse>(create);
+  static GetFrequencyResponse? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $core.int get frequency => $_getIZ(0);
+  @$pb.TagNumber(1)
+  set frequency($core.int v) { $_setUnsignedInt32(0, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasFrequency() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearFrequency() => clearField(1);
+}
+
+class SetFrequencyRequest extends $pb.GeneratedMessage {
+  factory SetFrequencyRequest({
+    $core.int? frequency,
+  }) {
+    final $result = create();
+    if (frequency != null) {
+      $result.frequency = frequency;
+    }
+    return $result;
+  }
+  SetFrequencyRequest._() : super();
+  factory SetFrequencyRequest.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory SetFrequencyRequest.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'SetFrequencyRequest', package: const $pb.PackageName(_omitMessageNames ? '' : 'automotivegradelinux'), createEmptyInstance: create)
+    ..a<$core.int>(1, _omitFieldNames ? '' : 'frequency', $pb.PbFieldType.OU3)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  SetFrequencyRequest clone() => SetFrequencyRequest()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  SetFrequencyRequest copyWith(void Function(SetFrequencyRequest) updates) => super.copyWith((message) => updates(message as SetFrequencyRequest)) as SetFrequencyRequest;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static SetFrequencyRequest create() => SetFrequencyRequest._();
+  SetFrequencyRequest createEmptyInstance() => create();
+  static $pb.PbList<SetFrequencyRequest> createRepeated() => $pb.PbList<SetFrequencyRequest>();
+  @$core.pragma('dart2js:noInline')
+  static SetFrequencyRequest getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<SetFrequencyRequest>(create);
+  static SetFrequencyRequest? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $core.int get frequency => $_getIZ(0);
+  @$pb.TagNumber(1)
+  set frequency($core.int v) { $_setUnsignedInt32(0, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasFrequency() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearFrequency() => clearField(1);
+}
+
+class SetFrequencyResponse extends $pb.GeneratedMessage {
+  factory SetFrequencyResponse({
+    $core.int? frequency,
+  }) {
+    final $result = create();
+    if (frequency != null) {
+      $result.frequency = frequency;
+    }
+    return $result;
+  }
+  SetFrequencyResponse._() : super();
+  factory SetFrequencyResponse.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory SetFrequencyResponse.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'SetFrequencyResponse', package: const $pb.PackageName(_omitMessageNames ? '' : 'automotivegradelinux'), createEmptyInstance: create)
+    ..a<$core.int>(1, _omitFieldNames ? '' : 'frequency', $pb.PbFieldType.OU3)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  SetFrequencyResponse clone() => SetFrequencyResponse()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  SetFrequencyResponse copyWith(void Function(SetFrequencyResponse) updates) => super.copyWith((message) => updates(message as SetFrequencyResponse)) as SetFrequencyResponse;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static SetFrequencyResponse create() => SetFrequencyResponse._();
+  SetFrequencyResponse createEmptyInstance() => create();
+  static $pb.PbList<SetFrequencyResponse> createRepeated() => $pb.PbList<SetFrequencyResponse>();
+  @$core.pragma('dart2js:noInline')
+  static SetFrequencyResponse getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<SetFrequencyResponse>(create);
+  static SetFrequencyResponse? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $core.int get frequency => $_getIZ(0);
+  @$pb.TagNumber(1)
+  set frequency($core.int v) { $_setUnsignedInt32(0, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasFrequency() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearFrequency() => clearField(1);
+}
+
+class GetBandRequest extends $pb.GeneratedMessage {
+  factory GetBandRequest() => create();
+  GetBandRequest._() : super();
+  factory GetBandRequest.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory GetBandRequest.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'GetBandRequest', package: const $pb.PackageName(_omitMessageNames ? '' : 'automotivegradelinux'), createEmptyInstance: create)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  GetBandRequest clone() => GetBandRequest()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  GetBandRequest copyWith(void Function(GetBandRequest) updates) => super.copyWith((message) => updates(message as GetBandRequest)) as GetBandRequest;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static GetBandRequest create() => GetBandRequest._();
+  GetBandRequest createEmptyInstance() => create();
+  static $pb.PbList<GetBandRequest> createRepeated() => $pb.PbList<GetBandRequest>();
+  @$core.pragma('dart2js:noInline')
+  static GetBandRequest getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<GetBandRequest>(create);
+  static GetBandRequest? _defaultInstance;
+}
+
+class GetBandResponse extends $pb.GeneratedMessage {
+  factory GetBandResponse({
+    Band? band,
+  }) {
+    final $result = create();
+    if (band != null) {
+      $result.band = band;
+    }
+    return $result;
+  }
+  GetBandResponse._() : super();
+  factory GetBandResponse.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory GetBandResponse.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'GetBandResponse', package: const $pb.PackageName(_omitMessageNames ? '' : 'automotivegradelinux'), createEmptyInstance: create)
+    ..e<Band>(1, _omitFieldNames ? '' : 'band', $pb.PbFieldType.OE, defaultOrMaker: Band.BAND_UNSPECIFIED, valueOf: Band.valueOf, enumValues: Band.values)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  GetBandResponse clone() => GetBandResponse()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  GetBandResponse copyWith(void Function(GetBandResponse) updates) => super.copyWith((message) => updates(message as GetBandResponse)) as GetBandResponse;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static GetBandResponse create() => GetBandResponse._();
+  GetBandResponse createEmptyInstance() => create();
+  static $pb.PbList<GetBandResponse> createRepeated() => $pb.PbList<GetBandResponse>();
+  @$core.pragma('dart2js:noInline')
+  static GetBandResponse getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<GetBandResponse>(create);
+  static GetBandResponse? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  Band get band => $_getN(0);
+  @$pb.TagNumber(1)
+  set band(Band v) { setField(1, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasBand() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearBand() => clearField(1);
+}
+
+class SetBandRequest extends $pb.GeneratedMessage {
+  factory SetBandRequest({
+    Band? band,
+  }) {
+    final $result = create();
+    if (band != null) {
+      $result.band = band;
+    }
+    return $result;
+  }
+  SetBandRequest._() : super();
+  factory SetBandRequest.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory SetBandRequest.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'SetBandRequest', package: const $pb.PackageName(_omitMessageNames ? '' : 'automotivegradelinux'), createEmptyInstance: create)
+    ..e<Band>(1, _omitFieldNames ? '' : 'band', $pb.PbFieldType.OE, defaultOrMaker: Band.BAND_UNSPECIFIED, valueOf: Band.valueOf, enumValues: Band.values)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  SetBandRequest clone() => SetBandRequest()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  SetBandRequest copyWith(void Function(SetBandRequest) updates) => super.copyWith((message) => updates(message as SetBandRequest)) as SetBandRequest;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static SetBandRequest create() => SetBandRequest._();
+  SetBandRequest createEmptyInstance() => create();
+  static $pb.PbList<SetBandRequest> createRepeated() => $pb.PbList<SetBandRequest>();
+  @$core.pragma('dart2js:noInline')
+  static SetBandRequest getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<SetBandRequest>(create);
+  static SetBandRequest? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  Band get band => $_getN(0);
+  @$pb.TagNumber(1)
+  set band(Band v) { setField(1, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasBand() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearBand() => clearField(1);
+}
+
+class SetBandResponse extends $pb.GeneratedMessage {
+  factory SetBandResponse({
+    Band? band,
+  }) {
+    final $result = create();
+    if (band != null) {
+      $result.band = band;
+    }
+    return $result;
+  }
+  SetBandResponse._() : super();
+  factory SetBandResponse.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory SetBandResponse.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'SetBandResponse', package: const $pb.PackageName(_omitMessageNames ? '' : 'automotivegradelinux'), createEmptyInstance: create)
+    ..e<Band>(1, _omitFieldNames ? '' : 'band', $pb.PbFieldType.OE, defaultOrMaker: Band.BAND_UNSPECIFIED, valueOf: Band.valueOf, enumValues: Band.values)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  SetBandResponse clone() => SetBandResponse()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  SetBandResponse copyWith(void Function(SetBandResponse) updates) => super.copyWith((message) => updates(message as SetBandResponse)) as SetBandResponse;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static SetBandResponse create() => SetBandResponse._();
+  SetBandResponse createEmptyInstance() => create();
+  static $pb.PbList<SetBandResponse> createRepeated() => $pb.PbList<SetBandResponse>();
+  @$core.pragma('dart2js:noInline')
+  static SetBandResponse getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<SetBandResponse>(create);
+  static SetBandResponse? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  Band get band => $_getN(0);
+  @$pb.TagNumber(1)
+  set band(Band v) { setField(1, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasBand() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearBand() => clearField(1);
+}
+
+class GetBandSupportedRequest extends $pb.GeneratedMessage {
+  factory GetBandSupportedRequest({
+    Band? band,
+  }) {
+    final $result = create();
+    if (band != null) {
+      $result.band = band;
+    }
+    return $result;
+  }
+  GetBandSupportedRequest._() : super();
+  factory GetBandSupportedRequest.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory GetBandSupportedRequest.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'GetBandSupportedRequest', package: const $pb.PackageName(_omitMessageNames ? '' : 'automotivegradelinux'), createEmptyInstance: create)
+    ..e<Band>(1, _omitFieldNames ? '' : 'band', $pb.PbFieldType.OE, defaultOrMaker: Band.BAND_UNSPECIFIED, valueOf: Band.valueOf, enumValues: Band.values)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  GetBandSupportedRequest clone() => GetBandSupportedRequest()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  GetBandSupportedRequest copyWith(void Function(GetBandSupportedRequest) updates) => super.copyWith((message) => updates(message as GetBandSupportedRequest)) as GetBandSupportedRequest;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static GetBandSupportedRequest create() => GetBandSupportedRequest._();
+  GetBandSupportedRequest createEmptyInstance() => create();
+  static $pb.PbList<GetBandSupportedRequest> createRepeated() => $pb.PbList<GetBandSupportedRequest>();
+  @$core.pragma('dart2js:noInline')
+  static GetBandSupportedRequest getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<GetBandSupportedRequest>(create);
+  static GetBandSupportedRequest? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  Band get band => $_getN(0);
+  @$pb.TagNumber(1)
+  set band(Band v) { setField(1, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasBand() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearBand() => clearField(1);
+}
+
+class GetBandSupportedResponse extends $pb.GeneratedMessage {
+  factory GetBandSupportedResponse({
+    $core.bool? supported,
+  }) {
+    final $result = create();
+    if (supported != null) {
+      $result.supported = supported;
+    }
+    return $result;
+  }
+  GetBandSupportedResponse._() : super();
+  factory GetBandSupportedResponse.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory GetBandSupportedResponse.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'GetBandSupportedResponse', package: const $pb.PackageName(_omitMessageNames ? '' : 'automotivegradelinux'), createEmptyInstance: create)
+    ..aOB(1, _omitFieldNames ? '' : 'supported')
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  GetBandSupportedResponse clone() => GetBandSupportedResponse()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  GetBandSupportedResponse copyWith(void Function(GetBandSupportedResponse) updates) => super.copyWith((message) => updates(message as GetBandSupportedResponse)) as GetBandSupportedResponse;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static GetBandSupportedResponse create() => GetBandSupportedResponse._();
+  GetBandSupportedResponse createEmptyInstance() => create();
+  static $pb.PbList<GetBandSupportedResponse> createRepeated() => $pb.PbList<GetBandSupportedResponse>();
+  @$core.pragma('dart2js:noInline')
+  static GetBandSupportedResponse getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<GetBandSupportedResponse>(create);
+  static GetBandSupportedResponse? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $core.bool get supported => $_getBF(0);
+  @$pb.TagNumber(1)
+  set supported($core.bool v) { $_setBool(0, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasSupported() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearSupported() => clearField(1);
+}
+
+class GetBandParametersRequest extends $pb.GeneratedMessage {
+  factory GetBandParametersRequest({
+    Band? band,
+  }) {
+    final $result = create();
+    if (band != null) {
+      $result.band = band;
+    }
+    return $result;
+  }
+  GetBandParametersRequest._() : super();
+  factory GetBandParametersRequest.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory GetBandParametersRequest.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'GetBandParametersRequest', package: const $pb.PackageName(_omitMessageNames ? '' : 'automotivegradelinux'), createEmptyInstance: create)
+    ..e<Band>(1, _omitFieldNames ? '' : 'band', $pb.PbFieldType.OE, defaultOrMaker: Band.BAND_UNSPECIFIED, valueOf: Band.valueOf, enumValues: Band.values)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  GetBandParametersRequest clone() => GetBandParametersRequest()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  GetBandParametersRequest copyWith(void Function(GetBandParametersRequest) updates) => super.copyWith((message) => updates(message as GetBandParametersRequest)) as GetBandParametersRequest;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static GetBandParametersRequest create() => GetBandParametersRequest._();
+  GetBandParametersRequest createEmptyInstance() => create();
+  static $pb.PbList<GetBandParametersRequest> createRepeated() => $pb.PbList<GetBandParametersRequest>();
+  @$core.pragma('dart2js:noInline')
+  static GetBandParametersRequest getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<GetBandParametersRequest>(create);
+  static GetBandParametersRequest? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  Band get band => $_getN(0);
+  @$pb.TagNumber(1)
+  set band(Band v) { setField(1, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasBand() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearBand() => clearField(1);
+}
+
+class GetBandParametersResponse extends $pb.GeneratedMessage {
+  factory GetBandParametersResponse({
+    $core.int? min,
+    $core.int? max,
+    $core.int? step,
+  }) {
+    final $result = create();
+    if (min != null) {
+      $result.min = min;
+    }
+    if (max != null) {
+      $result.max = max;
+    }
+    if (step != null) {
+      $result.step = step;
+    }
+    return $result;
+  }
+  GetBandParametersResponse._() : super();
+  factory GetBandParametersResponse.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory GetBandParametersResponse.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'GetBandParametersResponse', package: const $pb.PackageName(_omitMessageNames ? '' : 'automotivegradelinux'), createEmptyInstance: create)
+    ..a<$core.int>(1, _omitFieldNames ? '' : 'min', $pb.PbFieldType.OU3)
+    ..a<$core.int>(2, _omitFieldNames ? '' : 'max', $pb.PbFieldType.OU3)
+    ..a<$core.int>(3, _omitFieldNames ? '' : 'step', $pb.PbFieldType.OU3)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  GetBandParametersResponse clone() => GetBandParametersResponse()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  GetBandParametersResponse copyWith(void Function(GetBandParametersResponse) updates) => super.copyWith((message) => updates(message as GetBandParametersResponse)) as GetBandParametersResponse;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static GetBandParametersResponse create() => GetBandParametersResponse._();
+  GetBandParametersResponse createEmptyInstance() => create();
+  static $pb.PbList<GetBandParametersResponse> createRepeated() => $pb.PbList<GetBandParametersResponse>();
+  @$core.pragma('dart2js:noInline')
+  static GetBandParametersResponse getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<GetBandParametersResponse>(create);
+  static GetBandParametersResponse? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $core.int get min => $_getIZ(0);
+  @$pb.TagNumber(1)
+  set min($core.int v) { $_setUnsignedInt32(0, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasMin() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearMin() => clearField(1);
+
+  @$pb.TagNumber(2)
+  $core.int get max => $_getIZ(1);
+  @$pb.TagNumber(2)
+  set max($core.int v) { $_setUnsignedInt32(1, v); }
+  @$pb.TagNumber(2)
+  $core.bool hasMax() => $_has(1);
+  @$pb.TagNumber(2)
+  void clearMax() => clearField(2);
+
+  @$pb.TagNumber(3)
+  $core.int get step => $_getIZ(2);
+  @$pb.TagNumber(3)
+  set step($core.int v) { $_setUnsignedInt32(2, v); }
+  @$pb.TagNumber(3)
+  $core.bool hasStep() => $_has(2);
+  @$pb.TagNumber(3)
+  void clearStep() => clearField(3);
+}
+
+class GetStereoModeRequest extends $pb.GeneratedMessage {
+  factory GetStereoModeRequest() => create();
+  GetStereoModeRequest._() : super();
+  factory GetStereoModeRequest.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory GetStereoModeRequest.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'GetStereoModeRequest', package: const $pb.PackageName(_omitMessageNames ? '' : 'automotivegradelinux'), createEmptyInstance: create)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  GetStereoModeRequest clone() => GetStereoModeRequest()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  GetStereoModeRequest copyWith(void Function(GetStereoModeRequest) updates) => super.copyWith((message) => updates(message as GetStereoModeRequest)) as GetStereoModeRequest;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static GetStereoModeRequest create() => GetStereoModeRequest._();
+  GetStereoModeRequest createEmptyInstance() => create();
+  static $pb.PbList<GetStereoModeRequest> createRepeated() => $pb.PbList<GetStereoModeRequest>();
+  @$core.pragma('dart2js:noInline')
+  static GetStereoModeRequest getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<GetStereoModeRequest>(create);
+  static GetStereoModeRequest? _defaultInstance;
+}
+
+class GetStereoModeResponse extends $pb.GeneratedMessage {
+  factory GetStereoModeResponse({
+    StereoMode? mode,
+  }) {
+    final $result = create();
+    if (mode != null) {
+      $result.mode = mode;
+    }
+    return $result;
+  }
+  GetStereoModeResponse._() : super();
+  factory GetStereoModeResponse.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory GetStereoModeResponse.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'GetStereoModeResponse', package: const $pb.PackageName(_omitMessageNames ? '' : 'automotivegradelinux'), createEmptyInstance: create)
+    ..e<StereoMode>(1, _omitFieldNames ? '' : 'mode', $pb.PbFieldType.OE, defaultOrMaker: StereoMode.STEREO_MODE_UNSPECIFIED, valueOf: StereoMode.valueOf, enumValues: StereoMode.values)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  GetStereoModeResponse clone() => GetStereoModeResponse()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  GetStereoModeResponse copyWith(void Function(GetStereoModeResponse) updates) => super.copyWith((message) => updates(message as GetStereoModeResponse)) as GetStereoModeResponse;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static GetStereoModeResponse create() => GetStereoModeResponse._();
+  GetStereoModeResponse createEmptyInstance() => create();
+  static $pb.PbList<GetStereoModeResponse> createRepeated() => $pb.PbList<GetStereoModeResponse>();
+  @$core.pragma('dart2js:noInline')
+  static GetStereoModeResponse getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<GetStereoModeResponse>(create);
+  static GetStereoModeResponse? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  StereoMode get mode => $_getN(0);
+  @$pb.TagNumber(1)
+  set mode(StereoMode v) { setField(1, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasMode() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearMode() => clearField(1);
+}
+
+class SetStereoModeRequest extends $pb.GeneratedMessage {
+  factory SetStereoModeRequest({
+    StereoMode? mode,
+  }) {
+    final $result = create();
+    if (mode != null) {
+      $result.mode = mode;
+    }
+    return $result;
+  }
+  SetStereoModeRequest._() : super();
+  factory SetStereoModeRequest.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory SetStereoModeRequest.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'SetStereoModeRequest', package: const $pb.PackageName(_omitMessageNames ? '' : 'automotivegradelinux'), createEmptyInstance: create)
+    ..e<StereoMode>(1, _omitFieldNames ? '' : 'mode', $pb.PbFieldType.OE, defaultOrMaker: StereoMode.STEREO_MODE_UNSPECIFIED, valueOf: StereoMode.valueOf, enumValues: StereoMode.values)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  SetStereoModeRequest clone() => SetStereoModeRequest()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  SetStereoModeRequest copyWith(void Function(SetStereoModeRequest) updates) => super.copyWith((message) => updates(message as SetStereoModeRequest)) as SetStereoModeRequest;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static SetStereoModeRequest create() => SetStereoModeRequest._();
+  SetStereoModeRequest createEmptyInstance() => create();
+  static $pb.PbList<SetStereoModeRequest> createRepeated() => $pb.PbList<SetStereoModeRequest>();
+  @$core.pragma('dart2js:noInline')
+  static SetStereoModeRequest getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<SetStereoModeRequest>(create);
+  static SetStereoModeRequest? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  StereoMode get mode => $_getN(0);
+  @$pb.TagNumber(1)
+  set mode(StereoMode v) { setField(1, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasMode() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearMode() => clearField(1);
+}
+
+class SetStereoModeResponse extends $pb.GeneratedMessage {
+  factory SetStereoModeResponse({
+    StereoMode? mode,
+  }) {
+    final $result = create();
+    if (mode != null) {
+      $result.mode = mode;
+    }
+    return $result;
+  }
+  SetStereoModeResponse._() : super();
+  factory SetStereoModeResponse.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory SetStereoModeResponse.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'SetStereoModeResponse', package: const $pb.PackageName(_omitMessageNames ? '' : 'automotivegradelinux'), createEmptyInstance: create)
+    ..e<StereoMode>(1, _omitFieldNames ? '' : 'mode', $pb.PbFieldType.OE, defaultOrMaker: StereoMode.STEREO_MODE_UNSPECIFIED, valueOf: StereoMode.valueOf, enumValues: StereoMode.values)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  SetStereoModeResponse clone() => SetStereoModeResponse()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  SetStereoModeResponse copyWith(void Function(SetStereoModeResponse) updates) => super.copyWith((message) => updates(message as SetStereoModeResponse)) as SetStereoModeResponse;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static SetStereoModeResponse create() => SetStereoModeResponse._();
+  SetStereoModeResponse createEmptyInstance() => create();
+  static $pb.PbList<SetStereoModeResponse> createRepeated() => $pb.PbList<SetStereoModeResponse>();
+  @$core.pragma('dart2js:noInline')
+  static SetStereoModeResponse getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<SetStereoModeResponse>(create);
+  static SetStereoModeResponse? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  StereoMode get mode => $_getN(0);
+  @$pb.TagNumber(1)
+  set mode(StereoMode v) { setField(1, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasMode() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearMode() => clearField(1);
+}
+
+class StartRequest extends $pb.GeneratedMessage {
+  factory StartRequest() => create();
+  StartRequest._() : super();
+  factory StartRequest.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory StartRequest.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'StartRequest', package: const $pb.PackageName(_omitMessageNames ? '' : 'automotivegradelinux'), createEmptyInstance: create)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  StartRequest clone() => StartRequest()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  StartRequest copyWith(void Function(StartRequest) updates) => super.copyWith((message) => updates(message as StartRequest)) as StartRequest;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static StartRequest create() => StartRequest._();
+  StartRequest createEmptyInstance() => create();
+  static $pb.PbList<StartRequest> createRepeated() => $pb.PbList<StartRequest>();
+  @$core.pragma('dart2js:noInline')
+  static StartRequest getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<StartRequest>(create);
+  static StartRequest? _defaultInstance;
+}
+
+class StartResponse extends $pb.GeneratedMessage {
+  factory StartResponse() => create();
+  StartResponse._() : super();
+  factory StartResponse.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory StartResponse.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'StartResponse', package: const $pb.PackageName(_omitMessageNames ? '' : 'automotivegradelinux'), createEmptyInstance: create)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  StartResponse clone() => StartResponse()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  StartResponse copyWith(void Function(StartResponse) updates) => super.copyWith((message) => updates(message as StartResponse)) as StartResponse;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static StartResponse create() => StartResponse._();
+  StartResponse createEmptyInstance() => create();
+  static $pb.PbList<StartResponse> createRepeated() => $pb.PbList<StartResponse>();
+  @$core.pragma('dart2js:noInline')
+  static StartResponse getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<StartResponse>(create);
+  static StartResponse? _defaultInstance;
+}
+
+class StopRequest extends $pb.GeneratedMessage {
+  factory StopRequest() => create();
+  StopRequest._() : super();
+  factory StopRequest.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory StopRequest.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'StopRequest', package: const $pb.PackageName(_omitMessageNames ? '' : 'automotivegradelinux'), createEmptyInstance: create)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  StopRequest clone() => StopRequest()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  StopRequest copyWith(void Function(StopRequest) updates) => super.copyWith((message) => updates(message as StopRequest)) as StopRequest;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static StopRequest create() => StopRequest._();
+  StopRequest createEmptyInstance() => create();
+  static $pb.PbList<StopRequest> createRepeated() => $pb.PbList<StopRequest>();
+  @$core.pragma('dart2js:noInline')
+  static StopRequest getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<StopRequest>(create);
+  static StopRequest? _defaultInstance;
+}
+
+class StopResponse extends $pb.GeneratedMessage {
+  factory StopResponse() => create();
+  StopResponse._() : super();
+  factory StopResponse.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory StopResponse.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'StopResponse', package: const $pb.PackageName(_omitMessageNames ? '' : 'automotivegradelinux'), createEmptyInstance: create)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  StopResponse clone() => StopResponse()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  StopResponse copyWith(void Function(StopResponse) updates) => super.copyWith((message) => updates(message as StopResponse)) as StopResponse;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static StopResponse create() => StopResponse._();
+  StopResponse createEmptyInstance() => create();
+  static $pb.PbList<StopResponse> createRepeated() => $pb.PbList<StopResponse>();
+  @$core.pragma('dart2js:noInline')
+  static StopResponse getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<StopResponse>(create);
+  static StopResponse? _defaultInstance;
+}
+
+class ScanStartRequest extends $pb.GeneratedMessage {
+  factory ScanStartRequest({
+    ScanDirection? direction,
+  }) {
+    final $result = create();
+    if (direction != null) {
+      $result.direction = direction;
+    }
+    return $result;
+  }
+  ScanStartRequest._() : super();
+  factory ScanStartRequest.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory ScanStartRequest.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'ScanStartRequest', package: const $pb.PackageName(_omitMessageNames ? '' : 'automotivegradelinux'), createEmptyInstance: create)
+    ..e<ScanDirection>(1, _omitFieldNames ? '' : 'direction', $pb.PbFieldType.OE, defaultOrMaker: ScanDirection.SCAN_DIRECTION_UNSPECIFIED, valueOf: ScanDirection.valueOf, enumValues: ScanDirection.values)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  ScanStartRequest clone() => ScanStartRequest()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  ScanStartRequest copyWith(void Function(ScanStartRequest) updates) => super.copyWith((message) => updates(message as ScanStartRequest)) as ScanStartRequest;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static ScanStartRequest create() => ScanStartRequest._();
+  ScanStartRequest createEmptyInstance() => create();
+  static $pb.PbList<ScanStartRequest> createRepeated() => $pb.PbList<ScanStartRequest>();
+  @$core.pragma('dart2js:noInline')
+  static ScanStartRequest getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<ScanStartRequest>(create);
+  static ScanStartRequest? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  ScanDirection get direction => $_getN(0);
+  @$pb.TagNumber(1)
+  set direction(ScanDirection v) { setField(1, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasDirection() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearDirection() => clearField(1);
+}
+
+class ScanStartResponse extends $pb.GeneratedMessage {
+  factory ScanStartResponse() => create();
+  ScanStartResponse._() : super();
+  factory ScanStartResponse.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory ScanStartResponse.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'ScanStartResponse', package: const $pb.PackageName(_omitMessageNames ? '' : 'automotivegradelinux'), createEmptyInstance: create)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  ScanStartResponse clone() => ScanStartResponse()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  ScanStartResponse copyWith(void Function(ScanStartResponse) updates) => super.copyWith((message) => updates(message as ScanStartResponse)) as ScanStartResponse;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static ScanStartResponse create() => ScanStartResponse._();
+  ScanStartResponse createEmptyInstance() => create();
+  static $pb.PbList<ScanStartResponse> createRepeated() => $pb.PbList<ScanStartResponse>();
+  @$core.pragma('dart2js:noInline')
+  static ScanStartResponse getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<ScanStartResponse>(create);
+  static ScanStartResponse? _defaultInstance;
+}
+
+class ScanStopRequest extends $pb.GeneratedMessage {
+  factory ScanStopRequest() => create();
+  ScanStopRequest._() : super();
+  factory ScanStopRequest.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory ScanStopRequest.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'ScanStopRequest', package: const $pb.PackageName(_omitMessageNames ? '' : 'automotivegradelinux'), createEmptyInstance: create)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  ScanStopRequest clone() => ScanStopRequest()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  ScanStopRequest copyWith(void Function(ScanStopRequest) updates) => super.copyWith((message) => updates(message as ScanStopRequest)) as ScanStopRequest;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static ScanStopRequest create() => ScanStopRequest._();
+  ScanStopRequest createEmptyInstance() => create();
+  static $pb.PbList<ScanStopRequest> createRepeated() => $pb.PbList<ScanStopRequest>();
+  @$core.pragma('dart2js:noInline')
+  static ScanStopRequest getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<ScanStopRequest>(create);
+  static ScanStopRequest? _defaultInstance;
+}
+
+class ScanStopResponse extends $pb.GeneratedMessage {
+  factory ScanStopResponse() => create();
+  ScanStopResponse._() : super();
+  factory ScanStopResponse.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory ScanStopResponse.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'ScanStopResponse', package: const $pb.PackageName(_omitMessageNames ? '' : 'automotivegradelinux'), createEmptyInstance: create)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  ScanStopResponse clone() => ScanStopResponse()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  ScanStopResponse copyWith(void Function(ScanStopResponse) updates) => super.copyWith((message) => updates(message as ScanStopResponse)) as ScanStopResponse;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static ScanStopResponse create() => ScanStopResponse._();
+  ScanStopResponse createEmptyInstance() => create();
+  static $pb.PbList<ScanStopResponse> createRepeated() => $pb.PbList<ScanStopResponse>();
+  @$core.pragma('dart2js:noInline')
+  static ScanStopResponse getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<ScanStopResponse>(create);
+  static ScanStopResponse? _defaultInstance;
+}
+
+class GetRDSRequest extends $pb.GeneratedMessage {
+  factory GetRDSRequest() => create();
+  GetRDSRequest._() : super();
+  factory GetRDSRequest.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory GetRDSRequest.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'GetRDSRequest', package: const $pb.PackageName(_omitMessageNames ? '' : 'automotivegradelinux'), createEmptyInstance: create)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  GetRDSRequest clone() => GetRDSRequest()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  GetRDSRequest copyWith(void Function(GetRDSRequest) updates) => super.copyWith((message) => updates(message as GetRDSRequest)) as GetRDSRequest;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static GetRDSRequest create() => GetRDSRequest._();
+  GetRDSRequest createEmptyInstance() => create();
+  static $pb.PbList<GetRDSRequest> createRepeated() => $pb.PbList<GetRDSRequest>();
+  @$core.pragma('dart2js:noInline')
+  static GetRDSRequest getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<GetRDSRequest>(create);
+  static GetRDSRequest? _defaultInstance;
+}
+
+/// NOTE: This is a placeholder and will be revised!
+class GetRDSResponse extends $pb.GeneratedMessage {
+  factory GetRDSResponse({
+    $core.String? name,
+    $core.String? radioText,
+    $core.String? alternatives,
+    $core.String? minute,
+    $core.String? hour,
+    $core.String? day,
+    $core.String? month,
+    $core.String? year,
+    $core.String? pi,
+    $core.String? pty,
+    $core.String? ta,
+    $core.String? tp,
+    $core.String? ms,
+  }) {
+    final $result = create();
+    if (name != null) {
+      $result.name = name;
+    }
+    if (radioText != null) {
+      $result.radioText = radioText;
+    }
+    if (alternatives != null) {
+      $result.alternatives = alternatives;
+    }
+    if (minute != null) {
+      $result.minute = minute;
+    }
+    if (hour != null) {
+      $result.hour = hour;
+    }
+    if (day != null) {
+      $result.day = day;
+    }
+    if (month != null) {
+      $result.month = month;
+    }
+    if (year != null) {
+      $result.year = year;
+    }
+    if (pi != null) {
+      $result.pi = pi;
+    }
+    if (pty != null) {
+      $result.pty = pty;
+    }
+    if (ta != null) {
+      $result.ta = ta;
+    }
+    if (tp != null) {
+      $result.tp = tp;
+    }
+    if (ms != null) {
+      $result.ms = ms;
+    }
+    return $result;
+  }
+  GetRDSResponse._() : super();
+  factory GetRDSResponse.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory GetRDSResponse.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'GetRDSResponse', package: const $pb.PackageName(_omitMessageNames ? '' : 'automotivegradelinux'), createEmptyInstance: create)
+    ..aOS(1, _omitFieldNames ? '' : 'name')
+    ..aOS(2, _omitFieldNames ? '' : 'radioText')
+    ..aOS(3, _omitFieldNames ? '' : 'alternatives')
+    ..aOS(4, _omitFieldNames ? '' : 'minute')
+    ..aOS(5, _omitFieldNames ? '' : 'hour')
+    ..aOS(6, _omitFieldNames ? '' : 'day')
+    ..aOS(7, _omitFieldNames ? '' : 'month')
+    ..aOS(8, _omitFieldNames ? '' : 'year')
+    ..aOS(9, _omitFieldNames ? '' : 'pi')
+    ..aOS(10, _omitFieldNames ? '' : 'pty')
+    ..aOS(11, _omitFieldNames ? '' : 'ta')
+    ..aOS(12, _omitFieldNames ? '' : 'tp')
+    ..aOS(13, _omitFieldNames ? '' : 'ms')
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  GetRDSResponse clone() => GetRDSResponse()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  GetRDSResponse copyWith(void Function(GetRDSResponse) updates) => super.copyWith((message) => updates(message as GetRDSResponse)) as GetRDSResponse;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static GetRDSResponse create() => GetRDSResponse._();
+  GetRDSResponse createEmptyInstance() => create();
+  static $pb.PbList<GetRDSResponse> createRepeated() => $pb.PbList<GetRDSResponse>();
+  @$core.pragma('dart2js:noInline')
+  static GetRDSResponse getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<GetRDSResponse>(create);
+  static GetRDSResponse? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $core.String get name => $_getSZ(0);
+  @$pb.TagNumber(1)
+  set name($core.String v) { $_setString(0, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasName() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearName() => clearField(1);
+
+  @$pb.TagNumber(2)
+  $core.String get radioText => $_getSZ(1);
+  @$pb.TagNumber(2)
+  set radioText($core.String v) { $_setString(1, v); }
+  @$pb.TagNumber(2)
+  $core.bool hasRadioText() => $_has(1);
+  @$pb.TagNumber(2)
+  void clearRadioText() => clearField(2);
+
+  @$pb.TagNumber(3)
+  $core.String get alternatives => $_getSZ(2);
+  @$pb.TagNumber(3)
+  set alternatives($core.String v) { $_setString(2, v); }
+  @$pb.TagNumber(3)
+  $core.bool hasAlternatives() => $_has(2);
+  @$pb.TagNumber(3)
+  void clearAlternatives() => clearField(3);
+
+  @$pb.TagNumber(4)
+  $core.String get minute => $_getSZ(3);
+  @$pb.TagNumber(4)
+  set minute($core.String v) { $_setString(3, v); }
+  @$pb.TagNumber(4)
+  $core.bool hasMinute() => $_has(3);
+  @$pb.TagNumber(4)
+  void clearMinute() => clearField(4);
+
+  @$pb.TagNumber(5)
+  $core.String get hour => $_getSZ(4);
+  @$pb.TagNumber(5)
+  set hour($core.String v) { $_setString(4, v); }
+  @$pb.TagNumber(5)
+  $core.bool hasHour() => $_has(4);
+  @$pb.TagNumber(5)
+  void clearHour() => clearField(5);
+
+  @$pb.TagNumber(6)
+  $core.String get day => $_getSZ(5);
+  @$pb.TagNumber(6)
+  set day($core.String v) { $_setString(5, v); }
+  @$pb.TagNumber(6)
+  $core.bool hasDay() => $_has(5);
+  @$pb.TagNumber(6)
+  void clearDay() => clearField(6);
+
+  @$pb.TagNumber(7)
+  $core.String get month => $_getSZ(6);
+  @$pb.TagNumber(7)
+  set month($core.String v) { $_setString(6, v); }
+  @$pb.TagNumber(7)
+  $core.bool hasMonth() => $_has(6);
+  @$pb.TagNumber(7)
+  void clearMonth() => clearField(7);
+
+  @$pb.TagNumber(8)
+  $core.String get year => $_getSZ(7);
+  @$pb.TagNumber(8)
+  set year($core.String v) { $_setString(7, v); }
+  @$pb.TagNumber(8)
+  $core.bool hasYear() => $_has(7);
+  @$pb.TagNumber(8)
+  void clearYear() => clearField(8);
+
+  @$pb.TagNumber(9)
+  $core.String get pi => $_getSZ(8);
+  @$pb.TagNumber(9)
+  set pi($core.String v) { $_setString(8, v); }
+  @$pb.TagNumber(9)
+  $core.bool hasPi() => $_has(8);
+  @$pb.TagNumber(9)
+  void clearPi() => clearField(9);
+
+  @$pb.TagNumber(10)
+  $core.String get pty => $_getSZ(9);
+  @$pb.TagNumber(10)
+  set pty($core.String v) { $_setString(9, v); }
+  @$pb.TagNumber(10)
+  $core.bool hasPty() => $_has(9);
+  @$pb.TagNumber(10)
+  void clearPty() => clearField(10);
+
+  @$pb.TagNumber(11)
+  $core.String get ta => $_getSZ(10);
+  @$pb.TagNumber(11)
+  set ta($core.String v) { $_setString(10, v); }
+  @$pb.TagNumber(11)
+  $core.bool hasTa() => $_has(10);
+  @$pb.TagNumber(11)
+  void clearTa() => clearField(11);
+
+  @$pb.TagNumber(12)
+  $core.String get tp => $_getSZ(11);
+  @$pb.TagNumber(12)
+  set tp($core.String v) { $_setString(11, v); }
+  @$pb.TagNumber(12)
+  $core.bool hasTp() => $_has(11);
+  @$pb.TagNumber(12)
+  void clearTp() => clearField(12);
+
+  @$pb.TagNumber(13)
+  $core.String get ms => $_getSZ(12);
+  @$pb.TagNumber(13)
+  set ms($core.String v) { $_setString(12, v); }
+  @$pb.TagNumber(13)
+  $core.bool hasMs() => $_has(12);
+  @$pb.TagNumber(13)
+  void clearMs() => clearField(13);
+}
+
+class GetQualityRequest extends $pb.GeneratedMessage {
+  factory GetQualityRequest() => create();
+  GetQualityRequest._() : super();
+  factory GetQualityRequest.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory GetQualityRequest.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'GetQualityRequest', package: const $pb.PackageName(_omitMessageNames ? '' : 'automotivegradelinux'), createEmptyInstance: create)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  GetQualityRequest clone() => GetQualityRequest()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  GetQualityRequest copyWith(void Function(GetQualityRequest) updates) => super.copyWith((message) => updates(message as GetQualityRequest)) as GetQualityRequest;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static GetQualityRequest create() => GetQualityRequest._();
+  GetQualityRequest createEmptyInstance() => create();
+  static $pb.PbList<GetQualityRequest> createRepeated() => $pb.PbList<GetQualityRequest>();
+  @$core.pragma('dart2js:noInline')
+  static GetQualityRequest getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<GetQualityRequest>(create);
+  static GetQualityRequest? _defaultInstance;
+}
+
+class GetQualityResponse extends $pb.GeneratedMessage {
+  factory GetQualityResponse() => create();
+  GetQualityResponse._() : super();
+  factory GetQualityResponse.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory GetQualityResponse.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'GetQualityResponse', package: const $pb.PackageName(_omitMessageNames ? '' : 'automotivegradelinux'), createEmptyInstance: create)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  GetQualityResponse clone() => GetQualityResponse()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  GetQualityResponse copyWith(void Function(GetQualityResponse) updates) => super.copyWith((message) => updates(message as GetQualityResponse)) as GetQualityResponse;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static GetQualityResponse create() => GetQualityResponse._();
+  GetQualityResponse createEmptyInstance() => create();
+  static $pb.PbList<GetQualityResponse> createRepeated() => $pb.PbList<GetQualityResponse>();
+  @$core.pragma('dart2js:noInline')
+  static GetQualityResponse getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<GetQualityResponse>(create);
+  static GetQualityResponse? _defaultInstance;
+}
+
+class SetAlternativeFrequencyRequest extends $pb.GeneratedMessage {
+  factory SetAlternativeFrequencyRequest({
+    $core.int? frequency,
+  }) {
+    final $result = create();
+    if (frequency != null) {
+      $result.frequency = frequency;
+    }
+    return $result;
+  }
+  SetAlternativeFrequencyRequest._() : super();
+  factory SetAlternativeFrequencyRequest.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory SetAlternativeFrequencyRequest.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'SetAlternativeFrequencyRequest', package: const $pb.PackageName(_omitMessageNames ? '' : 'automotivegradelinux'), createEmptyInstance: create)
+    ..a<$core.int>(1, _omitFieldNames ? '' : 'frequency', $pb.PbFieldType.OU3)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  SetAlternativeFrequencyRequest clone() => SetAlternativeFrequencyRequest()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  SetAlternativeFrequencyRequest copyWith(void Function(SetAlternativeFrequencyRequest) updates) => super.copyWith((message) => updates(message as SetAlternativeFrequencyRequest)) as SetAlternativeFrequencyRequest;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static SetAlternativeFrequencyRequest create() => SetAlternativeFrequencyRequest._();
+  SetAlternativeFrequencyRequest createEmptyInstance() => create();
+  static $pb.PbList<SetAlternativeFrequencyRequest> createRepeated() => $pb.PbList<SetAlternativeFrequencyRequest>();
+  @$core.pragma('dart2js:noInline')
+  static SetAlternativeFrequencyRequest getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<SetAlternativeFrequencyRequest>(create);
+  static SetAlternativeFrequencyRequest? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $core.int get frequency => $_getIZ(0);
+  @$pb.TagNumber(1)
+  set frequency($core.int v) { $_setUnsignedInt32(0, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasFrequency() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearFrequency() => clearField(1);
+}
+
+class SetAlternativeFrequencyResponse extends $pb.GeneratedMessage {
+  factory SetAlternativeFrequencyResponse({
+    $core.int? frequency,
+  }) {
+    final $result = create();
+    if (frequency != null) {
+      $result.frequency = frequency;
+    }
+    return $result;
+  }
+  SetAlternativeFrequencyResponse._() : super();
+  factory SetAlternativeFrequencyResponse.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory SetAlternativeFrequencyResponse.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'SetAlternativeFrequencyResponse', package: const $pb.PackageName(_omitMessageNames ? '' : 'automotivegradelinux'), createEmptyInstance: create)
+    ..a<$core.int>(1, _omitFieldNames ? '' : 'frequency', $pb.PbFieldType.OU3)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  SetAlternativeFrequencyResponse clone() => SetAlternativeFrequencyResponse()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  SetAlternativeFrequencyResponse copyWith(void Function(SetAlternativeFrequencyResponse) updates) => super.copyWith((message) => updates(message as SetAlternativeFrequencyResponse)) as SetAlternativeFrequencyResponse;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static SetAlternativeFrequencyResponse create() => SetAlternativeFrequencyResponse._();
+  SetAlternativeFrequencyResponse createEmptyInstance() => create();
+  static $pb.PbList<SetAlternativeFrequencyResponse> createRepeated() => $pb.PbList<SetAlternativeFrequencyResponse>();
+  @$core.pragma('dart2js:noInline')
+  static SetAlternativeFrequencyResponse getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<SetAlternativeFrequencyResponse>(create);
+  static SetAlternativeFrequencyResponse? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $core.int get frequency => $_getIZ(0);
+  @$pb.TagNumber(1)
+  set frequency($core.int v) { $_setUnsignedInt32(0, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasFrequency() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearFrequency() => clearField(1);
+}
+
+class StatusRequest extends $pb.GeneratedMessage {
+  factory StatusRequest() => create();
+  StatusRequest._() : super();
+  factory StatusRequest.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory StatusRequest.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'StatusRequest', package: const $pb.PackageName(_omitMessageNames ? '' : 'automotivegradelinux'), createEmptyInstance: create)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  StatusRequest clone() => StatusRequest()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  StatusRequest copyWith(void Function(StatusRequest) updates) => super.copyWith((message) => updates(message as StatusRequest)) as StatusRequest;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static StatusRequest create() => StatusRequest._();
+  StatusRequest createEmptyInstance() => create();
+  static $pb.PbList<StatusRequest> createRepeated() => $pb.PbList<StatusRequest>();
+  @$core.pragma('dart2js:noInline')
+  static StatusRequest getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<StatusRequest>(create);
+  static StatusRequest? _defaultInstance;
+}
+
+class BandStatus extends $pb.GeneratedMessage {
+  factory BandStatus({
+    Band? band,
+  }) {
+    final $result = create();
+    if (band != null) {
+      $result.band = band;
+    }
+    return $result;
+  }
+  BandStatus._() : super();
+  factory BandStatus.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory BandStatus.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'BandStatus', package: const $pb.PackageName(_omitMessageNames ? '' : 'automotivegradelinux'), createEmptyInstance: create)
+    ..e<Band>(1, _omitFieldNames ? '' : 'band', $pb.PbFieldType.OE, defaultOrMaker: Band.BAND_UNSPECIFIED, valueOf: Band.valueOf, enumValues: Band.values)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  BandStatus clone() => BandStatus()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  BandStatus copyWith(void Function(BandStatus) updates) => super.copyWith((message) => updates(message as BandStatus)) as BandStatus;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static BandStatus create() => BandStatus._();
+  BandStatus createEmptyInstance() => create();
+  static $pb.PbList<BandStatus> createRepeated() => $pb.PbList<BandStatus>();
+  @$core.pragma('dart2js:noInline')
+  static BandStatus getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<BandStatus>(create);
+  static BandStatus? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  Band get band => $_getN(0);
+  @$pb.TagNumber(1)
+  set band(Band v) { setField(1, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasBand() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearBand() => clearField(1);
+}
+
+class FrequencyStatus extends $pb.GeneratedMessage {
+  factory FrequencyStatus({
+    $core.int? frequency,
+  }) {
+    final $result = create();
+    if (frequency != null) {
+      $result.frequency = frequency;
+    }
+    return $result;
+  }
+  FrequencyStatus._() : super();
+  factory FrequencyStatus.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory FrequencyStatus.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'FrequencyStatus', package: const $pb.PackageName(_omitMessageNames ? '' : 'automotivegradelinux'), createEmptyInstance: create)
+    ..a<$core.int>(1, _omitFieldNames ? '' : 'frequency', $pb.PbFieldType.OU3)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  FrequencyStatus clone() => FrequencyStatus()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  FrequencyStatus copyWith(void Function(FrequencyStatus) updates) => super.copyWith((message) => updates(message as FrequencyStatus)) as FrequencyStatus;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static FrequencyStatus create() => FrequencyStatus._();
+  FrequencyStatus createEmptyInstance() => create();
+  static $pb.PbList<FrequencyStatus> createRepeated() => $pb.PbList<FrequencyStatus>();
+  @$core.pragma('dart2js:noInline')
+  static FrequencyStatus getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<FrequencyStatus>(create);
+  static FrequencyStatus? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $core.int get frequency => $_getIZ(0);
+  @$pb.TagNumber(1)
+  set frequency($core.int v) { $_setUnsignedInt32(0, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasFrequency() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearFrequency() => clearField(1);
+}
+
+class PlayStatus extends $pb.GeneratedMessage {
+  factory PlayStatus({
+    $core.bool? playing,
+  }) {
+    final $result = create();
+    if (playing != null) {
+      $result.playing = playing;
+    }
+    return $result;
+  }
+  PlayStatus._() : super();
+  factory PlayStatus.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory PlayStatus.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'PlayStatus', package: const $pb.PackageName(_omitMessageNames ? '' : 'automotivegradelinux'), createEmptyInstance: create)
+    ..aOB(1, _omitFieldNames ? '' : 'playing')
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  PlayStatus clone() => PlayStatus()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  PlayStatus copyWith(void Function(PlayStatus) updates) => super.copyWith((message) => updates(message as PlayStatus)) as PlayStatus;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static PlayStatus create() => PlayStatus._();
+  PlayStatus createEmptyInstance() => create();
+  static $pb.PbList<PlayStatus> createRepeated() => $pb.PbList<PlayStatus>();
+  @$core.pragma('dart2js:noInline')
+  static PlayStatus getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<PlayStatus>(create);
+  static PlayStatus? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $core.bool get playing => $_getBF(0);
+  @$pb.TagNumber(1)
+  set playing($core.bool v) { $_setBool(0, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasPlaying() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearPlaying() => clearField(1);
+}
+
+class ScanStatus extends $pb.GeneratedMessage {
+  factory ScanStatus({
+    $core.bool? stationFound,
+  }) {
+    final $result = create();
+    if (stationFound != null) {
+      $result.stationFound = stationFound;
+    }
+    return $result;
+  }
+  ScanStatus._() : super();
+  factory ScanStatus.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory ScanStatus.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'ScanStatus', package: const $pb.PackageName(_omitMessageNames ? '' : 'automotivegradelinux'), createEmptyInstance: create)
+    ..aOB(1, _omitFieldNames ? '' : 'stationFound')
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  ScanStatus clone() => ScanStatus()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  ScanStatus copyWith(void Function(ScanStatus) updates) => super.copyWith((message) => updates(message as ScanStatus)) as ScanStatus;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static ScanStatus create() => ScanStatus._();
+  ScanStatus createEmptyInstance() => create();
+  static $pb.PbList<ScanStatus> createRepeated() => $pb.PbList<ScanStatus>();
+  @$core.pragma('dart2js:noInline')
+  static ScanStatus getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<ScanStatus>(create);
+  static ScanStatus? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $core.bool get stationFound => $_getBF(0);
+  @$pb.TagNumber(1)
+  set stationFound($core.bool v) { $_setBool(0, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasStationFound() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearStationFound() => clearField(1);
+}
+
+class StereoStatus extends $pb.GeneratedMessage {
+  factory StereoStatus({
+    StereoMode? mode,
+  }) {
+    final $result = create();
+    if (mode != null) {
+      $result.mode = mode;
+    }
+    return $result;
+  }
+  StereoStatus._() : super();
+  factory StereoStatus.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory StereoStatus.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'StereoStatus', package: const $pb.PackageName(_omitMessageNames ? '' : 'automotivegradelinux'), createEmptyInstance: create)
+    ..e<StereoMode>(1, _omitFieldNames ? '' : 'mode', $pb.PbFieldType.OE, defaultOrMaker: StereoMode.STEREO_MODE_UNSPECIFIED, valueOf: StereoMode.valueOf, enumValues: StereoMode.values)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  StereoStatus clone() => StereoStatus()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  StereoStatus copyWith(void Function(StereoStatus) updates) => super.copyWith((message) => updates(message as StereoStatus)) as StereoStatus;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static StereoStatus create() => StereoStatus._();
+  StereoStatus createEmptyInstance() => create();
+  static $pb.PbList<StereoStatus> createRepeated() => $pb.PbList<StereoStatus>();
+  @$core.pragma('dart2js:noInline')
+  static StereoStatus getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<StereoStatus>(create);
+  static StereoStatus? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  StereoMode get mode => $_getN(0);
+  @$pb.TagNumber(1)
+  set mode(StereoMode v) { setField(1, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasMode() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearMode() => clearField(1);
+}
+
+enum StatusResponse_Status {
+  band, 
+  frequency, 
+  play, 
+  stereo, 
+  scan, 
+  notSet
+}
+
+class StatusResponse extends $pb.GeneratedMessage {
+  factory StatusResponse({
+    BandStatus? band,
+    FrequencyStatus? frequency,
+    PlayStatus? play,
+    StereoStatus? stereo,
+    ScanStatus? scan,
+  }) {
+    final $result = create();
+    if (band != null) {
+      $result.band = band;
+    }
+    if (frequency != null) {
+      $result.frequency = frequency;
+    }
+    if (play != null) {
+      $result.play = play;
+    }
+    if (stereo != null) {
+      $result.stereo = stereo;
+    }
+    if (scan != null) {
+      $result.scan = scan;
+    }
+    return $result;
+  }
+  StatusResponse._() : super();
+  factory StatusResponse.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory StatusResponse.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static const $core.Map<$core.int, StatusResponse_Status> _StatusResponse_StatusByTag = {
+    1 : StatusResponse_Status.band,
+    2 : StatusResponse_Status.frequency,
+    3 : StatusResponse_Status.play,
+    4 : StatusResponse_Status.stereo,
+    5 : StatusResponse_Status.scan,
+    0 : StatusResponse_Status.notSet
+  };
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'StatusResponse', package: const $pb.PackageName(_omitMessageNames ? '' : 'automotivegradelinux'), createEmptyInstance: create)
+    ..oo(0, [1, 2, 3, 4, 5])
+    ..aOM<BandStatus>(1, _omitFieldNames ? '' : 'band', subBuilder: BandStatus.create)
+    ..aOM<FrequencyStatus>(2, _omitFieldNames ? '' : 'frequency', subBuilder: FrequencyStatus.create)
+    ..aOM<PlayStatus>(3, _omitFieldNames ? '' : 'play', subBuilder: PlayStatus.create)
+    ..aOM<StereoStatus>(4, _omitFieldNames ? '' : 'stereo', subBuilder: StereoStatus.create)
+    ..aOM<ScanStatus>(5, _omitFieldNames ? '' : 'scan', subBuilder: ScanStatus.create)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  StatusResponse clone() => StatusResponse()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  StatusResponse copyWith(void Function(StatusResponse) updates) => super.copyWith((message) => updates(message as StatusResponse)) as StatusResponse;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static StatusResponse create() => StatusResponse._();
+  StatusResponse createEmptyInstance() => create();
+  static $pb.PbList<StatusResponse> createRepeated() => $pb.PbList<StatusResponse>();
+  @$core.pragma('dart2js:noInline')
+  static StatusResponse getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<StatusResponse>(create);
+  static StatusResponse? _defaultInstance;
+
+  StatusResponse_Status whichStatus() => _StatusResponse_StatusByTag[$_whichOneof(0)]!;
+  void clearStatus() => clearField($_whichOneof(0));
+
+  @$pb.TagNumber(1)
+  BandStatus get band => $_getN(0);
+  @$pb.TagNumber(1)
+  set band(BandStatus v) { setField(1, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasBand() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearBand() => clearField(1);
+  @$pb.TagNumber(1)
+  BandStatus ensureBand() => $_ensure(0);
+
+  @$pb.TagNumber(2)
+  FrequencyStatus get frequency => $_getN(1);
+  @$pb.TagNumber(2)
+  set frequency(FrequencyStatus v) { setField(2, v); }
+  @$pb.TagNumber(2)
+  $core.bool hasFrequency() => $_has(1);
+  @$pb.TagNumber(2)
+  void clearFrequency() => clearField(2);
+  @$pb.TagNumber(2)
+  FrequencyStatus ensureFrequency() => $_ensure(1);
+
+  @$pb.TagNumber(3)
+  PlayStatus get play => $_getN(2);
+  @$pb.TagNumber(3)
+  set play(PlayStatus v) { setField(3, v); }
+  @$pb.TagNumber(3)
+  $core.bool hasPlay() => $_has(2);
+  @$pb.TagNumber(3)
+  void clearPlay() => clearField(3);
+  @$pb.TagNumber(3)
+  PlayStatus ensurePlay() => $_ensure(2);
+
+  @$pb.TagNumber(4)
+  StereoStatus get stereo => $_getN(3);
+  @$pb.TagNumber(4)
+  set stereo(StereoStatus v) { setField(4, v); }
+  @$pb.TagNumber(4)
+  $core.bool hasStereo() => $_has(3);
+  @$pb.TagNumber(4)
+  void clearStereo() => clearField(4);
+  @$pb.TagNumber(4)
+  StereoStatus ensureStereo() => $_ensure(3);
+
+  @$pb.TagNumber(5)
+  ScanStatus get scan => $_getN(4);
+  @$pb.TagNumber(5)
+  set scan(ScanStatus v) { setField(5, v); }
+  @$pb.TagNumber(5)
+  $core.bool hasScan() => $_has(4);
+  @$pb.TagNumber(5)
+  void clearScan() => clearField(5);
+  @$pb.TagNumber(5)
+  ScanStatus ensureScan() => $_ensure(4);
+}
+
+
+const _omitFieldNames = $core.bool.fromEnvironment('protobuf.omit_field_names');
+const _omitMessageNames = $core.bool.fromEnvironment('protobuf.omit_message_names');
diff --git a/protos/lib/src/generated/radio.pbenum.dart b/protos/lib/src/generated/radio.pbenum.dart
new file mode 100644 (file)
index 0000000..f22c535
--- /dev/null
@@ -0,0 +1,70 @@
+//
+//  Generated code. Do not modify.
+//  source: radio.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:core' as $core;
+
+import 'package:protobuf/protobuf.dart' as $pb;
+
+class Band extends $pb.ProtobufEnum {
+  static const Band BAND_UNSPECIFIED = Band._(0, _omitEnumNames ? '' : 'BAND_UNSPECIFIED');
+  static const Band BAND_AM = Band._(1, _omitEnumNames ? '' : 'BAND_AM');
+  static const Band BAND_FM = Band._(2, _omitEnumNames ? '' : 'BAND_FM');
+  static const Band BAND_DBS = Band._(3, _omitEnumNames ? '' : 'BAND_DBS');
+
+  static const $core.List<Band> values = <Band> [
+    BAND_UNSPECIFIED,
+    BAND_AM,
+    BAND_FM,
+    BAND_DBS,
+  ];
+
+  static final $core.Map<$core.int, Band> _byValue = $pb.ProtobufEnum.initByValue(values);
+  static Band? valueOf($core.int value) => _byValue[value];
+
+  const Band._($core.int v, $core.String n) : super(v, n);
+}
+
+class StereoMode extends $pb.ProtobufEnum {
+  static const StereoMode STEREO_MODE_UNSPECIFIED = StereoMode._(0, _omitEnumNames ? '' : 'STEREO_MODE_UNSPECIFIED');
+  static const StereoMode STEREO_MODE_MONO = StereoMode._(1, _omitEnumNames ? '' : 'STEREO_MODE_MONO');
+  static const StereoMode STEREO_MODE_STEREO = StereoMode._(2, _omitEnumNames ? '' : 'STEREO_MODE_STEREO');
+
+  static const $core.List<StereoMode> values = <StereoMode> [
+    STEREO_MODE_UNSPECIFIED,
+    STEREO_MODE_MONO,
+    STEREO_MODE_STEREO,
+  ];
+
+  static final $core.Map<$core.int, StereoMode> _byValue = $pb.ProtobufEnum.initByValue(values);
+  static StereoMode? valueOf($core.int value) => _byValue[value];
+
+  const StereoMode._($core.int v, $core.String n) : super(v, n);
+}
+
+class ScanDirection extends $pb.ProtobufEnum {
+  static const ScanDirection SCAN_DIRECTION_UNSPECIFIED = ScanDirection._(0, _omitEnumNames ? '' : 'SCAN_DIRECTION_UNSPECIFIED');
+  static const ScanDirection SCAN_DIRECTION_FORWARD = ScanDirection._(1, _omitEnumNames ? '' : 'SCAN_DIRECTION_FORWARD');
+  static const ScanDirection SCAN_DIRECTION_BACKWARD = ScanDirection._(2, _omitEnumNames ? '' : 'SCAN_DIRECTION_BACKWARD');
+
+  static const $core.List<ScanDirection> values = <ScanDirection> [
+    SCAN_DIRECTION_UNSPECIFIED,
+    SCAN_DIRECTION_FORWARD,
+    SCAN_DIRECTION_BACKWARD,
+  ];
+
+  static final $core.Map<$core.int, ScanDirection> _byValue = $pb.ProtobufEnum.initByValue(values);
+  static ScanDirection? valueOf($core.int value) => _byValue[value];
+
+  const ScanDirection._($core.int v, $core.String n) : super(v, n);
+}
+
+
+const _omitEnumNames = $core.bool.fromEnvironment('protobuf.omit_enum_names');
diff --git a/protos/lib/src/generated/radio.pbgrpc.dart b/protos/lib/src/generated/radio.pbgrpc.dart
new file mode 100644 (file)
index 0000000..7e4233a
--- /dev/null
@@ -0,0 +1,359 @@
+//
+//  Generated code. Do not modify.
+//  source: radio.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:async' as $async;
+import 'dart:core' as $core;
+
+import 'package:grpc/service_api.dart' as $grpc;
+import 'package:protobuf/protobuf.dart' as $pb;
+
+import 'radio.pb.dart' as $0;
+
+export 'radio.pb.dart';
+
+@$pb.GrpcServiceName('automotivegradelinux.Radio')
+class RadioClient extends $grpc.Client {
+  static final _$getFrequency = $grpc.ClientMethod<$0.GetFrequencyRequest, $0.GetFrequencyResponse>(
+      '/automotivegradelinux.Radio/GetFrequency',
+      ($0.GetFrequencyRequest value) => value.writeToBuffer(),
+      ($core.List<$core.int> value) => $0.GetFrequencyResponse.fromBuffer(value));
+  static final _$setFrequency = $grpc.ClientMethod<$0.SetFrequencyRequest, $0.SetFrequencyResponse>(
+      '/automotivegradelinux.Radio/SetFrequency',
+      ($0.SetFrequencyRequest value) => value.writeToBuffer(),
+      ($core.List<$core.int> value) => $0.SetFrequencyResponse.fromBuffer(value));
+  static final _$getBand = $grpc.ClientMethod<$0.GetBandRequest, $0.GetBandResponse>(
+      '/automotivegradelinux.Radio/GetBand',
+      ($0.GetBandRequest value) => value.writeToBuffer(),
+      ($core.List<$core.int> value) => $0.GetBandResponse.fromBuffer(value));
+  static final _$setBand = $grpc.ClientMethod<$0.SetBandRequest, $0.SetBandResponse>(
+      '/automotivegradelinux.Radio/SetBand',
+      ($0.SetBandRequest value) => value.writeToBuffer(),
+      ($core.List<$core.int> value) => $0.SetBandResponse.fromBuffer(value));
+  static final _$getBandSupported = $grpc.ClientMethod<$0.GetBandSupportedRequest, $0.GetBandSupportedResponse>(
+      '/automotivegradelinux.Radio/GetBandSupported',
+      ($0.GetBandSupportedRequest value) => value.writeToBuffer(),
+      ($core.List<$core.int> value) => $0.GetBandSupportedResponse.fromBuffer(value));
+  static final _$getBandParameters = $grpc.ClientMethod<$0.GetBandParametersRequest, $0.GetBandParametersResponse>(
+      '/automotivegradelinux.Radio/GetBandParameters',
+      ($0.GetBandParametersRequest value) => value.writeToBuffer(),
+      ($core.List<$core.int> value) => $0.GetBandParametersResponse.fromBuffer(value));
+  static final _$getStereoMode = $grpc.ClientMethod<$0.GetStereoModeRequest, $0.GetStereoModeResponse>(
+      '/automotivegradelinux.Radio/GetStereoMode',
+      ($0.GetStereoModeRequest value) => value.writeToBuffer(),
+      ($core.List<$core.int> value) => $0.GetStereoModeResponse.fromBuffer(value));
+  static final _$setStereoMode = $grpc.ClientMethod<$0.SetStereoModeRequest, $0.SetStereoModeResponse>(
+      '/automotivegradelinux.Radio/SetStereoMode',
+      ($0.SetStereoModeRequest value) => value.writeToBuffer(),
+      ($core.List<$core.int> value) => $0.SetStereoModeResponse.fromBuffer(value));
+  static final _$start = $grpc.ClientMethod<$0.StartRequest, $0.StartResponse>(
+      '/automotivegradelinux.Radio/Start',
+      ($0.StartRequest value) => value.writeToBuffer(),
+      ($core.List<$core.int> value) => $0.StartResponse.fromBuffer(value));
+  static final _$stop = $grpc.ClientMethod<$0.StopRequest, $0.StopResponse>(
+      '/automotivegradelinux.Radio/Stop',
+      ($0.StopRequest value) => value.writeToBuffer(),
+      ($core.List<$core.int> value) => $0.StopResponse.fromBuffer(value));
+  static final _$scanStart = $grpc.ClientMethod<$0.ScanStartRequest, $0.ScanStartResponse>(
+      '/automotivegradelinux.Radio/ScanStart',
+      ($0.ScanStartRequest value) => value.writeToBuffer(),
+      ($core.List<$core.int> value) => $0.ScanStartResponse.fromBuffer(value));
+  static final _$scanStop = $grpc.ClientMethod<$0.ScanStopRequest, $0.ScanStopResponse>(
+      '/automotivegradelinux.Radio/ScanStop',
+      ($0.ScanStopRequest value) => value.writeToBuffer(),
+      ($core.List<$core.int> value) => $0.ScanStopResponse.fromBuffer(value));
+  static final _$getRDS = $grpc.ClientMethod<$0.GetRDSRequest, $0.GetRDSResponse>(
+      '/automotivegradelinux.Radio/GetRDS',
+      ($0.GetRDSRequest value) => value.writeToBuffer(),
+      ($core.List<$core.int> value) => $0.GetRDSResponse.fromBuffer(value));
+  static final _$getQuality = $grpc.ClientMethod<$0.GetQualityRequest, $0.GetQualityResponse>(
+      '/automotivegradelinux.Radio/GetQuality',
+      ($0.GetQualityRequest value) => value.writeToBuffer(),
+      ($core.List<$core.int> value) => $0.GetQualityResponse.fromBuffer(value));
+  static final _$setAlternativeFrequency = $grpc.ClientMethod<$0.SetAlternativeFrequencyRequest, $0.SetAlternativeFrequencyResponse>(
+      '/automotivegradelinux.Radio/SetAlternativeFrequency',
+      ($0.SetAlternativeFrequencyRequest value) => value.writeToBuffer(),
+      ($core.List<$core.int> value) => $0.SetAlternativeFrequencyResponse.fromBuffer(value));
+  static final _$getStatusEvents = $grpc.ClientMethod<$0.StatusRequest, $0.StatusResponse>(
+      '/automotivegradelinux.Radio/GetStatusEvents',
+      ($0.StatusRequest value) => value.writeToBuffer(),
+      ($core.List<$core.int> value) => $0.StatusResponse.fromBuffer(value));
+
+  RadioClient($grpc.ClientChannel channel,
+      {$grpc.CallOptions? options,
+      $core.Iterable<$grpc.ClientInterceptor>? interceptors})
+      : super(channel, options: options,
+        interceptors: interceptors);
+
+  $grpc.ResponseFuture<$0.GetFrequencyResponse> getFrequency($0.GetFrequencyRequest request, {$grpc.CallOptions? options}) {
+    return $createUnaryCall(_$getFrequency, request, options: options);
+  }
+
+  $grpc.ResponseFuture<$0.SetFrequencyResponse> setFrequency($0.SetFrequencyRequest request, {$grpc.CallOptions? options}) {
+    return $createUnaryCall(_$setFrequency, request, options: options);
+  }
+
+  $grpc.ResponseFuture<$0.GetBandResponse> getBand($0.GetBandRequest request, {$grpc.CallOptions? options}) {
+    return $createUnaryCall(_$getBand, request, options: options);
+  }
+
+  $grpc.ResponseFuture<$0.SetBandResponse> setBand($0.SetBandRequest request, {$grpc.CallOptions? options}) {
+    return $createUnaryCall(_$setBand, request, options: options);
+  }
+
+  $grpc.ResponseFuture<$0.GetBandSupportedResponse> getBandSupported($0.GetBandSupportedRequest request, {$grpc.CallOptions? options}) {
+    return $createUnaryCall(_$getBandSupported, request, options: options);
+  }
+
+  $grpc.ResponseFuture<$0.GetBandParametersResponse> getBandParameters($0.GetBandParametersRequest request, {$grpc.CallOptions? options}) {
+    return $createUnaryCall(_$getBandParameters, request, options: options);
+  }
+
+  $grpc.ResponseFuture<$0.GetStereoModeResponse> getStereoMode($0.GetStereoModeRequest request, {$grpc.CallOptions? options}) {
+    return $createUnaryCall(_$getStereoMode, request, options: options);
+  }
+
+  $grpc.ResponseFuture<$0.SetStereoModeResponse> setStereoMode($0.SetStereoModeRequest request, {$grpc.CallOptions? options}) {
+    return $createUnaryCall(_$setStereoMode, request, options: options);
+  }
+
+  $grpc.ResponseFuture<$0.StartResponse> start($0.StartRequest request, {$grpc.CallOptions? options}) {
+    return $createUnaryCall(_$start, request, options: options);
+  }
+
+  $grpc.ResponseFuture<$0.StopResponse> stop($0.StopRequest request, {$grpc.CallOptions? options}) {
+    return $createUnaryCall(_$stop, request, options: options);
+  }
+
+  $grpc.ResponseFuture<$0.ScanStartResponse> scanStart($0.ScanStartRequest request, {$grpc.CallOptions? options}) {
+    return $createUnaryCall(_$scanStart, request, options: options);
+  }
+
+  $grpc.ResponseFuture<$0.ScanStopResponse> scanStop($0.ScanStopRequest request, {$grpc.CallOptions? options}) {
+    return $createUnaryCall(_$scanStop, request, options: options);
+  }
+
+  $grpc.ResponseFuture<$0.GetRDSResponse> getRDS($0.GetRDSRequest request, {$grpc.CallOptions? options}) {
+    return $createUnaryCall(_$getRDS, request, options: options);
+  }
+
+  $grpc.ResponseFuture<$0.GetQualityResponse> getQuality($0.GetQualityRequest request, {$grpc.CallOptions? options}) {
+    return $createUnaryCall(_$getQuality, request, options: options);
+  }
+
+  $grpc.ResponseFuture<$0.SetAlternativeFrequencyResponse> setAlternativeFrequency($0.SetAlternativeFrequencyRequest request, {$grpc.CallOptions? options}) {
+    return $createUnaryCall(_$setAlternativeFrequency, request, options: options);
+  }
+
+  $grpc.ResponseStream<$0.StatusResponse> getStatusEvents($0.StatusRequest request, {$grpc.CallOptions? options}) {
+    return $createStreamingCall(_$getStatusEvents, $async.Stream.fromIterable([request]), options: options);
+  }
+}
+
+@$pb.GrpcServiceName('automotivegradelinux.Radio')
+abstract class RadioServiceBase extends $grpc.Service {
+  $core.String get $name => 'automotivegradelinux.Radio';
+
+  RadioServiceBase() {
+    $addMethod($grpc.ServiceMethod<$0.GetFrequencyRequest, $0.GetFrequencyResponse>(
+        'GetFrequency',
+        getFrequency_Pre,
+        false,
+        false,
+        ($core.List<$core.int> value) => $0.GetFrequencyRequest.fromBuffer(value),
+        ($0.GetFrequencyResponse value) => value.writeToBuffer()));
+    $addMethod($grpc.ServiceMethod<$0.SetFrequencyRequest, $0.SetFrequencyResponse>(
+        'SetFrequency',
+        setFrequency_Pre,
+        false,
+        false,
+        ($core.List<$core.int> value) => $0.SetFrequencyRequest.fromBuffer(value),
+        ($0.SetFrequencyResponse value) => value.writeToBuffer()));
+    $addMethod($grpc.ServiceMethod<$0.GetBandRequest, $0.GetBandResponse>(
+        'GetBand',
+        getBand_Pre,
+        false,
+        false,
+        ($core.List<$core.int> value) => $0.GetBandRequest.fromBuffer(value),
+        ($0.GetBandResponse value) => value.writeToBuffer()));
+    $addMethod($grpc.ServiceMethod<$0.SetBandRequest, $0.SetBandResponse>(
+        'SetBand',
+        setBand_Pre,
+        false,
+        false,
+        ($core.List<$core.int> value) => $0.SetBandRequest.fromBuffer(value),
+        ($0.SetBandResponse value) => value.writeToBuffer()));
+    $addMethod($grpc.ServiceMethod<$0.GetBandSupportedRequest, $0.GetBandSupportedResponse>(
+        'GetBandSupported',
+        getBandSupported_Pre,
+        false,
+        false,
+        ($core.List<$core.int> value) => $0.GetBandSupportedRequest.fromBuffer(value),
+        ($0.GetBandSupportedResponse value) => value.writeToBuffer()));
+    $addMethod($grpc.ServiceMethod<$0.GetBandParametersRequest, $0.GetBandParametersResponse>(
+        'GetBandParameters',
+        getBandParameters_Pre,
+        false,
+        false,
+        ($core.List<$core.int> value) => $0.GetBandParametersRequest.fromBuffer(value),
+        ($0.GetBandParametersResponse value) => value.writeToBuffer()));
+    $addMethod($grpc.ServiceMethod<$0.GetStereoModeRequest, $0.GetStereoModeResponse>(
+        'GetStereoMode',
+        getStereoMode_Pre,
+        false,
+        false,
+        ($core.List<$core.int> value) => $0.GetStereoModeRequest.fromBuffer(value),
+        ($0.GetStereoModeResponse value) => value.writeToBuffer()));
+    $addMethod($grpc.ServiceMethod<$0.SetStereoModeRequest, $0.SetStereoModeResponse>(
+        'SetStereoMode',
+        setStereoMode_Pre,
+        false,
+        false,
+        ($core.List<$core.int> value) => $0.SetStereoModeRequest.fromBuffer(value),
+        ($0.SetStereoModeResponse value) => value.writeToBuffer()));
+    $addMethod($grpc.ServiceMethod<$0.StartRequest, $0.StartResponse>(
+        'Start',
+        start_Pre,
+        false,
+        false,
+        ($core.List<$core.int> value) => $0.StartRequest.fromBuffer(value),
+        ($0.StartResponse value) => value.writeToBuffer()));
+    $addMethod($grpc.ServiceMethod<$0.StopRequest, $0.StopResponse>(
+        'Stop',
+        stop_Pre,
+        false,
+        false,
+        ($core.List<$core.int> value) => $0.StopRequest.fromBuffer(value),
+        ($0.StopResponse value) => value.writeToBuffer()));
+    $addMethod($grpc.ServiceMethod<$0.ScanStartRequest, $0.ScanStartResponse>(
+        'ScanStart',
+        scanStart_Pre,
+        false,
+        false,
+        ($core.List<$core.int> value) => $0.ScanStartRequest.fromBuffer(value),
+        ($0.ScanStartResponse value) => value.writeToBuffer()));
+    $addMethod($grpc.ServiceMethod<$0.ScanStopRequest, $0.ScanStopResponse>(
+        'ScanStop',
+        scanStop_Pre,
+        false,
+        false,
+        ($core.List<$core.int> value) => $0.ScanStopRequest.fromBuffer(value),
+        ($0.ScanStopResponse value) => value.writeToBuffer()));
+    $addMethod($grpc.ServiceMethod<$0.GetRDSRequest, $0.GetRDSResponse>(
+        'GetRDS',
+        getRDS_Pre,
+        false,
+        false,
+        ($core.List<$core.int> value) => $0.GetRDSRequest.fromBuffer(value),
+        ($0.GetRDSResponse value) => value.writeToBuffer()));
+    $addMethod($grpc.ServiceMethod<$0.GetQualityRequest, $0.GetQualityResponse>(
+        'GetQuality',
+        getQuality_Pre,
+        false,
+        false,
+        ($core.List<$core.int> value) => $0.GetQualityRequest.fromBuffer(value),
+        ($0.GetQualityResponse value) => value.writeToBuffer()));
+    $addMethod($grpc.ServiceMethod<$0.SetAlternativeFrequencyRequest, $0.SetAlternativeFrequencyResponse>(
+        'SetAlternativeFrequency',
+        setAlternativeFrequency_Pre,
+        false,
+        false,
+        ($core.List<$core.int> value) => $0.SetAlternativeFrequencyRequest.fromBuffer(value),
+        ($0.SetAlternativeFrequencyResponse value) => value.writeToBuffer()));
+    $addMethod($grpc.ServiceMethod<$0.StatusRequest, $0.StatusResponse>(
+        'GetStatusEvents',
+        getStatusEvents_Pre,
+        false,
+        true,
+        ($core.List<$core.int> value) => $0.StatusRequest.fromBuffer(value),
+        ($0.StatusResponse value) => value.writeToBuffer()));
+  }
+
+  $async.Future<$0.GetFrequencyResponse> getFrequency_Pre($grpc.ServiceCall call, $async.Future<$0.GetFrequencyRequest> request) async {
+    return getFrequency(call, await request);
+  }
+
+  $async.Future<$0.SetFrequencyResponse> setFrequency_Pre($grpc.ServiceCall call, $async.Future<$0.SetFrequencyRequest> request) async {
+    return setFrequency(call, await request);
+  }
+
+  $async.Future<$0.GetBandResponse> getBand_Pre($grpc.ServiceCall call, $async.Future<$0.GetBandRequest> request) async {
+    return getBand(call, await request);
+  }
+
+  $async.Future<$0.SetBandResponse> setBand_Pre($grpc.ServiceCall call, $async.Future<$0.SetBandRequest> request) async {
+    return setBand(call, await request);
+  }
+
+  $async.Future<$0.GetBandSupportedResponse> getBandSupported_Pre($grpc.ServiceCall call, $async.Future<$0.GetBandSupportedRequest> request) async {
+    return getBandSupported(call, await request);
+  }
+
+  $async.Future<$0.GetBandParametersResponse> getBandParameters_Pre($grpc.ServiceCall call, $async.Future<$0.GetBandParametersRequest> request) async {
+    return getBandParameters(call, await request);
+  }
+
+  $async.Future<$0.GetStereoModeResponse> getStereoMode_Pre($grpc.ServiceCall call, $async.Future<$0.GetStereoModeRequest> request) async {
+    return getStereoMode(call, await request);
+  }
+
+  $async.Future<$0.SetStereoModeResponse> setStereoMode_Pre($grpc.ServiceCall call, $async.Future<$0.SetStereoModeRequest> request) async {
+    return setStereoMode(call, await request);
+  }
+
+  $async.Future<$0.StartResponse> start_Pre($grpc.ServiceCall call, $async.Future<$0.StartRequest> request) async {
+    return start(call, await request);
+  }
+
+  $async.Future<$0.StopResponse> stop_Pre($grpc.ServiceCall call, $async.Future<$0.StopRequest> request) async {
+    return stop(call, await request);
+  }
+
+  $async.Future<$0.ScanStartResponse> scanStart_Pre($grpc.ServiceCall call, $async.Future<$0.ScanStartRequest> request) async {
+    return scanStart(call, await request);
+  }
+
+  $async.Future<$0.ScanStopResponse> scanStop_Pre($grpc.ServiceCall call, $async.Future<$0.ScanStopRequest> request) async {
+    return scanStop(call, await request);
+  }
+
+  $async.Future<$0.GetRDSResponse> getRDS_Pre($grpc.ServiceCall call, $async.Future<$0.GetRDSRequest> request) async {
+    return getRDS(call, await request);
+  }
+
+  $async.Future<$0.GetQualityResponse> getQuality_Pre($grpc.ServiceCall call, $async.Future<$0.GetQualityRequest> request) async {
+    return getQuality(call, await request);
+  }
+
+  $async.Future<$0.SetAlternativeFrequencyResponse> setAlternativeFrequency_Pre($grpc.ServiceCall call, $async.Future<$0.SetAlternativeFrequencyRequest> request) async {
+    return setAlternativeFrequency(call, await request);
+  }
+
+  $async.Stream<$0.StatusResponse> getStatusEvents_Pre($grpc.ServiceCall call, $async.Future<$0.StatusRequest> request) async* {
+    yield* getStatusEvents(call, await request);
+  }
+
+  $async.Future<$0.GetFrequencyResponse> getFrequency($grpc.ServiceCall call, $0.GetFrequencyRequest request);
+  $async.Future<$0.SetFrequencyResponse> setFrequency($grpc.ServiceCall call, $0.SetFrequencyRequest request);
+  $async.Future<$0.GetBandResponse> getBand($grpc.ServiceCall call, $0.GetBandRequest request);
+  $async.Future<$0.SetBandResponse> setBand($grpc.ServiceCall call, $0.SetBandRequest request);
+  $async.Future<$0.GetBandSupportedResponse> getBandSupported($grpc.ServiceCall call, $0.GetBandSupportedRequest request);
+  $async.Future<$0.GetBandParametersResponse> getBandParameters($grpc.ServiceCall call, $0.GetBandParametersRequest request);
+  $async.Future<$0.GetStereoModeResponse> getStereoMode($grpc.ServiceCall call, $0.GetStereoModeRequest request);
+  $async.Future<$0.SetStereoModeResponse> setStereoMode($grpc.ServiceCall call, $0.SetStereoModeRequest request);
+  $async.Future<$0.StartResponse> start($grpc.ServiceCall call, $0.StartRequest request);
+  $async.Future<$0.StopResponse> stop($grpc.ServiceCall call, $0.StopRequest request);
+  $async.Future<$0.ScanStartResponse> scanStart($grpc.ServiceCall call, $0.ScanStartRequest request);
+  $async.Future<$0.ScanStopResponse> scanStop($grpc.ServiceCall call, $0.ScanStopRequest request);
+  $async.Future<$0.GetRDSResponse> getRDS($grpc.ServiceCall call, $0.GetRDSRequest request);
+  $async.Future<$0.GetQualityResponse> getQuality($grpc.ServiceCall call, $0.GetQualityRequest request);
+  $async.Future<$0.SetAlternativeFrequencyResponse> setAlternativeFrequency($grpc.ServiceCall call, $0.SetAlternativeFrequencyRequest request);
+  $async.Stream<$0.StatusResponse> getStatusEvents($grpc.ServiceCall call, $0.StatusRequest request);
+}
diff --git a/protos/lib/src/generated/radio.pbjson.dart b/protos/lib/src/generated/radio.pbjson.dart
new file mode 100644 (file)
index 0000000..75dac79
--- /dev/null
@@ -0,0 +1,509 @@
+//
+//  Generated code. Do not modify.
+//  source: radio.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:convert' as $convert;
+import 'dart:core' as $core;
+import 'dart:typed_data' as $typed_data;
+
+@$core.Deprecated('Use bandDescriptor instead')
+const Band$json = {
+  '1': 'Band',
+  '2': [
+    {'1': 'BAND_UNSPECIFIED', '2': 0},
+    {'1': 'BAND_AM', '2': 1},
+    {'1': 'BAND_FM', '2': 2},
+    {'1': 'BAND_DBS', '2': 3},
+  ],
+};
+
+/// Descriptor for `Band`. Decode as a `google.protobuf.EnumDescriptorProto`.
+final $typed_data.Uint8List bandDescriptor = $convert.base64Decode(
+    'CgRCYW5kEhQKEEJBTkRfVU5TUEVDSUZJRUQQABILCgdCQU5EX0FNEAESCwoHQkFORF9GTRACEg'
+    'wKCEJBTkRfREJTEAM=');
+
+@$core.Deprecated('Use stereoModeDescriptor instead')
+const StereoMode$json = {
+  '1': 'StereoMode',
+  '2': [
+    {'1': 'STEREO_MODE_UNSPECIFIED', '2': 0},
+    {'1': 'STEREO_MODE_MONO', '2': 1},
+    {'1': 'STEREO_MODE_STEREO', '2': 2},
+  ],
+};
+
+/// Descriptor for `StereoMode`. Decode as a `google.protobuf.EnumDescriptorProto`.
+final $typed_data.Uint8List stereoModeDescriptor = $convert.base64Decode(
+    'CgpTdGVyZW9Nb2RlEhsKF1NURVJFT19NT0RFX1VOU1BFQ0lGSUVEEAASFAoQU1RFUkVPX01PRE'
+    'VfTU9OTxABEhYKElNURVJFT19NT0RFX1NURVJFTxAC');
+
+@$core.Deprecated('Use scanDirectionDescriptor instead')
+const ScanDirection$json = {
+  '1': 'ScanDirection',
+  '2': [
+    {'1': 'SCAN_DIRECTION_UNSPECIFIED', '2': 0},
+    {'1': 'SCAN_DIRECTION_FORWARD', '2': 1},
+    {'1': 'SCAN_DIRECTION_BACKWARD', '2': 2},
+  ],
+};
+
+/// Descriptor for `ScanDirection`. Decode as a `google.protobuf.EnumDescriptorProto`.
+final $typed_data.Uint8List scanDirectionDescriptor = $convert.base64Decode(
+    'Cg1TY2FuRGlyZWN0aW9uEh4KGlNDQU5fRElSRUNUSU9OX1VOU1BFQ0lGSUVEEAASGgoWU0NBTl'
+    '9ESVJFQ1RJT05fRk9SV0FSRBABEhsKF1NDQU5fRElSRUNUSU9OX0JBQ0tXQVJEEAI=');
+
+@$core.Deprecated('Use getFrequencyRequestDescriptor instead')
+const GetFrequencyRequest$json = {
+  '1': 'GetFrequencyRequest',
+};
+
+/// Descriptor for `GetFrequencyRequest`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List getFrequencyRequestDescriptor = $convert.base64Decode(
+    'ChNHZXRGcmVxdWVuY3lSZXF1ZXN0');
+
+@$core.Deprecated('Use getFrequencyResponseDescriptor instead')
+const GetFrequencyResponse$json = {
+  '1': 'GetFrequencyResponse',
+  '2': [
+    {'1': 'frequency', '3': 1, '4': 1, '5': 13, '10': 'frequency'},
+  ],
+};
+
+/// Descriptor for `GetFrequencyResponse`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List getFrequencyResponseDescriptor = $convert.base64Decode(
+    'ChRHZXRGcmVxdWVuY3lSZXNwb25zZRIcCglmcmVxdWVuY3kYASABKA1SCWZyZXF1ZW5jeQ==');
+
+@$core.Deprecated('Use setFrequencyRequestDescriptor instead')
+const SetFrequencyRequest$json = {
+  '1': 'SetFrequencyRequest',
+  '2': [
+    {'1': 'frequency', '3': 1, '4': 1, '5': 13, '10': 'frequency'},
+  ],
+};
+
+/// Descriptor for `SetFrequencyRequest`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List setFrequencyRequestDescriptor = $convert.base64Decode(
+    'ChNTZXRGcmVxdWVuY3lSZXF1ZXN0EhwKCWZyZXF1ZW5jeRgBIAEoDVIJZnJlcXVlbmN5');
+
+@$core.Deprecated('Use setFrequencyResponseDescriptor instead')
+const SetFrequencyResponse$json = {
+  '1': 'SetFrequencyResponse',
+  '2': [
+    {'1': 'frequency', '3': 1, '4': 1, '5': 13, '10': 'frequency'},
+  ],
+};
+
+/// Descriptor for `SetFrequencyResponse`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List setFrequencyResponseDescriptor = $convert.base64Decode(
+    'ChRTZXRGcmVxdWVuY3lSZXNwb25zZRIcCglmcmVxdWVuY3kYASABKA1SCWZyZXF1ZW5jeQ==');
+
+@$core.Deprecated('Use getBandRequestDescriptor instead')
+const GetBandRequest$json = {
+  '1': 'GetBandRequest',
+};
+
+/// Descriptor for `GetBandRequest`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List getBandRequestDescriptor = $convert.base64Decode(
+    'Cg5HZXRCYW5kUmVxdWVzdA==');
+
+@$core.Deprecated('Use getBandResponseDescriptor instead')
+const GetBandResponse$json = {
+  '1': 'GetBandResponse',
+  '2': [
+    {'1': 'band', '3': 1, '4': 1, '5': 14, '6': '.automotivegradelinux.Band', '10': 'band'},
+  ],
+};
+
+/// Descriptor for `GetBandResponse`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List getBandResponseDescriptor = $convert.base64Decode(
+    'Cg9HZXRCYW5kUmVzcG9uc2USLgoEYmFuZBgBIAEoDjIaLmF1dG9tb3RpdmVncmFkZWxpbnV4Lk'
+    'JhbmRSBGJhbmQ=');
+
+@$core.Deprecated('Use setBandRequestDescriptor instead')
+const SetBandRequest$json = {
+  '1': 'SetBandRequest',
+  '2': [
+    {'1': 'band', '3': 1, '4': 1, '5': 14, '6': '.automotivegradelinux.Band', '10': 'band'},
+  ],
+};
+
+/// Descriptor for `SetBandRequest`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List setBandRequestDescriptor = $convert.base64Decode(
+    'Cg5TZXRCYW5kUmVxdWVzdBIuCgRiYW5kGAEgASgOMhouYXV0b21vdGl2ZWdyYWRlbGludXguQm'
+    'FuZFIEYmFuZA==');
+
+@$core.Deprecated('Use setBandResponseDescriptor instead')
+const SetBandResponse$json = {
+  '1': 'SetBandResponse',
+  '2': [
+    {'1': 'band', '3': 1, '4': 1, '5': 14, '6': '.automotivegradelinux.Band', '10': 'band'},
+  ],
+};
+
+/// Descriptor for `SetBandResponse`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List setBandResponseDescriptor = $convert.base64Decode(
+    'Cg9TZXRCYW5kUmVzcG9uc2USLgoEYmFuZBgBIAEoDjIaLmF1dG9tb3RpdmVncmFkZWxpbnV4Lk'
+    'JhbmRSBGJhbmQ=');
+
+@$core.Deprecated('Use getBandSupportedRequestDescriptor instead')
+const GetBandSupportedRequest$json = {
+  '1': 'GetBandSupportedRequest',
+  '2': [
+    {'1': 'band', '3': 1, '4': 1, '5': 14, '6': '.automotivegradelinux.Band', '10': 'band'},
+  ],
+};
+
+/// Descriptor for `GetBandSupportedRequest`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List getBandSupportedRequestDescriptor = $convert.base64Decode(
+    'ChdHZXRCYW5kU3VwcG9ydGVkUmVxdWVzdBIuCgRiYW5kGAEgASgOMhouYXV0b21vdGl2ZWdyYW'
+    'RlbGludXguQmFuZFIEYmFuZA==');
+
+@$core.Deprecated('Use getBandSupportedResponseDescriptor instead')
+const GetBandSupportedResponse$json = {
+  '1': 'GetBandSupportedResponse',
+  '2': [
+    {'1': 'supported', '3': 1, '4': 1, '5': 8, '10': 'supported'},
+  ],
+};
+
+/// Descriptor for `GetBandSupportedResponse`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List getBandSupportedResponseDescriptor = $convert.base64Decode(
+    'ChhHZXRCYW5kU3VwcG9ydGVkUmVzcG9uc2USHAoJc3VwcG9ydGVkGAEgASgIUglzdXBwb3J0ZW'
+    'Q=');
+
+@$core.Deprecated('Use getBandParametersRequestDescriptor instead')
+const GetBandParametersRequest$json = {
+  '1': 'GetBandParametersRequest',
+  '2': [
+    {'1': 'band', '3': 1, '4': 1, '5': 14, '6': '.automotivegradelinux.Band', '10': 'band'},
+  ],
+};
+
+/// Descriptor for `GetBandParametersRequest`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List getBandParametersRequestDescriptor = $convert.base64Decode(
+    'ChhHZXRCYW5kUGFyYW1ldGVyc1JlcXVlc3QSLgoEYmFuZBgBIAEoDjIaLmF1dG9tb3RpdmVncm'
+    'FkZWxpbnV4LkJhbmRSBGJhbmQ=');
+
+@$core.Deprecated('Use getBandParametersResponseDescriptor instead')
+const GetBandParametersResponse$json = {
+  '1': 'GetBandParametersResponse',
+  '2': [
+    {'1': 'min', '3': 1, '4': 1, '5': 13, '10': 'min'},
+    {'1': 'max', '3': 2, '4': 1, '5': 13, '10': 'max'},
+    {'1': 'step', '3': 3, '4': 1, '5': 13, '10': 'step'},
+  ],
+};
+
+/// Descriptor for `GetBandParametersResponse`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List getBandParametersResponseDescriptor = $convert.base64Decode(
+    'ChlHZXRCYW5kUGFyYW1ldGVyc1Jlc3BvbnNlEhAKA21pbhgBIAEoDVIDbWluEhAKA21heBgCIA'
+    'EoDVIDbWF4EhIKBHN0ZXAYAyABKA1SBHN0ZXA=');
+
+@$core.Deprecated('Use getStereoModeRequestDescriptor instead')
+const GetStereoModeRequest$json = {
+  '1': 'GetStereoModeRequest',
+};
+
+/// Descriptor for `GetStereoModeRequest`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List getStereoModeRequestDescriptor = $convert.base64Decode(
+    'ChRHZXRTdGVyZW9Nb2RlUmVxdWVzdA==');
+
+@$core.Deprecated('Use getStereoModeResponseDescriptor instead')
+const GetStereoModeResponse$json = {
+  '1': 'GetStereoModeResponse',
+  '2': [
+    {'1': 'mode', '3': 1, '4': 1, '5': 14, '6': '.automotivegradelinux.StereoMode', '10': 'mode'},
+  ],
+};
+
+/// Descriptor for `GetStereoModeResponse`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List getStereoModeResponseDescriptor = $convert.base64Decode(
+    'ChVHZXRTdGVyZW9Nb2RlUmVzcG9uc2USNAoEbW9kZRgBIAEoDjIgLmF1dG9tb3RpdmVncmFkZW'
+    'xpbnV4LlN0ZXJlb01vZGVSBG1vZGU=');
+
+@$core.Deprecated('Use setStereoModeRequestDescriptor instead')
+const SetStereoModeRequest$json = {
+  '1': 'SetStereoModeRequest',
+  '2': [
+    {'1': 'mode', '3': 1, '4': 1, '5': 14, '6': '.automotivegradelinux.StereoMode', '10': 'mode'},
+  ],
+};
+
+/// Descriptor for `SetStereoModeRequest`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List setStereoModeRequestDescriptor = $convert.base64Decode(
+    'ChRTZXRTdGVyZW9Nb2RlUmVxdWVzdBI0CgRtb2RlGAEgASgOMiAuYXV0b21vdGl2ZWdyYWRlbG'
+    'ludXguU3RlcmVvTW9kZVIEbW9kZQ==');
+
+@$core.Deprecated('Use setStereoModeResponseDescriptor instead')
+const SetStereoModeResponse$json = {
+  '1': 'SetStereoModeResponse',
+  '2': [
+    {'1': 'mode', '3': 1, '4': 1, '5': 14, '6': '.automotivegradelinux.StereoMode', '10': 'mode'},
+  ],
+};
+
+/// Descriptor for `SetStereoModeResponse`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List setStereoModeResponseDescriptor = $convert.base64Decode(
+    'ChVTZXRTdGVyZW9Nb2RlUmVzcG9uc2USNAoEbW9kZRgBIAEoDjIgLmF1dG9tb3RpdmVncmFkZW'
+    'xpbnV4LlN0ZXJlb01vZGVSBG1vZGU=');
+
+@$core.Deprecated('Use startRequestDescriptor instead')
+const StartRequest$json = {
+  '1': 'StartRequest',
+};
+
+/// Descriptor for `StartRequest`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List startRequestDescriptor = $convert.base64Decode(
+    'CgxTdGFydFJlcXVlc3Q=');
+
+@$core.Deprecated('Use startResponseDescriptor instead')
+const StartResponse$json = {
+  '1': 'StartResponse',
+};
+
+/// Descriptor for `StartResponse`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List startResponseDescriptor = $convert.base64Decode(
+    'Cg1TdGFydFJlc3BvbnNl');
+
+@$core.Deprecated('Use stopRequestDescriptor instead')
+const StopRequest$json = {
+  '1': 'StopRequest',
+};
+
+/// Descriptor for `StopRequest`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List stopRequestDescriptor = $convert.base64Decode(
+    'CgtTdG9wUmVxdWVzdA==');
+
+@$core.Deprecated('Use stopResponseDescriptor instead')
+const StopResponse$json = {
+  '1': 'StopResponse',
+};
+
+/// Descriptor for `StopResponse`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List stopResponseDescriptor = $convert.base64Decode(
+    'CgxTdG9wUmVzcG9uc2U=');
+
+@$core.Deprecated('Use scanStartRequestDescriptor instead')
+const ScanStartRequest$json = {
+  '1': 'ScanStartRequest',
+  '2': [
+    {'1': 'direction', '3': 1, '4': 1, '5': 14, '6': '.automotivegradelinux.ScanDirection', '10': 'direction'},
+  ],
+};
+
+/// Descriptor for `ScanStartRequest`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List scanStartRequestDescriptor = $convert.base64Decode(
+    'ChBTY2FuU3RhcnRSZXF1ZXN0EkEKCWRpcmVjdGlvbhgBIAEoDjIjLmF1dG9tb3RpdmVncmFkZW'
+    'xpbnV4LlNjYW5EaXJlY3Rpb25SCWRpcmVjdGlvbg==');
+
+@$core.Deprecated('Use scanStartResponseDescriptor instead')
+const ScanStartResponse$json = {
+  '1': 'ScanStartResponse',
+};
+
+/// Descriptor for `ScanStartResponse`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List scanStartResponseDescriptor = $convert.base64Decode(
+    'ChFTY2FuU3RhcnRSZXNwb25zZQ==');
+
+@$core.Deprecated('Use scanStopRequestDescriptor instead')
+const ScanStopRequest$json = {
+  '1': 'ScanStopRequest',
+};
+
+/// Descriptor for `ScanStopRequest`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List scanStopRequestDescriptor = $convert.base64Decode(
+    'Cg9TY2FuU3RvcFJlcXVlc3Q=');
+
+@$core.Deprecated('Use scanStopResponseDescriptor instead')
+const ScanStopResponse$json = {
+  '1': 'ScanStopResponse',
+};
+
+/// Descriptor for `ScanStopResponse`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List scanStopResponseDescriptor = $convert.base64Decode(
+    'ChBTY2FuU3RvcFJlc3BvbnNl');
+
+@$core.Deprecated('Use getRDSRequestDescriptor instead')
+const GetRDSRequest$json = {
+  '1': 'GetRDSRequest',
+};
+
+/// Descriptor for `GetRDSRequest`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List getRDSRequestDescriptor = $convert.base64Decode(
+    'Cg1HZXRSRFNSZXF1ZXN0');
+
+@$core.Deprecated('Use getRDSResponseDescriptor instead')
+const GetRDSResponse$json = {
+  '1': 'GetRDSResponse',
+  '2': [
+    {'1': 'name', '3': 1, '4': 1, '5': 9, '10': 'name'},
+    {'1': 'radio_text', '3': 2, '4': 1, '5': 9, '10': 'radioText'},
+    {'1': 'alternatives', '3': 3, '4': 1, '5': 9, '10': 'alternatives'},
+    {'1': 'minute', '3': 4, '4': 1, '5': 9, '10': 'minute'},
+    {'1': 'hour', '3': 5, '4': 1, '5': 9, '10': 'hour'},
+    {'1': 'day', '3': 6, '4': 1, '5': 9, '10': 'day'},
+    {'1': 'month', '3': 7, '4': 1, '5': 9, '10': 'month'},
+    {'1': 'year', '3': 8, '4': 1, '5': 9, '10': 'year'},
+    {'1': 'pi', '3': 9, '4': 1, '5': 9, '10': 'pi'},
+    {'1': 'pty', '3': 10, '4': 1, '5': 9, '10': 'pty'},
+    {'1': 'ta', '3': 11, '4': 1, '5': 9, '10': 'ta'},
+    {'1': 'tp', '3': 12, '4': 1, '5': 9, '10': 'tp'},
+    {'1': 'ms', '3': 13, '4': 1, '5': 9, '10': 'ms'},
+  ],
+};
+
+/// Descriptor for `GetRDSResponse`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List getRDSResponseDescriptor = $convert.base64Decode(
+    'Cg5HZXRSRFNSZXNwb25zZRISCgRuYW1lGAEgASgJUgRuYW1lEh0KCnJhZGlvX3RleHQYAiABKA'
+    'lSCXJhZGlvVGV4dBIiCgxhbHRlcm5hdGl2ZXMYAyABKAlSDGFsdGVybmF0aXZlcxIWCgZtaW51'
+    'dGUYBCABKAlSBm1pbnV0ZRISCgRob3VyGAUgASgJUgRob3VyEhAKA2RheRgGIAEoCVIDZGF5Eh'
+    'QKBW1vbnRoGAcgASgJUgVtb250aBISCgR5ZWFyGAggASgJUgR5ZWFyEg4KAnBpGAkgASgJUgJw'
+    'aRIQCgNwdHkYCiABKAlSA3B0eRIOCgJ0YRgLIAEoCVICdGESDgoCdHAYDCABKAlSAnRwEg4KAm'
+    '1zGA0gASgJUgJtcw==');
+
+@$core.Deprecated('Use getQualityRequestDescriptor instead')
+const GetQualityRequest$json = {
+  '1': 'GetQualityRequest',
+};
+
+/// Descriptor for `GetQualityRequest`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List getQualityRequestDescriptor = $convert.base64Decode(
+    'ChFHZXRRdWFsaXR5UmVxdWVzdA==');
+
+@$core.Deprecated('Use getQualityResponseDescriptor instead')
+const GetQualityResponse$json = {
+  '1': 'GetQualityResponse',
+};
+
+/// Descriptor for `GetQualityResponse`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List getQualityResponseDescriptor = $convert.base64Decode(
+    'ChJHZXRRdWFsaXR5UmVzcG9uc2U=');
+
+@$core.Deprecated('Use setAlternativeFrequencyRequestDescriptor instead')
+const SetAlternativeFrequencyRequest$json = {
+  '1': 'SetAlternativeFrequencyRequest',
+  '2': [
+    {'1': 'frequency', '3': 1, '4': 1, '5': 13, '10': 'frequency'},
+  ],
+};
+
+/// Descriptor for `SetAlternativeFrequencyRequest`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List setAlternativeFrequencyRequestDescriptor = $convert.base64Decode(
+    'Ch5TZXRBbHRlcm5hdGl2ZUZyZXF1ZW5jeVJlcXVlc3QSHAoJZnJlcXVlbmN5GAEgASgNUglmcm'
+    'VxdWVuY3k=');
+
+@$core.Deprecated('Use setAlternativeFrequencyResponseDescriptor instead')
+const SetAlternativeFrequencyResponse$json = {
+  '1': 'SetAlternativeFrequencyResponse',
+  '2': [
+    {'1': 'frequency', '3': 1, '4': 1, '5': 13, '10': 'frequency'},
+  ],
+};
+
+/// Descriptor for `SetAlternativeFrequencyResponse`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List setAlternativeFrequencyResponseDescriptor = $convert.base64Decode(
+    'Ch9TZXRBbHRlcm5hdGl2ZUZyZXF1ZW5jeVJlc3BvbnNlEhwKCWZyZXF1ZW5jeRgBIAEoDVIJZn'
+    'JlcXVlbmN5');
+
+@$core.Deprecated('Use statusRequestDescriptor instead')
+const StatusRequest$json = {
+  '1': 'StatusRequest',
+};
+
+/// Descriptor for `StatusRequest`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List statusRequestDescriptor = $convert.base64Decode(
+    'Cg1TdGF0dXNSZXF1ZXN0');
+
+@$core.Deprecated('Use bandStatusDescriptor instead')
+const BandStatus$json = {
+  '1': 'BandStatus',
+  '2': [
+    {'1': 'band', '3': 1, '4': 1, '5': 14, '6': '.automotivegradelinux.Band', '10': 'band'},
+  ],
+};
+
+/// Descriptor for `BandStatus`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List bandStatusDescriptor = $convert.base64Decode(
+    'CgpCYW5kU3RhdHVzEi4KBGJhbmQYASABKA4yGi5hdXRvbW90aXZlZ3JhZGVsaW51eC5CYW5kUg'
+    'RiYW5k');
+
+@$core.Deprecated('Use frequencyStatusDescriptor instead')
+const FrequencyStatus$json = {
+  '1': 'FrequencyStatus',
+  '2': [
+    {'1': 'frequency', '3': 1, '4': 1, '5': 13, '10': 'frequency'},
+  ],
+};
+
+/// Descriptor for `FrequencyStatus`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List frequencyStatusDescriptor = $convert.base64Decode(
+    'Cg9GcmVxdWVuY3lTdGF0dXMSHAoJZnJlcXVlbmN5GAEgASgNUglmcmVxdWVuY3k=');
+
+@$core.Deprecated('Use playStatusDescriptor instead')
+const PlayStatus$json = {
+  '1': 'PlayStatus',
+  '2': [
+    {'1': 'playing', '3': 1, '4': 1, '5': 8, '10': 'playing'},
+  ],
+};
+
+/// Descriptor for `PlayStatus`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List playStatusDescriptor = $convert.base64Decode(
+    'CgpQbGF5U3RhdHVzEhgKB3BsYXlpbmcYASABKAhSB3BsYXlpbmc=');
+
+@$core.Deprecated('Use scanStatusDescriptor instead')
+const ScanStatus$json = {
+  '1': 'ScanStatus',
+  '2': [
+    {'1': 'station_found', '3': 1, '4': 1, '5': 8, '10': 'stationFound'},
+  ],
+};
+
+/// Descriptor for `ScanStatus`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List scanStatusDescriptor = $convert.base64Decode(
+    'CgpTY2FuU3RhdHVzEiMKDXN0YXRpb25fZm91bmQYASABKAhSDHN0YXRpb25Gb3VuZA==');
+
+@$core.Deprecated('Use stereoStatusDescriptor instead')
+const StereoStatus$json = {
+  '1': 'StereoStatus',
+  '2': [
+    {'1': 'mode', '3': 1, '4': 1, '5': 14, '6': '.automotivegradelinux.StereoMode', '10': 'mode'},
+  ],
+};
+
+/// Descriptor for `StereoStatus`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List stereoStatusDescriptor = $convert.base64Decode(
+    'CgxTdGVyZW9TdGF0dXMSNAoEbW9kZRgBIAEoDjIgLmF1dG9tb3RpdmVncmFkZWxpbnV4LlN0ZX'
+    'Jlb01vZGVSBG1vZGU=');
+
+@$core.Deprecated('Use statusResponseDescriptor instead')
+const StatusResponse$json = {
+  '1': 'StatusResponse',
+  '2': [
+    {'1': 'band', '3': 1, '4': 1, '5': 11, '6': '.automotivegradelinux.BandStatus', '9': 0, '10': 'band'},
+    {'1': 'frequency', '3': 2, '4': 1, '5': 11, '6': '.automotivegradelinux.FrequencyStatus', '9': 0, '10': 'frequency'},
+    {'1': 'play', '3': 3, '4': 1, '5': 11, '6': '.automotivegradelinux.PlayStatus', '9': 0, '10': 'play'},
+    {'1': 'stereo', '3': 4, '4': 1, '5': 11, '6': '.automotivegradelinux.StereoStatus', '9': 0, '10': 'stereo'},
+    {'1': 'scan', '3': 5, '4': 1, '5': 11, '6': '.automotivegradelinux.ScanStatus', '9': 0, '10': 'scan'},
+  ],
+  '8': [
+    {'1': 'status'},
+  ],
+};
+
+/// Descriptor for `StatusResponse`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List statusResponseDescriptor = $convert.base64Decode(
+    'Cg5TdGF0dXNSZXNwb25zZRI2CgRiYW5kGAEgASgLMiAuYXV0b21vdGl2ZWdyYWRlbGludXguQm'
+    'FuZFN0YXR1c0gAUgRiYW5kEkUKCWZyZXF1ZW5jeRgCIAEoCzIlLmF1dG9tb3RpdmVncmFkZWxp'
+    'bnV4LkZyZXF1ZW5jeVN0YXR1c0gAUglmcmVxdWVuY3kSNgoEcGxheRgDIAEoCzIgLmF1dG9tb3'
+    'RpdmVncmFkZWxpbnV4LlBsYXlTdGF0dXNIAFIEcGxheRI8CgZzdGVyZW8YBCABKAsyIi5hdXRv'
+    'bW90aXZlZ3JhZGVsaW51eC5TdGVyZW9TdGF0dXNIAFIGc3RlcmVvEjYKBHNjYW4YBSABKAsyIC'
+    '5hdXRvbW90aXZlZ3JhZGVsaW51eC5TY2FuU3RhdHVzSABSBHNjYW5CCAoGc3RhdHVz');
+
diff --git a/protos/lib/src/generated/todo.pb.dart b/protos/lib/src/generated/todo.pb.dart
deleted file mode 100644 (file)
index d42a385..0000000
+++ /dev/null
@@ -1,146 +0,0 @@
-//
-//  Generated code. Do not modify.
-//  source: todo.proto
-//
-// @dart = 2.12
-
-// ignore_for_file: annotate_overrides, camel_case_types, comment_references
-// ignore_for_file: constant_identifier_names, library_prefixes
-// ignore_for_file: non_constant_identifier_names, prefer_final_fields
-// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
-
-import 'dart:core' as $core;
-
-import 'package:protobuf/protobuf.dart' as $pb;
-
-class Todo extends $pb.GeneratedMessage {
-  factory Todo({
-    $core.int? id,
-    $core.String? title,
-    $core.bool? completed,
-  }) {
-    final $result = create();
-    if (id != null) {
-      $result.id = id;
-    }
-    if (title != null) {
-      $result.title = title;
-    }
-    if (completed != null) {
-      $result.completed = completed;
-    }
-    return $result;
-  }
-  Todo._() : super();
-  factory Todo.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
-  factory Todo.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
-
-  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'Todo', createEmptyInstance: create)
-    ..a<$core.int>(1, _omitFieldNames ? '' : 'id', $pb.PbFieldType.O3)
-    ..aOS(2, _omitFieldNames ? '' : 'title')
-    ..aOB(3, _omitFieldNames ? '' : 'completed')
-    ..hasRequiredFields = false
-  ;
-
-  @$core.Deprecated(
-  'Using this can add significant overhead to your binary. '
-  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
-  'Will be removed in next major version')
-  Todo clone() => Todo()..mergeFromMessage(this);
-  @$core.Deprecated(
-  'Using this can add significant overhead to your binary. '
-  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
-  'Will be removed in next major version')
-  Todo copyWith(void Function(Todo) updates) => super.copyWith((message) => updates(message as Todo)) as Todo;
-
-  $pb.BuilderInfo get info_ => _i;
-
-  @$core.pragma('dart2js:noInline')
-  static Todo create() => Todo._();
-  Todo createEmptyInstance() => create();
-  static $pb.PbList<Todo> createRepeated() => $pb.PbList<Todo>();
-  @$core.pragma('dart2js:noInline')
-  static Todo getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<Todo>(create);
-  static Todo? _defaultInstance;
-
-  @$pb.TagNumber(1)
-  $core.int get id => $_getIZ(0);
-  @$pb.TagNumber(1)
-  set id($core.int v) { $_setSignedInt32(0, v); }
-  @$pb.TagNumber(1)
-  $core.bool hasId() => $_has(0);
-  @$pb.TagNumber(1)
-  void clearId() => clearField(1);
-
-  @$pb.TagNumber(2)
-  $core.String get title => $_getSZ(1);
-  @$pb.TagNumber(2)
-  set title($core.String v) { $_setString(1, v); }
-  @$pb.TagNumber(2)
-  $core.bool hasTitle() => $_has(1);
-  @$pb.TagNumber(2)
-  void clearTitle() => clearField(2);
-
-  @$pb.TagNumber(3)
-  $core.bool get completed => $_getBF(2);
-  @$pb.TagNumber(3)
-  set completed($core.bool v) { $_setBool(2, v); }
-  @$pb.TagNumber(3)
-  $core.bool hasCompleted() => $_has(2);
-  @$pb.TagNumber(3)
-  void clearCompleted() => clearField(3);
-}
-
-class GetTodoByIdRequest extends $pb.GeneratedMessage {
-  factory GetTodoByIdRequest({
-    $core.int? id,
-  }) {
-    final $result = create();
-    if (id != null) {
-      $result.id = id;
-    }
-    return $result;
-  }
-  GetTodoByIdRequest._() : super();
-  factory GetTodoByIdRequest.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
-  factory GetTodoByIdRequest.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
-
-  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'GetTodoByIdRequest', createEmptyInstance: create)
-    ..a<$core.int>(1, _omitFieldNames ? '' : 'id', $pb.PbFieldType.O3)
-    ..hasRequiredFields = false
-  ;
-
-  @$core.Deprecated(
-  'Using this can add significant overhead to your binary. '
-  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
-  'Will be removed in next major version')
-  GetTodoByIdRequest clone() => GetTodoByIdRequest()..mergeFromMessage(this);
-  @$core.Deprecated(
-  'Using this can add significant overhead to your binary. '
-  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
-  'Will be removed in next major version')
-  GetTodoByIdRequest copyWith(void Function(GetTodoByIdRequest) updates) => super.copyWith((message) => updates(message as GetTodoByIdRequest)) as GetTodoByIdRequest;
-
-  $pb.BuilderInfo get info_ => _i;
-
-  @$core.pragma('dart2js:noInline')
-  static GetTodoByIdRequest create() => GetTodoByIdRequest._();
-  GetTodoByIdRequest createEmptyInstance() => create();
-  static $pb.PbList<GetTodoByIdRequest> createRepeated() => $pb.PbList<GetTodoByIdRequest>();
-  @$core.pragma('dart2js:noInline')
-  static GetTodoByIdRequest getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<GetTodoByIdRequest>(create);
-  static GetTodoByIdRequest? _defaultInstance;
-
-  @$pb.TagNumber(1)
-  $core.int get id => $_getIZ(0);
-  @$pb.TagNumber(1)
-  set id($core.int v) { $_setSignedInt32(0, v); }
-  @$pb.TagNumber(1)
-  $core.bool hasId() => $_has(0);
-  @$pb.TagNumber(1)
-  void clearId() => clearField(1);
-}
-
-
-const _omitFieldNames = $core.bool.fromEnvironment('protobuf.omit_field_names');
-const _omitMessageNames = $core.bool.fromEnvironment('protobuf.omit_message_names');
diff --git a/protos/lib/src/generated/todo.pbenum.dart b/protos/lib/src/generated/todo.pbenum.dart
deleted file mode 100644 (file)
index 9569c62..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-//
-//  Generated code. Do not modify.
-//  source: todo.proto
-//
-// @dart = 2.12
-
-// ignore_for_file: annotate_overrides, camel_case_types, comment_references
-// ignore_for_file: constant_identifier_names, library_prefixes
-// ignore_for_file: non_constant_identifier_names, prefer_final_fields
-// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
-
diff --git a/protos/lib/src/generated/todo.pbgrpc.dart b/protos/lib/src/generated/todo.pbgrpc.dart
deleted file mode 100644 (file)
index 35e0860..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-//
-//  Generated code. Do not modify.
-//  source: todo.proto
-//
-// @dart = 2.12
-
-// ignore_for_file: annotate_overrides, camel_case_types, comment_references
-// ignore_for_file: constant_identifier_names, library_prefixes
-// ignore_for_file: non_constant_identifier_names, prefer_final_fields
-// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
-
-import 'dart:async' as $async;
-import 'dart:core' as $core;
-
-import 'package:grpc/service_api.dart' as $grpc;
-import 'package:protobuf/protobuf.dart' as $pb;
-
-import 'todo.pb.dart' as $0;
-
-export 'todo.pb.dart';
-
-@$pb.GrpcServiceName('TodoService')
-class TodoServiceClient extends $grpc.Client {
-  static final _$getTodo = $grpc.ClientMethod<$0.GetTodoByIdRequest, $0.Todo>(
-      '/TodoService/getTodo',
-      ($0.GetTodoByIdRequest value) => value.writeToBuffer(),
-      ($core.List<$core.int> value) => $0.Todo.fromBuffer(value));
-  static final _$getTodoStream = $grpc.ClientMethod<$0.GetTodoByIdRequest, $0.Todo>(
-      '/TodoService/getTodoStream',
-      ($0.GetTodoByIdRequest value) => value.writeToBuffer(),
-      ($core.List<$core.int> value) => $0.Todo.fromBuffer(value));
-
-  TodoServiceClient($grpc.ClientChannel channel,
-      {$grpc.CallOptions? options,
-      $core.Iterable<$grpc.ClientInterceptor>? interceptors})
-      : super(channel, options: options,
-        interceptors: interceptors);
-
-  $grpc.ResponseFuture<$0.Todo> getTodo($0.GetTodoByIdRequest request, {$grpc.CallOptions? options}) {
-    return $createUnaryCall(_$getTodo, request, options: options);
-  }
-
-  $grpc.ResponseStream<$0.Todo> getTodoStream($0.GetTodoByIdRequest request, {$grpc.CallOptions? options}) {
-    return $createStreamingCall(_$getTodoStream, $async.Stream.fromIterable([request]), options: options);
-  }
-}
-
-@$pb.GrpcServiceName('TodoService')
-abstract class TodoServiceBase extends $grpc.Service {
-  $core.String get $name => 'TodoService';
-
-  TodoServiceBase() {
-    $addMethod($grpc.ServiceMethod<$0.GetTodoByIdRequest, $0.Todo>(
-        'getTodo',
-        getTodo_Pre,
-        false,
-        false,
-        ($core.List<$core.int> value) => $0.GetTodoByIdRequest.fromBuffer(value),
-        ($0.Todo value) => value.writeToBuffer()));
-    $addMethod($grpc.ServiceMethod<$0.GetTodoByIdRequest, $0.Todo>(
-        'getTodoStream',
-        getTodoStream_Pre,
-        false,
-        true,
-        ($core.List<$core.int> value) => $0.GetTodoByIdRequest.fromBuffer(value),
-        ($0.Todo value) => value.writeToBuffer()));
-  }
-
-  $async.Future<$0.Todo> getTodo_Pre($grpc.ServiceCall call, $async.Future<$0.GetTodoByIdRequest> request) async {
-    return getTodo(call, await request);
-  }
-
-  $async.Stream<$0.Todo> getTodoStream_Pre($grpc.ServiceCall call, $async.Future<$0.GetTodoByIdRequest> request) async* {
-    yield* getTodoStream(call, await request);
-  }
-
-  $async.Future<$0.Todo> getTodo($grpc.ServiceCall call, $0.GetTodoByIdRequest request);
-  $async.Stream<$0.Todo> getTodoStream($grpc.ServiceCall call, $0.GetTodoByIdRequest request);
-}
diff --git a/protos/lib/src/generated/todo.pbjson.dart b/protos/lib/src/generated/todo.pbjson.dart
deleted file mode 100644 (file)
index 8d6afaa..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-//
-//  Generated code. Do not modify.
-//  source: todo.proto
-//
-// @dart = 2.12
-
-// ignore_for_file: annotate_overrides, camel_case_types, comment_references
-// ignore_for_file: constant_identifier_names, library_prefixes
-// ignore_for_file: non_constant_identifier_names, prefer_final_fields
-// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
-
-import 'dart:convert' as $convert;
-import 'dart:core' as $core;
-import 'dart:typed_data' as $typed_data;
-
-@$core.Deprecated('Use todoDescriptor instead')
-const Todo$json = {
-  '1': 'Todo',
-  '2': [
-    {'1': 'id', '3': 1, '4': 1, '5': 5, '10': 'id'},
-    {'1': 'title', '3': 2, '4': 1, '5': 9, '10': 'title'},
-    {'1': 'completed', '3': 3, '4': 1, '5': 8, '10': 'completed'},
-  ],
-};
-
-/// Descriptor for `Todo`. Decode as a `google.protobuf.DescriptorProto`.
-final $typed_data.Uint8List todoDescriptor = $convert.base64Decode(
-    'CgRUb2RvEg4KAmlkGAEgASgFUgJpZBIUCgV0aXRsZRgCIAEoCVIFdGl0bGUSHAoJY29tcGxldG'
-    'VkGAMgASgIUgljb21wbGV0ZWQ=');
-
-@$core.Deprecated('Use getTodoByIdRequestDescriptor instead')
-const GetTodoByIdRequest$json = {
-  '1': 'GetTodoByIdRequest',
-  '2': [
-    {'1': 'id', '3': 1, '4': 1, '5': 5, '10': 'id'},
-  ],
-};
-
-/// Descriptor for `GetTodoByIdRequest`. Decode as a `google.protobuf.DescriptorProto`.
-final $typed_data.Uint8List getTodoByIdRequestDescriptor = $convert.base64Decode(
-    'ChJHZXRUb2RvQnlJZFJlcXVlc3QSDgoCaWQYASABKAVSAmlk');
-
similarity index 51%
rename from protos/lib/protos.dart
rename to protos/lib/val-api.dart
index e3b0568..de6dfac 100644 (file)
@@ -1,10 +1,4 @@
-
-library protos;
-
-export 'src/generated/todo.pb.dart';
-export 'src/generated/todo.pbenum.dart';
-export 'src/generated/todo.pbgrpc.dart';
-export 'src/generated/todo.pbjson.dart';
+library val_api;
 
 export 'src/generated/google/protobuf/timestamp.pb.dart';
 export 'src/generated/google/protobuf/timestamp.pbenum.dart';
@@ -19,14 +13,4 @@ export 'src/generated/kuksa/val/v1/val.pbenum.dart';
 export 'src/generated/kuksa/val/v1/val.pbjson.dart';
 export 'src/generated/kuksa/val/v1/val.pbgrpc.dart';
 
-export 'src/generated/agl_shell.pb.dart';
-export 'src/generated/agl_shell.pbenum.dart';
-export 'src/generated/agl_shell.pbgrpc.dart';
-export 'src/generated/agl_shell.pbjson.dart';
-
-export 'src/generated/applauncher.pb.dart';
-export 'src/generated/applauncher.pbenum.dart';
-export 'src/generated/applauncher.pbgrpc.dart';
-export 'src/generated/applauncher.pbjson.dart';
-
 export 'package:grpc/grpc.dart';
diff --git a/protos/protos/radio.proto b/protos/protos/radio.proto
new file mode 100644 (file)
index 0000000..c7ee16f
--- /dev/null
@@ -0,0 +1,205 @@
+syntax = "proto3";
+
+package automotivegradelinux;
+
+service Radio {
+  rpc GetFrequency(GetFrequencyRequest) returns (GetFrequencyResponse) {}
+  rpc SetFrequency(SetFrequencyRequest) returns (SetFrequencyResponse) {}  
+
+  rpc GetBand(GetBandRequest) returns (GetBandResponse) {}
+  rpc SetBand(SetBandRequest) returns (SetBandResponse) {}  
+
+  rpc GetBandSupported(GetBandSupportedRequest) returns (GetBandSupportedResponse) {}
+  rpc GetBandParameters(GetBandParametersRequest) returns (GetBandParametersResponse) {}
+
+  rpc GetStereoMode(GetStereoModeRequest) returns (GetStereoModeResponse) {}
+  rpc SetStereoMode(SetStereoModeRequest) returns (SetStereoModeResponse) {}  
+
+  rpc Start(StartRequest) returns (StartResponse) {}
+  rpc Stop(StopRequest) returns (StopResponse) {}      
+
+  rpc ScanStart(ScanStartRequest) returns (ScanStartResponse) {}
+  rpc ScanStop(ScanStopRequest) returns (ScanStopResponse) {}      
+
+  rpc GetRDS(GetRDSRequest) returns (GetRDSResponse) {}
+
+  rpc GetQuality(GetQualityRequest) returns (GetQualityResponse) {}
+
+  rpc SetAlternativeFrequency(SetAlternativeFrequencyRequest) returns (SetAlternativeFrequencyResponse) {}    
+
+  rpc GetStatusEvents(StatusRequest) returns (stream StatusResponse) {}
+}
+
+message GetFrequencyRequest {
+}
+
+message GetFrequencyResponse {
+  uint32 frequency = 1;
+}
+
+message SetFrequencyRequest {
+  uint32 frequency = 1;
+}
+
+message SetFrequencyResponse {
+  uint32 frequency = 1;
+}
+
+message GetBandRequest {
+}
+
+enum Band {
+  BAND_UNSPECIFIED = 0;
+  BAND_AM = 1;
+  BAND_FM = 2;
+  BAND_DBS = 3;
+}
+
+message GetBandResponse {
+  Band band = 1;
+}
+
+message SetBandRequest {
+  Band band = 1;
+}
+
+message SetBandResponse {
+  Band band = 1;
+}
+
+message GetBandSupportedRequest {
+  Band band = 1;
+}
+
+message GetBandSupportedResponse {
+  bool supported = 1;
+}
+
+message GetBandParametersRequest {
+  Band band = 1;
+}
+
+message GetBandParametersResponse {
+  uint32 min = 1;
+  uint32 max = 2;
+  uint32 step = 3;
+}
+
+enum StereoMode {
+  STEREO_MODE_UNSPECIFIED = 0;
+  STEREO_MODE_MONO = 1;
+  STEREO_MODE_STEREO = 2;
+}
+
+message GetStereoModeRequest {
+}
+
+message GetStereoModeResponse {
+  StereoMode mode = 1;
+}
+
+message SetStereoModeRequest {
+  StereoMode mode = 1;
+}
+
+message SetStereoModeResponse {
+  StereoMode mode = 1;
+}
+
+message StartRequest {
+}
+
+message StartResponse {
+}
+
+message StopRequest {
+}
+
+message StopResponse {
+}
+
+enum ScanDirection {
+  SCAN_DIRECTION_UNSPECIFIED = 0;
+  SCAN_DIRECTION_FORWARD = 1;
+  SCAN_DIRECTION_BACKWARD = 2;
+}
+
+message ScanStartRequest {
+  ScanDirection direction = 1;
+}
+
+message ScanStartResponse {
+}
+
+message ScanStopRequest {
+}
+
+message ScanStopResponse {
+}
+
+message GetRDSRequest {
+}
+
+// NOTE: This is a placeholder and will be revised!
+message GetRDSResponse {
+  string name = 1;
+  string radio_text = 2;
+  string alternatives = 3;
+  string minute = 4;
+  string hour = 5;
+  string day = 6;
+  string month = 7;
+  string year = 8;
+  string pi = 9;
+  string pty = 10;
+  string ta = 11;
+  string tp = 12;
+  string ms = 13;
+}
+
+message GetQualityRequest {
+}
+
+message GetQualityResponse {
+}
+
+message SetAlternativeFrequencyRequest {
+  uint32 frequency = 1;
+}
+
+message SetAlternativeFrequencyResponse {
+  uint32 frequency = 1;
+}
+
+message StatusRequest {
+}
+
+message BandStatus {
+  Band band = 1;
+}
+
+message FrequencyStatus {
+  uint32 frequency = 1;
+}
+
+message PlayStatus {
+  bool playing = 1;
+}
+
+message ScanStatus {
+  bool station_found = 1;
+}
+
+message StereoStatus {
+  StereoMode mode = 1;
+}
+
+message StatusResponse {
+  oneof status {
+    BandStatus band = 1;
+    FrequencyStatus frequency = 2;
+    PlayStatus play = 3;
+    StereoStatus stereo = 4;
+    ScanStatus scan = 5;
+  }
+}
diff --git a/protos/protos/todo.proto b/protos/protos/todo.proto
deleted file mode 100644 (file)
index 9152814..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-syntax = 'proto3';
-
-message Todo {
- int32 id = 1;
- string title = 2;
- bool completed = 3;
-}
-
-message GetTodoByIdRequest {
-    int32 id = 1;
-}
-service TodoService {
-    rpc getTodo(GetTodoByIdRequest) returns (Todo);
-    rpc getTodoStream(GetTodoByIdRequest) returns (stream Todo);
-}
-