avaibility, compass big box

This commit is contained in:
jusax23 2023-09-21 16:05:34 +02:00
parent 0ce9f9c1a1
commit 1a714bcdeb
Signed by: jusax23
GPG key ID: 499E2AA870C1CD41
3 changed files with 284 additions and 192 deletions

View file

@ -27,35 +27,50 @@ base class GnssLocData extends Struct {
// end c-structs // end c-structs
class Compass extends JuBox { class Compass extends JuBox {
const Compass({super.key}); final bool small;
const Compass(this.small, {super.key});
@override @override
State<StatefulWidget> createState() => _CompassState(); // ignore: no_logic_in_create_state
State<StatefulWidget> createState() => _CompassState(small);
} }
class _CompassState extends State<Compass> { class _CompassState extends State<Compass> {
final bool small;
_CompassState(this.small) : super();
USerial serial = getSerial(); USerial serial = getSerial();
late Timer timer; Timer? timer;
int _magX = 0, _magY = 0, _magZ = 0, _magAngle = 0; int _magX = 0, _magY = 0, _magZ = 0, _magAngle = 0;
bool available = true;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
SensorReader.listen(serialListen); SensorReader.listen(serialListen);
timer = Timer.periodic(const Duration(milliseconds: 500), (_) async { if (small) {
serial.sprintln("<rfSystemSensor>2200", system: true); timer = Timer.periodic(const Duration(milliseconds: 500), (_) async {
}); if (available) serial.sprintln("<rfSystemSensor>2200", system: true);
});
}
} }
@override @override
void dispose() { void dispose() {
SensorReader.removeListen(serialListen); SensorReader.removeListen(serialListen);
timer.cancel(); timer?.cancel();
super.dispose(); super.dispose();
} }
void serialListen(int type, int command, Pointer<ArrayCStruct> ptr) { void serialListen(int type, int command, Pointer<ArrayCStruct> ptr) {
if (type == 0x22 && command == 0xff) {
setState(() {
available = false;
});
return;
}
if (type != 0x22 || command != 0x00) return; if (type != 0x22 || command != 0x00) return;
var loc = ptr as Pointer<GnssLocData>; var loc = ptr as Pointer<GnssLocData>;
setState(() { setState(() {
@ -70,64 +85,101 @@ class _CompassState extends State<Compass> {
} }
@override @override
Widget build(BuildContext context) => Stack( Widget build(BuildContext context) => small
children: [ ? GestureDetector(
SvgPicture.asset('assets/compass.svg'), onTap: () {
AnimatedRotation( if (available) {
turns: _magAngle / 360.0, Navigator.push(
duration: const Duration(milliseconds: 500), context,
alignment: Alignment.center, // Rotate around the center MaterialPageRoute(builder: (context) => const Compass(false)),
child: SvgPicture.asset('assets/needle.svg')), );
Column( } else {
crossAxisAlignment: CrossAxisAlignment.start, available = true;
children: [ }
Text( },
"x: ${(_magX * 8.0 / 32768.0 * 100.0).toStringAsFixed(2)}µT"), child: buildLoc(context))
Text( : Scaffold(
"y: ${(_magY * 8.0 / 32768.0 * 100.0).toStringAsFixed(2)}µT"), appBar: AppBar(
Text( backgroundColor: Theme.of(context).colorScheme.inversePrimary,
"z: ${(_magZ * 8.0 / 32768.0 * 100.0).toStringAsFixed(2)}µT"), title: const Text(
Expanded( "Compass",
child: Align( style: TextStyle(
alignment: Alignment.bottomLeft, fontSize: 16,
child: FilledButton(
child: const Icon(Icons.calculate),
onPressed: () {
showDialog<String>(
context: context,
builder: (BuildContext context) => AlertDialog(
title: const Text('Callibrate Compass'),
content: const Text(
'When clicking okay the compass will be calibrated, \ncompletely blocking all radio communication for 10 sec. \nWhile calibrating rotate the sensor in ever direction.'),
actions: <Widget>[
TextButton(
onPressed: () => Navigator.pop(context, 'Cancel'),
child: const Text('Cancel'),
),
TextButton(
onPressed: () {
serial.sprintln("<rfSystemSensor>2201",
system: true);
Navigator.pop(context, 'OK');
},
child: const Text('OK'),
),
],
),
);
//
},
),
),
), ),
], ),
toolbarHeight: 40,
), ),
Expanded( body: Container(
child: Align( padding: const EdgeInsets.all(0.3 * 2 * 20),
alignment: Alignment.topRight, child: buildLoc(context)),
child: Text( );
"t: ${(sqrt(_magX * _magX + _magY * _magY + _magZ * _magZ) * 8.0 / 32768.0 * 100.0).toStringAsFixed(2)}µT"),
)) Widget buildLoc(BuildContext context) => !available
], ? const Center(
); child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [Text("Compass is not available!"), Icon(Icons.block)]))
: Stack(
children: [
Center(child: SvgPicture.asset('assets/compass.svg')),
Center(
child: AnimatedRotation(
turns: _magAngle / 360.0,
duration: const Duration(milliseconds: 500),
alignment: Alignment.center, // Rotate around the center
child: SvgPicture.asset('assets/needle.svg'))),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"x: ${(_magX * 8.0 / 32768.0 * 100.0).toStringAsFixed(2)}µT"),
Text(
"y: ${(_magY * 8.0 / 32768.0 * 100.0).toStringAsFixed(2)}µT"),
Text(
"z: ${(_magZ * 8.0 / 32768.0 * 100.0).toStringAsFixed(2)}µT"),
if (!small)
Expanded(
child: Align(
alignment: Alignment.bottomLeft,
child: FilledButton(
child: const Icon(Icons.calculate),
onPressed: () {
showDialog<String>(
context: context,
builder: (BuildContext context) => AlertDialog(
title: const Text('Callibrate Compass'),
content: const Text(
'When clicking okay the compass will be calibrated, \ncompletely blocking all radio communication for 10 sec. \nWhile calibrating rotate the sensor in ever direction.'),
actions: <Widget>[
TextButton(
onPressed: () =>
Navigator.pop(context, 'Cancel'),
child: const Text('Cancel'),
),
TextButton(
onPressed: () {
serial.sprintln("<rfSystemSensor>2201",
system: true);
Navigator.pop(context, 'OK');
},
child: const Text('OK'),
),
],
),
);
//
},
),
),
),
],
),
Align(
alignment: Alignment.topRight,
child: Text(
"t: ${(sqrt(_magX * _magX + _magY * _magY + _magZ * _magZ) * 8.0 / 32768.0 * 100.0).toStringAsFixed(2)}µT"),
)
],
);
} }

