51 Commits

Author SHA1 Message Date
0967b6aa65 Bugfix in LoRa-Uart 2023-05-28 19:36:39 +02:00
498d813624 increase Version after Release 2023-05-25 20:59:18 +02:00
268c204957 added LoraUartCommand Interpreter 2023-05-25 19:59:34 +02:00
65d51f13aa added Pinout for LoRa-UART 2023-05-25 14:00:18 +02:00
f727bb3247 first Draft of UART for external LoRa-Module 2023-05-25 14:00:06 +02:00
cd1379f90c updated project-config 2023-05-25 10:58:50 +02:00
0363b1eebc increase Version after Release 2023-04-30 10:08:34 +02:00
e6f1283aae final fixes before Release for DE XI 2023-04-30 10:05:41 +02:00
a92b1edfd9 reformated points-table on WebUI 2023-04-18 20:07:52 +02:00
4cce7c1c86 fixed show setting in WebUI 2023-04-18 20:07:38 +02:00
0a1625e9b8 made Faction-Names configurable 2023-04-18 20:06:57 +02:00
c24829ed70 added Device-ID to SystemInfo 2023-04-18 13:00:34 +02:00
a102405596 reverted calculation-order of checksum and store 2023-04-18 12:53:27 +02:00
1b7157dbdc read back EEPROM after Format to Maintain DTC 2023-04-18 12:50:26 +02:00
cad34d6b84 swapped migration of Persistance and Config 2023-04-18 12:47:04 +02:00
701bf9f457 fixed another warning and bug in Logoutput 2023-04-18 12:30:14 +02:00
0a895a00b9 fixed warning 2023-04-18 12:29:55 +02:00
22a62e3d1e refactoring 2023-04-18 12:28:11 +02:00
f48b5a09ed renamed eeprom-files and added migrator 2023-04-18 12:27:04 +02:00
7f6c486eab fixed config if checkbox not set 2023-04-17 23:14:46 +02:00
3e77f89538 propely handle sysstart and display Startup 2023-04-17 23:12:13 +02:00
f33076a0a3 fixed typo 2023-04-17 22:57:43 +02:00
7e58db489d made active faction recovery configurable 2023-04-17 22:55:16 +02:00
eb771d07d3 fixed copy&paste-error 2023-04-17 22:29:19 +02:00
e2059cb587 reworked DisplayOverride 2023-04-17 22:28:16 +02:00
6702154ef5 made dot blink if faction active 2023-04-17 22:27:26 +02:00
a899cf4dcf Log-Output Format fix 2023-04-17 22:27:01 +02:00
ea230bcee7 bumped Version 2023-04-17 22:02:37 +02:00
c059d7d085 more Sysinfo on WebUI 2023-04-17 22:00:06 +02:00
b8c79955a8 fixed warning 2023-04-17 21:54:46 +02:00
44240aa7bf extended DTC-output by DebugVal 2023-04-17 21:54:36 +02:00
6bc523b2a8 fixed Display of current SysStatus 2023-04-17 21:53:52 +02:00
97cdd7fad1 changed Reset via Buttons during Startup 2023-04-17 21:52:49 +02:00
ec62eeee1e corrected ColorScheme on WebUI 2023-04-17 21:51:27 +02:00
7b166caf84 points and reset-function on webUI 2023-04-17 21:51:13 +02:00
62a7cd1b9c correct EEPROM-Type 2023-04-17 20:23:17 +02:00
7e047c0c09 some Wifi-defines renamed for consistency 2023-04-17 20:23:05 +02:00
8c2d553dfb switched Factions 2023-04-13 21:04:29 +02:00
ca9409e328 more fixes 2023-04-13 01:28:41 +02:00
5a6dc524ad removed Artifacts from other Project 2023-04-13 00:56:35 +02:00
41b27c02dd fixed DTC-Numbering 2023-04-13 00:55:55 +02:00
e344977b8f fixed WiFi-Client Feature 2023-04-13 00:48:43 +02:00
aeab80d5a8 Updated Debugging-Stuff and WebUI Backend 2023-04-13 00:35:24 +02:00
4507c80eba Updated WebUI 2023-04-13 00:32:50 +02:00
427e5e5d16 restructured Folders and Files 2023-04-12 23:05:46 +02:00
3a0e1a931d disabled Lora by define 2023-04-12 22:56:36 +02:00
a960e67c7d smaller fixes 2023-04-12 22:49:04 +02:00
9e1a4d821f added defines for Versioning 2023-04-12 22:47:56 +02:00
4d0a9918ce Some LoRa-stuff 2023-04-12 22:47:17 +02:00
53928a93b0 Reworked KeyCombo to support 2-Button-Variant 2023-04-12 22:45:24 +02:00
6b89ed9a8c reworked WiFi-Stuff 2023-04-12 22:43:25 +02:00
53 changed files with 18798 additions and 4607 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

View File

