Skip to content

Commit

Permalink
#336 Present the exact display of the AVR LCD: implemented
Browse files Browse the repository at this point in the history
  • Loading branch information
mkulesh committed Jan 30, 2025
1 parent 413dfed commit 85f0bb8
Show file tree
Hide file tree
Showing 21 changed files with 321 additions and 30 deletions.
11 changes: 10 additions & 1 deletion integration_test/onpc_test_utils.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* Enhanced Music Controller
* Copyright (C) 2019-2024 by Mikhail Kulesh
* Copyright (C) 2019-2025 by Mikhail Kulesh
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU
* General Public License as published by the Free Software Foundation, either version 3 of the License,
Expand All @@ -19,6 +19,8 @@ import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:onpc/constants/Dimens.dart';
import 'package:onpc/constants/Version.dart';
import 'package:onpc/iscp/StateManager.dart';
import 'package:onpc/main.dart' as app;
import 'package:onpc/utils/Logging.dart';
import 'package:onpc/utils/Pair.dart';
import 'package:onpc/utils/Platform.dart';
Expand Down Expand Up @@ -50,6 +52,13 @@ class OnpcTestUtils {

OnpcTestUtils(this.tester);

StateManager getStateManager() {
final Finder fab = find.byType(app.MusicControllerApp);
expect(fab, findsOneWidget);
final app.MusicControllerApp mainWidget = fab.evaluate().first.widget as app.MusicControllerApp;
return mainWidget.viewContext.stateManager;
}

Future<void> connect(String device, String searchFor) async {
await stepDelayMs();
if (find.textContaining(searchFor).evaluate().isEmpty) {
Expand Down
97 changes: 97 additions & 0 deletions integration_test/sim_device_display.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/*
* Enhanced Music Controller
* Copyright (C) 2019-2025 by Mikhail Kulesh
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU
* General Public License as published by the Free Software Foundation, either version 3 of the License,
* or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. You should have received a copy of the GNU General
* Public License along with this program.
*/

import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:onpc/iscp/EISCPMessage.dart';
import 'package:onpc/iscp/StateManager.dart';
import 'package:onpc/main.dart' as app;

import 'onpc_test_utils.dart';

void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();

testWidgets('Simulation of the device display', (tester) async {
final OnpcTestUtils tu = OnpcTestUtils(tester);
app.main();

await tu.stepDelayMs();
await tu.openTab("RC");

final List<String> messages = [
"4368726F6D6563617320372F3130",
"20436F6E6E656374696E672E2E2E",
"1B4368726F6D6563617374206275",
"4368726F6D656361737420627569",
"68726F6D6563617374206275696C",
"726F6D6563617374206275696C74",
"6F6D6563617374206275696C742D",
"6D6563617374206275696C742D69",
"1A416E67656C2028666561742E20",
"6563617374206275696C742D696E",
"63617374206275696C742D696E20",
"617374206275696C742D696E2020",
"7374206275696C742D696E202020",
"74206275696C742D696E20202020",
"206275696C742D696E2020202020",
"6275696C742D696E202020202020",
"75696C742D696E20202020202020",
"696C742D696E2020202020202020",
"6C742D696E202020202020202020",
"742D696E20202020202020202020",
"2D696E2020202020202020202020",
"696E202020202020202020202020",
"6E20202020202020202020202020",
"566F6C756D652020202D34352E30",
"5456206541524320202D34352E30",
"53797374656D2053657475702020",
"4D43414343202020202020202020",
"4E6574776F726B20202020202020",
"496E2F4F75742041737369676E20",
"537065616B657220202020202020",
"417564696F2041646A7573742020",
"536F757263652020202020202020",
"4861726477617265202020202020",
"4D697363656C6C616E656F757320",
"5456204F75742F4F534420202020",
"48444D4920496E70757420202020",
"566964656F20496E707574202020",
"4469676974616C20417564696F20",
"416E616C6F6720417564696F2020",
"496E70757420536B697020202020",
"546F6E6520202020202020202020",
"4C6576656C202020202020202020",
"4F74686572202020202020202020",
"566F6C756D652020202D34342E35",
"5456206541524320202D34342E35",
"566F6C756D652020202D34342E30",
"566F6C756D652020202D34332E35",
"566F6C756D652020202D34332E30",
"566F6C756D652020202D34322E35",
"5456206541524320202D34322E35",
"5043202020202020202D34322E35",
"476F6F676C654361732D34322E35",
"5456202020202020202D34322E35",
"425420415544494F202D34322E35"
];

final StateManager sm = tu.getStateManager();
for(String element in messages) {
final EISCPMessage raw = EISCPMessage.outputCat("s", "FLD", element);
sm.injectIscpMessage(raw);
await tu.stepDelayMs(delay: 501);
}
});
}
4 changes: 3 additions & 1 deletion lib/config/CfgAppSettings.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* Enhanced Music Controller
* Copyright (C) 2019-2024 by Mikhail Kulesh
* Copyright (C) 2019-2025 by Mikhail Kulesh
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU
* General Public License as published by the Free Software Foundation, either version 3 of the License,
Expand Down Expand Up @@ -441,13 +441,15 @@ class CfgAppSettings extends CfgModule
);
_tabSettings.add(CfgTabSettings(this, AppTabs.RC,
controlsPortrait: [
AppControl.DEVICE_DISPLAY,
AppControl.SETUP_OP_CMD,
AppControl.DIVIDER1,
AppControl.SETUP_NAV_CMD,
AppControl.DIVIDER2,
AppControl.LISTENING_MODE_SWITCH
],
controlsLandscapeLeft: [
AppControl.DEVICE_DISPLAY,
AppControl.SETUP_OP_CMD,
AppControl.DIVIDER1,
AppControl.LISTENING_MODE_SWITCH
Expand Down
4 changes: 3 additions & 1 deletion lib/config/CfgTabSettings.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* Enhanced Music Controller
* Copyright (C) 2019-2023 by Mikhail Kulesh
* Copyright (C) 2019-2025 by Mikhail Kulesh
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU
* General Public License as published by the Free Software Foundation, either version 3 of the License,
Expand Down Expand Up @@ -49,6 +49,7 @@ enum AppControl
RI_CD_PLAYER,
RI_MD_PLAYER,
RI_TAPE_DECK,
DEVICE_DISPLAY
}

enum AppControlGroup
Expand Down Expand Up @@ -86,6 +87,7 @@ class CfgTabSettings
EnumItem.code(AppControl.RI_CD_PLAYER, "RIC", descrList: Strings.l_app_control_ri_cd_player),
EnumItem.code(AppControl.RI_MD_PLAYER, "RIM", descrList: Strings.l_app_control_ri_md_player),
EnumItem.code(AppControl.RI_TAPE_DECK, "RIT", descrList: Strings.l_app_control_ri_tape_deck),
EnumItem.code(AppControl.DEVICE_DISPLAY, "DDP", descrList: Strings.l_app_control_device_display),
]);

static final String TAB_SETTINGS = "tab_settings";
Expand Down
8 changes: 8 additions & 0 deletions lib/constants/Strings.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1173,6 +1173,14 @@ Enjoy!"""];
/*pl*/ "Tape Deck (RI)"];
static String get app_control_ri_tape_deck => l_app_control_ri_tape_deck[_language];

static const List<String> l_app_control_device_display = [
/*en*/ "Device display",
/*ru*/ "Дисплей устройства",
/*de*/ "Gerätedisplay",
/*fr*/ "Affichage de l\'appareil",
/*pl*/ "Wyświetlacz urządzenia"];
static String get app_control_device_display => l_app_control_device_display[_language];

static const List<String> l_tv_display_mode = [
/*en*/ "Display mode on device",
/*ru*/ "Режим отображения на дисплее устройства",
Expand Down
8 changes: 7 additions & 1 deletion lib/iscp/State.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* Enhanced Music Controller
* Copyright (C) 2019-2024 by Mikhail Kulesh
* Copyright (C) 2019-2025 by Mikhail Kulesh
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU
* General Public License as published by the Free Software Foundation, either version 3 of the License,
Expand Down Expand Up @@ -63,6 +63,7 @@ import "messages/PlayStatusMsg.dart";
import "messages/PowerStatusMsg.dart";
import "messages/PresetCommandMsg.dart";
import "messages/RadioStationNameMsg.dart";
import "messages/DeviceDisplayMsg.dart";
import "messages/ReceiverInformationMsg.dart";
import "messages/ServiceType.dart";
import "messages/SleepSetCommandMsg.dart";
Expand Down Expand Up @@ -283,6 +284,11 @@ class State with ProtoTypeMix
return _isChange(GoogleCastVersionMsg.CODE,
_receiverInformation.processGoogleCastVersion(msg));
}
else if (msg is DeviceDisplayMsg)
{
return _isChange(DeviceDisplayMsg.CODE,
_receiverInformation.processDeviceDisplay(msg));
}

// Device settings
if (msg is DimmerLevelMsg)
Expand Down
11 changes: 10 additions & 1 deletion lib/iscp/StateManager.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* Enhanced Music Controller
* Copyright (C) 2019-2024 by Mikhail Kulesh
* Copyright (C) 2019-2025 by Mikhail Kulesh
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU
* General Public License as published by the Free Software Foundation, either version 3 of the License,
Expand Down Expand Up @@ -798,6 +798,15 @@ class StateManager
}
}

void injectIscpMessage(EISCPMessage raw)
{
Logging.info(this, "Injecting ISCP message: " + raw.toString());
if (_messageChannel.getProtoType == ProtoType.ISCP)
{
_onNewEISCPMessage(raw, _messageChannel);
}
}

void sendQueries(final List<String> queries)
=> _messageChannel.sendQueries(queries);

Expand Down
47 changes: 47 additions & 0 deletions lib/iscp/messages/DeviceDisplayMsg.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* Enhanced Music Controller
* Copyright (C) 2019-2025 by Mikhail Kulesh
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU
* General Public License as published by the Free Software Foundation, either version 3 of the License,
* or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. You should have received a copy of the GNU General
* Public License along with this program.
*/

import "dart:convert";

import "../../utils/Convert.dart";
import "../EISCPMessage.dart";
import "../ISCPMessage.dart";

/*
* FL Display Information Command
*/
class DeviceDisplayMsg extends ISCPMessage
{
static const String CODE = "FLD";

late String _value;

DeviceDisplayMsg(EISCPMessage raw) : super(CODE, raw)
{
final List<int> s1 = Convert.convertRaw(getData);
_value = utf8.decode(s1, allowMalformed: true);
}

String get getValue => _value;

@override
String toString()
=> super.toString() + "[VALUE=\"" + _value + "\"]";

@override
bool hasImpactOnMediaList()
{
return false;
}
}
17 changes: 3 additions & 14 deletions lib/iscp/messages/JacketArtMsg.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* Enhanced Music Controller
* Copyright (C) 2019-2023 by Mikhail Kulesh
* Copyright (C) 2019-2025 by Mikhail Kulesh
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU
* General Public License as published by the Free Software Foundation, either version 3 of the License,
Expand All @@ -16,6 +16,7 @@ import "dart:typed_data";

import "package:flutter/widgets.dart";

import "../../utils/Convert.dart";
import "../../utils/UrlLoader.dart";
import "../DcpHeosMessage.dart";
import "../EISCPMessage.dart";
Expand Down Expand Up @@ -95,7 +96,7 @@ class JacketArtMsg extends ISCPMessage
break;
case ImageType.BMP:
case ImageType.JPEG:
rawData = convertRaw(getData.substring(2));
rawData = Convert.convertRaw(getData.substring(2));
break;
case ImageType.NO_IMAGE:
// nothing to do;
Expand Down Expand Up @@ -130,18 +131,6 @@ class JacketArtMsg extends ISCPMessage
+ "]";
}

List<int> convertRaw(String str)
{
final int size = (str.length / 2).floor();
final List<int> bytes = List.generate(size, (i)
{
final int j1 = 2 * i;
final int j2 = 2 * i + 1;
return (j1 < str.length && j2 < str.length) ? ISCPMessage.nonNullInteger(str.substring(j1, j2 + 1), 16, 0) : 0;
});
return bytes;
}

Future<Image?> loadFromUrl()
{
if (url == null)
Expand Down
7 changes: 6 additions & 1 deletion lib/iscp/messages/MessageFactory.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* Enhanced Music Controller
* Copyright (C) 2019-2024 by Mikhail Kulesh
* Copyright (C) 2019-2025 by Mikhail Kulesh
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU
* General Public License as published by the Free Software Foundation, either version 3 of the License,
Expand Down Expand Up @@ -53,6 +53,7 @@ import "PowerStatusMsg.dart";
import "PresetCommandMsg.dart";
import "PresetMemoryMsg.dart";
import "PrivacyPolicyStatusMsg.dart";
import "DeviceDisplayMsg.dart";
import "ReceiverInformationMsg.dart";
import "SleepSetCommandMsg.dart";
import "SpeakerACommandMsg.dart";
Expand Down Expand Up @@ -215,6 +216,10 @@ class MessageFactory
case PrivacyPolicyStatusMsg.CODE:
return PrivacyPolicyStatusMsg(raw);

// Receiver display
case DeviceDisplayMsg.CODE:
return DeviceDisplayMsg(raw);

default:
throw Exception("No factory method for message " + raw.getCode);
}
Expand Down
Loading

0 comments on commit 85f0bb8

Please sign in to comment.