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
class Compass extends JuBox {
const Compass({super.key});
final bool small;
const Compass(this.small, {super.key});
@override
State<StatefulWidget> createState() => _CompassState();
// ignore: no_logic_in_create_state
State<StatefulWidget> createState() => _CompassState(small);
}
class _CompassState extends State<Compass> {
final bool small;
_CompassState(this.small) : super();
USerial serial = getSerial();
late Timer timer;
Timer? timer;
int _magX = 0, _magY = 0, _magZ = 0, _magAngle = 0;
bool available = true;
@override
void initState() {
super.initState();
SensorReader.listen(serialListen);
timer = Timer.periodic(const Duration(milliseconds: 500), (_) async {
serial.sprintln("<rfSystemSensor>2200", system: true);
});
if (small) {
timer = Timer.periodic(const Duration(milliseconds: 500), (_) async {
if (available) serial.sprintln("<rfSystemSensor>2200", system: true);
});
}
}
@override
void dispose() {
SensorReader.removeListen(serialListen);
timer.cancel();
timer?.cancel();
super.dispose();
}
void serialListen(int type, int command, Pointer<ArrayCStruct> ptr) {
if (type == 0x22 && command == 0xff) {
setState(() {
available = false;
});
return;
}
if (type != 0x22 || command != 0x00) return;
var loc = ptr as Pointer<GnssLocData>;
setState(() {
@ -70,64 +85,101 @@ class _CompassState extends State<Compass> {
}
@override
Widget build(BuildContext context) => Stack(
children: [
SvgPicture.asset('assets/compass.svg'),
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"),
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'),
),
],
),
);
//
},
),
),
Widget build(BuildContext context) => small
? GestureDetector(
onTap: () {
if (available) {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => const Compass(false)),
);
} else {
available = true;
}
},
child: buildLoc(context))
: Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: const Text(
"Compass",
style: TextStyle(
fontSize: 16,
),
],
),
toolbarHeight: 40,
),
Expanded(
child: Align(
alignment: Alignment.topRight,
child: Text(
"t: ${(sqrt(_magX * _magX + _magY * _magY + _magZ * _magZ) * 8.0 / 32768.0 * 100.0).toStringAsFixed(2)}µT"),
))
],
);
body: Container(
padding: const EdgeInsets.all(0.3 * 2 * 20),
child: buildLoc(context)),
);
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;
bool _wasVaild = false;
final _mapController = MapController();
bool available = true;
@override
void initState() {
super.initState();
SensorReader.listen(serialListen);
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) {
if (type == 0x23 && command == 0xff) {
setState(() {
available = false;
});
return;
}
if (type != 0x23 || command != 0x00) return;
var loc = ptr as Pointer<GnssLocData>;
setState(() {
@ -140,46 +147,61 @@ class _MapsState extends State<Maps> with TickerProviderStateMixin {
}
@override
Widget build(BuildContext context) => FlutterMap(
options: MapOptions(
center: LatLng(_lat, _long),
zoom: _wasVaild ? 17 : 6,
maxZoom: _wasVaild ? 17 : 6,
minZoom: _wasVaild ? 17 : 6,
interactiveFlags: InteractiveFlag.none,
onTap: (TapPosition pos, LatLng ll) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const SerialDetailPage()),
);
}),
mapController: _mapController,
children: [
TileLayer(
urlTemplate: 'https://tile.openstreetmap.de/{z}/{x}/{y}.png',
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,
Widget build(BuildContext context) => !available
? GestureDetector(
onTap: () {
if (!available) {
available = true;
}
},
child: const Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text("GNSS is not available!"),
Icon(Icons.block)
])))
: FlutterMap(
options: MapOptions(
center: LatLng(_lat, _long),
zoom: _wasVaild ? 17 : 6,
maxZoom: _wasVaild ? 17 : 6,
minZoom: _wasVaild ? 17 : 6,
interactiveFlags: InteractiveFlag.none,
onTap: (TapPosition pos, LatLng ll) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const SerialDetailPage()),
);
}),
mapController: _mapController,
children: [
TileLayer(
urlTemplate: 'https://tile.openstreetmap.de/{z}/{x}/{y}.png',
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 {
@ -206,11 +228,13 @@ class _SerialDetailPageState extends State<SerialDetailPage>
_hdopState = false;
int _satN = -1;
bool _follow = true;
bool available = true;
@override
void initState() {
super.initState();
timer = Timer.periodic(const Duration(seconds: 2), (_) async {
if(!available) return;
serial.sprintln("<rfSystemSensor>2303", system: true);
sleep(const Duration(milliseconds: 200));
serial.sprintln("<rfSystemSensor>2304", system: true);
@ -233,6 +257,7 @@ class _SerialDetailPageState extends State<SerialDetailPage>
void serialListen(int type, int command, Pointer<ArrayCStruct> ptr) {
if (type != 0x23) return;
command = 0xff;
switch (command) {
case 0:
{
@ -295,7 +320,11 @@ class _SerialDetailPageState extends State<SerialDetailPage>
}
break;
case 0xff:
{}
{
setState(() {
available = false;
});
}
break;
}
}
@ -327,91 +356,102 @@ class _SerialDetailPageState extends State<SerialDetailPage>
},
child: Icon(_follow ? Icons.near_me : Icons.near_me_outlined),
),
body: Column(children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"Speed: ${_mps.toStringAsPrecision(3)}m/s",
style: TextStyle(
backgroundColor:
_mpsState ? Colors.green[shade()] : Colors.red[shade()]),
),
const VerticalDivider(width: 5),
Text("Course: ${_course.toStringAsFixed(0)}°",
style: TextStyle(
backgroundColor: _courseState
? Colors.green[shade()]
: Colors.red[shade()])),
const VerticalDivider(width: 5),
Text("Alt: ${_alt.toStringAsPrecision(4)}m",
style: TextStyle(
backgroundColor: _altState
? Colors.green[shade()]
: Colors.red[shade()])),
const VerticalDivider(width: 5),
Text("Sats: $_satN",
style: TextStyle(
backgroundColor: _satNState
? Colors.green[shade()]
: Colors.red[shade()])),
const VerticalDivider(width: 5),
Text("Hdop: ${_hdop.toStringAsPrecision(2)}",
style: TextStyle(
backgroundColor: _hdopState
? Colors.green[shade()]
: Colors.red[shade()])),
],
),
Expanded(
child: FlutterMap(
mapController: _mapController,
options: MapOptions(
center: const LatLng(51.1667, 10.4500),
zoom: 6,
maxZoom: 18,
interactiveFlags: InteractiveFlag.drag |
InteractiveFlag.flingAnimation |
InteractiveFlag.pinchMove |
InteractiveFlag.pinchZoom |
InteractiveFlag.doubleTapZoom,
onPositionChanged: (MapPosition pos, bool user) {
if (user) {
setState(() {
_follow = false;
});
}
}),
children: [
TileLayer(
urlTemplate: 'https://tile.openstreetmap.de/{z}/{x}/{y}.png',
//urlTemplate: 'https://sgx.geodatenzentrum.de/wmts_basemapde/tile/1.0.0/de_basemapde_web_raster_farbe/default/GLOBAL_WEBMERCATOR/{z}/{y}/{x}.png',
userAgentPackageName: 'de.jusax.ju_rc_app',
),
MarkerLayer(
markers: [
Marker(
point: LatLng(_lat, _long),
width: 100,
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,
),
)),
],
),
],
))
]));
body: !available
? const Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text("GNSS is not available!"),
Icon(Icons.block)
]))
: Column(children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"Speed: ${_mps.toStringAsPrecision(3)}m/s",
style: TextStyle(
backgroundColor: _mpsState
? Colors.green[shade()]
: Colors.red[shade()]),
),
const VerticalDivider(width: 5),
Text("Course: ${_course.toStringAsFixed(0)}°",
style: TextStyle(
backgroundColor: _courseState
? Colors.green[shade()]
: Colors.red[shade()])),
const VerticalDivider(width: 5),
Text("Alt: ${_alt.toStringAsPrecision(4)}m",
style: TextStyle(
backgroundColor: _altState
? Colors.green[shade()]
: Colors.red[shade()])),
const VerticalDivider(width: 5),
Text("Sats: $_satN",
style: TextStyle(
backgroundColor: _satNState
? Colors.green[shade()]
: Colors.red[shade()])),
const VerticalDivider(width: 5),
Text("Hdop: ${_hdop.toStringAsPrecision(2)}",
style: TextStyle(
backgroundColor: _hdopState
? Colors.green[shade()]
: Colors.red[shade()])),
],
),
Expanded(
child: FlutterMap(
mapController: _mapController,
options: MapOptions(
center: const LatLng(51.1667, 10.4500),
zoom: 6,
maxZoom: 18,
interactiveFlags: InteractiveFlag.drag |
InteractiveFlag.flingAnimation |
InteractiveFlag.pinchMove |
InteractiveFlag.pinchZoom |
InteractiveFlag.doubleTapZoom,
onPositionChanged: (MapPosition pos, bool user) {
if (user) {
setState(() {
_follow = false;
});
}
}),
children: [
TileLayer(
urlTemplate:
'https://tile.openstreetmap.de/{z}/{x}/{y}.png',
//urlTemplate: 'https://sgx.geodatenzentrum.de/wmts_basemapde/tile/1.0.0/de_basemapde_web_raster_farbe/default/GLOBAL_WEBMERCATOR/{z}/{y}/{x}.png',
userAgentPackageName: 'de.jusax.ju_rc_app',
),
MarkerLayer(
markers: [
Marker(
point: LatLng(_lat, _long),
width: 100,
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

View file

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