mirror of
https://github.com/seemoo-lab/openhaystack.git
synced 2026-05-19 06:56:51 +00:00
Adding OpenHaystack Mobile app
Co-Authored-By: Lukas Burg <lukas.burg@hemalu.de>
This commit is contained in:
committed by
Alexander Heinrich
parent
b65a6e6be0
commit
3d593a006c
43
openhaystack-mobile/lib/deployment/code_block.dart
Normal file
43
openhaystack-mobile/lib/deployment/code_block.dart
Normal file
@@ -0,0 +1,43 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
class CodeBlock extends StatelessWidget {
|
||||
String text;
|
||||
|
||||
/// Displays a code block that can easily copied by the user.
|
||||
CodeBlock({
|
||||
Key? key,
|
||||
required this.text,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8.0),
|
||||
child: Stack(
|
||||
children: [
|
||||
Container(
|
||||
width: double.infinity,
|
||||
constraints: const BoxConstraints(minHeight: 50),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: const BorderRadius.all(Radius.circular(10)),
|
||||
color: Theme.of(context).colorScheme.background,
|
||||
),
|
||||
padding: const EdgeInsets.all(5),
|
||||
child: SelectableText(text),
|
||||
),
|
||||
Positioned(
|
||||
top: 0,
|
||||
right: 5,
|
||||
child: OutlinedButton(
|
||||
child: const Text('Copy'),
|
||||
onPressed: () {
|
||||
Clipboard.setData(ClipboardData(text: text));
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
87
openhaystack-mobile/lib/deployment/deployment_details.dart
Normal file
87
openhaystack-mobile/lib/deployment/deployment_details.dart
Normal file
@@ -0,0 +1,87 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class DeploymentDetails extends StatefulWidget {
|
||||
/// The steps required to deploy on this target.
|
||||
List<Step> steps;
|
||||
/// The name of the deployment target.
|
||||
String title;
|
||||
|
||||
/// Describes a generic step-by-step deployment for a special hardware target.
|
||||
///
|
||||
/// The actual steps depend on the target platform and are provided in [steps].
|
||||
DeploymentDetails({
|
||||
Key? key,
|
||||
required this.title,
|
||||
required this.steps,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
_DeploymentDetailsState createState() => _DeploymentDetailsState();
|
||||
}
|
||||
|
||||
class _DeploymentDetailsState extends State<DeploymentDetails> {
|
||||
/// The index of the currently displayed step.
|
||||
int _index = 0;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var stepCount = widget.steps.length;
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(widget.title),
|
||||
),
|
||||
body: SafeArea(
|
||||
child: Stepper(
|
||||
currentStep: _index,
|
||||
controlsBuilder: (BuildContext context, ControlsDetails details) {
|
||||
String continueText = _index < stepCount - 1 ? 'CONTINUE' : 'FINISH';
|
||||
return Row(
|
||||
children: <Widget>[
|
||||
ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(1))),
|
||||
onPressed: details.onStepContinue,
|
||||
child: Text(continueText),
|
||||
),
|
||||
if (_index > 0) TextButton(
|
||||
onPressed: details.onStepCancel,
|
||||
child: const Text('BACK'),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
onStepCancel: () {
|
||||
// Back button clicked
|
||||
if (_index == 0) {
|
||||
// Cancel deployment and return
|
||||
Navigator.pop(context);
|
||||
}
|
||||
else if (_index > 0) {
|
||||
setState(() {
|
||||
_index -= 1;
|
||||
});
|
||||
}
|
||||
},
|
||||
onStepContinue: () {
|
||||
// Continue button clicked
|
||||
if (_index == stepCount - 1) {
|
||||
// TODO: Mark accessory as deployed
|
||||
// Deployment finished
|
||||
Navigator.pop(context);
|
||||
Navigator.pop(context);
|
||||
} else {
|
||||
setState(() {
|
||||
_index += 1;
|
||||
});
|
||||
}
|
||||
},
|
||||
onStepTapped: (int index) {
|
||||
setState(() {
|
||||
_index = index;
|
||||
});
|
||||
},
|
||||
steps: widget.steps,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
95
openhaystack-mobile/lib/deployment/deployment_email.dart
Normal file
95
openhaystack-mobile/lib/deployment/deployment_email.dart
Normal file
@@ -0,0 +1,95 @@
|
||||
class DeploymentEmail {
|
||||
static const _mailtoLink =
|
||||
'mailto:?subject=Open%20Haystack%20Deplyoment%20Instructions&body=';
|
||||
|
||||
static const _welcomeMessage = 'OpenHaystack Deployment Guide\n\n'
|
||||
'This is the deployment guide for your recently created OpenHaystack accessory. '
|
||||
'The next step is to deploy the generated cryptographic key to a compatible '
|
||||
'Bluetooth device.\n\n';
|
||||
|
||||
static const _finishedMessage =
|
||||
'\n\nThe device now sends out Bluetooth advertisements. '
|
||||
'It can take up to an hour for the location updates to appear in the app.\n';
|
||||
|
||||
static String getMicrobitDeploymentEmail(String advertisementKey) {
|
||||
String mailContent = 'nRF51822 Deployment:\n\n'
|
||||
'Requirements\n'
|
||||
'To build the firmware the GNU Arm Embedded Toolchain is required.\n\n'
|
||||
'Download\n'
|
||||
'Download the firmware source code from GitHub and navigate to the '
|
||||
'given folder.\n'
|
||||
'https://github.com/seemoo-lab/openhaystack\n'
|
||||
'git clone https://github.com/seemoo-lab/openhaystack.git && '
|
||||
'cd openhaystack/Firmware/Microbit_v1\n\n'
|
||||
'Build\n'
|
||||
'Replace the public_key in main.c (initially '
|
||||
'OFFLINEFINEINGPUBLICKEYHERE!) with the actual advertisement key. '
|
||||
'Then execute make to create the firmware. You can export your '
|
||||
'advertisement key directly from the OpenHaystack app.\n'
|
||||
'static char public_key[28] = $advertisementKey;\n'
|
||||
'make\n\n'
|
||||
'Firmware Deployment\n'
|
||||
'If the firmware is built successfully it can be deployed to the '
|
||||
'microcontroller with the following command. (Please fill in the '
|
||||
'volume of your microcontroller) \n'
|
||||
'make install DEPLOY_PATH=/Volumes/MICROBIT';
|
||||
|
||||
return _mailtoLink +
|
||||
Uri.encodeComponent(_welcomeMessage) +
|
||||
Uri.encodeComponent(mailContent) +
|
||||
Uri.encodeComponent(_finishedMessage);
|
||||
}
|
||||
|
||||
static String getESP32DeploymentEmail(String advertisementKey) {
|
||||
String mailContent = 'Espressif ESP32 Deployment: \n\n'
|
||||
'Requirements\n'
|
||||
'To build the firmware for the ESP32 Espressif\'s IoT Development '
|
||||
'Framework (ESP-IDF) is required. Additionally Python 3 and the venv '
|
||||
'module need to be installed.\n\n'
|
||||
'Download\n'
|
||||
'Download the firmware source code from GitHub and navigate to the '
|
||||
'given folder.\n'
|
||||
'https://github.com/seemoo-lab/openhaystack\n'
|
||||
'git clone https://github.com/seemoo-lab/openhaystack.git '
|
||||
'&& cd openhaystack/Firmware/ESP32\n\n'
|
||||
'Build\n'
|
||||
'Execute the ESP-IDF build command to create the ESP32 firmware.\n'
|
||||
'idf.py build\n\n'
|
||||
'Firmware Deployment\n'
|
||||
'If the firmware is built successfully it can be flashed onto the '
|
||||
'ESP32. This action is performed by the flash_esp32.sh script that '
|
||||
'is provided with the advertisement key of the newly created accessory.\n'
|
||||
'Please fill in the serial port of your microcontroller.\n'
|
||||
'You can export your advertisement key directly from the '
|
||||
'OpenHaystack app.\n'
|
||||
'./flash_esp32.sh -p /dev/yourSerialPort $advertisementKey';
|
||||
|
||||
return _mailtoLink +
|
||||
Uri.encodeComponent(_welcomeMessage) +
|
||||
Uri.encodeComponent(mailContent) +
|
||||
Uri.encodeComponent(_finishedMessage);
|
||||
}
|
||||
|
||||
static String getLinuxHCIDeploymentEmail(String advertisementKey) {
|
||||
String mailContent = 'Linux HCI Deployment:\n\n'
|
||||
'Requirements\n'
|
||||
'Install the hcitool software on a Bluetooth Low Energy Linux device, '
|
||||
'for example a Raspberry Pi. Additionally Pyhton 3 needs to be '
|
||||
'installed.\n\n'
|
||||
'Download\n'
|
||||
'Next download the python script that configures the HCI tool to '
|
||||
'send out BLE advertisements.\n'
|
||||
'https://raw.githubusercontent.com/seemoo-lab/openhaystack/main/Firmware/Linux_HCI/HCI.py\n'
|
||||
'curl -o HCI.py https://raw.githubusercontent.com/seemoo-lab/openhaystack/main/Firmware/Linux_HCI/HCI.py\n\n'
|
||||
'Usage\n'
|
||||
'To start the BLE advertisements run the script.\n'
|
||||
'You can export your advertisement key directly from the '
|
||||
'OpenHaystack app.\n'
|
||||
'sudo python3 HCI.py --key $advertisementKey';
|
||||
|
||||
return _mailtoLink +
|
||||
Uri.encodeComponent(_welcomeMessage) +
|
||||
Uri.encodeComponent(mailContent) +
|
||||
Uri.encodeComponent(_finishedMessage);
|
||||
}
|
||||
}
|
||||
67
openhaystack-mobile/lib/deployment/deployment_esp32.dart
Normal file
67
openhaystack-mobile/lib/deployment/deployment_esp32.dart
Normal file
@@ -0,0 +1,67 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:openhaystack_mobile/deployment/code_block.dart';
|
||||
import 'package:openhaystack_mobile/deployment/deployment_details.dart';
|
||||
import 'package:openhaystack_mobile/deployment/hyperlink.dart';
|
||||
|
||||
class DeploymentInstructionsESP32 extends StatelessWidget {
|
||||
String advertisementKey;
|
||||
|
||||
/// Displays a deployment guide for the ESP32 platform.
|
||||
DeploymentInstructionsESP32({
|
||||
Key? key,
|
||||
this.advertisementKey = '<ADVERTISEMENT_KEY>',
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return DeploymentDetails(
|
||||
title: 'ESP32 Deployment',
|
||||
steps: [
|
||||
const Step(
|
||||
title: Text('Requirements'),
|
||||
content: Text('To build the firmware for the ESP32 Espressif\'s '
|
||||
'IoT Development Framework (ESP-IDF) is required. Additionally '
|
||||
'Python 3 and the venv module need to be installed.'),
|
||||
),
|
||||
Step(
|
||||
title: const Text('Download'),
|
||||
content: Column(
|
||||
children: [
|
||||
const Text('Download the firmware source code from GitHub '
|
||||
'and navigate to the given folder.'),
|
||||
Hyperlink(target: 'https://github.com/seemoo-lab/openhaystack'),
|
||||
CodeBlock(text: 'git clone https://github.com/seemoo-lab/openhaystack.git && cd openhaystack/Firmware/ESP32'),
|
||||
],
|
||||
),
|
||||
),
|
||||
Step(
|
||||
title: const Text('Build'),
|
||||
content: Column(
|
||||
children: [
|
||||
const Text('Execute the ESP-IDF build command to create the ESP32 firmware.'),
|
||||
CodeBlock(text: 'idf.py build'),
|
||||
],
|
||||
),
|
||||
),
|
||||
Step(
|
||||
title: const Text('Firmware Deployment'),
|
||||
content: Column(
|
||||
children: [
|
||||
const Text('If the firmware is built successfully it can '
|
||||
'be flashed onto the ESP32. This action is performed by '
|
||||
'the flash_esp32.sh script that is provided with the '
|
||||
'advertisement key of the newly created accessory.'),
|
||||
const Text(
|
||||
'Please fill in the serial port of your microcontroller.',
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
CodeBlock(text: './flash_esp32.sh -p /dev/yourSerialPort "$advertisementKey"'),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
253
openhaystack-mobile/lib/deployment/deployment_instructions.dart
Normal file
253
openhaystack-mobile/lib/deployment/deployment_instructions.dart
Normal file
@@ -0,0 +1,253 @@
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:openhaystack_mobile/deployment/deployment_email.dart';
|
||||
import 'package:openhaystack_mobile/deployment/deployment_esp32.dart';
|
||||
import 'package:openhaystack_mobile/deployment/deployment_linux_hci.dart';
|
||||
import 'package:openhaystack_mobile/deployment/deployment_nrf51.dart';
|
||||
import 'package:openhaystack_mobile/deployment/hyperlink.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
class DeploymentInstructions extends StatefulWidget {
|
||||
String advertisementKey;
|
||||
|
||||
/// Displays deployment instructions for an already created accessory.
|
||||
///
|
||||
/// Provides general information about the created accessory and deployment.
|
||||
/// Deployment guides for special hardware can be accessed separately.
|
||||
///
|
||||
/// The deployment instructions are customized with the [advertisementKey].
|
||||
DeploymentInstructions({
|
||||
Key? key,
|
||||
this.advertisementKey = '<ADVERTISEMENT_KEY>',
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
_DeploymentInstructionsState createState() => _DeploymentInstructionsState();
|
||||
}
|
||||
|
||||
class _DeploymentInstructionsState extends State<DeploymentInstructions> {
|
||||
final List<bool> _expanded = [false, false, false];
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('How to Deploy'),
|
||||
),
|
||||
body: SafeArea(
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
ListTile(
|
||||
title: RichText(
|
||||
text: TextSpan(
|
||||
children: [
|
||||
TextSpan(
|
||||
text: 'Congratulations, you successfully created '
|
||||
'your accessory!\nThe next step is to deploy the generated '
|
||||
'key to a Bluetooth device. OpenHaystack currently '
|
||||
'supports three different deployment targets:\n'
|
||||
'Nordic nRF51, Espressif ESP32 and the generic Linux HCI '
|
||||
'platform.\nAdditional information about the deployment '
|
||||
'can be found on ',
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
fontSize: 18,
|
||||
),
|
||||
),
|
||||
TextSpan(
|
||||
text: 'GitHub',
|
||||
style: const TextStyle(
|
||||
color: Colors.blue,
|
||||
decoration: TextDecoration.underline,
|
||||
fontSize: 18,
|
||||
),
|
||||
recognizer: TapGestureRecognizer()
|
||||
..onTap = () {
|
||||
launch(
|
||||
'https://github.com/seemoo-lab/openhaystack/');
|
||||
},
|
||||
),
|
||||
const TextSpan(
|
||||
text: '.',
|
||||
style: TextStyle(color: Colors.black, fontSize: 18),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
ExpansionPanelList(
|
||||
expansionCallback: (int index, bool isExpanded) {
|
||||
setState(() {
|
||||
_expanded[index] = !isExpanded;
|
||||
});
|
||||
},
|
||||
children: [
|
||||
ExpansionPanel(
|
||||
headerBuilder: (BuildContext context, bool isExpanded) {
|
||||
return const ListTile(
|
||||
title: Text('Nordic vRF51'),
|
||||
);
|
||||
},
|
||||
body: Column(
|
||||
children: <Widget>[
|
||||
const ListTile(
|
||||
title: Text(
|
||||
'For this firmware you need a nFR51822 platform '
|
||||
'microcontroller. The provided firmware will send out '
|
||||
'the created key so it can be found by Apple\'s Find My '
|
||||
'network.'),
|
||||
),
|
||||
ListTile(
|
||||
title: Hyperlink(
|
||||
text: 'See deployment guide on GitHub',
|
||||
target:
|
||||
'https://github.com/seemoo-lab/openhaystack/tree/main/Firmware/Microbit_v1',
|
||||
),
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
OutlinedButton(
|
||||
child: const Text('Send per mail'),
|
||||
onPressed: () async {
|
||||
await launch(
|
||||
DeploymentEmail.getMicrobitDeploymentEmail(
|
||||
widget.advertisementKey));
|
||||
},
|
||||
),
|
||||
ElevatedButton(
|
||||
child: const Text('Continue'),
|
||||
onPressed: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) =>
|
||||
DeploymentInstructionsNRF51(
|
||||
advertisementKey:
|
||||
widget.advertisementKey,
|
||||
)),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
isExpanded: _expanded[0],
|
||||
),
|
||||
ExpansionPanel(
|
||||
headerBuilder: (BuildContext context, bool isExpanded) {
|
||||
return const ListTile(
|
||||
title: Text('Espressif ESP32'),
|
||||
);
|
||||
},
|
||||
body: Column(
|
||||
children: <Widget>[
|
||||
const ListTile(
|
||||
title: Text(
|
||||
'For this firmware you need an ESP32 platform '
|
||||
'microcontroller. The provided firmware will send out '
|
||||
'the created key so it can be found by Apple\'s Find My '
|
||||
'network.'),
|
||||
),
|
||||
ListTile(
|
||||
title: Hyperlink(
|
||||
text: 'See deployment guide on GitHub',
|
||||
target:
|
||||
'https://github.com/seemoo-lab/openhaystack/tree/main/Firmware/ESP32',
|
||||
),
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
OutlinedButton(
|
||||
child: const Text('Send per mail'),
|
||||
onPressed: () async {
|
||||
await launch(
|
||||
DeploymentEmail.getESP32DeploymentEmail(
|
||||
widget.advertisementKey));
|
||||
},
|
||||
),
|
||||
ElevatedButton(
|
||||
child: const Text('Continue'),
|
||||
onPressed: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) =>
|
||||
DeploymentInstructionsESP32(
|
||||
advertisementKey:
|
||||
widget.advertisementKey,
|
||||
)),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
isExpanded: _expanded[1],
|
||||
),
|
||||
ExpansionPanel(
|
||||
headerBuilder: (BuildContext context, bool isExpanded) {
|
||||
return const ListTile(
|
||||
title: Text('Linux HCI'),
|
||||
);
|
||||
},
|
||||
body: Column(
|
||||
children: <Widget>[
|
||||
const ListTile(
|
||||
title: Text(
|
||||
'This method only requires a Bluetooth enabled '
|
||||
'Linux device. Using the hcitool and a provided script '
|
||||
'the devices advertises the created key so it can be '
|
||||
'found by Apple\'s Find My network.'),
|
||||
),
|
||||
ListTile(
|
||||
title: Hyperlink(
|
||||
text: 'See deployment guide on GitHub',
|
||||
target:
|
||||
'https://github.com/seemoo-lab/openhaystack/tree/main/Firmware/Linux_HCI',
|
||||
),
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
OutlinedButton(
|
||||
child: const Text('Send per mail'),
|
||||
onPressed: () async {
|
||||
await launch(
|
||||
DeploymentEmail.getLinuxHCIDeploymentEmail(
|
||||
widget.advertisementKey));
|
||||
},
|
||||
),
|
||||
ElevatedButton(
|
||||
child: const Text('Continue'),
|
||||
onPressed: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) =>
|
||||
DeploymentInstructionsLinux(
|
||||
advertisementKey:
|
||||
widget.advertisementKey,
|
||||
)),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
isExpanded: _expanded[2],
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
49
openhaystack-mobile/lib/deployment/deployment_linux_hci.dart
Normal file
49
openhaystack-mobile/lib/deployment/deployment_linux_hci.dart
Normal file
@@ -0,0 +1,49 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:openhaystack_mobile/deployment/code_block.dart';
|
||||
import 'package:openhaystack_mobile/deployment/deployment_details.dart';
|
||||
import 'package:openhaystack_mobile/deployment/hyperlink.dart';
|
||||
|
||||
class DeploymentInstructionsLinux extends StatelessWidget {
|
||||
String advertisementKey;
|
||||
|
||||
/// Displays a deployment guide for the generic Linux HCI platform.
|
||||
DeploymentInstructionsLinux({
|
||||
Key? key,
|
||||
this.advertisementKey = '<ADVERTISEMENT_KEY>',
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return DeploymentDetails(
|
||||
title: 'Linux HCI Deployment',
|
||||
steps: [
|
||||
const Step(
|
||||
title: Text('Requirements'),
|
||||
content: Text('Install the hcitool software on a Bluetooth '
|
||||
'Low Energy Linux device, for example a Raspberry Pi. '
|
||||
'Additionally Pyhton 3 needs to be installed.'),
|
||||
),
|
||||
Step(
|
||||
title: const Text('Download'),
|
||||
content: Column(
|
||||
children: [
|
||||
const Text('Next download the python script that '
|
||||
'configures the HCI tool to send out BLE advertisements.'),
|
||||
Hyperlink(target: 'https://raw.githubusercontent.com/seemoo-lab/openhaystack/main/Firmware/Linux_HCI/HCI.py'),
|
||||
CodeBlock(text: 'curl -o HCI.py https://raw.githubusercontent.com/seemoo-lab/openhaystack/main/Firmware/Linux_HCI/HCI.py'),
|
||||
],
|
||||
),
|
||||
),
|
||||
Step(
|
||||
title: const Text('Usage'),
|
||||
content: Column(
|
||||
children: [
|
||||
const Text('To start the BLE advertisements run the script.'),
|
||||
CodeBlock(text: 'sudo python3 HCI.py --key $advertisementKey'),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
70
openhaystack-mobile/lib/deployment/deployment_nrf51.dart
Normal file
70
openhaystack-mobile/lib/deployment/deployment_nrf51.dart
Normal file
@@ -0,0 +1,70 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:openhaystack_mobile/deployment/code_block.dart';
|
||||
import 'package:openhaystack_mobile/deployment/deployment_details.dart';
|
||||
import 'package:openhaystack_mobile/deployment/hyperlink.dart';
|
||||
|
||||
class DeploymentInstructionsNRF51 extends StatelessWidget {
|
||||
String advertisementKey;
|
||||
|
||||
/// Displays a deployment guide for the NRF51 platform.
|
||||
DeploymentInstructionsNRF51({
|
||||
Key? key,
|
||||
this.advertisementKey = '<ADVERTISEMENT_KEY>',
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return DeploymentDetails(
|
||||
title: 'nRF51822 Deployment',
|
||||
steps: [
|
||||
const Step(
|
||||
title: Text('Requirements'),
|
||||
content: Text('To build the firmware the GNU Arm Embedded '
|
||||
'Toolchain is required.'),
|
||||
),
|
||||
Step(
|
||||
title: const Text('Download'),
|
||||
content: Column(
|
||||
children: [
|
||||
const Text('Download the firmware source code from GitHub '
|
||||
'and navigate to the given folder.'),
|
||||
Hyperlink(target: 'https://github.com/seemoo-lab/openhaystack'),
|
||||
CodeBlock(text: 'git clone https://github.com/seemoo-lab/openhaystack.git && cd openhaystack/Firmware/Microbit_v1'),
|
||||
],
|
||||
),
|
||||
),
|
||||
Step(
|
||||
title: const Text('Build'),
|
||||
content: Column(
|
||||
children: [
|
||||
const Text('Replace the public_key in main.c (initially '
|
||||
'OFFLINEFINEINGPUBLICKEYHERE!) with the actual '
|
||||
'advertisement key. Then execute make to create the '
|
||||
'firmware.'),
|
||||
CodeBlock(text: 'static char public_key[28] = "$advertisementKey";'),
|
||||
CodeBlock(text: 'make'),
|
||||
],
|
||||
),
|
||||
),
|
||||
Step(
|
||||
title: const Text('Firmware Deployment'),
|
||||
content: Column(
|
||||
children: [
|
||||
const Text('If the firmware is built successfully it can '
|
||||
'be deployed to the microcontroller with the following '
|
||||
'command.'),
|
||||
const Text(
|
||||
'Please fill in the volume of your microcontroller.',
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
|
||||
CodeBlock(text: 'make install DEPLOY_PATH=/Volumes/MICROBIT'),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
31
openhaystack-mobile/lib/deployment/hyperlink.dart
Normal file
31
openhaystack-mobile/lib/deployment/hyperlink.dart
Normal file
@@ -0,0 +1,31 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
class Hyperlink extends StatelessWidget {
|
||||
/// The target url to open.
|
||||
String target;
|
||||
/// The display text of the hyperlink. Default is [target].
|
||||
String _text;
|
||||
|
||||
/// Displays a hyperlink that can be opened by a tap.
|
||||
Hyperlink({
|
||||
Key? key,
|
||||
required this.target,
|
||||
text,
|
||||
}) : _text = text ?? target, super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return InkWell(
|
||||
child: Text(_text,
|
||||
style: const TextStyle(
|
||||
color: Colors.blue,
|
||||
decoration: TextDecoration.underline,
|
||||
),
|
||||
),
|
||||
onTap: () {
|
||||
launch(target);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user