View file

@ -108,13 +108,14 @@ class _MapsState extends State<Maps> with TickerProviderStateMixin {
int _state = 0; int _state = 0;
bool _wasVaild = false; bool _wasVaild = false;
final _mapController = MapController(); final _mapController = MapController();
bool available = true;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
SensorReader.listen(serialListen); SensorReader.listen(serialListen);
timer = Timer.periodic(const Duration(seconds: 1), (_) async { timer = Timer.periodic(const Duration(seconds: 1), (_) async {
serial.sprintln("<rfSystemSensor>2300", system: true); if (available) serial.sprintln("<rfSystemSensor>2300", system: true);
}); });
} }
@ -126,6 +127,12 @@ class _MapsState extends State<Maps> with TickerProviderStateMixin {
} }
void serialListen(int type, int command, Pointer<ArrayCStruct> ptr) { void serialListen(int type, int command, Pointer<ArrayCStruct> ptr) {
if (type == 0x23 && command == 0xff) {
setState(() {
available = false;
});
return;
}
if (type != 0x23 || command != 0x00) return; if (type != 0x23 || command != 0x00) return;
var loc = ptr as Pointer<GnssLocData>; var loc = ptr as Pointer<GnssLocData>;
setState(() { setState(() {
@ -140,46 +147,61 @@ class _MapsState extends State<Maps> with TickerProviderStateMixin {
} }
@override @override
Widget build(BuildContext context) => FlutterMap( Widget build(BuildContext context) => !available
options: MapOptions( ? GestureDetector(
center: LatLng(_lat, _long), onTap: () {
zoom: _wasVaild ? 17 : 6, if (!available) {
maxZoom: _wasVaild ? 17 : 6, available = true;
minZoom: _wasVaild ? 17 : 6, }
interactiveFlags: InteractiveFlag.none, },
onTap: (TapPosition pos, LatLng ll) { child: const Center(
Navigator.push( child: Column(
context, mainAxisAlignment: MainAxisAlignment.center,
MaterialPageRoute( crossAxisAlignment: CrossAxisAlignment.center,
builder: (context) => const SerialDetailPage()), children: [
); Text("GNSS is not available!"),
}), Icon(Icons.block)
mapController: _mapController, ])))
children: [ : FlutterMap(
TileLayer( options: MapOptions(
urlTemplate: 'https://tile.openstreetmap.de/{z}/{x}/{y}.png', center: LatLng(_lat, _long),
userAgentPackageName: 'de.jusax.ju_rc_app', zoom: _wasVaild ? 17 : 6,
), maxZoom: _wasVaild ? 17 : 6,
MarkerLayer( minZoom: _wasVaild ? 17 : 6,
markers: [ interactiveFlags: InteractiveFlag.none,
Marker( onTap: (TapPosition pos, LatLng ll) {
point: LatLng(_lat, _long), Navigator.push(
width: 100, context,
height: 100, MaterialPageRoute(
builder: (context) => Icon( builder: (context) => const SerialDetailPage()),
switch (_state) { );
3 => Icons.location_on, }),
2 => Icons.location_off, mapController: _mapController,
1 => Icons.location_on_outlined, children: [
int() => Icons.location_off_outlined, TileLayer(
}, urlTemplate: 'https://tile.openstreetmap.de/{z}/{x}/{y}.png',
color: Theme.of(context).colorScheme.primary, userAgentPackageName: 'de.jusax.ju_rc_app',
),
MarkerLayer(
markers: [
Marker(
point: LatLng(_lat, _long),
width: 100,
height: 100,
builder: (context) => Icon(
switch (_state) {
3 => Icons.location_on,
2 => Icons.location_off,
1 => Icons.location_on_outlined,
int() => Icons.location_off_outlined,
},
color: Theme.of(context).colorScheme.primary,
),
), ),
), ],
], ),
), ],
], );
);
} }
class SerialDetailPage extends StatefulWidget { class SerialDetailPage extends StatefulWidget {
@ -206,11 +228,13 @@ class _SerialDetailPageState extends State<SerialDetailPage>
_hdopState = false; _hdopState = false;
int _satN = -1; int _satN = -1;
bool _follow = true; bool _follow = true;
bool available = true;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
timer = Timer.periodic(const Duration(seconds: 2), (_) async { timer = Timer.periodic(const Duration(seconds: 2), (_) async {
if(!available) return;
serial.sprintln("<rfSystemSensor>2303", system: true); serial.sprintln("<rfSystemSensor>2303", system: true);
sleep(const Duration(milliseconds: 200)); sleep(const Duration(milliseconds: 200));
serial.sprintln("<rfSystemSensor>2304", system: true); serial.sprintln("<rfSystemSensor>2304", system: true);
@ -233,6 +257,7 @@ class _SerialDetailPageState extends State<SerialDetailPage>
void serialListen(int type, int command, Pointer<ArrayCStruct> ptr) { void serialListen(int type, int command, Pointer<ArrayCStruct> ptr) {
if (type != 0x23) return; if (type != 0x23) return;
command = 0xff;
switch (command) { switch (command) {
case 0: case 0:
{ {
@ -295,7 +320,11 @@ class _SerialDetailPageState extends State<SerialDetailPage>
} }
break; break;
case 0xff: case 0xff:
{} {
setState(() {
available = false;
});
}
break; break;
} }
} }
@ -327,91 +356,102 @@ class _SerialDetailPageState extends State<SerialDetailPage>
}, },
child: Icon(_follow ? Icons.near_me : Icons.near_me_outlined), child: Icon(_follow ? Icons.near_me : Icons.near_me_outlined),
), ),
body: Column(children: [ body: !available
Row( ? const Center(
mainAxisAlignment: MainAxisAlignment.center, child: Column(
children: [ mainAxisAlignment: MainAxisAlignment.center,
Text( crossAxisAlignment: CrossAxisAlignment.center,
"Speed: ${_mps.toStringAsPrecision(3)}m/s", children: [
style: TextStyle( Text("GNSS is not available!"),
backgroundColor: Icon(Icons.block)
_mpsState ? Colors.green[shade()] : Colors.red[shade()]), ]))
), : Column(children: [
const VerticalDivider(width: 5), Row(
Text("Course: ${_course.toStringAsFixed(0)}°", mainAxisAlignment: MainAxisAlignment.center,
style: TextStyle( children: [
backgroundColor: _courseState Text(
? Colors.green[shade()] "Speed: ${_mps.toStringAsPrecision(3)}m/s",
: Colors.red[shade()])), style: TextStyle(
const VerticalDivider(width: 5), backgroundColor: _mpsState
Text("Alt: ${_alt.toStringAsPrecision(4)}m", ? Colors.green[shade()]
style: TextStyle( : Colors.red[shade()]),
backgroundColor: _altState ),
? Colors.green[shade()] const VerticalDivider(width: 5),
: Colors.red[shade()])), Text("Course: ${_course.toStringAsFixed(0)}°",
const VerticalDivider(width: 5), style: TextStyle(
Text("Sats: $_satN", backgroundColor: _courseState
style: TextStyle( ? Colors.green[shade()]
backgroundColor: _satNState : Colors.red[shade()])),
? Colors.green[shade()] const VerticalDivider(width: 5),
: Colors.red[shade()])), Text("Alt: ${_alt.toStringAsPrecision(4)}m",
const VerticalDivider(width: 5), style: TextStyle(
Text("Hdop: ${_hdop.toStringAsPrecision(2)}", backgroundColor: _altState
style: TextStyle( ? Colors.green[shade()]
backgroundColor: _hdopState : Colors.red[shade()])),
? Colors.green[shade()] const VerticalDivider(width: 5),
: Colors.red[shade()])), Text("Sats: $_satN",
], style: TextStyle(
), backgroundColor: _satNState
Expanded( ? Colors.green[shade()]
child: FlutterMap( : Colors.red[shade()])),
mapController: _mapController, const VerticalDivider(width: 5),
options: MapOptions( Text("Hdop: ${_hdop.toStringAsPrecision(2)}",
center: const LatLng(51.1667, 10.4500), style: TextStyle(
zoom: 6, backgroundColor: _hdopState
maxZoom: 18, ? Colors.green[shade()]
interactiveFlags: InteractiveFlag.drag | : Colors.red[shade()])),
InteractiveFlag.flingAnimation | ],
InteractiveFlag.pinchMove | ),
InteractiveFlag.pinchZoom | Expanded(
InteractiveFlag.doubleTapZoom, child: FlutterMap(
onPositionChanged: (MapPosition pos, bool user) { mapController: _mapController,
if (user) { options: MapOptions(
setState(() { center: const LatLng(51.1667, 10.4500),
_follow = false; zoom: 6,
}); maxZoom: 18,
} interactiveFlags: InteractiveFlag.drag |
}), InteractiveFlag.flingAnimation |
children: [ InteractiveFlag.pinchMove |
TileLayer( InteractiveFlag.pinchZoom |
urlTemplate: 'https://tile.openstreetmap.de/{z}/{x}/{y}.png', InteractiveFlag.doubleTapZoom,
//urlTemplate: 'https://sgx.geodatenzentrum.de/wmts_basemapde/tile/1.0.0/de_basemapde_web_raster_farbe/default/GLOBAL_WEBMERCATOR/{z}/{y}/{x}.png', onPositionChanged: (MapPosition pos, bool user) {
userAgentPackageName: 'de.jusax.ju_rc_app', if (user) {
), setState(() {
MarkerLayer( _follow = false;
markers: [ });
Marker( }
point: LatLng(_lat, _long), }),
width: 100, children: [
height: 100, TileLayer(
builder: (context) => Transform.rotate( urlTemplate:
angle: _course * 'https://tile.openstreetmap.de/{z}/{x}/{y}.png',
(pi / 180), // Convert degrees to radians //urlTemplate: 'https://sgx.geodatenzentrum.de/wmts_basemapde/tile/1.0.0/de_basemapde_web_raster_farbe/default/GLOBAL_WEBMERCATOR/{z}/{y}/{x}.png',
child: Icon( userAgentPackageName: 'de.jusax.ju_rc_app',
switch (_state) { ),
3 => Icons.navigation, MarkerLayer(
2 => Icons.location_off, markers: [
1 => Icons.navigation_outlined, Marker(
int() => Icons.location_off_outlined, point: LatLng(_lat, _long),
}, width: 100,
color: Theme.of(context).colorScheme.primary, height: 100,
), builder: (context) => Transform.rotate(
)), angle: _course *
], (pi / 180), // Convert degrees to radians
), child: Icon(
], switch (_state) {
)) 3 => Icons.navigation,
])); 2 => Icons.location_off,
1 => Icons.navigation_outlined,
int() => Icons.location_off_outlined,
},
color: Theme.of(context).colorScheme.primary,
),
)),
],
),
],
))
]));
} }
// animated Map from Map lib provider // animated Map from Map lib provider

View file

@ -49,8 +49,8 @@ class _MyHomePageState extends State<MyHomePage> {
static List<JuBox> boxes = [ static List<JuBox> boxes = [
const ControllerState(), const ControllerState(),
const Compass(true),
const Maps(), const Maps(),
const Compass(),
const SerialBox(), const SerialBox(),
]; ];