@@ -3,198 +3,564 @@
<head>
<meta charset="utf-8" />
<title>%DEVICE_NAME%</title>
<meta http-equiv="content-type" content="text/html;charset=UTF-8">
<title>%DEVICENAME%</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="static/css/bootstrap.min.css">
<link rel="stylesheet" href="static/css/custom.css">
<script src="static/js/jquery-3.3.1.min.js"></script>
<script src="static/js/bootstrap.bundle.min.js"></script>
<link rel="stylesheet" href="static/css/tweaks.css">
<script src="static/js/jquery.min.js"></script>
<script src="static/js/bootstrap.min.js"></script>
<script src="static/js/websocket.js"></script>
<link rel="apple-touch-icon" sizes="180x180" href="static/img/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="static/img/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="static/img/favicon-16x16.png">
<link rel="manifest" href="static/img/site.webmanifest">
<link rel="mask-icon" href="static/img/safari-pinned-tab.svg" color="#111111">
<link rel="shortcut icon" href="static/img/favicon.ico">
<meta name="msapplication-TileColor" content="#111111">
<meta name="msapplication-config" content="static/img/browserconfig.xml">
<meta name="theme-color" content="#111111">
<script type="text/javascript">
var opacity = 0;
var intervalID = 0;
window.onload = setTimeout(() => { fadeout(); }, 4000);
function fadeout() {
intervalID = setInterval(hide, 200);
}
function hide() {
var responseMessage = document.getElementById("responseMessage");
opacity =
Number(window.getComputedStyle(responseMessage).getPropertyValue("opacity"))
if (opacity > 0) {
opacity = opacity - 0.1;
responseMessage.style.opacity = opacity
}
else {
responseMessage.remove()
clearInterval(intervalID);
}
}
</script>
</head>
<body>
<header class="sticky-top">
<nav class="navbar navbar-expand-sm navbar-dark bg-dark">
<a class="navbar-brand" href="#">
<img src="static/img/logo.png" width="30" height="30" class="d-inline-block align-top" alt="">
%DEVICE_NAME%</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNavAltMarkup"
aria-controls="navbarNavAltMarkup" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<nav class="navbar fixed-top navbar-dark bg-primary" id="navbar1">
<a class="navbar-brand" href="#">
<img src="static/img/logo.png" width="30" height="30" class="d-inline-block align-top mr-1" alt="">
%DEVICENAME%
</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#collapsingNavbar"
aria-controls="collapsingNavbar" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="collapsingNavbar">
<ul class="navbar-nav nav mr-auto mt-2 mt-lg-0">
<div class="collapse navbar-collapse pr-2 mt-2 bg-secondary" id="navbarNavAltMarkup">
<ul class="navbar-nav nav align-items-end">
<li class="nav-item">
<a class="nav-link active" href="#tab_home" data-toggle="tab">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#tab_settings" data-toggle="tab">Settings</a>
</li>
</ul>
</div>
</nav>
</header>
<li class="nav-item"><a class="nav-link active" role="tab" data-toggle="tab" href="#tab_home">Home</a></li>
<li class="nav-item"><a class="nav-link" role="tab" data-toggle="tab" href="#tab_maintenance">Wartung</a></li>
<li class="nav-item"><a class="nav-link" role="tab" data-toggle="tab" href="#tab_source">Einstellungen</a></li>
<li class="nav-item"><a class="nav-link" role="tab" data-toggle="tab" href="#tab_sysinfo">Systeminfo</a></li>
<li class="nav-item"><a class="nav-link" role="tab" data-toggle="tab" href="#tab_fwupdate">Update</a></li>
</ul>
</div>
</nav>
<main class="container">
<main class="container-fluid py-3 flex-fill">
<!-- Tabs Content -->
<div class="tab-content">
<!-- Div Tab Home-->
<div class="tab-pane fade show active" id="tab_home" role="tabpanel">
<!-- Jumbotron -->
<div class="jumbotron text-center">
<p class="p-4">
<img src="static/img/logo.png">
</p>
<h3>%DEVICE_NAME%</h3>
<div id="tab_home" class="tab-pane fade show active" role="tabpanel">
<div class="col text-center">
<div class="jumbotron">
<img src="static/img/logo.png" width="120" height="120" class="img-fluid" alt="">
<h3 class="pt-3">%DEVICENAME%</h3>
</div>
</div>
<!-- AlertMessageBox-->
<div id="responseMessage" class="alert alert-%RESP_MESSAGE_TYPE%" %SHOW_RESP_MESSAGE%>
%RESP_MESSAGE%
<!-- Div Group Battery remain -->
<hr />
<p>
<h4>Akku Ladestand</h4>
<div class="progress">
<div class="progress-bar text-light" role="progressbar" aria-valuenow="%BAT_REMAIN_CAPACITY%"
aria-valuemin="0" aria-valuemax="100" style="width: %BAT_REMAIN_CAPACITY%&#37;">
%BAT_REMAIN_CAPACITY%&#37;
</div>
</div>
<div class="container-fluid pb-5">
<h4>BATTERY: %BATTERY_TYPE%</h4>
<div class="progress">
<div class="progress-bar text-light" role="progressbar" aria-valuenow="%BAT_REMAIN_CAPACITY%"
aria-valuemin="0" aria-valuemax="100" style="width: %BAT_REMAIN_CAPACITY%&#37;">
%BAT_REMAIN_CAPACITY%&#37; / %BAT_VOLTAGE% V
</p>
<!-- Div Group Battery remain -->
<!-- Div Group current Mode -->
<hr />
<p>
<h4>aktueller Modus</h4>
<input class="form-control" type="text" placeholder="%SYSTEM_STATUS%" readonly>
</p>
<!-- Div Group current Mode -->
<!-- Div Group Faction Points -->
<hr />
<p>
<h4>aktueller Punktestand</h4>
<div class="container-fluid">
<div class="row">
<div class="col text-center %FACTION_1_ACTIVE% text-white p-3">%NAME_FAC_1%</div>
<div class="col text-center %FACTION_2_ACTIVE% text-white p-3">%NAME_FAC_2%</div>
<div class="col text-center %FACTION_3_ACTIVE% text-white p-3">%NAME_FAC_3%</div>
</div>
<div class="row">
<div class="col bg-dark text-white p-3"><img src="static/img/logo_fac1.png"
class="rounded mx-auto img-fluid d-block" alt="...">
</div>
<div class="col bg-dark text-white p-3"><img src="static/img/logo_fac2.png"
class="rounded mx-auto img-fluid d-block" alt="...">
</div>
<div class="col bg-dark text-white p-3"><img src="static/img/logo_fac3.png"
class="rounded mx-auto img-fluid d-block" alt="...">
</div>
</div>
</div>
<div class="container-fluid pb-5">
<h4>FACTIONS</h4>
<div class="table-responsive">
<table class="table text-light text-center">
<thead>
<tr>
<th scope="col">Faction</td>
<th scope="col">Time</td>
</tr>
</thead>
<tbody>
<tr>
<td class="align-items-center justify-content-center" scope="col">
<a href="#">
<img src="static/img/logo_fac1.png" class="img-responsive" alt="" />
<div class="desc">
<p class="desc_content">%NAME_FAC_1%</p>
</div>
</a>
</td>
<td class="align-items-center justify-content-center" scope="col">%POINTS_FAC_1%</td>
</tr>
<tr>
<td class="align-items-center justify-content-center" scope="col">
<a href="#">
<img src="static/img/logo_fac2.png" class="img-responsive" alt="" />
<div class="desc">
<p class="desc_content">%NAME_FAC_2%</p>
</div>
</a>
</td>
<td class="align-items-center justify-content-center" scope="col">%POINTS_FAC_2%</td>
</tr>
<tr>
<td class="align-items-center justify-content-center" scope="col">
<a href="#">
<img src="static/img/logo_fac3.png" class="img-responsive" alt="" />
<div class="desc">
<p class="desc_content">%NAME_FAC_3%</p>
</div>
</a>
</td>
<td class="align-items-center justify-content-center" scope="col">%POINTS_FAC_3%</td>
</tr>
</tbody>
</table>
<div class="row">
<div class="col text-center bg-secondary text-white p-3">%POINTS_FAC_1%</div>
<div class="col text-center bg-secondary text-white p-3">%POINTS_FAC_2%</div>
<div class="col text-center bg-secondary text-white p-3">%POINTS_FAC_3%</div>
</div>
</div>
<div class="container-fluid pb-5" %SHOW_DTC_TABLE%>
</p>
<!-- Div GroupFaction Points -->
<!-- Div Group DTC Table -->
<div %SHOW_DTC_TABLE%>
<hr />
<p>
<h4>Fehlercodes</h4>
<table class="table text-light">
<table class="table">
<tbody>
<tr>
<th class="col-md-4" scope="col">Timestamp</td>
<th class="col-md-4" scope="col">DTC</td>
<th class="col-md-4" scope="col">active</td>
<th class="col-6" scope="col">Zeitstempel</th>
<th class="col-2" scope="col">Fehlercode</th>
<th class="col-2" scope="col">Schwere</th>
<th class="col-2" scope="col">Aktiv</th>
</tr>
%DTC_TABLE%
</tbody>
</table>
</p>
</div>
<!-- Div Group DTC Table -->
</div>
<!-- Div Tab Home-->
<!-- Div Tab Settings-->
<div class="tab-pane fade" id="tab_settings" role="tabpanel">
<h3>Settings</h3>
<hr>
<form method="POST">
<!-- Div Tab Maintenance -->
<div id="tab_maintenance" class="tab-pane fade" role="tabpanel">
<h3>Wartung</h3>
<!-- Div Group Reset Timers -->
<hr />
<p>
<h4>Punkte zur&uuml;cksetzen</h4>
<form action="post.htm" method="POST" class="form-horizontal">
<div class="form-group row">
<label for="commandInput" class="col-sm-2 col-form-label">Command</label>
<div class="col-sm-10">
<input type="text" name="commandInput" class="form-control bg-light" id="commandInput"
placeholder="type command here...">
</div>
</div>
<div class="form-group row">
<div class="col-sm-12">
<button name="cmdsubmit" type="submit" class="btn btn-primary float-right">Apply</button>
<div class="col text-center">
<button name="resetpoints" type="submit" class="btn btn-outline-primary">Reset</button>
</div>
</div>
</form>
</p>
<!-- Div Group Reset Timers -->
<!-- Div Group EEPROM formatting -->
<hr />
<p>
<h4>EEPROM formatieren</h4>
<div class="alert alert-primary alert-dismissable show fade" role="alert">
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
<strong>Achtung!</strong><br>
Das Formatieren der EEPROM-Bereiche sollte nur ausgeführt werden wenn es unbedingt erforderlich ist!
Hierdurch werden alle Einstellungen zurück gesetzt bzw. alle Betriebsdaten gehen verloren.
Folgende Situationen erfordern unter anderem eine Formatierung:
- Erstinitialisierung (bei neu aufgebautem Gerät)
- Firmware-Update (nur wenn es die Release-Notes fordern)
</div>
<form action="post.htm" method="POST" class="form-horizontal">
<div class="form-group row">
<div class="offset-4 col-8">
<div class="form-check">
<input class="form-check-input" type="checkbox" name="reset_ee_cfg" id="reset_ee_cfg">
<label class="form-check-label" for="reset_ee_cfg">
Bereich "CFG"
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" name="reset_ee_pds" id="reset_ee_pds">
<label class="form-check-label" for="reset_ee_pds">
Bereich "PDS"
</label>
</div>
</div>
</div>
<div class="form-group row">
<div class="col text-center">
<button name="reset_ee_btn" type="submit" class="btn btn-outline-primary">EEPROM formatieren</button>
</div>
</div>
</form>
</p>
<!-- Div Group EEPROM formatting -->
<!-- Div Group Device Reboot -->
<hr />
<p>
<h4>Ger&auml;t neustarten</h4>
<form action="post.htm" method="POST" class="form-horizontal">
<div class="form-group row">
<div class="col text-center">
<button name="reboot" type="submit" class="btn btn-outline-primary">Reboot</button>
</div>
</div>
</form>
</p>
<!-- Div Group Device Reboot -->
</div>
<!-- Div Tab Maintenance -->
<!-- Div Tab Settings-->
<div id="tab_source" class="tab-pane fade" role="tabpanel">
<h3>Einstellungen</h3>
<!-- Div Group Battery Type -->
<hr />
<p>
<form action="post.htm" method="POST" class="form-horizontal">
<h4>Akku-Variante</h4>
<div class="form-group row">
<label for="battery_select" class="control-label col-4">Akku</label>
<div class="col-8">
<select id="battery_select" name="battery_select" class="select form-control">
%BATTERY_SELECT_OPTIONS%
</select>
</div>
</div>
<h4>Timer-Einstellungen</h4>
<div class="form-group row">
<label for="factionreboot_cont" class="control-label col-4">active Faction Recovery</label>
<div class="col-8">
<div class="form-check">
<input class="form-check-input" type="checkbox" name="factionreboot_cont" id="factionreboot_cont"
%FACTIONREBOOT_CHECKED%>
<label class="form-check-label" for="factionreboot_cont">
aktive Faktion beim booten wiederherstellen ?
</label>
</div>
</div>
</div>
<h4>Faktionsbezeichnungen</h4>
<div class="alert alert-primary alert-dismissable show fade" role="alert">
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
<strong>Achtung!</strong><br>
Faktionsbezeichnungen können nur aus ASCII-Zeichen bestehen, also A-Z, a-z und 0-9
</div>
<div class="form-group row">
<label for="faction_1_name" class="control-label col-4">Faktion 1</label>
<div class="col-8">
<div class="input-group">
<input id="faction_1_name" name="faction_1_name" value="%NAME_FAC_1%" type="text" class="form-control" pattern="[A-Za-z0-9 _-]{1,32}">
<div class="input-group-append">
<span class="input-group-text">max 32 Zeichen</span>
</div>
</div>
</div>
</div>
<div class="form-group row">
<label for="faction_2_name" class="control-label col-4">Faktion 2</label>
<div class="col-8">
<div class="input-group">
<input id="faction_2_name" name="faction_2_name" value="%NAME_FAC_2%" type="text" class="form-control" pattern="[A-Za-z0-9 _-]{1,32}">
<div class="input-group-append">
<span class="input-group-text">max 32 Zeichen</span>
</div>
</div>
</div>
</div>
<div class="form-group row">
<label for="faction_3_name" class="control-label col-4">Faktion 3</label>
<div class="col-8">
<div class="input-group">
<input id="faction_3_name" name="faction_3_name" value="%NAME_FAC_3%" type="text" class="form-control" pattern="[A-Za-z0-9 _-]{1,32}">
<div class="input-group-append">
<span class="input-group-text">max 32 Zeichen</span>
</div>
</div>
</div>
</div>
<div class="form-group row">
<div class="col text-center">
<button name="settingssave" type="submit" class="btn btn-outline-primary">&Uuml;bernehmen</button>
</div>
</div>
</form>
</p>
<!-- Div Group Battery Type -->
</div>
<!-- Div Tab Settings -->
<!-- Div Tab SystemInfo -->
<div id="tab_sysinfo" class="tab-pane fade" role="tabpanel">
<h3>Systeminfo</h3>
<!-- Div Group Sysinfo:Geraeteinfo -->
<hr />
<p>
<h4>Ger&auml;t</h4>
<table class="table">
<tbody>
<tr>
<th class="col-7" scope="col">Parameter</td>
<th class="col-5" scope="col">Value</td>
</tr>
<tr>
<td>Hostname</td>
<td>%HOSTNAME%</td>
</tr>
<tr>
<td>Device-ID</td>
<td>%DEVICENAME_ID%</td>
</tr>
<tr>
<td>Battery Voltage</td>
<td>%BAT_VOLTAGE%V</td>
</tr>
<tr>
<td>Battery Remain</td>
<td>%BAT_REMAIN_CAPACITY%&#37;</td>
</tr>
</table>
</p>
<!-- Div Group Sysinfo:Geraeteinfo -->
<!-- Div Group Sysinfo:Settings -->
<hr />
<p>
<h4>Einstellungen</h4>
<table class="table">
<tbody>
<tr>
<th class="col-7" scope="col">Parameter</td>
<th class="col-5" scope="col">Value</td>
</tr>
<tr>
<td>Battery_type</td>
<td>%BATTERY_TYPE%</td>
</tr>
<tr>
<td>Faction_recovery</td>
<td>%FACTION_RECOVERY%</td>
</tr>
<tr>
<td>EEPROM Version</td>
<td>%EEPROM_VERSION%</td>
</tr>
<tr>
<td>Checksum</td>
<td>%CONFIG_CHECKSUM%</td>
</tr>
</tbody>
</table>
</p>
<!-- Div Group Sysinfo:Settings -->
<!-- Div Group Sysinfo:Persistance -->
<hr />
<p>
<h4>Betriebsdaten</h4>
<table class="table">
<tbody>
<tr>
<th class="col-7" scope="col">Parameter</td>
<th class="col-5" scope="col">Value</td>
</tr>
<tr>
<td>writeCycleCounter</td>
<td>%WRITE_CYCLE_COUNT%</td>
</tr>
<tr>
<td>PersistenceMarker</td>
<td>%PERSISTENCE_MARKER%</td>
</tr>
<tr>
<td>activeFaction</td>
<td>%ACTIVE_FACTION%</td>
</tr>
<tr>
<td>faction_1_timer</td>
<td>%POINTS_FAC_1%</td>
</tr>
<tr>
<td>faction_2_timer</td>
<td>%POINTS_FAC_2%</td>
</tr>
<tr>
<td>faction_3_timer</td>
<td>%POINTS_FAC_3%</td>
</tr>
<tr>
<td>checksum</td>
<td>%PERSISTANCE_CHECKSUM%</td>
</tr>
</table>
</p>
<!-- Div Group Sysinfo:Persistance -->
<!-- Div Group LiveDebug -->
<hr />
<p>
<h4>Live Debug</h4>
<div class="form-group row">
<textarea class="form-control" spellcheck="false" id="livedebug-out" rows="3" readonly></textarea>
</div>
<div class="form-group row">
<div class="col text-center">
<button id="btn-ws-start" class="btn btn-outline-primary">Start</button>
<button id="btn-ws-stop" class="btn btn-outline-primary ml-2">Stop</button>
</div>
</div>
</p>
<!-- Div Group LiveDebug -->
</div>
<!-- Div Tab SystemInfo -->
<!-- Div Tab Firmware Update-->
<div id="tab_fwupdate" class="tab-pane fade" role="tabpanel">
<h3>Firmware</h3>
<!-- Div Group VersionInfo -->
<hr />
<p>
<h4>Version-Info</h4>
<table class="table">
<tbody>
<tr>
<th class="col-7" scope="col">Parameter</td>
<th class="col-5" scope="col">Value</td>
</tr>
<tr>
<td>Firmware Version</td>
<td>%SW_VERSION%</td>
</tr>
<tr>
<td>Flash Version</td>
<td>%FS_VERSION%</td>
</tr>
<tr>
<td>Git Revision</td>
<td>%GIT_REV%</td>
</tr>
</table>
</p>
<!-- Div Group VersionInfo -->
<!-- Div Group EEPROM Backup -->
<hr />
<p>
<h4>EEPROM-Backup</h4>
<div class="form-group row">
<div class="col text-center">
<a class="btn btn-outline-primary" href="eejson" role="button" id="ee-backup-download">Download</a>
</div>
</div>
</p>
<!-- Div Group EEPROM Backup -->
<!-- Div Group EEPROM Restore -->
<hr />
<p>
<h4>EEPROM-Restore</h4>
<form method='POST' action='eeRestore' enctype='multipart/form-data'>
<div class="form-group row">
<div class="custom-file">
<input type="file" name="ee-restore-file" class="custom-file-input" id="ee-restore-file" accept=".ee.json"
required />
<label class="custom-file-label" for="ee-restore-file">EEPROM-Backup ausw&auml;hlen</label>
</div>
</div>
<div class="form-group row">
<div class="col text-center">
<button name="submit" type="submit" class="btn btn-outline-primary">Restore starten</button>
</div>
</div>
</form>
</p>
<!-- Div Group EEPROM Restore -->
<!-- Div Group Firmware Update -->
<hr />
<p>
<h4>Firmware-Update</h4>
<form method='POST' action='doUpdate' enctype='multipart/form-data'>
<div class="form-group row">
<div class="custom-file">
<input type="file" name="fw-update-file" class="custom-file-input" id="fw-update-file"
accept=".fw.bin,.fs.gz" required />
<label class="custom-file-label" for="fw-update-file">Firmware-Update ausw&auml;hlen</label>
</div>
</div>
<div class="form-group row">
<div class="col text-center">
<button name="submit" type="submit" class="btn btn-outline-primary">Update starten</button>
</div>
</div>
</form>
</p>
<!-- Div Group Firmware Update -->
</div>
<!-- Div Tab Firmware Update-->
</div>
<!-- Tabs Content -->
</main>
<!-- Footer -->
<footer class="fixed-bottom bg-secondary font-weight-light text-light text-center py-3">
<!-- Copyright -->
<span class=" footer-copyright">
© 2022 <a class="text-reset fw-bold" href="https://hiabuto.de/">Hiabuto Defence Systems</a>
</span>
<!-- Copyright -->
<footer class="page-footer navbar-dark bg-primary font-small fixed-bottom">
<div class="container-fluid text-center">
<div class="footer-copyright text-center py-3">
<span class="text-muted">© 2023 -
<a class="text-reset fw-bold" href="https://hiabuto.de/">Hiabuto Defense Systems</a></span>
</div>
</div>
</footer>
<!-- Footer -->
<!-- Modal Dialog -->
<div class="modal fade" id="dtcModal" tabindex="-1" role="dialog" aria-labelledby="dtcModalLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="dtcModalLabel">DTC-Description</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<p class="dtc-desc">DTC Description</p>
<p class="dtc-debugval">DTC DebugVal</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-outline-secondary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
<!-- Modal Dialog -->
<script>
$('.navbar-nav>li>a').on('click', function () {
$('.navbar-collapse').collapse('hide');
});
document.querySelector('.custom-file-input').addEventListener('change', function (e) {
var fileName = document.getElementById("fw-update-file").files[0].name;
var nextSibling = e.target.nextElementSibling
nextSibling.innerText = fileName
});
$(document).ready(function () {
$("tr[data-dtc]").each(function (i) {
$(this).attr('data-toggle', "modal");
$(this).attr('data-target', "#dtcModal");
});
});
$('#dtcModal').on('show.bs.modal', function (event) {
var dtctr = $(event.relatedTarget)
var dtc = dtctr.data('dtc')
var debugval = dtctr.data('debugval')
var modal = $(this)
$.getJSON('static/tt_dtc/dtc_' + dtc + '.json', function (data) {
modal.find('.modal-title').text(data.title)
modal.find('.dtc-desc').text(data.description)
if (debugval > 0) {
modal.find('.dtc-debugval').text("Debugvalue: " + debugval)
}
else {
modal.find('.dtc-debugval').remove()
}
}).fail(function () {
console.log("An error has occurred.");
modal.find('.modal-title').text("Fehler")
modal.find('.dtc-desc').text("DTC-Beschreibung konnte nicht geladen werden")
});
});
</script>
</body>
</html>

View File

