feat(#304): FEM LNA connector state + gated Radio Settings toggle

Completes the client half against the firmware as-built (#298):

- Device-info offset 83 carries the FEM LNA state on v16+, appended
  unconditionally (reads 0 on non-capable boards). parseFemLnaState is
  length-guarded and returns null pre-v16. Byte presence signals firmware
  version, not capability — the cap BIT gates the UI.
- 0xC3 reply handler adopts the reported value verbatim: firmware returns
  post-apply hardware state, not an echo, so a refused write surfaces as
  truth rather than a lie.
- setFemLna / requestFemLnaState no-op unless the capability bit is set,
  so a non-capable radio never sees 0xC3 traffic.
- Radio Settings toggle rendered only when the bit is set, driven by
  connector state via ListenableBuilder rather than local optimistic
  state, so it always shows what the radio reports.
- errCodeUnsupportedCmd documented: a mis-gated request draws [0x01][0x01],
  not [0x01][0x06]. Neither is 0xC3-prefixed, so no new error path.

Gating is on the bit alone, never model or version: firmware derives it
from a runtime FEM probe, so two Heltec V4s can legitimately disagree and
rak3401 reports false by design (its SKY66122 gates LNA and PA together).

13 tests. Not hardware-validated — firmware 0xC3 is still on a branch.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
pull/317/head
Strycher 3 days ago
parent 8f11fe5b4a
commit d60627a059

@ -282,6 +282,7 @@ class MeshCoreConnector extends ChangeNotifier {
String? _firmwareVersion;
String? _deviceModel;
int? _offbandCaps;
bool? _femLnaEnabled;
int _pathHashByteWidth = 1;
CompanionRadioStats? _latestRadioStats;
Stopwatch? _airtimeBumpStopwatch;
@ -589,6 +590,48 @@ class MeshCoreConnector extends ChangeNotifier {
/// True when the radio's block store hit `MAX_BLOCKED_KEYS` (32) and rejected
/// an ADD (ok=0). Local block still applies; those keys just aren't portable.
bool get blockOffloadStoreFull => _blockOffloadStoreFull;
/// Whether this specific radio can control its external FEM LNA (#304).
///
/// Gated on the capability BIT alone firmware derives it from a runtime FEM
/// probe, so it is a per-unit answer: two Heltec V4s can legitimately disagree
/// depending on the fitted chip, and `rak3401` reports false by design (its
/// SKY66122 gates LNA and PA off one line, so a toggle would kill TX).
/// Never shortcut this to a model or version check.
bool get supportsOffbandFemLna => firmwareSupportsOffbandFemLna(_offbandCaps);
/// Current FEM LNA state as last reported by the radio, or null if unknown
/// (pre-v16 firmware). Always reflects hardware truth, never a local guess.
bool? get femLnaEnabled => _femLnaEnabled;
/// Ask the radio to enable or bypass its FEM LNA. No-op unless the capability
/// bit is set, so a non-capable radio never sees `0xC3` traffic. State is
/// updated from the reply, not optimistically.
Future<void> setFemLna(bool enabled) async {
if (!isConnected || !supportsOffbandFemLna) return;
await sendFrame(buildOffbandFemLnaSetFrame(enabled));
}
/// Fallback read; device-info (offset 83) is the primary source on connect.
Future<void> requestFemLnaState() async {
if (!isConnected || !supportsOffbandFemLna) return;
await sendFrame(buildOffbandFemLnaGetFrame());
}
/// `[0xC3][sub][value]` the value is the post-apply hardware state, so it is
/// adopted verbatim rather than assuming a SET took effect (#304).
void _handleOffbandFemLnaReply(Uint8List frame) {
final reply = parseOffbandFemLnaReply(frame);
if (reply == null) return;
if (_femLnaEnabled == reply.enabled) return;
_femLnaEnabled = reply.enabled;
appLogger.info(
'FEM LNA now ${reply.enabled ? 'enabled' : 'bypassed'}',
tag: 'Connector',
);
notifyListeners();
}
Map<String, String>? get currentCustomVars => _currentCustomVars;
int? get batteryMillivolts => _batteryMillivolts;
int? get storageUsedKb => _storageUsedKb;
@ -4323,6 +4366,9 @@ class MeshCoreConnector extends ChangeNotifier {
case cmdOffbandBlock:
_handleOffbandBlockFrame(frame);
break;
case cmdOffbandFemLna:
_handleOffbandFemLnaReply(frame);
break;
case respCodeSelfInfo:
debugPrint('Got SELF_INFO');
_handleSelfInfo(frame);
@ -4627,6 +4673,14 @@ class MeshCoreConnector extends ChangeNotifier {
static int? parseOffbandCaps(Uint8List frame) =>
frame.length >= 83 ? frame[82] : null;
/// FEM LNA state byte, appended immediately after the caps byte in device-info
/// v16+ (firmware #298). Appended **unconditionally** including on
/// non-capable boards, where it reads 0 so the byte's presence indicates
/// firmware version, not capability. The capability BIT is what decides
/// whether to render the control. Null on v15 and older (shorter frame).
static bool? parseFemLnaState(Uint8List frame) =>
frame.length >= 84 ? frame[83] != femLnaBypass : null;
void _handleDeviceInfo(Uint8List frame) {
if (frame.length < 4) return;
if (_shouldGateInitialChannelSync) {
@ -4674,6 +4728,9 @@ class MeshCoreConnector extends ChangeNotifier {
// Offband config capability v14+ (byte 82). Extracted + bounds-checked in a
// testable helper; offset verified against firmware (see parseOffbandCaps).
_offbandCaps = parseOffbandCaps(frame);
// FEM LNA state rides one byte past the caps byte on v16+ (#304). Primary
// read on connect a 0xC3 GET is only the fallback.
_femLnaEnabled = parseFemLnaState(frame);
// Caps just landed; (re)evaluate GPS polling in case a `gps=1` custom-var
// frame arrived before this device-info reply set support. (#144)
_reconcileGpsPolling();

@ -287,9 +287,17 @@ Uint8List buildOffbandFemLnaSetFrame(bool enabled) => Uint8List.fromList([
Uint8List buildOffbandFemLnaGetFrame() =>
Uint8List.fromList([cmdOffbandFemLna, offbandFemLnaGet]);
/// Reply to a `0xC3` request: `[0xC3][sub][value]`. A malformed request draws
/// the generic `[respCodeErr][errCodeIllegalArg]` instead, which is NOT
/// 0xC3-prefixed and so never reaches this parser.
/// Reply to a `0xC3` request: `[0xC3][sub][value]`.
///
/// The value is the **post-apply hardware state, not an echo of the request**
/// (firmware #298 as-built): if the FEM ever refused a write, this reports the
/// truth rather than confirming a change that didn't take. Always render from
/// this value; never assume the written value stuck.
///
/// Error replies are never 0xC3-prefixed, so they don't reach this parser:
/// malformed `[respCodeErr][errCodeIllegalArg]`; a request to a non-capable
/// board `[respCodeErr][errCodeUnsupportedCmd]` (unreachable when gated on
/// the capability bit, but firmware answers it defensively).
class OffbandFemLnaReply {
const OffbandFemLnaReply(this.subType, this.value);
final int subType;
@ -316,6 +324,12 @@ const int offbandBlockClear = 0x04;
/// app must recognise the 2-byte error frame and not wait for a 0xC2 echo.
const int errCodeIllegalArg = 6;
/// `ERR_CODE_UNSUPPORTED_CMD` returned for an Offband command the connected
/// board can't service (e.g. a `0xC3` FEM LNA request to a board without FEM
/// control). Unreachable when the capability bit is respected; firmware answers
/// it defensively against a stale or mis-gated client. (#304)
const int errCodeUnsupportedCmd = 1;
Uint8List buildOffbandBlockAddFrame(Uint8List pubKey) =>
Uint8List.fromList([cmdOffbandBlock, offbandBlockAdd, ...pubKey]);
Uint8List buildOffbandBlockRemoveFrame(Uint8List pubKey) =>

@ -253,6 +253,8 @@
"settings_txPowerInvalid": "Invalid TX power (0-22 dBm)",
"settings_clientRepeat": "Off-Grid Repeat",
"settings_clientRepeatSubtitle": "Allow this device to repeat mesh packets for others",
"settings_femLna": "Receive amplifier (FEM LNA)",
"settings_femLnaSubtitle": "Boosts receive sensitivity. Leave on unless you are troubleshooting a strong nearby signal.",
"settings_clientRepeatFreqWarning": "Off-grid repeat requires 433, 869, or 918 MHz frequency",
"settings_error": "Error: {message}",
"@settings_error": {

@ -1276,6 +1276,18 @@ abstract class AppLocalizations {
/// **'Allow this device to repeat mesh packets for others'**
String get settings_clientRepeatSubtitle;
/// No description provided for @settings_femLna.
///
/// In en, this message translates to:
/// **'Receive amplifier (FEM LNA)'**
String get settings_femLna;
/// No description provided for @settings_femLnaSubtitle.
///
/// In en, this message translates to:
/// **'Boosts receive sensitivity. Leave on unless you are troubleshooting a strong nearby signal.'**
String get settings_femLnaSubtitle;
/// No description provided for @settings_clientRepeatFreqWarning.
///
/// In en, this message translates to:

@ -642,6 +642,13 @@ class AppLocalizationsBg extends AppLocalizations {
String get settings_clientRepeatSubtitle =>
'Позволете на това устройство да предава пакети към мрежата за други устройства.';
@override
String get settings_femLna => 'Receive amplifier (FEM LNA)';
@override
String get settings_femLnaSubtitle =>
'Boosts receive sensitivity. Leave on unless you are troubleshooting a strong nearby signal.';
@override
String get settings_clientRepeatFreqWarning =>
'За повторение извън мрежата са необходими честоти от 433, 869 или 918 MHz.';

@ -637,6 +637,13 @@ class AppLocalizationsDe extends AppLocalizations {
String get settings_clientRepeatSubtitle =>
'Ermöglichen Sie diesem Gerät, Mesh-Pakete für andere zu wiederholen.';
@override
String get settings_femLna => 'Receive amplifier (FEM LNA)';
@override
String get settings_femLnaSubtitle =>
'Boosts receive sensitivity. Leave on unless you are troubleshooting a strong nearby signal.';
@override
String get settings_clientRepeatFreqWarning =>
'Die Kommunikation ohne Stromversorgung erfordert Frequenzen von 433, 869 oder 918 MHz.';

@ -627,6 +627,13 @@ class AppLocalizationsEn extends AppLocalizations {
String get settings_clientRepeatSubtitle =>
'Allow this device to repeat mesh packets for others';
@override
String get settings_femLna => 'Receive amplifier (FEM LNA)';
@override
String get settings_femLnaSubtitle =>
'Boosts receive sensitivity. Leave on unless you are troubleshooting a strong nearby signal.';
@override
String get settings_clientRepeatFreqWarning =>
'Off-grid repeat requires 433, 869, or 918 MHz frequency';

@ -638,6 +638,13 @@ class AppLocalizationsEs extends AppLocalizations {
String get settings_clientRepeatSubtitle =>
'Permita que este dispositivo repita los paquetes de red para otros usuarios.';
@override
String get settings_femLna => 'Receive amplifier (FEM LNA)';
@override
String get settings_femLnaSubtitle =>
'Boosts receive sensitivity. Leave on unless you are troubleshooting a strong nearby signal.';
@override
String get settings_clientRepeatFreqWarning =>
'Para la comunicación fuera de la red, se requiere una frecuencia de 433, 869 o 918 MHz.';

@ -642,6 +642,13 @@ class AppLocalizationsFr extends AppLocalizations {
String get settings_clientRepeatSubtitle =>
'Permettez à cet appareil de répéter les paquets de données pour les autres.';
@override
String get settings_femLna => 'Receive amplifier (FEM LNA)';
@override
String get settings_femLnaSubtitle =>
'Boosts receive sensitivity. Leave on unless you are troubleshooting a strong nearby signal.';
@override
String get settings_clientRepeatFreqWarning =>
'Pour les transmissions hors réseau, il est nécessaire d\'utiliser les fréquences de 433, 869 ou 918 MHz.';

@ -642,6 +642,13 @@ class AppLocalizationsHu extends AppLocalizations {
String get settings_clientRepeatSubtitle =>
'Engedje, hogy ez a eszköz mások számára is ismételje a hálózati csomagokat.';
@override
String get settings_femLna => 'Receive amplifier (FEM LNA)';
@override
String get settings_femLnaSubtitle =>
'Boosts receive sensitivity. Leave on unless you are troubleshooting a strong nearby signal.';
@override
String get settings_clientRepeatFreqWarning =>
'A hálózat nélküli kommunikációhoz 433, 869 vagy 918 MHz frekvenciát igényel.';

@ -640,6 +640,13 @@ class AppLocalizationsIt extends AppLocalizations {
String get settings_clientRepeatSubtitle =>
'Permetti a questo dispositivo di ripetere i pacchetti di rete per gli altri.';
@override
String get settings_femLna => 'Receive amplifier (FEM LNA)';
@override
String get settings_femLnaSubtitle =>
'Boosts receive sensitivity. Leave on unless you are troubleshooting a strong nearby signal.';
@override
String get settings_clientRepeatFreqWarning =>
'Per la comunicazione fuori rete, è necessario utilizzare frequenze di 433, 869 o 918 MHz.';

@ -613,6 +613,13 @@ class AppLocalizationsJa extends AppLocalizations {
String get settings_clientRepeatSubtitle =>
'このデバイスが、他のデバイスに対してメッシュパケットを繰り返し送信できるようにする。';
@override
String get settings_femLna => 'Receive amplifier (FEM LNA)';
@override
String get settings_femLnaSubtitle =>
'Boosts receive sensitivity. Leave on unless you are troubleshooting a strong nearby signal.';
@override
String get settings_clientRepeatFreqWarning =>
'オフグリッドでの再送には、433MHz、869MHz、または918MHzの周波数が必要です。';

@ -613,6 +613,13 @@ class AppLocalizationsKo extends AppLocalizations {
String get settings_clientRepeatSubtitle =>
'이 장치가 다른 사람들을 위해 메시 패킷을 반복하도록 허용합니다.';
@override
String get settings_femLna => 'Receive amplifier (FEM LNA)';
@override
String get settings_femLnaSubtitle =>
'Boosts receive sensitivity. Leave on unless you are troubleshooting a strong nearby signal.';
@override
String get settings_clientRepeatFreqWarning =>
'오프그리드(무전력) 시스템 재연결에는 433MHz, 869MHz, 또는 918MHz 주파수가 필요합니다.';

@ -634,6 +634,13 @@ class AppLocalizationsNl extends AppLocalizations {
String get settings_clientRepeatSubtitle =>
'Laat dit apparaat de berichten van andere apparaten doorsturen.';
@override
String get settings_femLna => 'Receive amplifier (FEM LNA)';
@override
String get settings_femLnaSubtitle =>
'Boosts receive sensitivity. Leave on unless you are troubleshooting a strong nearby signal.';
@override
String get settings_clientRepeatFreqWarning =>
'Om een signaal buiten het netwerk te versturen, zijn frequenties van 433, 869 of 918 MHz vereist.';

@ -643,6 +643,13 @@ class AppLocalizationsPl extends AppLocalizations {
String get settings_clientRepeatSubtitle =>
'Pozwól temu urządzeniu powtarzać pakiety danych dla innych urządzeń.';
@override
String get settings_femLna => 'Receive amplifier (FEM LNA)';
@override
String get settings_femLnaSubtitle =>
'Boosts receive sensitivity. Leave on unless you are troubleshooting a strong nearby signal.';
@override
String get settings_clientRepeatFreqWarning =>
'Powtórka poza siecią wymaga częstotliwości 433, 869 lub 918 MHz.';

@ -640,6 +640,13 @@ class AppLocalizationsPt extends AppLocalizations {
String get settings_clientRepeatSubtitle =>
'Permita que este dispositivo repita pacotes de rede para outros dispositivos.';
@override
String get settings_femLna => 'Receive amplifier (FEM LNA)';
@override
String get settings_femLnaSubtitle =>
'Boosts receive sensitivity. Leave on unless you are troubleshooting a strong nearby signal.';
@override
String get settings_clientRepeatFreqWarning =>
'A repetição fora da rede requer frequências de 433, 869 ou 918 MHz.';

@ -640,6 +640,13 @@ class AppLocalizationsRu extends AppLocalizations {
String get settings_clientRepeatSubtitle =>
'Позвольте этому устройству повторять пакеты данных для других устройств.';
@override
String get settings_femLna => 'Receive amplifier (FEM LNA)';
@override
String get settings_femLnaSubtitle =>
'Boosts receive sensitivity. Leave on unless you are troubleshooting a strong nearby signal.';
@override
String get settings_clientRepeatFreqWarning =>
'Для работы в режиме \"без подключения к сети\" требуется частота 433, 869 или 918 МГц.';

@ -634,6 +634,13 @@ class AppLocalizationsSk extends AppLocalizations {
String get settings_clientRepeatSubtitle =>
'Umožnite, aby toto zariadenie opakovávalo siete pre ostatných.';
@override
String get settings_femLna => 'Receive amplifier (FEM LNA)';
@override
String get settings_femLnaSubtitle =>
'Boosts receive sensitivity. Leave on unless you are troubleshooting a strong nearby signal.';
@override
String get settings_clientRepeatFreqWarning =>
'Použitie off-grid systému vyžaduje frekvencie 433, 869 alebo 918 MHz.';

@ -631,6 +631,13 @@ class AppLocalizationsSl extends AppLocalizations {
String get settings_clientRepeatSubtitle =>
'Omogočite temu naprave, da ponavlja paketne sporočila za druge.';
@override
String get settings_femLna => 'Receive amplifier (FEM LNA)';
@override
String get settings_femLnaSubtitle =>
'Boosts receive sensitivity. Leave on unless you are troubleshooting a strong nearby signal.';
@override
String get settings_clientRepeatFreqWarning =>
'Za ponovni prenos na brezžični način so potrebne frekvence 433, 869 ali 918 MHz.';

@ -629,6 +629,13 @@ class AppLocalizationsSv extends AppLocalizations {
String get settings_clientRepeatSubtitle =>
'Låt enheten repetera nätpaket för andra användare.';
@override
String get settings_femLna => 'Receive amplifier (FEM LNA)';
@override
String get settings_femLnaSubtitle =>
'Boosts receive sensitivity. Leave on unless you are troubleshooting a strong nearby signal.';
@override
String get settings_clientRepeatFreqWarning =>
'För att kunna kommunicera utanför elnätet krävs frekvenserna 433, 869 eller 918 MHz.';

@ -637,6 +637,13 @@ class AppLocalizationsUk extends AppLocalizations {
String get settings_clientRepeatSubtitle =>
'Дозвольте цьому пристрою повторювати пакети даних для інших пристроїв.';
@override
String get settings_femLna => 'Receive amplifier (FEM LNA)';
@override
String get settings_femLnaSubtitle =>
'Boosts receive sensitivity. Leave on unless you are troubleshooting a strong nearby signal.';
@override
String get settings_clientRepeatFreqWarning =>
'Повтор без підключення до мережі вимагає частоти 433, 869 або 918 МГц.';

@ -604,6 +604,13 @@ class AppLocalizationsZh extends AppLocalizations {
@override
String get settings_clientRepeatSubtitle => '允许此设备重复发送网状数据包给其他设备';
@override
String get settings_femLna => 'Receive amplifier (FEM LNA)';
@override
String get settings_femLnaSubtitle =>
'Boosts receive sensitivity. Leave on unless you are troubleshooting a strong nearby signal.';
@override
String get settings_clientRepeatFreqWarning =>
'离网重复通信需要使用 433、869 或 918 兆赫兹的频率。';

@ -2192,6 +2192,23 @@ class _RadioSettingsFormState extends State<_RadioSettingsForm> {
contentPadding: EdgeInsets.zero,
),
],
// Only this radio's own FEM probe decides whether this appears — never
// model or version (#304). Deliberately not mirrored into local state:
// firmware returns post-apply hardware truth, so the switch renders
// what the radio reports rather than what we asked for.
if (widget.connector.supportsOffbandFemLna) ...[
const SizedBox(height: 16),
ListenableBuilder(
listenable: widget.connector,
builder: (context, _) => SwitchListTile(
title: Text(l10n.settings_femLna),
subtitle: Text(l10n.settings_femLnaSubtitle),
value: widget.connector.femLnaEnabled ?? true,
onChanged: (value) => widget.connector.setFemLna(value),
contentPadding: EdgeInsets.zero,
),
),
],
const SizedBox(height: 16),
SizedBox(
width: double.infinity,

@ -1,6 +1,7 @@
import 'dart:typed_data';
import 'package:flutter_test/flutter_test.dart';
import 'package:meshcore_open/connector/meshcore_connector.dart';
import 'package:meshcore_open/connector/meshcore_protocol.dart';
void main() {
@ -28,6 +29,55 @@ void main() {
});
});
group('FEM LNA device-info state byte, offset 83 (#304)', () {
Uint8List deviceInfo({required int length, int femByte = 0}) {
final frame = Uint8List(length);
frame[0] = respCodeDeviceInfo;
if (length >= 84) frame[83] = femByte;
return frame;
}
test('reads the byte immediately after caps on v16+', () {
expect(
MeshCoreConnector.parseFemLnaState(deviceInfo(length: 84, femByte: 1)),
isTrue,
);
expect(
MeshCoreConnector.parseFemLnaState(deviceInfo(length: 84, femByte: 0)),
isFalse,
);
});
test('null on pre-v16 firmware that stops at the caps byte', () {
expect(
MeshCoreConnector.parseFemLnaState(deviceInfo(length: 83)),
isNull,
);
expect(MeshCoreConnector.parseFemLnaState(Uint8List(0)), isNull);
});
test('does not disturb the caps byte at offset 82', () {
final frame = deviceInfo(length: 84, femByte: 1);
frame[82] = offbandCapBlock | offbandCapFemLna;
expect(MeshCoreConnector.parseOffbandCaps(frame), equals(0x06));
expect(MeshCoreConnector.parseFemLnaState(frame), isTrue);
});
test('byte is present on non-capable boards and reads as bypassed', () {
// Firmware appends it unconditionally, so presence indicates version,
// not capability the cap bit is what gates the UI.
final frame = deviceInfo(length: 84, femByte: 0);
frame[82] = 0x00;
expect(MeshCoreConnector.parseFemLnaState(frame), isFalse);
expect(
firmwareSupportsOffbandFemLna(
MeshCoreConnector.parseOffbandCaps(frame),
),
isFalse,
);
});
});
group('FEM LNA frames (#304)', () {
test('SET carries the enable value', () {
expect(

@ -15,6 +15,8 @@
"settings_infoFirmware",
"settings_infoModel",
"settings_publicKeyCopied",
"settings_femLna",
"settings_femLnaSubtitle",
"appSettings_clock",
"appSettings_clockSystem",
"appSettings_clock12h",
@ -73,6 +75,8 @@
"settings_infoFirmware",
"settings_infoModel",
"settings_publicKeyCopied",
"settings_femLna",
"settings_femLnaSubtitle",
"appSettings_clock",
"appSettings_clockSystem",
"appSettings_clock12h",
@ -131,6 +135,8 @@
"settings_infoFirmware",
"settings_infoModel",
"settings_publicKeyCopied",
"settings_femLna",
"settings_femLnaSubtitle",
"appSettings_clock",
"appSettings_clockSystem",
"appSettings_clock12h",
@ -189,6 +195,8 @@
"settings_infoFirmware",
"settings_infoModel",
"settings_publicKeyCopied",
"settings_femLna",
"settings_femLnaSubtitle",
"appSettings_clock",
"appSettings_clockSystem",
"appSettings_clock12h",
@ -247,6 +255,8 @@
"settings_infoFirmware",
"settings_infoModel",
"settings_publicKeyCopied",
"settings_femLna",
"settings_femLnaSubtitle",
"appSettings_clock",
"appSettings_clockSystem",
"appSettings_clock12h",
@ -305,6 +315,8 @@
"settings_infoFirmware",
"settings_infoModel",
"settings_publicKeyCopied",
"settings_femLna",
"settings_femLnaSubtitle",
"appSettings_clock",
"appSettings_clockSystem",
"appSettings_clock12h",
@ -363,6 +375,8 @@
"settings_infoFirmware",
"settings_infoModel",
"settings_publicKeyCopied",
"settings_femLna",
"settings_femLnaSubtitle",
"appSettings_clock",
"appSettings_clockSystem",
"appSettings_clock12h",
@ -421,6 +435,8 @@
"settings_infoFirmware",
"settings_infoModel",
"settings_publicKeyCopied",
"settings_femLna",
"settings_femLnaSubtitle",
"appSettings_clock",
"appSettings_clockSystem",
"appSettings_clock12h",
@ -479,6 +495,8 @@
"settings_infoFirmware",
"settings_infoModel",
"settings_publicKeyCopied",
"settings_femLna",
"settings_femLnaSubtitle",
"appSettings_clock",
"appSettings_clockSystem",
"appSettings_clock12h",
@ -537,6 +555,8 @@
"settings_infoFirmware",
"settings_infoModel",
"settings_publicKeyCopied",
"settings_femLna",
"settings_femLnaSubtitle",
"appSettings_clock",
"appSettings_clockSystem",
"appSettings_clock12h",
@ -595,6 +615,8 @@
"settings_infoFirmware",
"settings_infoModel",
"settings_publicKeyCopied",
"settings_femLna",
"settings_femLnaSubtitle",
"appSettings_clock",
"appSettings_clockSystem",
"appSettings_clock12h",
@ -653,6 +675,8 @@
"settings_infoFirmware",
"settings_infoModel",
"settings_publicKeyCopied",
"settings_femLna",
"settings_femLnaSubtitle",
"appSettings_clock",
"appSettings_clockSystem",
"appSettings_clock12h",
@ -711,6 +735,8 @@
"settings_infoFirmware",
"settings_infoModel",
"settings_publicKeyCopied",
"settings_femLna",
"settings_femLnaSubtitle",
"appSettings_clock",
"appSettings_clockSystem",
"appSettings_clock12h",
@ -769,6 +795,8 @@
"settings_infoFirmware",
"settings_infoModel",
"settings_publicKeyCopied",
"settings_femLna",
"settings_femLnaSubtitle",
"appSettings_clock",
"appSettings_clockSystem",
"appSettings_clock12h",
@ -827,6 +855,8 @@
"settings_infoFirmware",
"settings_infoModel",
"settings_publicKeyCopied",
"settings_femLna",
"settings_femLnaSubtitle",
"appSettings_clock",
"appSettings_clockSystem",
"appSettings_clock12h",
@ -885,6 +915,8 @@
"settings_infoFirmware",
"settings_infoModel",
"settings_publicKeyCopied",
"settings_femLna",
"settings_femLnaSubtitle",
"appSettings_clock",
"appSettings_clockSystem",
"appSettings_clock12h",
@ -943,6 +975,8 @@
"settings_infoFirmware",
"settings_infoModel",
"settings_publicKeyCopied",
"settings_femLna",
"settings_femLnaSubtitle",
"appSettings_clock",
"appSettings_clockSystem",
"appSettings_clock12h",

Loading…
Cancel
Save

Powered by TurnKey Linux.