@@ -3,7 +3,7 @@
<head>
<meta charset="utf-8" />
<title>%DEVICE_NAME%</title>
<title>KTM CAN Chain Oiler</title>
<meta http-equiv="content-type" content="text/html;charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="static/css/bootstrap.min.css">
@@ -14,7 +14,7 @@
<link rel="icon" type="image/png" sizes="32x32" href="static/img/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="static/img/favicon-16x16.png">
<link rel="manifest" href="static/img/site.webmanifest">
<meta http-equiv="refresh" content="3; url='/index.htm'" />
<meta http-equiv="refresh" content="3; url='index.htm'" />
</head>
<body>

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,27 @@
@font-face {
font-family: 'Comfortaa';
font-style: normal;
font-weight: 300;
src: url(../fonts/comfortaa.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
body {
padding-top: 70px;
margin-bottom: 70px;
}
hr {
height: 2px;
border-width: 0;
color: gray;
background-color: gray
}
.dtc-debugval {
color: #F2771A;
font: 0.8rem Inconsolata, monospace;
background-color: black;
padding: 10px;
}

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,84 @@
var gateway = `ws://${window.location.hostname}/ws`;
var websocket;
window.addEventListener("load", onLoad);
function initWebSocket() {
console.log("Trying to open a WebSocket connection...");
websocket = new WebSocket(gateway);
websocket.onopen = onOpen;
websocket.onclose = onClose;
websocket.onmessage = onMessage; // <-- add this line
}
function initButtons() {
document
.getElementById("btn-ws-stop")
.addEventListener("click", livedebug_stop);
document
.getElementById("btn-ws-start")
.addEventListener("click", livedebug_start);
}
function onOpen(event) {
console.log("Connection opened");
}
function onClose(event) {
console.log("Connection closed");
setTimeout(initWebSocket, 2000);
}
function onMessage(event) {
var livedebug_out = document.getElementById("livedebug-out");
var textarea_heigth = livedebug_out.scrollHeight;
livedebug_out.value += event.data;
livedebug_out.scrollTop = livedebug_out.scrollHeight;
do_resize(livedebug_out);
}
function onLoad(event) {
initWebSocket();
initButtons();
}
function livedebug_start() {
websocket.send("start");
}
function livedebug_stop() {
websocket.send("stop");
}
function do_resize(textbox) {
var maxrows = 15;
var minrows = 3;
var txt = textbox.value;
var cols = textbox.cols;
var arraytxt = txt.split("\n");
var rows = arraytxt.length;
for (i = 0; i < arraytxt.length; i++)
rows += parseInt(arraytxt[i].length / cols);
if (rows > maxrows) textbox.rows = maxrows;
else if (rows < minrows) textbox.rows = minrows;
else textbox.rows = rows;
}
function notifyMe() {
if (!("Notification" in window)) {
alert("This browser does not support desktop notification");
} else if (Notification.permission === "granted") {
const notification = new Notification("Hi there!");
// …
} else if (Notification.permission !== "denied") {
Notification.requestPermission().then((permission) => {
if (permission === "granted") {
const notification = new Notification("Hi there!");
// …
}
});
}
}

View File

@@ -0,0 +1,4 @@
{
"title": "kein EEPROM gefunden",
"description": "Es wurde kein EEPROM gefunden. Dies lässt einen Hardware-Defekt vermuten."
}

View File

@@ -0,0 +1,4 @@
{
"title": "Power-Monitor Fehler",
"description": "Es gibt ein Problem mit dem Power-Monitoring. Die Akku-Überwachung ist ohne Funktion! Bitte Hardware prüfen"
}

View File

@@ -0,0 +1,4 @@
{
"title": "Akku-Spannung niedrig",
"description": "Die Akkuspannung ist niedrig. Bitte Akku bald aufladen!"
}

View File

@@ -0,0 +1,4 @@
{
"title": "Akku-Spannung kritisch",
"description": "Die Akkuspannung ist sehr niedrig. Bitte Akku umgehend ersetzen um eine schädliche Tiefentladung zu vermeiden!"
}

View File

@@ -0,0 +1,4 @@
{
"title": "EEPROM-Migration failed",
"description": "Migration of EEPROM-Image from an other FW-Version failed - you need to reset everything manually!"
}

View File

@@ -0,0 +1,4 @@
{
"title": "EEPROM CFG Checksumme",
"description": "Die Checksumme der Config-Partition des EEPROM ist ungültig. Setzen sie den EEPROM-Bereich 'CFG' im Menu 'Wartung' zurück"
}

View File

@@ -0,0 +1,4 @@
{
"title": "EEPROM PDS Checksumme",
"description": "Die Checksumme der Betriebsdaten-Partition des EEPROM ist ungültig. Setzen sie den EEPROM-Bereich 'PDS' im Menu 'Wartung' zurück"
}

View File

@@ -0,0 +1,4 @@
{
"title": "EEPROM PDS Adresse",
"description": "Die Adresse der Betriebsdaten-Partition im EEPROM ist ungültig. Setzen sie den EEPROM-Bereich 'PDS' im Menu 'Wartung' zurück"
}

View File

@@ -0,0 +1,4 @@
{
"title": "EEPROM Version falsch",
"description": "Die Layout-Version des EEPROM stimmt nicht mit der Firmware-Version überein. Setzen sie den EEPROM-Bereich 'CFG' im Menu 'Wartung' zurück"
}

View File

@@ -0,0 +1,4 @@
{
"title": "Flashstorage Fehler",
"description": "Der Flashstorage konnte nicht initialisiert werden. Aktualisieren sie Flash & Firmware"
}

View File

@@ -0,0 +1,4 @@
{
"title": "Flashstorage Version falsch",
"description": "Die Version des Flashstorage stimmt nicht mit der Firmware-Version überein. Aktualisieren sie den Flash mit der passenden Update-Datei"
}

View File

@@ -0,0 +1,4 @@
{
"title": "Config-Validierung",
"description": "Ein oder mehrer Einstellungswerte sind ausserhalb plausibler Werte. Prüfen Sie Ihre Einstellungen"
}

View File

@@ -0,0 +1,4 @@
{
"title": "LoRa-Modul Fehler",
"description": "Es gibt ein Problem mit dem LoRa-Modul. Es konnte keine LoRa-Verbindung aufgebaut werden. Bitte Hardware prüfen"
}

View File

@@ -1 +1 @@
1.0
1.04

View File

@@ -13,6 +13,7 @@
#define HOST_NAME "AirsoftTimer_%08X"
#define SHUTDOWN_DELAY_MS 5000
#define STARTUP_DELAY_MS 20000
#define GPIO_LORA_TX D3
#define GPIO_LORA_RX D4
@@ -43,17 +44,6 @@
#define OTA_DELAY 50 // ticks -> 10ms / tick
#endif
#ifndef ADMIN_PASSWORD
#error "You need to define ADMIN_PASSWORD for OTA-Update"
#endif
#ifndef WIFI_PASSWORD
#error "You must define an WIFI_PASSWORD for OTA-Update"
#endif
#ifndef WIFI_SSID
#error "You must define an WIFI_SSID for OTA-Update"
#endif
#ifndef WIFI_AP_PASSWORD
#error "You must define an WIFI_AP_PASSWORD for Standalone AP-Mode"
#endif
#endif

View File

@@ -0,0 +1,46 @@
#ifndef _DEBUGGER_H_
#define _DEBUGGER_H_
#include <Arduino.h>
#include "webui.h"
const char PROGMEM helpCmd[] = "sysinfo - System Info\n"
"netinfo - WiFi Info\n"
"formatPDS - Format Persistence EEPROM Data\n"
"formatCFG - Format Configuration EEPROM Data\n"
"checkEE - Check EEPROM with checksum\n"
"dumpEE1k - dump the first 1kb of EEPROM to Serial\n"
"dumpEE - dump the whole EPPROM to Serial\n"
"resetPageEE - Reset the PersistenceData Page\n"
"dumpCFG - print Config struct\n"
"dumpPDS - print PersistanceStruct\n"
"saveEE - save EE-Data\n"
"showdtc - Show all DTCs\n"
"dumpGlobals - print globals\n";
typedef enum DebugStatus_e
{
disabled,
enabled
} DebugStatus_t;
typedef enum DebugPorts_e
{
dbg_Serial,
dbg_Webui,
dbg_cntElements
} DebugPorts_t;
const char sDebugPorts[dbg_cntElements][7] = {
"Serial",
"WebUI"};
extern DebugStatus_t DebuggerStatus[dbg_cntElements];
void initDebugger();
void pushCANDebug(uint32_t id, uint8_t dlc, uint8_t *data);
void Debug_pushMessage(const char *format, ...);
void SetDebugportStatus(DebugPorts_t port, DebugStatus_t status);
void Debug_Process();
#endif

View File

@@ -3,11 +3,11 @@
#include <Arduino.h>
#define MAX_DTC_STORAGE 6
#define MAX_DTC_STORAGE 12
typedef enum DTCNums_e
{
DTC_NO_EEPROM_FOUND,
DTC_NO_EEPROM_FOUND = 1,
DTC_EEPROM_CFG_BAD,
DTC_EEPROM_PDS_BAD,
DTC_EEPROM_PDSADRESS_BAD,
@@ -15,14 +15,19 @@ typedef enum DTCNums_e
DTC_FLASHFS_ERROR,
DTC_FLASHFS_VERSION_ERROR,
DTC_EEPROM_CFG_SANITY,
DTC_NO_LORA_FOUND,
DTC_NO_BATMNON_FOUND,
DTC_BAT_LOW,
DTC_BAT_CRITICAL,
DTC_EEPROM_MIGRATE_FAILED,
DTC_LAST_DTC
} DTCNums_t;
typedef enum DTCActive_e
{
DTC_NONE,
DTC_ACTIVE,
DTC_PREVIOUS,
DTC_NONE
DTC_PREVIOUS
} DTCActive_t;
typedef enum DTCSeverity_e
@@ -46,6 +51,7 @@ void ClearDTC(DTCNums_t DTC_no);
void ClearAllDTC();
DTCNums_t getlastDTC(boolean only_active);
DTCNums_t getlastDTC_Severity(boolean only_active, DTCSeverity_t severity);
void DTC_Process();
extern DTCEntry_s DTCStorage[MAX_DTC_STORAGE];
#endif

View File

@@ -1,5 +1,5 @@
#ifndef _CONFIG_H_
#define _CONFIG_H_
#ifndef _EEPROM_H_
#define _EEPROM_H_
#include <Arduino.h>
#include <Wire.h>
@@ -8,8 +8,10 @@
#include "globals.h"
#include "dtc.h"
#include "common.h"
#include "debugger.h"
#define EEPROM_SIZE_BYTES I2C_DEVICESIZE_24LC01
#define I2C_EE_ADDRESS 0x50
#define EEPROM_SIZE_BYTES I2C_DEVICESIZE_24LC64
#define EEPROM_ENDURANCE 1000000
typedef enum
@@ -30,6 +32,7 @@ typedef struct
uint32_t checksum = 0;
} persistenceData_t;
extern persistenceData_t PersistenceData;
typedef enum
{
BATTERY_UNDEFINED,
@@ -38,22 +41,38 @@ typedef enum
} batteryType_t;
const char BatteryString[][10]{
"Undefined",
"LiPo 2S",
"LiPo 3S"
};
"Undefined",
"LiPo 2S",
"LiPo 3S"};
const size_t BatteryString_Elements = sizeof(BatteryString) / sizeof(BatteryString[0]);
typedef struct
{
uint8_t EEPROM_Version = 1;
batteryType_t batteryType = BATTERY_UNDEFINED;
uint32_t checksum = 0;
uint8_t EEPROM_Version;
batteryType_t batteryType;
bool active_faction_on_reboot;
char Faction_1_Name[33];
char Faction_2_Name[33];
char Faction_3_Name[33];
uint32_t checksum;
} configData_t;
extern configData_t ConfigData;
const configData_t ConfigData_defaults = {
0, BATTERY_LIPO_3S, 0
2, // EEPROM_Version (incerease this if anything on Layout changes!)
BATTERY_LIPO_3S, // batteryType
false, // active_faction_on_reboot
"FACTION 1", // Faction_1_Name
"FACTION 2", // Faction_2_Name
"FACTION 3", // Faction_3_Name
0 // checksum
};
const uint16_t startofConfigData = 16;
const uint16_t startofPersistence = 16 + sizeof(ConfigData) + (sizeof(ConfigData) % 16);
void InitEEPROM();
void EEPROM_Process();
void StoreConfig_EEPROM();
@@ -67,6 +86,4 @@ void dumpEEPROM(uint16_t memoryAddress, uint16_t length);
void MovePersistencePage_EEPROM(boolean reset);
uint32_t ConfigSanityCheck(bool autocorrect = false);
extern configData_t ConfigData;
extern persistenceData_t PersistenceData;
#endif // _CONFIG_H_
#endif // _EEPROM_H_

View File

@@ -5,12 +5,21 @@
typedef enum eSystem_Status
{
sysStat_null,
sysStat_Startup,
sysStat_Normal,
sysStat_Error,
sysStat_Shutdown
} tSystem_Status;
const char sSystem_Status_txt[][9] = {
"Null",
"Startup",
"Normal",
"Error",
"Shutdown"
};
typedef enum eEERequest
{
EE_IDLE,
@@ -31,15 +40,30 @@ typedef struct Globals_s
char DeviceName_ID[43];
char FlashVersion[10];
tSystem_Status systemStatus = sysStat_Startup;
tSystem_Status resumeStatus = sysStat_Startup;
char systemStatustxt[16] = "";
eEERequest requestEEAction = EE_IDLE;
uint16_t eePersistanceAdress;
bool hasDTC;
int loadvoltage_mV = 0;
int battery_level = 0;
bool timer_disabled = false;
} Globals_t;
extern Globals_t globals;
typedef struct Constants_s
{
uint8_t FW_Version_major;
uint8_t FW_Version_minor;
uint8_t Required_Flash_Version_major;
uint8_t Required_Flash_Version_minor;
char GitHash[11];
} Constants_t;
const Constants_t constants PROGMEM = {
1,4, // Firmware_Version
1,4, // Required Flash Version
GIT_REV // Git-Hash-String
};
void initGlobals();
#endif

View File

@@ -2,10 +2,16 @@
#define _LORA_NET_H_
#include <Arduino.h>
#ifdef LORA_FEATURE_ENABLED
#include <LoRa_E220.h>
#elif defined(FEATURE_ENABLE_UARTLORA)
#include <SoftwareSerial.h>
#endif
// local includes
#include "lora_messages.h"
#include "debugger.h"
#include "defaults.h"
#include "config.h"
#include "globals.h"
@@ -14,7 +20,7 @@
#define FREQUENCY_868
void InitLoRa(void (*MPinHelper)(int, int));
bool InitLoRa(void (*MPinHelper)(int, int));
void LoRa_Process();
void sendStatus_LoRa();

View File

@@ -6,7 +6,7 @@
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include "globals.h"
#include "config.h"
#include "eeprom.h"
#define OLED_SDA 4
#define OLED_SCL 15

View File

@@ -0,0 +1,31 @@
#ifndef _SANITYCHECK_H_
#define _SANITYCHECK_H_
#ifndef ADMIN_PASSWORD
#error "You need to define ADMIN_PASSWORD for OTA-Update"
#endif
#ifndef WIFI_AP_SSID
#warning "No WIFI_AP_SSID defined. Using DeviceName"
#define WIFI_AP_SSID DEVICE_NAME
#endif
#ifndef WIFI_AP_PASSWORD
#error "You must define an WIFI_AP_PASSWORD for Standalone AP-Mode"
#endif
#if defined(FEATURE_ENABLE_UARTLORA) && defined(FEATURE_ENABLE_LORA)
#error "You cannot enable LoRa and UART-Protocol at the same time!"
#endif
#ifdef FEATURE_ENABLE_WIFI_CLIENT
#ifndef WIFI_CLIENT_PASSWORD
#error "You must define an WIFI_PASSWORD for OTA-Update"
#endif
#ifndef WIFI_CLIENT_SSID
#error "You must define an WIFI_SSID for OTA-Update"
#endif
#endif
#endif //_SANITYCHECK_H_

View File

@@ -11,11 +11,14 @@
#include <AsyncJson.h>
#include <ArduinoJson.h>
#include "config.h"
#include "eeprom.h"
#include "globals.h"
#include "dtc.h"
#include "common.h"
#include "debugger.h"
void initWebUI();
void Webserver_Process();
void Websocket_PushLiveDebug(String Message);
#endif

View File

@@ -274,7 +274,7 @@ bool LoRa_E220::begin(){
this->serialDef.stream->setTimeout(100);
Status status = setMode(MODE_0_NORMAL);
return status==E220_SUCCESS;
return status;
}
/*

View File

@@ -22,22 +22,22 @@ upload_speed = 921600
;upload_port = 10.0.1.48
;upload_protocol = espota
;upload_flags =
; --auth=${wifi_cred.admin_password}
; --auth=${wifi_cred.ota_password}
build_flags=
!python git_rev_macro.py
;-DSERIAL_DEBUG
;-DWIFI_CLIENT
-DATOMIC_FS_UPDATE
;-DFEATURE_ENABLE_WIFI_CLIENT
;-DFEATURE_ENABLE_LORA
;-DCAPTIVE
-DWIFI_AP_IP_GW=10,0,1,1
-DADMIN_PASSWORD=${wifi_cred.admin_password}
-DWIFI_SSID=${wifi_cred.wifi_ssid}
-DWIFI_PASSWORD=${wifi_cred.wifi_password}
-DFEATURE_ENABLE_UARTLORA
-DWIFI_AP_IP_GW=10,0,0,1
-DADMIN_PASSWORD=${wifi_cred.ota_password}
-DWIFI_CLIENT_SSID=${wifi_cred.wifi_client_ssid}
-DWIFI_CLIENT_PASSWORD=${wifi_cred.wifi_client_password}
-DWIFI_AP_SSID=${wifi_cred.wifi_ap_ssid}
-DWIFI_AP_PASSWORD=${wifi_cred.wifi_ap_password}
-DDEVICE_NAME='"Dark Emergency Timer"'
-DFACTION_1_NAME='"GOF"'
-DFACTION_2_NAME='"MILIZ"'
-DFACTION_3_NAME='"KGG"'
;build_type = debug

302
Software/src/debugger.cpp Normal file
View File

@@ -0,0 +1,302 @@
#include "debugger.h"
DebugStatus_t DebuggerStatus[dbg_cntElements];
String IpAddress2String(const IPAddress &ipAddress);
void processCmdDebug(String command);
void Debug_formatCFG();
void Debug_formatPersistence();
void Debug_printSystemInfo();
void Debug_printWifiInfo();
void Debug_CheckEEPOM();
void Debug_dumpConfig();
void Debug_dumpPersistance();
void Debug_ShowDTCs();
void Debug_dumpGlobals();
void Debug_printHelp();
void initDebugger()
{
DebuggerStatus[dbg_Serial] = disabled;
DebuggerStatus[dbg_Webui] = disabled;
Serial.setDebugOutput(false);
}
void Debug_Process()
{
typedef enum InputProcessed_e
{
IDLE,
CMD_COMPLETE,
CMD_ABORT,
CMD_OVERFLOW
} InputProcessed_t;
static unsigned int inputCnt = 0;
static char inputBuffer[32];
InputProcessed_t InputProcessed = IDLE;
if (Serial.available())
{
char inputChar = Serial.read();
switch (inputChar)
{
case '\n':
inputBuffer[inputCnt] = 0; // terminate the String
inputCnt = 0;
InputProcessed = CMD_COMPLETE;
break;
case 0x1B: // Esc
inputBuffer[0] = 0;
inputCnt = 0;
InputProcessed = CMD_ABORT;
break;
case 0x21 ... 0x7E: // its a real letter or sign and not some control-chars
inputBuffer[inputCnt] = inputChar;
inputCnt++;
break;
default:
break;
}
if (inputCnt > sizeof(inputBuffer))
{
inputCnt = 0;
inputBuffer[sizeof(inputBuffer) - 1] = 0; // terminate the String
InputProcessed = CMD_OVERFLOW;
}
}
switch (InputProcessed)
{
case CMD_ABORT:
Debug_pushMessage("Abort\n");
break;
case CMD_COMPLETE:
processCmdDebug(String(inputBuffer));
break;
case CMD_OVERFLOW:
Debug_pushMessage("input Buffer overflow\n");
break;
default:
break;
}
InputProcessed = IDLE;
}
void SetDebugportStatus(DebugPorts_t port, DebugStatus_t status)
{
if (status == disabled)
Debug_pushMessage("disable DebugPort %s\n", sDebugPorts[port]);
DebuggerStatus[port] = status;
if (status == enabled)
Debug_pushMessage("enabled DebugPort %s\n", sDebugPorts[port]);
}
void Debug_pushMessage(const char *format, ...)
{
if ((DebuggerStatus[dbg_Serial] == enabled) || (DebuggerStatus[dbg_Webui] == enabled))
{
char buff[64];
va_list arg;
va_start(arg, format);
vsnprintf(buff, sizeof(buff), format, arg);
va_end(arg);
if (DebuggerStatus[dbg_Serial] == enabled)
{
Serial.print(buff);
}
if (DebuggerStatus[dbg_Webui] == enabled)
{
Websocket_PushLiveDebug(String(buff));
}
}
}
void processCmdDebug(String command)
{
if (command == "help")
Debug_printHelp();
else if (command == "sysinfo")
Debug_printSystemInfo();
else if (command == "netinfo")
Debug_printWifiInfo();
else if (command == "formatCFG")
Debug_formatCFG();
else if (command == "formatPDS")
Debug_formatPersistence();
else if (command == "checkEE")
Debug_CheckEEPOM();
else if (command == "dumpEE1k")
dumpEEPROM(0, 1024);
else if (command == "dumpEE")
dumpEEPROM(0, EEPROM_SIZE_BYTES);
else if (command == "resetPageEE")
MovePersistencePage_EEPROM(true);
else if (command == "dumpCFG")
Debug_dumpConfig();
else if (command == "dumpPDS")
Debug_dumpPersistance();
else if (command == "saveEE")
globals.requestEEAction = EE_ALL_SAVE;
else if (command == "showdtc")
Debug_ShowDTCs();
else if (command == "dumpGlobals")
Debug_dumpGlobals();
else if (command == "sdbg")
SetDebugportStatus(dbg_Serial, enabled);
else
Debug_pushMessage("unknown Command\n");
}
void Debug_formatCFG()
{
Debug_pushMessage("Formatting Config-EEPROM and reseting to default\n");
FormatConfig_EEPROM();
}
void Debug_formatPersistence()
{
Debug_pushMessage("Formatting Persistence-EEPROM and reseting to default\n");
FormatPersistence_EEPROM();
}
void Debug_printSystemInfo()
{
Debug_pushMessage("Hostname: %s\n", globals.DeviceName);
FlashMode_t ideMode = ESP.getFlashChipMode();
Debug_pushMessage("Sdk version: %s\n", ESP.getSdkVersion());
Debug_pushMessage("Core Version: %s\n", ESP.getCoreVersion().c_str());
Debug_pushMessage("Boot Version: %u\n", ESP.getBootVersion());
Debug_pushMessage("Boot Mode: %u\n", ESP.getBootMode());
Debug_pushMessage("CPU Frequency: %u MHz\n", ESP.getCpuFreqMHz());
Debug_pushMessage("Reset reason: %s\n", ESP.getResetReason().c_str());
Debug_pushMessage("Flash Size: %d\n", ESP.getFlashChipRealSize());
Debug_pushMessage("Flash Size IDE: %d\n", ESP.getFlashChipSize());
Debug_pushMessage("Flash ide mode: %s\n", (ideMode == FM_QIO ? "QIO" : ideMode == FM_QOUT ? "QOUT"
: ideMode == FM_DIO ? "DIO"
: ideMode == FM_DOUT ? "DOUT"
: "UNKNOWN"));
Debug_pushMessage("OTA-Pass: %s\n", QUOTE(ADMIN_PASSWORD));
Debug_pushMessage("Git-Revison: %s\n", constants.GitHash);
Debug_pushMessage("Sw-Version: %d.%02d\n", constants.FW_Version_major, constants.FW_Version_minor);
}
void Debug_dumpConfig()
{
Debug_pushMessage("batteryType: %d\n", ConfigData.batteryType);
Debug_pushMessage("EEPROM_Version: %d\n", ConfigData.EEPROM_Version);
Debug_pushMessage("checksum: 0x%08X\n", ConfigData.checksum);
}
void Debug_dumpGlobals()
{
Debug_pushMessage("systemStatus: %d\n", globals.systemStatus);
Debug_pushMessage("battery_level: %d\n", globals.battery_level);
Debug_pushMessage("loadvoltage_mV: %d\n", globals.loadvoltage_mV);
Debug_pushMessage("requestEEAction: %d\n", globals.requestEEAction);
Debug_pushMessage("DeviceName: %s\n", globals.DeviceName);
Debug_pushMessage("DeviceName_ID: %s\n", globals.DeviceName_ID);
Debug_pushMessage("FlashVersion: %s\n", globals.FlashVersion);
Debug_pushMessage("eePersistanceAdress: %d\n", globals.eePersistanceAdress);
Debug_pushMessage("hasDTC: %d\n", globals.hasDTC);
}
void Debug_dumpPersistance()
{
Debug_pushMessage("writeCycleCounter: %d\n", PersistenceData.writeCycleCounter);
Debug_pushMessage("activeFaction: %d\n", PersistenceData.activeFaction);
Debug_pushMessage("faction_1_timer: %d\n", PersistenceData.faction_1_timer);
Debug_pushMessage("faction_2_timer: %d\n", PersistenceData.faction_2_timer);
Debug_pushMessage("faction_3_timer: %d\n", PersistenceData.faction_3_timer);
Debug_pushMessage("checksum: %d\n", PersistenceData.checksum);
Debug_pushMessage("PSD Adress: 0x%04X\n", globals.eePersistanceAdress);
}
void Debug_printWifiInfo()
{
}
void Debug_CheckEEPOM()
{
uint32_t checksum = PersistenceData.checksum;
PersistenceData.checksum = 0;
if (Checksum_EEPROM((uint8_t *)&PersistenceData, sizeof(PersistenceData)) == checksum)
{
Debug_pushMessage("PersistenceData EEPROM Checksum OK\n");
}
else
{
Debug_pushMessage("PersistenceData EEPROM Checksum BAD\n");
}
PersistenceData.checksum = checksum;
checksum = ConfigData.checksum;
ConfigData.checksum = 0;
if (Checksum_EEPROM((uint8_t *)&ConfigData, sizeof(ConfigData)) == checksum)
{
Debug_pushMessage("ConfigData EEPROM Checksum OK\n");
}
else
{
Debug_pushMessage("ConfigData EEPROM Checksum BAD\n");
}
ConfigData.checksum = checksum;
}
void Debug_ShowDTCs()
{
char buff_timestamp[16]; // Format: DD-hh:mm:ss:xxx
char buff_active[9];
Debug_pushMessage("\n timestamp | DTC-Nr. | status | severity | debugVal\n");
for (uint32_t i = 0; i < MAX_DTC_STORAGE; i++)
{
if (DTCStorage[i].Number < DTC_LAST_DTC)
{
sprintf(buff_timestamp, "%02d-%02d:%02d:%02d:%03d",
DTCStorage[i].timestamp / 86400000, // Days
DTCStorage[i].timestamp / 360000 % 24, // Hours
DTCStorage[i].timestamp / 60000 % 60, // Minutes
DTCStorage[i].timestamp / 1000 % 60, // Seconds
DTCStorage[i].timestamp % 1000); // milliseconds
if (DTCStorage[i].active == DTC_ACTIVE)
strcpy(buff_active, "active");
else if (DTCStorage[i].active == DTC_PREVIOUS)
strcpy(buff_active, "previous");
else
strcpy(buff_active, "none");
Debug_pushMessage("%s %7d %8s %8d %8d\n", buff_timestamp, DTCStorage[i].Number, buff_active, DTCStorage[i].severity, DTCStorage[i].debugVal);
}
}
}
void Debug_printHelp()
{
char buff[64];
for (unsigned int i = sizeof(helpCmd) / 63; i < sizeof(helpCmd) / 63; i++)
{
memcpy_P(buff, (helpCmd + (i * 63)), 63);
buff[63] = 0;
Debug_pushMessage(buff);
}
}

View File

@@ -1,4 +1,5 @@
#include "dtc.h"
#include "debugger.h"
DTCEntry_s DTCStorage[MAX_DTC_STORAGE];
@@ -10,7 +11,7 @@ void MaintainDTC(DTCNums_t DTC_no, DTCSeverity_t DTC_severity, boolean active, u
{
if (active && DTCStorage[i].active != DTC_ACTIVE)
{
Serial.printf("DTC gone active: %d, DebugVal: %d\n", DTC_no, DebugValue);
Debug_pushMessage("DTC gone active: %d, DebugVal: %d\n", DTC_no, DebugValue);
DTCStorage[i].timestamp = millis();
DTCStorage[i].active = DTC_ACTIVE;
DTCStorage[i].severity = DTC_severity;
@@ -18,7 +19,7 @@ void MaintainDTC(DTCNums_t DTC_no, DTCSeverity_t DTC_severity, boolean active, u
}
if (!active && DTCStorage[i].active == DTC_ACTIVE)
{
Serial.printf("DTC gone previous: %d\n", DTC_no);
Debug_pushMessage("DTC gone previous: %d\n", DTC_no);
DTCStorage[i].active = DTC_PREVIOUS;
}
return;
@@ -33,11 +34,12 @@ void MaintainDTC(DTCNums_t DTC_no, DTCSeverity_t DTC_severity, boolean active, u
{
if (DTCStorage[i].Number == DTC_LAST_DTC)
{
Serial.printf("new DTC registered: %d, DebugVal: %d\n", DTC_no, DebugValue);
Debug_pushMessage("new DTC registered: %d, DebugVal: %d\n", DTC_no, DebugValue);
DTCStorage[i].Number = DTC_no;
DTCStorage[i].timestamp = millis();
DTCStorage[i].active = DTC_ACTIVE;
DTCStorage[i].debugVal = DebugValue;
DTCStorage[i].severity = DTC_severity;
return;
}
}
@@ -105,4 +107,33 @@ DTCNums_t getlastDTC_Severity(boolean only_active, DTCSeverity_t severity)
}
return pointer >= 0 ? DTCStorage[pointer].Number : DTC_LAST_DTC;
}
void DTC_Process()
{
static tSystem_Status preserverSysStatusError;
if (getlastDTC(false) < DTC_LAST_DTC)
{
globals.hasDTC = true;
if (getlastDTC_Severity(true, DTC_CRITICAL) < DTC_LAST_DTC && globals.systemStatus != sysStat_Shutdown)
{
if (globals.systemStatus != sysStat_Error)
{
preserverSysStatusError = globals.systemStatus;
}
globals.systemStatus = sysStat_Error;
}
else
{
if (globals.systemStatus == sysStat_Error)
{
globals.systemStatus = preserverSysStatusError;
}
}
}
else
{
globals.hasDTC = false;
}
}

View File

@@ -1,25 +1,28 @@
#include "config.h"
#include "eeprom.h"
I2C_eeprom ee(0x50, EEPROM_SIZE_BYTES);
I2C_eeprom ee(I2C_EE_ADDRESS, EEPROM_SIZE_BYTES);
configData_t ConfigData;
persistenceData_t PersistenceData;
const uint16_t eeVersion = 1; // inc
boolean eeAvailable = false;
bool eeAvailable = false;
const uint16_t startofConfigData = 16;
const uint16_t startofPersistence = 16 + sizeof(ConfigData) + (sizeof(ConfigData) % 16);
boolean checkEEPROMavailable();
bool checkEEPROMavailable();
bool ValidateEEPROM_Version();
bool MigrateEEPROM(uint8_t fromVersion);
void InitEEPROM()
{
ee.begin();
checkEEPROMavailable();
eeAvailable = checkEEPROMavailable();
eeAvailable = ValidateEEPROM_Version();
Serial.printf("Initialized EEPROM at Address 0x%02X\n", I2C_EE_ADDRESS);
}
void EEPROM_Process()
{
if (eeAvailable == false)
return;
switch (globals.requestEEAction)
{
case EE_CFG_SAVE:
@@ -73,17 +76,18 @@ void EEPROM_Process()
void StoreConfig_EEPROM()
{
if (eeAvailable == false)
return;
ConfigData.checksum = 0;
ConfigData.checksum = Checksum_EEPROM((uint8_t *)&ConfigData, sizeof(ConfigData));
if (!checkEEPROMavailable())
return;
ee.updateBlock(startofConfigData, (uint8_t *)&ConfigData, sizeof(ConfigData));
}
void GetConfig_EEPROM()
{
if (!checkEEPROMavailable())
if (eeAvailable == false)
return;
ee.readBlock(startofConfigData, (uint8_t *)&ConfigData, sizeof(ConfigData));
@@ -108,6 +112,9 @@ void GetConfig_EEPROM()
void StorePersistence_EEPROM()
{
if (eeAvailable == false)
return;
if (PersistenceData.writeCycleCounter >= 0xFFF0)
MovePersistencePage_EEPROM(false);
else
@@ -116,15 +123,12 @@ void StorePersistence_EEPROM()
PersistenceData.checksum = 0;
PersistenceData.checksum = Checksum_EEPROM((uint8_t *)&PersistenceData, sizeof(PersistenceData));
if (!checkEEPROMavailable())
return;
ee.updateBlock(globals.eePersistanceAdress, (uint8_t *)&PersistenceData, sizeof(PersistenceData));
}
void GetPersistence_EEPROM()
{
if (!checkEEPROMavailable())
if (eeAvailable == false)
return;
ee.readBlock(0, (uint8_t *)&globals.eePersistanceAdress, sizeof(globals.eePersistanceAdress));
@@ -153,22 +157,29 @@ void GetPersistence_EEPROM()
void FormatConfig_EEPROM()
{
if (eeAvailable == false)
return;
Serial.println("Formatting Config-Partition");
ConfigData = ConfigData_defaults;
ConfigData.EEPROM_Version = eeVersion;
StoreConfig_EEPROM();
GetConfig_EEPROM();
}
void FormatPersistence_EEPROM()
{
if (eeAvailable == false)
return;
Serial.println("Formatting Persistance-Partition");
memset(&PersistenceData, 0, sizeof(PersistenceData));
PersistenceData = {0};
StorePersistence_EEPROM();
GetPersistence_EEPROM();
}
void MovePersistencePage_EEPROM(boolean reset)
{
if (!checkEEPROMavailable())
if (eeAvailable == false)
return;
globals.eePersistanceAdress = +sizeof(PersistenceData);
@@ -206,7 +217,7 @@ void dumpEEPROM(uint16_t memoryAddress, uint16_t length)
{
#define BLOCK_TO_LENGTH 16
if (!checkEEPROMavailable())
if (eeAvailable == false)
return;
char ascii_buf[BLOCK_TO_LENGTH + 1];
@@ -236,15 +247,13 @@ void dumpEEPROM(uint16_t memoryAddress, uint16_t length)
Serial.println();
}
boolean checkEEPROMavailable()
bool checkEEPROMavailable()
{
if (!ee.isConnected())
{
MaintainDTC(DTC_NO_EEPROM_FOUND, DTC_CRITICAL, true);
globals.systemStatus = sysStat_Error;
return false;
}
MaintainDTC(DTC_NO_EEPROM_FOUND, DTC_CRITICAL, false);
return true;
}
@@ -260,4 +269,90 @@ uint32_t ConfigSanityCheck(bool autocorrect)
}
return setting_reset_bits;
}
bool ValidateEEPROM_Version()
{
if (eeAvailable == false)
return false;
uint8_t EEPROMVersionOnChip = ee.readByte(startofConfigData);
if (EEPROMVersionOnChip < ConfigData_defaults.EEPROM_Version)
{
Serial.printf("EEPROM Image Version is %d, but %d expected - trying to migrate\n", EEPROMVersionOnChip, ConfigData_defaults.EEPROM_Version);
if (!MigrateEEPROM(EEPROMVersionOnChip))
{
Serial.print("Error\n");
MaintainDTC(DTC_EEPROM_MIGRATE_FAILED, DTC_CRITICAL, true, EEPROMVersionOnChip);
return false;
}
else
{
Serial.print("Success\n");
}
}
return true;
}
bool MigrateEEPROM(uint8_t fromVersion)
{
uint16_t persistanceMarker_onChip;
switch (fromVersion)
{
// Version 1 EEPROM Layout: startAdress size (byte)
// const uint16_t startofConfigData = 16 16
// const uint16_t startofPersistence = 32 24
//
// typedef struct
// {
// uint8_t EEPROM_Version = 1; 16 1
// batteryType_t batteryType = BATTERY_UNDEFINED; 17 4
// bool active_faction_on_reboot = false; 21 1
// uint32_t checksum = 0; 22 4
// } configData_t;
//
// typedef struct offset
// {
// uint32_t writeCycleCounter = 0; 0 4
// uint32_t faction_1_timer = 0; 4 4
// uint32_t faction_2_timer = 0; 8 4
// uint32_t faction_3_timer = 0; 12 4
// factions_t activeFaction = NONE; 16 4
// uint32_t checksum = 0; 20 4
// } persistenceData_t;
case 1:
// Migrate Persistance-Data
ee.readBlock(0, (uint8_t *)&persistanceMarker_onChip, sizeof(uint16_t));
if (persistanceMarker_onChip < startofPersistence)
{
ee.readBlock(persistanceMarker_onChip + 0, (uint8_t *)&PersistenceData.writeCycleCounter, 4);
ee.readBlock(persistanceMarker_onChip + 4, (uint8_t *)&PersistenceData.faction_1_timer, 4);
ee.readBlock(persistanceMarker_onChip + 8, (uint8_t *)&PersistenceData.faction_2_timer, 4);
ee.readBlock(persistanceMarker_onChip + 12, (uint8_t *)&PersistenceData.faction_3_timer, 4);
ee.readBlock(persistanceMarker_onChip + 16, (uint8_t *)&PersistenceData.activeFaction, 4);
ee.readBlock(persistanceMarker_onChip + 20, (uint8_t *)&PersistenceData.checksum, 4);
MovePersistencePage_EEPROM(true);
StorePersistence_EEPROM();
}
// Migrate Config-Data and set defaults for Values which doesn't exists in this earlier Version
ConfigData.EEPROM_Version = ConfigData_defaults.EEPROM_Version;
strncpy(ConfigData.Faction_1_Name, ConfigData_defaults.Faction_1_Name, sizeof(ConfigData.Faction_1_Name));
strncpy(ConfigData.Faction_2_Name, ConfigData_defaults.Faction_2_Name, sizeof(ConfigData.Faction_2_Name));
strncpy(ConfigData.Faction_3_Name, ConfigData_defaults.Faction_3_Name, sizeof(ConfigData.Faction_3_Name));
ee.readBlock(17, (uint8_t *)&ConfigData.batteryType, 4);
ee.readBlock(21, (uint8_t *)&ConfigData.active_faction_on_reboot, 1);
StoreConfig_EEPROM();
return true;
break;
default:
return false;
break;
}
}

9
Software/src/globals.cpp Normal file
View File

@@ -0,0 +1,9 @@
#include "globals.h"
Globals_t globals;
void initGlobals()
{
globals.systemStatus = sysStat_Startup;
globals.requestEEAction = EE_IDLE;
}

View File

@@ -1,60 +1,81 @@
#include "lora_net.h"
#ifdef FEATURE_ENABLE_LORA
LoRa_E220 e220ttl(GPIO_LORA_TX, GPIO_LORA_RX, GPIO_LORA_AUX, 3, 4); // Arduino RX <-- e220 TX, Arduino TX --> e220 RX AUX M0 M1
void printParameters(struct Configuration configuration);
void printModuleInformation(struct ModuleInformation moduleInformation);
#elif defined(FEATURE_ENABLE_UARTLORA)
SoftwareSerial SerialLoRa(GPIO_LORA_RX, GPIO_LORA_TX); // RX, TX
void Parse_LoRa_UartCommand(char input[], int size);
#endif
void InitLoRa(void (*MPinHelper)(int, int))
bool InitLoRa(void (*MPinHelper)(int, int))
{
bool returnval = false;
#ifdef FEATURE_ENABLE_LORA
e220ttl.setMPins = MPinHelper;
e220ttl.begin();
returnval = e220ttl.begin();
ResponseStructContainer c;
c = e220ttl.getConfiguration();
// It's important get configuration pointer before all other operation
Configuration configuration = *(Configuration *)c.data;
Serial.println(c.status.getResponseDescription());
Serial.println(c.status.code);
if (returnval == true)
{
ResponseStructContainer c;
c = e220ttl.getConfiguration();
// It's important get configuration pointer before all other operation
Configuration configuration = *(Configuration *)c.data;
Serial.println(c.status.getResponseDescription());
Serial.println(c.status.code);
ResponseStructContainer cMi;
cMi = e220ttl.getModuleInformation();
// It's important get information pointer before all other operation
// ModuleInformation mi = *(ModuleInformation *)cMi.data;
ResponseStructContainer cMi;
cMi = e220ttl.getModuleInformation();
// It's important get information pointer before all other operation
// ModuleInformation mi = *(ModuleInformation *)cMi.data;
Serial.println(cMi.status.getResponseDescription());
Serial.println(cMi.status.code);
Serial.println(cMi.status.getResponseDescription());
Serial.println(cMi.status.code);
// ----------------------- DEFAULT TRANSPARENT WITH RSSI -----------------------
configuration.ADDL = 0x02;
configuration.ADDH = 0x00;
// ----------------------- DEFAULT TRANSPARENT WITH RSSI -----------------------
configuration.ADDL = 0x02;
configuration.ADDH = 0x00;
configuration.CHAN = 23;
configuration.CHAN = 23;
configuration.SPED.uartBaudRate = UART_BPS_9600;
configuration.SPED.airDataRate = AIR_DATA_RATE_010_24;
configuration.SPED.uartParity = MODE_00_8N1;
configuration.SPED.uartBaudRate = UART_BPS_9600;
configuration.SPED.airDataRate = AIR_DATA_RATE_010_24;
configuration.SPED.uartParity = MODE_00_8N1;
configuration.OPTION.subPacketSetting = SPS_200_00;
configuration.OPTION.RSSIAmbientNoise = RSSI_AMBIENT_NOISE_ENABLED;
configuration.OPTION.transmissionPower = POWER_22;
configuration.OPTION.subPacketSetting = SPS_200_00;
configuration.OPTION.RSSIAmbientNoise = RSSI_AMBIENT_NOISE_ENABLED;
configuration.OPTION.transmissionPower = POWER_22;
configuration.TRANSMISSION_MODE.enableRSSI = RSSI_ENABLED;
configuration.TRANSMISSION_MODE.fixedTransmission = FT_FIXED_TRANSMISSION;
configuration.TRANSMISSION_MODE.enableLBT = LBT_ENABLED;
configuration.TRANSMISSION_MODE.WORPeriod = WOR_2000_011;
configuration.TRANSMISSION_MODE.enableRSSI = RSSI_ENABLED;
configuration.TRANSMISSION_MODE.fixedTransmission = FT_FIXED_TRANSMISSION;
configuration.TRANSMISSION_MODE.enableLBT = LBT_ENABLED;
configuration.TRANSMISSION_MODE.WORPeriod = WOR_2000_011;
// Set configuration changed and set to not hold the configuration
ResponseStatus rs = e220ttl.setConfiguration(configuration, WRITE_CFG_PWR_DWN_LOSE);
Serial.println(rs.getResponseDescription());
Serial.println(rs.code);
c.close();
// Set configuration changed and set to not hold the configuration
ResponseStatus rs = e220ttl.setConfiguration(configuration, WRITE_CFG_PWR_DWN_LOSE);
Serial.println(rs.getResponseDescription());
Serial.println(rs.code);
c.close();
printParameters(configuration);
printParameters(configuration);
}
else
{
MaintainDTC(DTC_NO_LORA_FOUND, DTC_WARN, true);
}
#elif defined(FEATURE_ENABLE_UARTLORA)
SerialLoRa.begin(9600);
returnval = true;
#endif
return returnval;
}
void LoRa_Process()
{
#ifdef FEATURE_ENABLE_LORA
if (e220ttl.available() > 1)
{
ResponseContainer rc = e220ttl.receiveMessageRSSI();
@@ -72,10 +93,41 @@ void LoRa_Process()
Serial.println(rc.rssi, DEC);
}
}
#elif defined(FEATURE_ENABLE_UARTLORA)
static char packageInput[32];
static bool packageRecieved = false;
static unsigned int bufferPtr = 0;
while (SerialLoRa.available() && packageRecieved == false)
{
if (bufferPtr < sizeof(packageInput) - 1)
{
packageInput[bufferPtr] = SerialLoRa.read();
packageInput[bufferPtr + 1] = 0; // always terminate String
if (packageInput[bufferPtr] == '\n')
{
packageRecieved = true;
bufferPtr = 0;
Debug_pushMessage("Got LoRa UART: %s\n", packageInput);
}
else if ((packageInput[bufferPtr] >= 0x30) || (packageInput[bufferPtr] <= 0x5A)) // only accept Numbers, UpperCase-Letters and some special chars
{
bufferPtr++;
}
}
}
if (packageRecieved)
Parse_LoRa_UartCommand(packageInput, bufferPtr);
#endif
}
void sendStatus_LoRa()
{
#ifdef FEATURE_ENABLE_LORA
struct
{
MessageType_t type = "STATUS";
@@ -91,8 +143,25 @@ void sendStatus_LoRa()
ResponseStatus rs = e220ttl.sendFixedMessage(0xFF, 0xFF, 23, (byte *)&sendStatus, sizeof(sendStatus));
Serial.println(rs.getResponseDescription());
#elif defined(FEATURE_ENABLE_UARTLORA)
SerialLoRa.print(PersistenceData.faction_1_timer);
SerialLoRa.write(";");
SerialLoRa.print(PersistenceData.faction_2_timer);
SerialLoRa.write(";");
SerialLoRa.print(PersistenceData.faction_3_timer);
SerialLoRa.write(";");
SerialLoRa.print(PersistenceData.activeFaction);
SerialLoRa.write(";");
SerialLoRa.print(globals.battery_level);
SerialLoRa.write('\n');
#endif
}
#ifdef FEATURE_ENABLE_LORA
void printParameters(struct Configuration configuration)
{
Serial.println("----------------------------------------");
@@ -158,4 +227,71 @@ void printParameters(struct Configuration configuration)
Serial.println(configuration.TRANSMISSION_MODE.getFixedTransmissionDescription());
Serial.println("----------------------------------------");
}
}
#endif
#ifdef FEATURE_ENABLE_UARTLORA
void Parse_LoRa_UartCommand(char input[], int size)
{
char delimiter[] = ";";
char *ptr;
char command[8];
char value[8];
ptr = strtok(input, delimiter);
while (ptr != NULL)
{
strncpy(command, ptr, sizeof(command));
ptr = strtok(NULL, delimiter);
strncpy(value, ptr, sizeof(value));
}
Debug_pushMessage("Parsed LoRa UART Command: %s Value: %s\n", command, value);
if (!strcmp(command, "ENABLE"))
{
globals.timer_disabled = false;
}
else if (!strcmp(command, "DISABLE"))
{
globals.timer_disabled = false;
}
else if (!strcmp(command, "RESET"))
{
PersistenceData.activeFaction = NONE;
PersistenceData.faction_1_timer = 0;
PersistenceData.faction_2_timer = 0;
PersistenceData.faction_3_timer = 0;
}
else if (!strcmp(command, "TMRSTP"))
{
PersistenceData.activeFaction = NONE;
}
else if (!strcmp(command, "TMR1"))
{
PersistenceData.faction_1_timer = atol(value);
}
else if (!strcmp(command, "TMR2"))
{
PersistenceData.faction_2_timer = atol(value);
}
else if (!strcmp(command, "TMR3"))
{
PersistenceData.faction_3_timer = atol(value);
}
else if (!strcmp(command, "EFAC1"))
{
PersistenceData.activeFaction = FACTION_1;
}
else if (!strcmp(command, "EFAC2"))
{
PersistenceData.activeFaction = FACTION_2;
}
else if (!strcmp(command, "EFAC3"))
{
PersistenceData.activeFaction = FACTION_3;
}
}
#endif

View File

@@ -11,22 +11,26 @@
#include <ArduinoJson.h>
// local includes
#include "common.h"
#include "sanitycheck.h"
#include "defaults.h"
#include "webui.h"
#include "config.h"
#include "globals.h"
#include "dtc.h"
#include "common.h"
#include "debugger.h"
#if defined(FEATURE_ENABLE_LORA) || defined(FEATURE_ENABLE_UARTLORA)
#include "lora_net.h"
#endif
#ifdef WIFI_CLIENT
#include <WiFiMulti.h>
#ifdef FEATURE_ENABLE_WIFI_CLIENT
#include <ESP8266WiFiMulti.h>
const char *ssid = QUOTE(WIFI_SSID);
const char *password = QUOTE(WIFI_PASSWORD);
const char *ssid = QUOTE(WIFI_SSID_CLIENT);
const char *password = QUOTE(WIFI_PASSWORD_CLIENT);
const uint32_t connectTimeoutMs = 5000;
WiFiMulti wifiMulti;
ESP8266WiFiMulti wifiMulti;
#endif
PCF8574 i2c_io(I2C_IO_ADDRESS);
@@ -41,12 +45,16 @@ void toggleWiFiAP(boolean shutdown = false);
void SystemShutdown();
void SetBatteryType(batteryType_t type);
void ProcessKeyCombos(bool *btnState);
void OverrideDisplay(const uint8_t *message, uint32_t time);
void OverrideDisplay(uint32_t time, const char *message1, const char *message2, const char *message3);
void initGlobals();
void setMPins_Helper(int pin, int status);
void maintainSysStat();
#if defined(FEATURE_ENABLE_UARTLORA) || defined(FEATURE_ENABLE_LORA)
void setMPins_Helper(int pin, int status);
void tmrCallback_StatusSender();
Ticker tmrStatusSender(tmrCallback_StatusSender, 30000, 0, MILLIS);
#endif
void tmrCallback_PowerMonitor();
Ticker tmrPowerMonitor(tmrCallback_PowerMonitor, 10000, 0, MILLIS);
void tmrCallback_FactionTicker();
@@ -56,27 +64,20 @@ Ticker tmrInputGetter(tmrCallback_InputGetter, 250, 0, MILLIS);
void tmrCallback_EEPROMCyclicPDS();
Ticker tmrEEPROMCyclicPDS(tmrCallback_EEPROMCyclicPDS, 60000, 0, MILLIS);
#ifdef WIFI_CLIENT
#ifdef FEATURE_ENABLE_WIFI_CLIENT
void tmrCallback_WiFiMaintainConnection();
Ticker tmrWiFiMaintainConnection(tmrCallback_WiFiMaintainConnection, 1000, 0, MILLIS);
#endif
uint32_t DisplayOverrideFlag = 0;
char DisplayOverrideValue[5] = {0};
Globals_t globals;
void initGlobals()
{
globals.requestEEAction = EE_IDLE;
globals.resumeStatus = sysStat_Normal;
globals.systemStatus = sysStat_Startup;
}
char DisplayOverrideValue[3][5] = {0};
#if defined(FEATURE_ENABLE_UARTLORA) || defined(FEATURE_ENABLE_LORA)
void setMPins_Helper(int pin, int status)
{
i2c_io.write(pin, status);
}
#endif
void setup()
{
@@ -89,8 +90,9 @@ void setup()
Serial.begin(115200);
Serial.setDebugOutput(false);
Serial.println("\n\nDark Emergency Timer - by Hiabuto Defense");
Serial.println(globals.DeviceName);
Serial.print("\n\n-------------------START-------------------\n");
Serial.print(globals.DeviceName);
Serial.print("\nby Hiabuto Defense\n");
ClearAllDTC(); // Init DTC-Storage
@@ -117,17 +119,25 @@ void setup()
Serial.print("INA219 not Initialized\n");
}
InitLoRa(&setMPins_Helper);
tmrStatusSender.start();
#if defined(FEATURE_ENABLE_UARTLORA) || defined(FEATURE_ENABLE_LORA)
if (InitLoRa(&setMPins_Helper))
{
Serial.print("Initialized LoRa_Transceiver\n");
tmrStatusSender.start();
}
else
{
Serial.print("LoRa not Initialized\n");
}
#endif
#ifdef WIFI_CLIENT
#ifdef FEATURE_ENABLE_WIFI_CLIENT
WiFi.mode(WIFI_STA);
WiFi.setHostname(globals.DeviceName_ID);
wifiMulti.addAP(QUOTE(WIFI_SSID), QUOTE(WIFI_PASSWORD));
WiFi.setHostname(globals.DeviceName);
wifiMulti.addAP(QUOTE(WIFI_CLIENT_SSID), QUOTE(WIFI_CLIENT_PASSWORD));
tmrWiFiMaintainConnection.start();
Serial.print("WiFi-Client Initialized\n");
#else
WiFi.mode(WIFI_AP);
WiFi.begin(QUOTE(DEVICE_NAME), QUOTE(WIFI_AP_PASSWORD));
WiFi.mode(WIFI_OFF);
#endif
@@ -175,15 +185,17 @@ void setup()
Serial.println("Receive Failed");
else if (error == OTA_END_ERROR)
Serial.println("End Failed"); });
ArduinoOTA.begin();
ArduinoOTA.begin();
Serial.print("\nOTA-Init done");
initWebUI();
Serial.print("\nWebUI-Init done");
initGlobals();
Serial.print("\nglobals-Init done");
#ifdef CAPTIVE
dnsServer.start(53, "*", WiFi.softAPIP());
#endif
initWebUI();
initGlobals();
disp_FAC_1.init();
disp_FAC_1.setBrightness(5);
disp_FAC_2.init();
@@ -195,31 +207,39 @@ void setup()
tmrFactionTicker.start();
tmrInputGetter.start();
Serial.println("Setup Done");
if (ConfigData.active_faction_on_reboot == false)
PersistenceData.activeFaction = NONE;
Serial.print("\nSetup Done\n");
}
void loop()
{
maintainSysStat();
tmrEEPROMCyclicPDS.update();
tmrFactionTicker.update();
tmrInputGetter.update();
tmrStatusSender.update();
tmrPowerMonitor.update();
ArduinoOTA.handle();
SevenSeg_Output();
EEPROM_Process();
Webserver_Process();
DTC_Process();
Debug_Process();
#if defined(FEATURE_ENABLE_LORA) || defined(FEATURE_ENABLE_UARTLORA)
LoRa_Process();
tmrStatusSender.update();
#endif
#ifdef CAPTIVE
dnsServer.processNextRequest();
#endif
#ifdef WIFI_CLIENT
#ifdef FEATURE_ENABLE_WIFI_CLIENT
tmrWiFiMaintainConnection.update();
#endif
if (globals.systemStatus == sysStat_Shutdown)
SystemShutdown();
yield();
}
@@ -241,9 +261,9 @@ void SevenSeg_Output()
disp_FAC_1.setBrightness(5);
disp_FAC_2.setBrightness(5);
disp_FAC_3.setBrightness(5);
disp_FAC_1.display(String(DisplayOverrideValue));
disp_FAC_2.clearScreen();
disp_FAC_3.clearScreen();
disp_FAC_1.display(String(DisplayOverrideValue[0]));
disp_FAC_2.display(String(DisplayOverrideValue[1]));
disp_FAC_3.display(String(DisplayOverrideValue[2]));
}
else
{
@@ -252,13 +272,13 @@ void SevenSeg_Output()
if (millis() % 3000 < 1500)
snprintf(sevenSegBuff, sizeof(sevenSegBuff), "%4d", globals.battery_level);
else
snprintf(sevenSegBuff, sizeof(sevenSegBuff), "%2d.%1d", (globals.loadvoltage_mV / 1000), ((globals.loadvoltage_mV % 1000) / 100));
snprintf(sevenSegBuff, sizeof(sevenSegBuff), "%3d.%1d", (globals.loadvoltage_mV / 1000), ((globals.loadvoltage_mV % 1000) / 100));
disp_FAC_1.setBrightness(1);
disp_FAC_1.display(" BAT");
disp_FAC_1.display(" Bat");
disp_FAC_2.setBrightness(1);
disp_FAC_2.display("LOW ");
disp_FAC_2.display("low ");
disp_FAC_3.setBrightness(1);
disp_FAC_3.display(String(sevenSegBuff));
@@ -269,22 +289,28 @@ void SevenSeg_Output()
disp_FAC_1.refresh();
snprintf(sevenSegBuff, sizeof(sevenSegBuff), "%4d", PersistenceData.faction_1_timer / 60);
disp_FAC_1.display(String(sevenSegBuff), false, false);
disp_FAC_1.setDp((PersistenceData.activeFaction == FACTION_1) && (millis() % 1000 > 500) ? 0x08 : 0x00);
disp_FAC_2.setBrightness(PersistenceData.activeFaction == FACTION_2 ? 5 : 1);
disp_FAC_2.refresh();
snprintf(sevenSegBuff, sizeof(sevenSegBuff), "%4d", PersistenceData.faction_2_timer / 60);
disp_FAC_2.display(String(sevenSegBuff), false, false);
disp_FAC_2.setDp((PersistenceData.activeFaction == FACTION_2) && (millis() % 1000 > 500) ? 0x08 : 0x00);
disp_FAC_3.setBrightness(PersistenceData.activeFaction == FACTION_3 ? 5 : 1);
disp_FAC_3.refresh();
snprintf(sevenSegBuff, sizeof(sevenSegBuff), "%4d", PersistenceData.faction_3_timer / 60);
disp_FAC_3.display(String(sevenSegBuff), false, false);
disp_FAC_3.setDp((PersistenceData.activeFaction == FACTION_3) && (millis() % 1000 > 500) ? 0x08 : 0x00);
}
}
}
void tmrCallback_FactionTicker()
{
if (globals.timer_disabled == true)
PersistenceData.activeFaction = NONE;
switch (PersistenceData.activeFaction)
{
case FACTION_1:
@@ -321,43 +347,48 @@ void tmrCallback_InputGetter()
if (keysPressed > 1)
{
Serial.println("ERROR: More than one Flag active - setting no Faction active");
Debug_pushMessage("ERROR: More than one Flag active - setting no Faction active");
PersistenceData.activeFaction = NONE;
return;
}
if (btnState[0] == FAC_1_TRG_PRESSED)
if (btnState[0] == FAC_1_TRG_PRESSED && globals.timer_disabled == false)
{
if (PersistenceData.activeFaction != FACTION_1)
{
Serial.println("Faction 1 captured !");
Debug_pushMessage("Faction 1 captured !");
globals.requestEEAction = EE_PDS_SAVE;
}
PersistenceData.activeFaction = FACTION_1;
}
if (btnState[1] == FAC_2_TRG_PRESSED)
if (btnState[1] == FAC_2_TRG_PRESSED && globals.timer_disabled == false)
{
if (PersistenceData.activeFaction != FACTION_2)
{
Serial.println("Faction 2 captured !");
Debug_pushMessage("Faction 2 captured !");
globals.requestEEAction = EE_PDS_SAVE;
}
PersistenceData.activeFaction = FACTION_2;
}
if (btnState[2] == FAC_3_TRG_PRESSED)
if (btnState[2] == FAC_3_TRG_PRESSED && globals.timer_disabled == false)
{
if (PersistenceData.activeFaction != FACTION_3)
{
Serial.println("Faction 3 captured !");
Debug_pushMessage("Faction 3 captured !");
globals.requestEEAction = EE_PDS_SAVE;
}
PersistenceData.activeFaction = FACTION_3;
}
}
#if defined(FEATURE_ENABLE_LORA) || defined(FEATURE_ENABLE_UARTLORA)
void tmrCallback_StatusSender()
{
sendStatus_LoRa();
}
#endif
void tmrCallback_PowerMonitor()
{
@@ -394,6 +425,9 @@ void tmrCallback_PowerMonitor()
break;
}
MaintainDTC(DTC_BAT_LOW, DTC_WARN, (battery_level < 15 ? true : false), battery_level);
MaintainDTC(DTC_BAT_CRITICAL, DTC_CRITICAL, (battery_level < 5 ? true : false), battery_level);
// Serial.printf("Battery Level: %d %%\n", globals.battery_level);
// Serial.printf("Bus Voltage: %f V\n", busvoltage);
// Serial.printf("Shunt Voltage: %f mV\n", shuntvoltage);
@@ -407,7 +441,7 @@ void tmrCallback_EEPROMCyclicPDS()
StorePersistence_EEPROM();
}
#ifdef WIFI_CLIENT
#ifdef FEATURE_ENABLE_WIFI_CLIENT
void tmrCallback_WiFiMaintainConnection()
{
static uint32_t WiFiFailCount = 0;
@@ -420,29 +454,38 @@ void tmrCallback_WiFiMaintainConnection()
else
{
if (WiFiFailCount < WiFiFailMax)
{
WiFiFailCount++;
}
else
toggleWiFiAP(false);
{
Debug_pushMessage("WiFi not connected! - Start AP");
toggleWiFiAP();
}
}
}
#endif
void toggleWiFiAP(boolean shutdown)
{
if (WiFi.getMode() != WIFI_OFF && shutdown == true)
if (WiFi.getMode() != WIFI_OFF)
{
WiFi.mode(WIFI_OFF);
#ifdef WIFI_CLIENT
Serial.println("WiFi turned off");
#ifdef FEATURE_ENABLE_WIFI_CLIENT
tmrWiFiMaintainConnection.stop();
#endif
}
else if (shutdown == false)
else
{
WiFi.mode(WIFI_AP);
WiFi.softAPConfig(IPAddress(WIFI_AP_IP_GW), IPAddress(WIFI_AP_IP_GW), IPAddress(255, 255, 255, 0));
WiFi.softAP(globals.DeviceName_ID, QUOTE(WIFI_AP_PASSWORD));
#ifdef WIFI_CLIENT
WiFi.softAP(QUOTE(WIFI_AP_SSID), QUOTE(WIFI_AP_PASSWORD));
#ifdef FEATURE_ENABLE_WIFI_CLIENT
tmrWiFiMaintainConnection.stop();
Serial.println("WiFi AP started, stopped Maintain-Timer");
#else
Serial.println("WiFi AP started");
#endif
}
}
@@ -474,10 +517,12 @@ void SetBatteryType(batteryType_t type)
}
}
void OverrideDisplay(const char *message, uint32_t time)
void OverrideDisplay(uint32_t time, const char *message1, const char *message2, const char *message3)
{
DisplayOverrideFlag = millis() + time;
strcpy(DisplayOverrideValue, message);
strcpy(DisplayOverrideValue[0], message1);
strcpy(DisplayOverrideValue[1], message2);
strcpy(DisplayOverrideValue[2], message3);
}
void ProcessKeyCombos(bool *btnState)
@@ -489,24 +534,14 @@ void ProcessKeyCombos(bool *btnState)
} keyStatus_t;
static keyStatus_t keyStatus_Fac1 = KEY_RELEASED;
static uint8_t keyCount_Fac1 = 0;
static keyStatus_t keyStatus_Fac2 = KEY_RELEASED;
static uint8_t keyCount_Fac2 = 0;
static keyStatus_t keyStatus_Fac3 = KEY_RELEASED;
static uint8_t keyCount_Fac3 = 0;
if (btnState[2] == FAC_3_TRG_PRESSED)
if (btnState[0] == FAC_1_TRG_PRESSED)
{
keyStatus_Fac3 = KEY_PRESSED;
// Process FactionKey 1 ComboCounter
if (btnState[0] == FAC_1_TRG_PRESSED && keyStatus_Fac1 == KEY_RELEASED)
{
keyStatus_Fac1 = KEY_PRESSED;
keyCount_Fac1++;
}
if (btnState[0] != FAC_1_TRG_PRESSED)
keyStatus_Fac1 = KEY_RELEASED;
keyStatus_Fac1 = KEY_PRESSED;
// Process FactionKey 2 ComboCounter
if (btnState[1] == FAC_2_TRG_PRESSED && keyStatus_Fac2 == KEY_RELEASED)
@@ -517,24 +552,100 @@ void ProcessKeyCombos(bool *btnState)
if (btnState[1] != FAC_2_TRG_PRESSED)
keyStatus_Fac2 = KEY_RELEASED;
}
if (btnState[2] != FAC_3_TRG_PRESSED && keyStatus_Fac3 == KEY_PRESSED)
{
if (keyCount_Fac1 > 0 || keyCount_Fac2 > 0)
Serial.printf("KeyCombo 1: %d | 2: %d\n", keyCount_Fac1, keyCount_Fac2);
if (keyCount_Fac1 == 2 && keyCount_Fac2 == 2)
// Process FactionKey 3 ComboCounter
if (btnState[2] == FAC_3_TRG_PRESSED && keyStatus_Fac3 == KEY_RELEASED)
{
Serial.println("KeyCombo: WiFi AP ON");
OverrideDisplay("NET ", 5000);
toggleWiFiAP(false);
keyStatus_Fac3 = KEY_PRESSED;
keyCount_Fac3++;
}
if (btnState[2] != FAC_3_TRG_PRESSED)
keyStatus_Fac3 = KEY_RELEASED;
}
if (btnState[0] != FAC_1_TRG_PRESSED && keyStatus_Fac1 == KEY_PRESSED)
{
if (keyCount_Fac2 > 0 || keyCount_Fac3 > 0)
Debug_pushMessage("KeyCombo 2: %d | 3: %d\n", keyCount_Fac2, keyCount_Fac3);
if (keyCount_Fac2 == 2 && keyCount_Fac3 == 0)
{
Debug_pushMessage("KeyCombo: WiFi AP ON");
OverrideDisplay(5000, "NET ", " ", " ");
toggleWiFiAP(false);
}
else if (keyCount_Fac2 == 4 && keyCount_Fac3 == 0)
{
Debug_pushMessage("KeyCombo: Reset Timer\n");
if (globals.systemStatus == sysStat_Startup)
{
OverrideDisplay(5000, "RST ", " ", " ");
PersistenceData.faction_1_timer = 0;
PersistenceData.faction_2_timer = 0;
PersistenceData.faction_3_timer = 0;
PersistenceData.activeFaction = NONE;
globals.requestEEAction = EE_PDS_SAVE;
}
else
{
OverrideDisplay(5000, "ERR ", " ", " ");
Debug_pushMessage("ERROR: only %d seconds after Startup!\n", STARTUP_DELAY_MS / 1000);
}
}
keyCount_Fac1 = 0;
keyCount_Fac2 = 0;
keyCount_Fac3 = 0;
keyStatus_Fac1 = KEY_RELEASED;
keyStatus_Fac2 = KEY_RELEASED;
keyStatus_Fac3 = KEY_RELEASED;
}
}
void maintainSysStat()
{
static tSystem_Status lastStat = sysStat_null;
// system Status Transistions
switch (globals.systemStatus)
{
case sysStat_Shutdown:
SystemShutdown();
break;
case sysStat_Startup:
if (millis() > STARTUP_DELAY_MS)
globals.systemStatus = sysStat_Normal;
break;
case sysStat_Error:
case sysStat_Normal:
case sysStat_null:
default:
break;
}
// system Status Changed Actions
if (lastStat != globals.systemStatus)
{
switch (globals.systemStatus)
{
case sysStat_Shutdown:
OverrideDisplay(SHUTDOWN_DELAY_MS, " re", "boot", " ");
break;
case sysStat_Startup:
OverrideDisplay(STARTUP_DELAY_MS, "star", "t up", " ");
break;
case sysStat_Error:
case sysStat_Normal:
case sysStat_null:
default:
break;
}
lastStat = globals.systemStatus;
}
}

View File

@@ -33,10 +33,10 @@ void OLED_Process()
display.setCursor(0, 0);
display.printf("LiPo: %d%%\n", globals.battery_level);
display.print(PersistenceData.activeFaction == FACTION_1 ? "> " : " ");
display.printf("%-5s: %02d:%02d:%02d\n", FACTION_1_NAME, PersistenceData.faction_1_timer / 3600, (PersistenceData.faction_1_timer / 60) % 60, PersistenceData.faction_1_timer % 60);
display.printf("%-5s: %02d:%02d:%02d\n", PersistenceData.faction_1_timer, PersistenceData.faction_1_timer / 3600, (PersistenceData.faction_1_timer / 60) % 60, PersistenceData.faction_1_timer % 60);
display.print(PersistenceData.activeFaction == FACTION_2 ? "> " : " ");
display.printf("%-5s: %02d:%02d:%02d\n", FACTION_2_NAME, PersistenceData.faction_2_timer / 3600, (PersistenceData.faction_2_timer / 60) % 60, PersistenceData.faction_2_timer % 60);
display.printf("%-5s: %02d:%02d:%02d\n", PersistenceData.faction_2_timer, PersistenceData.faction_2_timer / 3600, (PersistenceData.faction_2_timer / 60) % 60, PersistenceData.faction_2_timer % 60);
display.print(PersistenceData.activeFaction == FACTION_3 ? "> " : " ");
display.printf("%-5s: %02d:%02d:%02d\n", FACTION_3_NAME, PersistenceData.faction_3_timer / 3600, (PersistenceData.faction_3_timer / 60) % 60, PersistenceData.faction_3_timer % 60);
display.printf("%-5s: %02d:%02d:%02d\n", PersistenceData.faction_3_timer, PersistenceData.faction_3_timer / 3600, (PersistenceData.faction_3_timer / 60) % 60, PersistenceData.faction_3_timer % 60);
display.display();
}

View File

@@ -2,52 +2,46 @@
AsyncWebServer webServer(80);
typedef enum
{
RESPMSG_HIDE,
RESPMSG_SUCCESS,
RESPMSG_INFO,
RESPMSG_WARNING,
RESPMSG_DANGER
} statusResponseMessage_Type_t;
char StatusResponseMessage[64];
statusResponseMessage_Type_t StatusResponseMessage_Type = RESPMSG_INFO;
#ifdef CAPTIVE
DNSServer dnsServer;
#endif
AsyncWebServer server(80);
const char *PARAM_MESSAGE = "message";
String processor(const String &var);
void WebserverPOST_Callback(AsyncWebServerRequest *request);
void WebserverNotFound_Callback(AsyncWebServerRequest *request);
void Webserver_Callback(AsyncWebServerRequest *request);
void WebserverCommands_Callback(String input);
void WebserverFirmwareUpdate_Callback(AsyncWebServerRequest *request, const String &filename, size_t index, uint8_t *data, size_t len, bool final);
void WebserverEERestore_Callback(AsyncWebServerRequest *request, const String &filename, size_t index, uint8_t *data, size_t len, bool final);
void WebServerEEJSON_Callback(AsyncWebServerRequest *request);
void GetFlashVersion(char *buff, size_t buff_size);
AsyncWebSocket webSocket("/ws");
void WebsocketEvent_Callback(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len);
void Websocket_HandleMessage(void *arg, uint8_t *data, size_t len);
void initWebUI()
{
if (!LittleFS.begin())
{
Serial.println("An Error has occurred while mounting LittleFS");
Debug_pushMessage("An Error has occurred while mounting LittleFS\n");
MaintainDTC(DTC_FLASHFS_ERROR, DTC_CRITICAL, true);
return;
}
GetFlashVersion(globals.FlashVersion, sizeof(globals.FlashVersion));
if (strcmp(globals.FlashVersion, QUOTE(FLASH_FS_VERSION)))
char buffer[6];
snprintf(buffer, sizeof(buffer), "%d.%02d", constants.Required_Flash_Version_major, constants.Required_Flash_Version_minor);
if (strcmp(globals.FlashVersion, buffer))
{
MaintainDTC(DTC_FLASHFS_VERSION_ERROR, DTC_WARN, true);
}
MDNS.begin(globals.DeviceName);
MDNS.addService("telnet", "tcp", 23);
MDNS.addService("http", "tcp", 80);
webSocket.onEvent(WebsocketEvent_Callback);
webServer.addHandler(&webSocket);
webServer.serveStatic("/static/", LittleFS, "/static/").setCacheControl("max-age=360000");
webServer.on("/", HTTP_GET, [](AsyncWebServerRequest *request)
{ request->redirect("/index.htm"); });
@@ -63,51 +57,65 @@ void initWebUI()
webServer.begin();
}
void Webserver_Process()
{
webSocket.cleanupClients();
}
String processor(const String &var)
{
if (var == "HOSTNAME")
return String(globals.DeviceName);
if (var == "SYSTEM_STATUS")
return String(sSystem_Status_txt[globals.systemStatus]);
if (var == "SW_VERSION")
{
char buffer[6];
snprintf(buffer, sizeof(buffer), "%d.%02d", constants.FW_Version_major, constants.FW_Version_minor);
return String(buffer);
}
if (var == "FS_VERSION")
return String(globals.FlashVersion);
if (var == "GIT_REV")
return String(constants.GitHash);
if (var == "SHOW_DTC_TABLE")
return globals.systemStatus == sysStat_Error ? "" : "hidden";
if (var == "SHOW_RESP_MESSAGE")
return StatusResponseMessage_Type != RESPMSG_HIDE ? "" : "hidden";
if (var == "RESP_MESSAGE_TYPE")
{
switch (StatusResponseMessage_Type)
{
case RESPMSG_SUCCESS:
return "success";
case RESPMSG_INFO:
return "info";
case RESPMSG_WARNING:
return "warning";
case RESPMSG_DANGER:
return "danger";
default:
return "info";
}
}
if (var == "RESP_MESSAGE")
return String(StatusResponseMessage);
if (var == "BAT_REMAIN_CAPACITY")
return String(globals.battery_level);
if (var == "DEVICE_NAME")
if (var == "DEVICENAME")
return String(globals.DeviceName);
if (var == "DEVICENAME_ID")
return String(globals.DeviceName_ID);
if (var == "BATTERY_TYPE")
return String(ConfigData.batteryType);
if (var == "BAT_VOLTAGE")
return String((float)globals.loadvoltage_mV / 1000.0);
if (var == "PERSISTANCE_CHECKSUM")
{
char buffer[7];
sprintf(buffer, "0x%04X", PersistenceData.checksum);
return String(buffer);
}
if (var == "WRITE_CYCLE_COUNT")
return String(PersistenceData.writeCycleCounter);
if (var == "PERSISTENCE_MARKER")
return String(globals.eePersistanceAdress);
if (var == "EEPROM_VERSION")
return String(ConfigData.EEPROM_Version);
if (var == "CONFIG_CHECKSUM")
{
char buffer[7];
sprintf(buffer, "0x%04X", ConfigData.checksum);
return String(buffer);
}
if (var == "DTC_TABLE")
{
String temp;
String temp = "";
char buff_timestamp[16]; // Format: DD-hh:mm:ss:xxx
for (uint32_t i = 0; i < MAX_DTC_STORAGE; i++)
{
if (DTCStorage[i].Number > 0)
if (DTCStorage[i].Number < DTC_LAST_DTC)
{
sprintf(buff_timestamp, "%02d-%02d:%02d:%02d:%03d",
DTCStorage[i].timestamp / 86400000, // Days
@@ -116,8 +124,23 @@ String processor(const String &var)
DTCStorage[i].timestamp / 1000 % 60, // Seconds
DTCStorage[i].timestamp % 1000); // milliseconds
temp = "<tr><td>" + String(buff_timestamp);
temp = temp + "<tr data-dtc=" + String(DTCStorage[i].Number);
temp = temp + " data-debugval=" + String(DTCStorage[i].debugVal) + "><td>" + String(buff_timestamp);
temp = temp + "</td><td>" + String(DTCStorage[i].Number) + "</td><td>";
temp = temp + "<img src=static/img/";
switch (DTCStorage[i].severity)
{
case DTC_CRITICAL:
temp = temp + "critical";
break;
case DTC_WARN:
temp = temp + "warn";
break;
case DTC_INFO:
temp = temp + "info";
break;
}
temp = temp + ".png></td><td>";
if (DTCStorage[i].active == DTC_ACTIVE)
temp = temp + "active";
@@ -156,39 +179,41 @@ String processor(const String &var)
return String(buff);
}
if (var == "STATUS_FAC_1")
return PersistenceData.activeFaction == FACTION_1 ? "ACTIVE" : "INACTIVE";
if (var == "ACTIVE_FACTION")
return String(PersistenceData.activeFaction);
if (var == "STATUS_FAC_2")
return PersistenceData.activeFaction == FACTION_2 ? "ACTIVE" : "INACTIVE";
if (var == "STATUS_FAC_3")
return PersistenceData.activeFaction == FACTION_3 ? "ACTIVE" : "INACTIVE";
if (var == "FACTION_1_ACTIVE")
return String(PersistenceData.activeFaction == FACTION_1 ? "bg-primary" : "bg-secondary");
if (var == "FACTION_2_ACTIVE")
return String(PersistenceData.activeFaction == FACTION_2 ? "bg-primary" : "bg-secondary");
if (var == "FACTION_3_ACTIVE")
return String(PersistenceData.activeFaction == FACTION_3 ? "bg-primary" : "bg-secondary");
if (var == "NAME_FAC_1")
return FACTION_1_NAME;
return String(ConfigData.Faction_1_Name);
if (var == "NAME_FAC_2")
return FACTION_2_NAME;
return String(ConfigData.Faction_2_Name);
if (var == "NAME_FAC_3")
return FACTION_3_NAME;
return String(ConfigData.Faction_3_Name);
if (var == "TITLE")
return DEVICE_NAME;
if (var == "BATTERY_SELECT_OPTIONS")
{
String temp;
for (uint32_t i = 0; i < BatteryString_Elements; i++)
{
String selected = ConfigData.batteryType == i ? " selected " : "";
temp = temp + "<option value=\"" + i + "\"" + selected + ">" + BatteryString[i] + "</option>";
}
return temp;
}
if (var == "BATTERY_LEVEL")
{
return String(globals.battery_level);
}
if (var == "BATTERY_TYPE")
{
return String(BatteryString[ConfigData.batteryType]);
}
if (var == "BATTERY_VOLTAGE")
{
return String((float)globals.loadvoltage_mV / 1000.0);
}
if (var == "FACTIONREBOOT_CHECKED")
return String(ConfigData.active_faction_on_reboot == true ? "checked" : "");
if (var == "FACTION_RECOVERY")
return String(ConfigData.active_faction_on_reboot);
return String();
}
@@ -196,19 +221,84 @@ String processor(const String &var)
void Webserver_Callback(AsyncWebServerRequest *request)
{
request->send(LittleFS, "/index.htm", "text/html", false, processor);
StatusResponseMessage_Type = RESPMSG_HIDE;
}
void WebserverPOST_Callback(AsyncWebServerRequest *request)
{
request->send(LittleFS, "/post.htm", "text/html", false, processor);
Debug_pushMessage("POST:\n");
int paramsNr = request->params();
for (int i = 0; i < paramsNr; i++)
{
AsyncWebParameter *p = request->getParam(i);
if (p->name() == "commandInput")
WebserverCommands_Callback(p->value());
Debug_pushMessage("%s : %s\n", p->name().c_str(), p->value().c_str());
// begin: POST Form Maintenance
if (p->name() == "reset_ee_btn")
{
if (request->hasParam("reset_ee_pds", true))
{
AsyncWebParameter *param = request->getParam("reset_ee_pds", true);
if (param->value() == "on")
globals.requestEEAction = globals.requestEEAction == EE_CFG_FORMAT ? EE_FORMAT_ALL : EE_PDS_FORMAT;
}
if (request->hasParam("reset_ee_cfg", true))
{
AsyncWebParameter *param = request->getParam("reset_ee_cfg", true);
if (param->value() == "on")
globals.requestEEAction = globals.requestEEAction == EE_PDS_FORMAT ? EE_FORMAT_ALL : EE_CFG_FORMAT;
}
}
if (p->name() == "reboot")
{
globals.systemStatus = sysStat_Shutdown;
}
if (p->name() == "resetpoints")
{
PersistenceData.faction_1_timer = 0;
PersistenceData.faction_2_timer = 0;
PersistenceData.faction_3_timer = 0;
PersistenceData.activeFaction = NONE;
globals.requestEEAction == EE_PDS_SAVE;
}
// end: POST Form Maintenance
// begin: POST Form Settings
if (p->name() == "battery_select")
{
batteryType_t temp = (batteryType_t)p->value().toInt();
ConfigData.batteryType = temp;
}
if (request->hasParam("factionreboot_cont", true))
{
AsyncWebParameter *param = request->getParam("factionreboot_cont", true);
if (param->value() == "on")
ConfigData.active_faction_on_reboot = true;
}
else
{
ConfigData.active_faction_on_reboot = false;
}
if (p->name() == "faction_1_name")
{
strncpy(ConfigData.Faction_1_Name, p->value().c_str(), sizeof(ConfigData.Faction_1_Name));
}
if (p->name() == "faction_2_name")
{
strncpy(ConfigData.Faction_2_Name, p->value().c_str(), sizeof(ConfigData.Faction_2_Name));
}
if (p->name() == "faction_3_name")
{
strncpy(ConfigData.Faction_3_Name, p->value().c_str(), sizeof(ConfigData.Faction_3_Name));
}
if (p->name() == "settingssave")
globals.requestEEAction = EE_CFG_SAVE;
// end: POST Form Settings
}
request->send(LittleFS, "/index.htm", "text/html", false, processor);
}
void WebserverNotFound_Callback(AsyncWebServerRequest *request)
@@ -216,41 +306,6 @@ void WebserverNotFound_Callback(AsyncWebServerRequest *request)
request->send(404, "text/html", "Not found");
}
void WebserverCommands_Callback(String input)
{
String command = input.substring(0, input.indexOf(' '));
command.toUpperCase();
StatusResponseMessage_Type = RESPMSG_HIDE;
if (command == "RESET")
{
strcpy(StatusResponseMessage, "Counter Reset done");
StatusResponseMessage_Type = RESPMSG_SUCCESS;
PersistenceData.faction_1_timer = 0;
PersistenceData.faction_2_timer = 0;
PersistenceData.faction_3_timer = 0;
PersistenceData.activeFaction = NONE;
}
else if (command == "BAT3S")
{
strcpy(StatusResponseMessage, "Set BatteryType to LiPo 3S");
StatusResponseMessage_Type = RESPMSG_SUCCESS;
ConfigData.batteryType = BATTERY_LIPO_3S;
globals.requestEEAction = EE_CFG_SAVE;
}
else if (command == "BAT2S")
{
strcpy(StatusResponseMessage, "Set BatteryType to LiPo 2S");
StatusResponseMessage_Type = RESPMSG_SUCCESS;
ConfigData.batteryType = BATTERY_LIPO_2S;
globals.requestEEAction = EE_CFG_SAVE;
}
}
void GetFlashVersion(char *buff, size_t buff_size)
{
File this_file = LittleFS.open("version", "r");
@@ -273,7 +328,7 @@ void WebserverFirmwareUpdate_Callback(AsyncWebServerRequest *request, const Stri
if (!index)
{
Serial.println("Update");
Debug_pushMessage("Update");
size_t content_len = request->contentLength();
int cmd = (filename.indexOf(".fs") > -1) ? U_FS : U_FLASH;
Update.runAsync(true);
@@ -289,7 +344,7 @@ void WebserverFirmwareUpdate_Callback(AsyncWebServerRequest *request, const Stri
}
else
{
Serial.printf("Progress: %d%%\n", (Update.progress() * 100) / Update.size());
Debug_pushMessage("Progress: %d%%\n", (Update.progress() * 100) / Update.size());
}
if (final)
@@ -304,8 +359,7 @@ void WebserverFirmwareUpdate_Callback(AsyncWebServerRequest *request, const Stri
}
else
{
Serial.println("Update complete");
Serial.flush();
Debug_pushMessage("Update complete\n");
globals.systemStatus = sysStat_Shutdown;
}
}
@@ -313,31 +367,71 @@ void WebserverFirmwareUpdate_Callback(AsyncWebServerRequest *request, const Stri
void WebserverEERestore_Callback(AsyncWebServerRequest *request, const String &filename, size_t index, uint8_t *data, size_t len, bool final)
{
bool ee_done = false;
bool validext = false;
static bool validext = false;
static char *buffer = NULL;
static uint32_t read_ptr = 0;
DeserializationError error;
if (!index)
{
Serial.println("EEPROM restore");
validext = (filename.indexOf(".ee.json") > -1);
if (validext)
{
buffer = (char *)malloc(1536);
read_ptr = 0;
if (buffer == NULL)
Debug_pushMessage("malloc() failed for EEPROM-Restore");
}
}
if (validext)
if (buffer != NULL)
{
Serial.println("Restoring EEPROM-Stuff");
memcpy(buffer + read_ptr, data, len);
read_ptr = read_ptr + len;
}
if (final)
{
if (buffer != NULL)
{
Serial.print(buffer);
StaticJsonDocument<1536> doc;
error = deserializeJson(doc, buffer);
if (error)
{
Debug_pushMessage("deserializeJson() failed: %s\n", error.f_str());
}
else
{
ConfigData.batteryType = (batteryType_t)doc["config"]["batteryType"].as<uint32_t>();
ConfigData.EEPROM_Version = doc["config"]["EEPROM_Version"].as<uint32_t>();
strncpy(ConfigData.Faction_1_Name, doc["config"]["Faction_1_Name"].as<String>().c_str(), sizeof(ConfigData.Faction_1_Name));
strncpy(ConfigData.Faction_2_Name, doc["config"]["Faction_2_Name"].as<String>().c_str(), sizeof(ConfigData.Faction_2_Name));
strncpy(ConfigData.Faction_3_Name, doc["config"]["Faction_3_Name"].as<String>().c_str(), sizeof(ConfigData.Faction_3_Name));
PersistenceData.writeCycleCounter = doc["persis"]["writeCycleCounter"].as<uint16_t>();
PersistenceData.activeFaction = (factions_t)doc["persis"]["activeFaction"].as<uint32_t>();
PersistenceData.faction_1_timer = doc["persis"]["faction_1_timer"].as<uint32_t>();
PersistenceData.faction_2_timer = doc["persis"]["faction_2_timer"].as<uint32_t>();
PersistenceData.faction_3_timer = doc["persis"]["faction_3_timer"].as<uint32_t>();
PersistenceData.checksum = doc["persis"]["checksum"].as<uint32_t>();
ee_done = true;
}
}
free(buffer);
AsyncWebServerResponse *response = request->beginResponse(302, "text/plain", "Please wait while the device reboots");
response->addHeader("Refresh", "20");
response->addHeader("Location", "/");
request->send(response);
if (ee_done)
{
Serial.println("Update complete");
Serial.flush();
Debug_pushMessage("Update complete");
globals.systemStatus = sysStat_Shutdown;
}
else
@@ -355,13 +449,19 @@ void WebServerEEJSON_Callback(AsyncWebServerRequest *request)
char buffer[16];
fwinfo["DeviceName"] = globals.DeviceName;
fwinfo["FW-Version"] = QUOTE(SW_VERSION);
sprintf(buffer, "%d.%02d", constants.Required_Flash_Version_major, constants.Required_Flash_Version_minor);
fwinfo["FW-Version"] = buffer;
fwinfo["FS-Version"] = globals.FlashVersion;
snprintf_P(buffer, sizeof(buffer), "%s", constants.GitHash);
fwinfo["Git-Hash"] = buffer;
JsonObject config = json.createNestedObject("config");
config["EEPROM_Version"] = ConfigData.EEPROM_Version;
config["batteryType"] = ConfigData.batteryType;
config["Faction_1_Name"] = ConfigData.Faction_1_Name;
config["Faction_2_Name"] = ConfigData.Faction_2_Name;
config["Faction_3_Name"] = ConfigData.Faction_3_Name;
sprintf(buffer, "0x%08X", ConfigData.checksum);
config["checksum"] = buffer;
@@ -373,7 +473,10 @@ void WebServerEEJSON_Callback(AsyncWebServerRequest *request)
JsonObject persis = json.createNestedObject("persis");
persis["writeCycleCounter"] = PersistenceData.writeCycleCounter;
persis["activeFaction"] = PersistenceData.activeFaction;
persis["faction_1_timer"] = PersistenceData.faction_1_timer;
persis["faction_2_timer"] = PersistenceData.faction_2_timer;
persis["faction_3_timer"] = PersistenceData.faction_3_timer;
sprintf(buffer, "0x%08X", PersistenceData.checksum);
persis["checksum"] = buffer;
@@ -382,4 +485,52 @@ void WebServerEEJSON_Callback(AsyncWebServerRequest *request)
response->addHeader("Content-disposition", "attachment; filename=backup.ee.json");
request->send(response);
}
void WebsocketEvent_Callback(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len)
{
switch (type)
{
case WS_EVT_CONNECT:
Debug_pushMessage("WebSocket client #%u connected from %s\n", client->id(), client->remoteIP().toString().c_str());
break;
case WS_EVT_DISCONNECT:
Debug_pushMessage("WebSocket client #%u disconnected\n", client->id());
break;
case WS_EVT_DATA:
Websocket_HandleMessage(arg, data, len);
break;
case WS_EVT_PONG:
case WS_EVT_ERROR:
break;
}
}
void Websocket_HandleMessage(void *arg, uint8_t *data, size_t len)
{
AwsFrameInfo *info = (AwsFrameInfo *)arg;
if (info->final && info->index == 0 && info->len == len && info->opcode == WS_TEXT)
{
data[len] = 0;
Debug_pushMessage("Got WebSocket Message: %s \n", (char *)data);
if (strcmp((char *)data, "start") == 0)
{
SetDebugportStatus(dbg_Webui, enabled);
}
else if (strcmp((char *)data, "stop") == 0)
{
SetDebugportStatus(dbg_Webui, disabled);
}
else if (strcmp((char *)data, "foo") == 0)
{
Debug_pushMessage("Got WebSocket Message 'foo' from client\n");
}
}
}
void Websocket_PushLiveDebug(String Message)
{
webSocket.textAll(Message + "\n");
}

View File

@@ -1,5 +1,6 @@
[wifi_cred]
wifi_ap_ssid = wifi-ap-ssid
wifi_ap_password = wifiappass
wifi_ssid = wifi-ssid
wifi_password = wifi-pass
admin_password = ota-password
wifi_client_ssid = wifi-ssid
wifi_client_password = wifi-pass
ota_password = ota-password