48 Commits

Author SHA1 Message Date
1cf0560957 updated FW Version Number 2024-05-01 20:42:34 +02:00
b66d175948 Fixed Bug in LoRa Uart Parser, because I'm stupid 2024-05-01 20:35:09 +02:00
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
52 changed files with 18711 additions and 4552 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

View File

@@ -3,198 +3,564 @@
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<title>%DEVICE_NAME%</title> <title>%DEVICENAME%</title>
<meta http-equiv="content-type" content="text/html;charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <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/bootstrap.min.css">
<link rel="stylesheet" href="static/css/custom.css"> <link rel="stylesheet" href="static/css/custom.css">
<script src="static/js/jquery-3.3.1.min.js"></script> <link rel="stylesheet" href="static/css/tweaks.css">
<script src="static/js/bootstrap.bundle.min.js"></script> <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="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="32x32" href="static/img/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="static/img/favicon-16x16.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="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> </head>
<body> <body>
<header class="sticky-top">
<nav class="navbar navbar-expand-sm navbar-dark bg-dark">
<nav class="navbar fixed-top navbar-dark bg-primary" id="navbar1">
<a class="navbar-brand" href="#"> <a class="navbar-brand" href="#">
<img src="static/img/logo.png" width="30" height="30" class="d-inline-block align-top" alt=""> <img src="static/img/logo.png" width="30" height="30" class="d-inline-block align-top mr-1" alt="">
%DEVICE_NAME%</a> %DEVICENAME%
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNavAltMarkup" </a>
aria-controls="navbarNavAltMarkup" aria-expanded="false" aria-label="Toggle navigation"> <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> <span class="navbar-toggler-icon"></span>
</button> </button>
<div class="collapse navbar-collapse" id="collapsingNavbar">
<ul class="navbar-nav nav mr-auto mt-2 mt-lg-0">
<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>
<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> </ul>
</div> </div>
</nav> </nav>
</header>
<main class="container-fluid py-3 flex-fill"> <main class="container">
<!-- Tabs Content --> <!-- Tabs Content -->
<div class="tab-content"> <div class="tab-content">
<!-- Div Tab Home--> <!-- Div Tab Home-->
<div class="tab-pane fade show active" id="tab_home" role="tabpanel"> <div id="tab_home" class="tab-pane fade show active" role="tabpanel">
<!-- Jumbotron --> <div class="col text-center">
<div class="jumbotron text-center"> <div class="jumbotron">
<p class="p-4"> <img src="static/img/logo.png" width="120" height="120" class="img-fluid" alt="">
<img src="static/img/logo.png"> <h3 class="pt-3">%DEVICENAME%</h3>
</p>
<h3>%DEVICE_NAME%</h3>
</div> </div>
<!-- AlertMessageBox-->
<div id="responseMessage" class="alert alert-%RESP_MESSAGE_TYPE%" %SHOW_RESP_MESSAGE%>
%RESP_MESSAGE%
</div> </div>
<div class="container-fluid pb-5"> <!-- Div Group Battery remain -->
<h4>BATTERY: %BATTERY_TYPE%</h4> <hr />
<p>
<h4>Akku Ladestand</h4>
<div class="progress"> <div class="progress">
<div class="progress-bar text-light" role="progressbar" aria-valuenow="%BAT_REMAIN_CAPACITY%" <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;"> aria-valuemin="0" aria-valuemax="100" style="width: %BAT_REMAIN_CAPACITY%&#37;">
%BAT_REMAIN_CAPACITY%&#37; / %BAT_VOLTAGE% V %BAT_REMAIN_CAPACITY%&#37;
</div> </div>
</div> </div>
</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>
<div class="container-fluid pb-5"> <div class="row">
<h4>FACTIONS</h4> <div class="col bg-dark text-white p-3"><img src="static/img/logo_fac1.png"
<div class="table-responsive"> class="rounded mx-auto img-fluid d-block" alt="...">
<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> </div>
</a> <div class="col bg-dark text-white p-3"><img src="static/img/logo_fac2.png"
</td> class="rounded mx-auto img-fluid d-block" alt="...">
<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> </div>
</a> <div class="col bg-dark text-white p-3"><img src="static/img/logo_fac3.png"
</td> class="rounded mx-auto img-fluid d-block" alt="...">
<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> </div>
</div> </div>
<div class="container-fluid pb-5" %SHOW_DTC_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>
</p>
<!-- Div GroupFaction Points -->
<!-- Div Group DTC Table -->
<div %SHOW_DTC_TABLE%>
<hr />
<p>
<h4>Fehlercodes</h4> <h4>Fehlercodes</h4>
<table class="table text-light"> <table class="table">
<tbody> <tbody>
<tr> <tr>
<th class="col-md-4" scope="col">Timestamp</td> <th class="col-6" scope="col">Zeitstempel</th>
<th class="col-md-4" scope="col">DTC</td> <th class="col-2" scope="col">Fehlercode</th>
<th class="col-md-4" scope="col">active</td> <th class="col-2" scope="col">Schwere</th>
<th class="col-2" scope="col">Aktiv</th>
</tr> </tr>
%DTC_TABLE% %DTC_TABLE%
</tbody> </tbody>
</table> </table>
</p>
</div> </div>
<!-- Div Group DTC Table -->
</div> </div>
<!-- Div Tab Home--> <!-- Div Tab Home-->
<!-- Div Tab Settings-->
<div class="tab-pane fade" id="tab_settings" role="tabpanel"> <!-- Div Tab Maintenance -->
<h3>Settings</h3> <div id="tab_maintenance" class="tab-pane fade" role="tabpanel">
<hr> <h3>Wartung</h3>
<form method="POST"> <!-- 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"> <div class="form-group row">
<label for="commandInput" class="col-sm-2 col-form-label">Command</label> <div class="col text-center">
<div class="col-sm-10"> <button name="resetpoints" type="submit" class="btn btn-outline-primary">Reset</button>
<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> </div>
</div> </div>
</form> </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> </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 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> </div>
<!-- Tabs Content --> <!-- Tabs Content -->
</main> </main>
<!-- Footer --> <!-- 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>
<!-- 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> </body>
</html> </html>

View File

@@ -3,7 +3,7 @@
<head> <head>
<meta charset="utf-8" /> <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 http-equiv="content-type" content="text/html;charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <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/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="32x32" href="static/img/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="static/img/favicon-16x16.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="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> </head>
<body> <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

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,7 +13,7 @@
#define HOST_NAME "AirsoftTimer_%08X" #define HOST_NAME "AirsoftTimer_%08X"
#define SHUTDOWN_DELAY_MS 5000 #define SHUTDOWN_DELAY_MS 5000
#define RESETABLE_AFTER_STARTUP_MS 30000 #define STARTUP_DELAY_MS 20000
#define GPIO_LORA_TX D3 #define GPIO_LORA_TX D3
#define GPIO_LORA_RX D4 #define GPIO_LORA_RX D4
@@ -40,28 +40,10 @@
#define I2C_POWER_ADDRESS 0x40 #define I2C_POWER_ADDRESS 0x40
#define I2C_EEPROM_ADDRESS 0x50 #define I2C_EEPROM_ADDRESS 0x50
#define SW_VERSION 1.0
#define FLASH_FS_VERSION 1.0
#ifndef OTA_DELAY #ifndef OTA_DELAY
#define OTA_DELAY 50 // ticks -> 10ms / tick #define OTA_DELAY 50 // ticks -> 10ms / tick
#endif #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_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
#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> #include <Arduino.h>
#define MAX_DTC_STORAGE 6 #define MAX_DTC_STORAGE 12
typedef enum DTCNums_e typedef enum DTCNums_e
{ {
DTC_NO_EEPROM_FOUND, DTC_NO_EEPROM_FOUND = 1,
DTC_EEPROM_CFG_BAD, DTC_EEPROM_CFG_BAD,
DTC_EEPROM_PDS_BAD, DTC_EEPROM_PDS_BAD,
DTC_EEPROM_PDSADRESS_BAD, DTC_EEPROM_PDSADRESS_BAD,
@@ -17,14 +17,17 @@ typedef enum DTCNums_e
DTC_EEPROM_CFG_SANITY, DTC_EEPROM_CFG_SANITY,
DTC_NO_LORA_FOUND, DTC_NO_LORA_FOUND,
DTC_NO_BATMNON_FOUND, DTC_NO_BATMNON_FOUND,
DTC_BAT_LOW,
DTC_BAT_CRITICAL,
DTC_EEPROM_MIGRATE_FAILED,
DTC_LAST_DTC DTC_LAST_DTC
} DTCNums_t; } DTCNums_t;
typedef enum DTCActive_e typedef enum DTCActive_e
{ {
DTC_NONE,
DTC_ACTIVE, DTC_ACTIVE,
DTC_PREVIOUS, DTC_PREVIOUS
DTC_NONE
} DTCActive_t; } DTCActive_t;
typedef enum DTCSeverity_e typedef enum DTCSeverity_e
@@ -48,6 +51,7 @@ void ClearDTC(DTCNums_t DTC_no);
void ClearAllDTC(); void ClearAllDTC();
DTCNums_t getlastDTC(boolean only_active); DTCNums_t getlastDTC(boolean only_active);
DTCNums_t getlastDTC_Severity(boolean only_active, DTCSeverity_t severity); DTCNums_t getlastDTC_Severity(boolean only_active, DTCSeverity_t severity);
void DTC_Process();
extern DTCEntry_s DTCStorage[MAX_DTC_STORAGE]; extern DTCEntry_s DTCStorage[MAX_DTC_STORAGE];
#endif #endif

View File

@@ -1,5 +1,5 @@
#ifndef _CONFIG_H_ #ifndef _EEPROM_H_
#define _CONFIG_H_ #define _EEPROM_H_
#include <Arduino.h> #include <Arduino.h>
#include <Wire.h> #include <Wire.h>
@@ -8,8 +8,10 @@
#include "globals.h" #include "globals.h"
#include "dtc.h" #include "dtc.h"
#include "common.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 #define EEPROM_ENDURANCE 1000000
typedef enum typedef enum
@@ -30,6 +32,7 @@ typedef struct
uint32_t checksum = 0; uint32_t checksum = 0;
} persistenceData_t; } persistenceData_t;
extern persistenceData_t PersistenceData;
typedef enum typedef enum
{ {
BATTERY_UNDEFINED, BATTERY_UNDEFINED,
@@ -40,20 +43,36 @@ typedef enum
const char BatteryString[][10]{ const char BatteryString[][10]{
"Undefined", "Undefined",
"LiPo 2S", "LiPo 2S",
"LiPo 3S" "LiPo 3S"};
};
const size_t BatteryString_Elements = sizeof(BatteryString) / sizeof(BatteryString[0]);
typedef struct typedef struct
{ {
uint8_t EEPROM_Version = 1; uint8_t EEPROM_Version;
batteryType_t batteryType = BATTERY_UNDEFINED; batteryType_t batteryType;
uint32_t checksum = 0; 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; } configData_t;
extern configData_t ConfigData;
const configData_t ConfigData_defaults = { 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 InitEEPROM();
void EEPROM_Process(); void EEPROM_Process();
void StoreConfig_EEPROM(); void StoreConfig_EEPROM();
@@ -67,6 +86,4 @@ void dumpEEPROM(uint16_t memoryAddress, uint16_t length);
void MovePersistencePage_EEPROM(boolean reset); void MovePersistencePage_EEPROM(boolean reset);
uint32_t ConfigSanityCheck(bool autocorrect = false); uint32_t ConfigSanityCheck(bool autocorrect = false);
extern configData_t ConfigData; #endif // _EEPROM_H_
extern persistenceData_t PersistenceData;
#endif // _CONFIG_H_

View File

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

View File

@@ -2,10 +2,16 @@
#define _LORA_NET_H_ #define _LORA_NET_H_
#include <Arduino.h> #include <Arduino.h>
#ifdef LORA_FEATURE_ENABLED
#include <LoRa_E220.h> #include <LoRa_E220.h>
#elif defined(FEATURE_ENABLE_UARTLORA)
#include <SoftwareSerial.h>
#endif
// local includes // local includes
#include "lora_messages.h" #include "lora_messages.h"
#include "debugger.h"
#include "defaults.h" #include "defaults.h"
#include "config.h" #include "config.h"
#include "globals.h" #include "globals.h"

View File

@@ -6,7 +6,7 @@
#include <Adafruit_GFX.h> #include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h> #include <Adafruit_SSD1306.h>
#include "globals.h" #include "globals.h"
#include "config.h" #include "eeprom.h"
#define OLED_SDA 4 #define OLED_SDA 4
#define OLED_SCL 15 #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 <AsyncJson.h>
#include <ArduinoJson.h> #include <ArduinoJson.h>
#include "config.h" #include "eeprom.h"
#include "globals.h" #include "globals.h"
#include "dtc.h" #include "dtc.h"
#include "common.h" #include "common.h"
#include "debugger.h"
void initWebUI(); void initWebUI();
void Webserver_Process();
void Websocket_PushLiveDebug(String Message);
#endif #endif

View File

@@ -22,23 +22,22 @@ upload_speed = 921600
;upload_port = 10.0.1.48 ;upload_port = 10.0.1.48
;upload_protocol = espota ;upload_protocol = espota
;upload_flags = ;upload_flags =
; --auth=${wifi_cred.admin_password} ; --auth=${wifi_cred.ota_password}
build_flags= build_flags=
!python git_rev_macro.py !python git_rev_macro.py
-DATOMIC_FS_UPDATE -DATOMIC_FS_UPDATE
;-DFEATURE_ENABLE_WIFI_CLIENT ;-DFEATURE_ENABLE_WIFI_CLIENT
;-DFEATURE_ENABLE_LORA
;-DCAPTIVE ;-DCAPTIVE
-DWIFI_AP_IP_GW=10,0,1,1 -DFEATURE_ENABLE_UARTLORA
-DADMIN_PASSWORD=${wifi_cred.admin_password} -DWIFI_AP_IP_GW=10,0,0,1
-DWIFI_SSID=${wifi_cred.wifi_ssid} -DADMIN_PASSWORD=${wifi_cred.ota_password}
-DWIFI_PASSWORD=${wifi_cred.wifi_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_SSID=${wifi_cred.wifi_ap_ssid}
-DWIFI_AP_PASSWORD=${wifi_cred.wifi_ap_password} -DWIFI_AP_PASSWORD=${wifi_cred.wifi_ap_password}
-DDEVICE_NAME='"Dark Emergency Timer"' -DDEVICE_NAME='"Dark Emergency Timer"'
-DFACTION_1_NAME='"GOF"'
-DFACTION_2_NAME='"MILIZ"'
-DFACTION_3_NAME='"KGG"'
;build_type = debug ;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 "dtc.h"
#include "debugger.h"
DTCEntry_s DTCStorage[MAX_DTC_STORAGE]; 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) 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].timestamp = millis();
DTCStorage[i].active = DTC_ACTIVE; DTCStorage[i].active = DTC_ACTIVE;
DTCStorage[i].severity = DTC_severity; 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) 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; DTCStorage[i].active = DTC_PREVIOUS;
} }
return; 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) 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].Number = DTC_no;
DTCStorage[i].timestamp = millis(); DTCStorage[i].timestamp = millis();
DTCStorage[i].active = DTC_ACTIVE; DTCStorage[i].active = DTC_ACTIVE;
DTCStorage[i].debugVal = DebugValue; DTCStorage[i].debugVal = DebugValue;
DTCStorage[i].severity = DTC_severity;
return; return;
} }
} }
@@ -106,3 +108,32 @@ DTCNums_t getlastDTC_Severity(boolean only_active, DTCSeverity_t severity)
return pointer >= 0 ? DTCStorage[pointer].Number : DTC_LAST_DTC; 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; configData_t ConfigData;
persistenceData_t PersistenceData; persistenceData_t PersistenceData;
const uint16_t eeVersion = 1; // inc bool eeAvailable = false;
boolean eeAvailable = false;
const uint16_t startofConfigData = 16; bool checkEEPROMavailable();
const uint16_t startofPersistence = 16 + sizeof(ConfigData) + (sizeof(ConfigData) % 16); bool ValidateEEPROM_Version();
bool MigrateEEPROM(uint8_t fromVersion);
boolean checkEEPROMavailable();
void InitEEPROM() void InitEEPROM()
{ {
ee.begin(); ee.begin();
checkEEPROMavailable(); eeAvailable = checkEEPROMavailable();
eeAvailable = ValidateEEPROM_Version();
Serial.printf("Initialized EEPROM at Address 0x%02X\n", I2C_EE_ADDRESS);
} }
void EEPROM_Process() void EEPROM_Process()
{ {
if (eeAvailable == false)
return;
switch (globals.requestEEAction) switch (globals.requestEEAction)
{ {
case EE_CFG_SAVE: case EE_CFG_SAVE:
@@ -73,17 +76,18 @@ void EEPROM_Process()
void StoreConfig_EEPROM() void StoreConfig_EEPROM()
{ {
if (eeAvailable == false)
return;
ConfigData.checksum = 0; ConfigData.checksum = 0;
ConfigData.checksum = Checksum_EEPROM((uint8_t *)&ConfigData, sizeof(ConfigData)); ConfigData.checksum = Checksum_EEPROM((uint8_t *)&ConfigData, sizeof(ConfigData));
if (!checkEEPROMavailable())
return;
ee.updateBlock(startofConfigData, (uint8_t *)&ConfigData, sizeof(ConfigData)); ee.updateBlock(startofConfigData, (uint8_t *)&ConfigData, sizeof(ConfigData));
} }
void GetConfig_EEPROM() void GetConfig_EEPROM()
{ {
if (!checkEEPROMavailable()) if (eeAvailable == false)
return; return;
ee.readBlock(startofConfigData, (uint8_t *)&ConfigData, sizeof(ConfigData)); ee.readBlock(startofConfigData, (uint8_t *)&ConfigData, sizeof(ConfigData));
@@ -108,6 +112,9 @@ void GetConfig_EEPROM()
void StorePersistence_EEPROM() void StorePersistence_EEPROM()
{ {
if (eeAvailable == false)
return;
if (PersistenceData.writeCycleCounter >= 0xFFF0) if (PersistenceData.writeCycleCounter >= 0xFFF0)
MovePersistencePage_EEPROM(false); MovePersistencePage_EEPROM(false);
else else
@@ -116,15 +123,12 @@ void StorePersistence_EEPROM()
PersistenceData.checksum = 0; PersistenceData.checksum = 0;
PersistenceData.checksum = Checksum_EEPROM((uint8_t *)&PersistenceData, sizeof(PersistenceData)); PersistenceData.checksum = Checksum_EEPROM((uint8_t *)&PersistenceData, sizeof(PersistenceData));
if (!checkEEPROMavailable())
return;
ee.updateBlock(globals.eePersistanceAdress, (uint8_t *)&PersistenceData, sizeof(PersistenceData)); ee.updateBlock(globals.eePersistanceAdress, (uint8_t *)&PersistenceData, sizeof(PersistenceData));
} }
void GetPersistence_EEPROM() void GetPersistence_EEPROM()
{ {
if (!checkEEPROMavailable()) if (eeAvailable == false)
return; return;
ee.readBlock(0, (uint8_t *)&globals.eePersistanceAdress, sizeof(globals.eePersistanceAdress)); ee.readBlock(0, (uint8_t *)&globals.eePersistanceAdress, sizeof(globals.eePersistanceAdress));
@@ -153,22 +157,29 @@ void GetPersistence_EEPROM()
void FormatConfig_EEPROM() void FormatConfig_EEPROM()
{ {
if (eeAvailable == false)
return;
Serial.println("Formatting Config-Partition"); Serial.println("Formatting Config-Partition");
ConfigData = ConfigData_defaults; ConfigData = ConfigData_defaults;
ConfigData.EEPROM_Version = eeVersion;
StoreConfig_EEPROM(); StoreConfig_EEPROM();
GetConfig_EEPROM();
} }
void FormatPersistence_EEPROM() void FormatPersistence_EEPROM()
{ {
if (eeAvailable == false)
return;
Serial.println("Formatting Persistance-Partition"); Serial.println("Formatting Persistance-Partition");
memset(&PersistenceData, 0, sizeof(PersistenceData)); PersistenceData = {0};
StorePersistence_EEPROM(); StorePersistence_EEPROM();
GetPersistence_EEPROM();
} }
void MovePersistencePage_EEPROM(boolean reset) void MovePersistencePage_EEPROM(boolean reset)
{ {
if (!checkEEPROMavailable()) if (eeAvailable == false)
return; return;
globals.eePersistanceAdress = +sizeof(PersistenceData); globals.eePersistanceAdress = +sizeof(PersistenceData);
@@ -206,7 +217,7 @@ void dumpEEPROM(uint16_t memoryAddress, uint16_t length)
{ {
#define BLOCK_TO_LENGTH 16 #define BLOCK_TO_LENGTH 16
if (!checkEEPROMavailable()) if (eeAvailable == false)
return; return;
char ascii_buf[BLOCK_TO_LENGTH + 1]; char ascii_buf[BLOCK_TO_LENGTH + 1];
@@ -236,15 +247,13 @@ void dumpEEPROM(uint16_t memoryAddress, uint16_t length)
Serial.println(); Serial.println();
} }
boolean checkEEPROMavailable() bool checkEEPROMavailable()
{ {
if (!ee.isConnected()) if (!ee.isConnected())
{ {
MaintainDTC(DTC_NO_EEPROM_FOUND, DTC_CRITICAL, true); MaintainDTC(DTC_NO_EEPROM_FOUND, DTC_CRITICAL, true);
globals.systemStatus = sysStat_Error;
return false; return false;
} }
MaintainDTC(DTC_NO_EEPROM_FOUND, DTC_CRITICAL, false);
return true; return true;
} }
@@ -261,3 +270,89 @@ uint32_t ConfigSanityCheck(bool autocorrect)
return setting_reset_bits; 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,13 +1,19 @@
#include "lora_net.h" #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 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 printParameters(struct Configuration configuration);
void printModuleInformation(struct ModuleInformation moduleInformation); 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
bool InitLoRa(void (*MPinHelper)(int, int)) bool InitLoRa(void (*MPinHelper)(int, int))
{ {
bool returnval; bool returnval = false;
#ifdef FEATURE_ENABLE_LORA
e220ttl.setMPins = MPinHelper; e220ttl.setMPins = MPinHelper;
returnval = e220ttl.begin(); returnval = e220ttl.begin();
@@ -60,11 +66,16 @@ bool InitLoRa(void (*MPinHelper)(int, int))
{ {
MaintainDTC(DTC_NO_LORA_FOUND, DTC_WARN, true); MaintainDTC(DTC_NO_LORA_FOUND, DTC_WARN, true);
} }
#elif defined(FEATURE_ENABLE_UARTLORA)
SerialLoRa.begin(9600);
returnval = true;
#endif
return returnval; return returnval;
} }
void LoRa_Process() void LoRa_Process()
{ {
#ifdef FEATURE_ENABLE_LORA
if (e220ttl.available() > 1) if (e220ttl.available() > 1)
{ {
ResponseContainer rc = e220ttl.receiveMessageRSSI(); ResponseContainer rc = e220ttl.receiveMessageRSSI();
@@ -82,10 +93,45 @@ void LoRa_Process()
Serial.println(rc.rssi, DEC); Serial.println(rc.rssi, DEC);
} }
} }
#elif defined(FEATURE_ENABLE_UARTLORA)
static char packageInput[32];
static bool packageRecieved = false;
static unsigned int bufferPtr = 0;
int recievedSize = 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;
recievedSize = bufferPtr;
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, recievedSize);
packageRecieved = false;
}
#endif
} }
void sendStatus_LoRa() void sendStatus_LoRa()
{ {
#ifdef FEATURE_ENABLE_LORA
struct struct
{ {
MessageType_t type = "STATUS"; MessageType_t type = "STATUS";
@@ -101,8 +147,25 @@ void sendStatus_LoRa()
ResponseStatus rs = e220ttl.sendFixedMessage(0xFF, 0xFF, 23, (byte *)&sendStatus, sizeof(sendStatus)); ResponseStatus rs = e220ttl.sendFixedMessage(0xFF, 0xFF, 23, (byte *)&sendStatus, sizeof(sendStatus));
Serial.println(rs.getResponseDescription()); 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) void printParameters(struct Configuration configuration)
{ {
Serial.println("----------------------------------------"); Serial.println("----------------------------------------");
@@ -169,3 +232,91 @@ void printParameters(struct Configuration configuration)
Serial.println("----------------------------------------"); Serial.println("----------------------------------------");
} }
#endif
#ifdef FEATURE_ENABLE_UARTLORA
void Parse_LoRa_UartCommand(char input[], int size)
{
Debug_pushMessage("Start parsing, size: %d", size);
char delimiter[] = ";";
char *ptr;
char command[8];
char value[8];
ptr = strtok(input, delimiter);
ptr = strtok(input, delimiter);
while (ptr != NULL)
{
strncpy(command, ptr, sizeof(command) - 1); // Platz für Nullterminator lassen
command[sizeof(command) - 1] = '\0'; // Nullterminator setzen
ptr = strtok(NULL, delimiter);
if (ptr != NULL)
{
strncpy(value, ptr, sizeof(value) - 1); // Platz für Nullterminator lassen
value[sizeof(value) - 1] = '\0'; // Nullterminator setzen
}
else
{
// Wenn ptr NULL ist, setze value auf leeren String
value[0] = '\0';
}
// Hier kannst du den Wert und das Kommando verarbeiten
Debug_pushMessage("Command: %s, Value: %s", command, value);
}
Debug_pushMessage("Parsed LoRa UART Command: %s Value: %s\n", command, value);
if (!strcmp(command, "ENABLE"))
{
globals.timer_disabled = false;
Debug_pushMessage("Enabled by LoRa");
}
else if (!strcmp(command, "DISABLE"))
{
globals.timer_disabled = true;
Debug_pushMessage("Disabled by LoRa");
}
else if (!strcmp(command, "RESET"))
{
PersistenceData.activeFaction = NONE;
PersistenceData.faction_1_timer = 0;
PersistenceData.faction_2_timer = 0;
PersistenceData.faction_3_timer = 0;
Debug_pushMessage("Reset by LoRa");
}
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,16 +11,17 @@
#include <ArduinoJson.h> #include <ArduinoJson.h>
// local includes // local includes
#include "common.h"
#include "sanitycheck.h"
#include "defaults.h" #include "defaults.h"
#include "webui.h" #include "webui.h"
#include "config.h" #include "config.h"
#include "globals.h" #include "globals.h"
#include "dtc.h" #include "dtc.h"
#include "common.h" #include "debugger.h"
#if defined(FEATURE_ENABLE_LORA) || defined(FEATURE_ENABLE_UARTLORA)
#include "lora_net.h" #include "lora_net.h"
#endif
#ifdef WIFI_CLIENT
#include <WiFiMulti.h>
#ifdef FEATURE_ENABLE_WIFI_CLIENT #ifdef FEATURE_ENABLE_WIFI_CLIENT
#include <ESP8266WiFiMulti.h> #include <ESP8266WiFiMulti.h>
@@ -44,12 +45,16 @@ void toggleWiFiAP(boolean shutdown = false);
void SystemShutdown(); void SystemShutdown();
void SetBatteryType(batteryType_t type); void SetBatteryType(batteryType_t type);
void ProcessKeyCombos(bool *btnState); 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 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(); void tmrCallback_StatusSender();
Ticker tmrStatusSender(tmrCallback_StatusSender, 30000, 0, MILLIS); Ticker tmrStatusSender(tmrCallback_StatusSender, 30000, 0, MILLIS);
#endif
void tmrCallback_PowerMonitor(); void tmrCallback_PowerMonitor();
Ticker tmrPowerMonitor(tmrCallback_PowerMonitor, 10000, 0, MILLIS); Ticker tmrPowerMonitor(tmrCallback_PowerMonitor, 10000, 0, MILLIS);
void tmrCallback_FactionTicker(); void tmrCallback_FactionTicker();
@@ -65,21 +70,14 @@ Ticker tmrWiFiMaintainConnection(tmrCallback_WiFiMaintainConnection, 1000, 0, MI
#endif #endif
uint32_t DisplayOverrideFlag = 0; uint32_t DisplayOverrideFlag = 0;
char DisplayOverrideValue[5] = {0}; char DisplayOverrideValue[3][5] = {0};
Globals_t globals;
void initGlobals()
{
globals.requestEEAction = EE_IDLE;
globals.resumeStatus = sysStat_Normal;
globals.systemStatus = sysStat_Startup;
}
#if defined(FEATURE_ENABLE_UARTLORA) || defined(FEATURE_ENABLE_LORA)
void setMPins_Helper(int pin, int status) void setMPins_Helper(int pin, int status)
{ {
i2c_io.write(pin, status); i2c_io.write(pin, status);
} }
#endif
void setup() void setup()
{ {
@@ -92,8 +90,9 @@ void setup()
Serial.begin(115200); Serial.begin(115200);
Serial.setDebugOutput(false); Serial.setDebugOutput(false);
Serial.println("\n\nDark Emergency Timer - by Hiabuto Defense"); Serial.print("\n\n-------------------START-------------------\n");
Serial.println(globals.DeviceName); Serial.print(globals.DeviceName);
Serial.print("\nby Hiabuto Defense\n");
ClearAllDTC(); // Init DTC-Storage ClearAllDTC(); // Init DTC-Storage
@@ -120,21 +119,24 @@ void setup()
Serial.print("INA219 not Initialized\n"); Serial.print("INA219 not Initialized\n");
} }
#if defined(FEATURE_ENABLE_UARTLORA) || defined(FEATURE_ENABLE_LORA)
if (InitLoRa(&setMPins_Helper)) if (InitLoRa(&setMPins_Helper))
{ {
Serial.printf("Initialized LoRa_Transceiver"); Serial.print("Initialized LoRa_Transceiver\n");
tmrStatusSender.start(); tmrStatusSender.start();
} }
else else
{ {
Serial.print("LoRa not Initialized\n"); Serial.print("LoRa not Initialized\n");
} }
#endif
#ifdef FEATURE_ENABLE_WIFI_CLIENT #ifdef FEATURE_ENABLE_WIFI_CLIENT
WiFi.mode(WIFI_STA); WiFi.mode(WIFI_STA);
WiFi.setHostname(globals.DeviceName); WiFi.setHostname(globals.DeviceName);
wifiMulti.addAP(QUOTE(WIFI_SSID_CLIENT), QUOTE(WIFI_PASSWORD_CLIENT)); wifiMulti.addAP(QUOTE(WIFI_CLIENT_SSID), QUOTE(WIFI_CLIENT_PASSWORD));
WiFiMaintainConnectionTicker.start(); tmrWiFiMaintainConnection.start();
Serial.print("WiFi-Client Initialized\n");
#else #else
WiFi.mode(WIFI_OFF); WiFi.mode(WIFI_OFF);
#endif #endif
@@ -183,15 +185,17 @@ void setup()
Serial.println("Receive Failed"); Serial.println("Receive Failed");
else if (error == OTA_END_ERROR) else if (error == OTA_END_ERROR)
Serial.println("End Failed"); }); 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 #ifdef CAPTIVE
dnsServer.start(53, "*", WiFi.softAPIP()); dnsServer.start(53, "*", WiFi.softAPIP());
#endif #endif
initWebUI();
initGlobals();
disp_FAC_1.init(); disp_FAC_1.init();
disp_FAC_1.setBrightness(5); disp_FAC_1.setBrightness(5);
disp_FAC_2.init(); disp_FAC_2.init();
@@ -203,31 +207,39 @@ void setup()
tmrFactionTicker.start(); tmrFactionTicker.start();
tmrInputGetter.start(); tmrInputGetter.start();
Serial.println("Setup Done"); if (ConfigData.active_faction_on_reboot == false)
PersistenceData.activeFaction = NONE;
Serial.print("\nSetup Done\n");
} }
void loop() void loop()
{ {
maintainSysStat();
tmrEEPROMCyclicPDS.update(); tmrEEPROMCyclicPDS.update();
tmrFactionTicker.update(); tmrFactionTicker.update();
tmrInputGetter.update(); tmrInputGetter.update();
tmrStatusSender.update();
tmrPowerMonitor.update(); tmrPowerMonitor.update();
ArduinoOTA.handle(); ArduinoOTA.handle();
SevenSeg_Output(); SevenSeg_Output();
EEPROM_Process(); EEPROM_Process();
Webserver_Process();
DTC_Process();
Debug_Process();
#if defined(FEATURE_ENABLE_LORA) || defined(FEATURE_ENABLE_UARTLORA)
LoRa_Process(); LoRa_Process();
tmrStatusSender.update();
#endif
#ifdef CAPTIVE #ifdef CAPTIVE
dnsServer.processNextRequest(); dnsServer.processNextRequest();
#endif #endif
#ifdef WIFI_CLIENT #ifdef FEATURE_ENABLE_WIFI_CLIENT
tmrWiFiMaintainConnection.update(); tmrWiFiMaintainConnection.update();
#endif #endif
if (globals.systemStatus == sysStat_Shutdown)
SystemShutdown();
yield(); yield();
} }
@@ -249,9 +261,9 @@ void SevenSeg_Output()
disp_FAC_1.setBrightness(5); disp_FAC_1.setBrightness(5);
disp_FAC_2.setBrightness(5); disp_FAC_2.setBrightness(5);
disp_FAC_3.setBrightness(5); disp_FAC_3.setBrightness(5);
disp_FAC_1.display(String(DisplayOverrideValue)); disp_FAC_1.display(String(DisplayOverrideValue[0]));
disp_FAC_2.clearScreen(); disp_FAC_2.display(String(DisplayOverrideValue[1]));
disp_FAC_3.clearScreen(); disp_FAC_3.display(String(DisplayOverrideValue[2]));
} }
else else
{ {
@@ -277,22 +289,28 @@ void SevenSeg_Output()
disp_FAC_1.refresh(); disp_FAC_1.refresh();
snprintf(sevenSegBuff, sizeof(sevenSegBuff), "%4d", PersistenceData.faction_1_timer / 60); snprintf(sevenSegBuff, sizeof(sevenSegBuff), "%4d", PersistenceData.faction_1_timer / 60);
disp_FAC_1.display(String(sevenSegBuff), false, false); 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.setBrightness(PersistenceData.activeFaction == FACTION_2 ? 5 : 1);
disp_FAC_2.refresh(); disp_FAC_2.refresh();
snprintf(sevenSegBuff, sizeof(sevenSegBuff), "%4d", PersistenceData.faction_2_timer / 60); snprintf(sevenSegBuff, sizeof(sevenSegBuff), "%4d", PersistenceData.faction_2_timer / 60);
disp_FAC_2.display(String(sevenSegBuff), false, false); 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.setBrightness(PersistenceData.activeFaction == FACTION_3 ? 5 : 1);
disp_FAC_3.refresh(); disp_FAC_3.refresh();
snprintf(sevenSegBuff, sizeof(sevenSegBuff), "%4d", PersistenceData.faction_3_timer / 60); snprintf(sevenSegBuff, sizeof(sevenSegBuff), "%4d", PersistenceData.faction_3_timer / 60);
disp_FAC_3.display(String(sevenSegBuff), false, false); disp_FAC_3.display(String(sevenSegBuff), false, false);
disp_FAC_3.setDp((PersistenceData.activeFaction == FACTION_3) && (millis() % 1000 > 500) ? 0x08 : 0x00);
} }
} }
} }
void tmrCallback_FactionTicker() void tmrCallback_FactionTicker()
{ {
if (globals.timer_disabled == true)
PersistenceData.activeFaction = NONE;
switch (PersistenceData.activeFaction) switch (PersistenceData.activeFaction)
{ {
case FACTION_1: case FACTION_1:
@@ -329,43 +347,48 @@ void tmrCallback_InputGetter()
if (keysPressed > 1) 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; PersistenceData.activeFaction = NONE;
return; return;
} }
if (btnState[0] == FAC_1_TRG_PRESSED) if (btnState[0] == FAC_1_TRG_PRESSED && globals.timer_disabled != true)
{ {
if (PersistenceData.activeFaction != FACTION_1) if (PersistenceData.activeFaction != FACTION_1)
{ {
Serial.println("Faction 1 captured !"); Debug_pushMessage("Faction 1 captured !");
globals.requestEEAction = EE_PDS_SAVE;
} }
PersistenceData.activeFaction = FACTION_1; PersistenceData.activeFaction = FACTION_1;
} }
if (btnState[1] == FAC_2_TRG_PRESSED) if (btnState[1] == FAC_2_TRG_PRESSED && globals.timer_disabled != true)
{ {
if (PersistenceData.activeFaction != FACTION_2) if (PersistenceData.activeFaction != FACTION_2)
{ {
Serial.println("Faction 2 captured !"); Debug_pushMessage("Faction 2 captured !");
globals.requestEEAction = EE_PDS_SAVE;
} }
PersistenceData.activeFaction = FACTION_2; PersistenceData.activeFaction = FACTION_2;
} }
if (btnState[2] == FAC_3_TRG_PRESSED) if (btnState[2] == FAC_3_TRG_PRESSED && globals.timer_disabled != true)
{ {
if (PersistenceData.activeFaction != FACTION_3) if (PersistenceData.activeFaction != FACTION_3)
{ {
Serial.println("Faction 3 captured !"); Debug_pushMessage("Faction 3 captured !");
globals.requestEEAction = EE_PDS_SAVE;
} }
PersistenceData.activeFaction = FACTION_3; PersistenceData.activeFaction = FACTION_3;
} }
} }
#if defined(FEATURE_ENABLE_LORA) || defined(FEATURE_ENABLE_UARTLORA)
void tmrCallback_StatusSender() void tmrCallback_StatusSender()
{ {
sendStatus_LoRa(); sendStatus_LoRa();
} }
#endif
void tmrCallback_PowerMonitor() void tmrCallback_PowerMonitor()
{ {
@@ -402,6 +425,9 @@ void tmrCallback_PowerMonitor()
break; 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("Battery Level: %d %%\n", globals.battery_level);
// Serial.printf("Bus Voltage: %f V\n", busvoltage); // Serial.printf("Bus Voltage: %f V\n", busvoltage);
// Serial.printf("Shunt Voltage: %f mV\n", shuntvoltage); // Serial.printf("Shunt Voltage: %f mV\n", shuntvoltage);
@@ -415,7 +441,7 @@ void tmrCallback_EEPROMCyclicPDS()
StorePersistence_EEPROM(); StorePersistence_EEPROM();
} }
#ifdef WIFI_CLIENT #ifdef FEATURE_ENABLE_WIFI_CLIENT
void tmrCallback_WiFiMaintainConnection() void tmrCallback_WiFiMaintainConnection()
{ {
static uint32_t WiFiFailCount = 0; static uint32_t WiFiFailCount = 0;
@@ -433,7 +459,7 @@ void tmrCallback_WiFiMaintainConnection()
} }
else else
{ {
debugV("WiFi not connected! - Start AP"); Debug_pushMessage("WiFi not connected! - Start AP");
toggleWiFiAP(); toggleWiFiAP();
} }
} }
@@ -445,9 +471,9 @@ void toggleWiFiAP(boolean shutdown)
if (WiFi.getMode() != WIFI_OFF) if (WiFi.getMode() != WIFI_OFF)
{ {
WiFi.mode(WIFI_OFF); WiFi.mode(WIFI_OFF);
debugV("WiFi turned off"); Serial.println("WiFi turned off");
#ifdef FEATURE_ENABLE_WIFI_CLIENT #ifdef FEATURE_ENABLE_WIFI_CLIENT
WiFiMaintainConnectionTicker.stop(); tmrWiFiMaintainConnection.stop();
#endif #endif
} }
else else
@@ -456,10 +482,10 @@ void toggleWiFiAP(boolean shutdown)
WiFi.softAPConfig(IPAddress(WIFI_AP_IP_GW), IPAddress(WIFI_AP_IP_GW), IPAddress(255, 255, 255, 0)); WiFi.softAPConfig(IPAddress(WIFI_AP_IP_GW), IPAddress(WIFI_AP_IP_GW), IPAddress(255, 255, 255, 0));
WiFi.softAP(QUOTE(WIFI_AP_SSID), QUOTE(WIFI_AP_PASSWORD)); WiFi.softAP(QUOTE(WIFI_AP_SSID), QUOTE(WIFI_AP_PASSWORD));
#ifdef FEATURE_ENABLE_WIFI_CLIENT #ifdef FEATURE_ENABLE_WIFI_CLIENT
WiFiMaintainConnectionTicker.stop(); tmrWiFiMaintainConnection.stop();
debugV("WiFi AP started, stopped Maintain-Timer"); Serial.println("WiFi AP started, stopped Maintain-Timer");
#else #else
debugV("WiFi AP started"); Serial.println("WiFi AP started");
#endif #endif
} }
} }
@@ -491,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; DisplayOverrideFlag = millis() + time;
strcpy(DisplayOverrideValue, message); strcpy(DisplayOverrideValue[0], message1);
strcpy(DisplayOverrideValue[1], message2);
strcpy(DisplayOverrideValue[2], message3);
} }
void ProcessKeyCombos(bool *btnState) void ProcessKeyCombos(bool *btnState)
@@ -539,20 +567,20 @@ void ProcessKeyCombos(bool *btnState)
if (btnState[0] != FAC_1_TRG_PRESSED && keyStatus_Fac1 == KEY_PRESSED) if (btnState[0] != FAC_1_TRG_PRESSED && keyStatus_Fac1 == KEY_PRESSED)
{ {
if (keyCount_Fac2 > 0 || keyCount_Fac3 > 0) if (keyCount_Fac2 > 0 || keyCount_Fac3 > 0)
Serial.printf("KeyCombo 2: %d | 3: %d\n", keyCount_Fac2, keyCount_Fac3); Debug_pushMessage("KeyCombo 2: %d | 3: %d\n", keyCount_Fac2, keyCount_Fac3);
if (keyCount_Fac2 == 2 && keyCount_Fac3 == 0) if (keyCount_Fac2 == 2 && keyCount_Fac3 == 0)
{ {
Serial.println("KeyCombo: WiFi AP ON"); Debug_pushMessage("KeyCombo: WiFi AP ON");
OverrideDisplay("NET ", 5000); OverrideDisplay(5000, "NET ", " ", " ");
toggleWiFiAP(false); toggleWiFiAP(false);
} }
else if (keyCount_Fac2 == 4 && keyCount_Fac3 == 0) else if (keyCount_Fac2 == 4 && keyCount_Fac3 == 0)
{ {
Serial.printf("KeyCombo: Reset Timer\n"); Debug_pushMessage("KeyCombo: Reset Timer\n");
if (millis() < RESETABLE_AFTER_STARTUP_MS) if (globals.systemStatus == sysStat_Startup)
{ {
OverrideDisplay("RST ", 5000); OverrideDisplay(5000, "RST ", " ", " ");
PersistenceData.faction_1_timer = 0; PersistenceData.faction_1_timer = 0;
PersistenceData.faction_2_timer = 0; PersistenceData.faction_2_timer = 0;
PersistenceData.faction_3_timer = 0; PersistenceData.faction_3_timer = 0;
@@ -561,8 +589,8 @@ void ProcessKeyCombos(bool *btnState)
} }
else else
{ {
OverrideDisplay("ERR ", 5000); OverrideDisplay(5000, "ERR ", " ", " ");
Serial.printf("ERROR: only %d seconds after Startup!\n", RESETABLE_AFTER_STARTUP_MS / 1000); Debug_pushMessage("ERROR: only %d seconds after Startup!\n", STARTUP_DELAY_MS / 1000);
} }
} }
@@ -573,3 +601,51 @@ void ProcessKeyCombos(bool *btnState)
keyStatus_Fac3 = 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.setCursor(0, 0);
display.printf("LiPo: %d%%\n", globals.battery_level); display.printf("LiPo: %d%%\n", globals.battery_level);
display.print(PersistenceData.activeFaction == FACTION_1 ? "> " : " "); 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.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.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(); display.display();
} }

View File

@@ -2,52 +2,46 @@
AsyncWebServer webServer(80); AsyncWebServer webServer(80);
typedef enum const char *PARAM_MESSAGE = "message";
{
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);
String processor(const String &var); String processor(const String &var);
void WebserverPOST_Callback(AsyncWebServerRequest *request); void WebserverPOST_Callback(AsyncWebServerRequest *request);
void WebserverNotFound_Callback(AsyncWebServerRequest *request); void WebserverNotFound_Callback(AsyncWebServerRequest *request);
void Webserver_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 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 WebserverEERestore_Callback(AsyncWebServerRequest *request, const String &filename, size_t index, uint8_t *data, size_t len, bool final);
void WebServerEEJSON_Callback(AsyncWebServerRequest *request); void WebServerEEJSON_Callback(AsyncWebServerRequest *request);
void GetFlashVersion(char *buff, size_t buff_size); 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() void initWebUI()
{ {
if (!LittleFS.begin()) 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); MaintainDTC(DTC_FLASHFS_ERROR, DTC_CRITICAL, true);
return; return;
} }
GetFlashVersion(globals.FlashVersion, sizeof(globals.FlashVersion)); 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); MaintainDTC(DTC_FLASHFS_VERSION_ERROR, DTC_WARN, true);
} }
MDNS.begin(globals.DeviceName); MDNS.begin(globals.DeviceName);
MDNS.addService("telnet", "tcp", 23);
MDNS.addService("http", "tcp", 80); MDNS.addService("http", "tcp", 80);
webSocket.onEvent(WebsocketEvent_Callback);
webServer.addHandler(&webSocket);
webServer.serveStatic("/static/", LittleFS, "/static/").setCacheControl("max-age=360000"); webServer.serveStatic("/static/", LittleFS, "/static/").setCacheControl("max-age=360000");
webServer.on("/", HTTP_GET, [](AsyncWebServerRequest *request) webServer.on("/", HTTP_GET, [](AsyncWebServerRequest *request)
{ request->redirect("/index.htm"); }); { request->redirect("/index.htm"); });
@@ -63,51 +57,65 @@ void initWebUI()
webServer.begin(); webServer.begin();
} }
void Webserver_Process()
{
webSocket.cleanupClients();
}
String processor(const String &var) 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") if (var == "SHOW_DTC_TABLE")
return globals.systemStatus == sysStat_Error ? "" : "hidden"; 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") if (var == "BAT_REMAIN_CAPACITY")
return String(globals.battery_level); return String(globals.battery_level);
if (var == "DEVICENAME")
if (var == "DEVICE_NAME")
return String(globals.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") if (var == "BAT_VOLTAGE")
return String((float)globals.loadvoltage_mV / 1000.0); 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") if (var == "DTC_TABLE")
{ {
String temp; String temp = "";
char buff_timestamp[16]; // Format: DD-hh:mm:ss:xxx char buff_timestamp[16]; // Format: DD-hh:mm:ss:xxx
for (uint32_t i = 0; i < MAX_DTC_STORAGE; i++) 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", sprintf(buff_timestamp, "%02d-%02d:%02d:%02d:%03d",
DTCStorage[i].timestamp / 86400000, // Days DTCStorage[i].timestamp / 86400000, // Days
@@ -116,8 +124,23 @@ String processor(const String &var)
DTCStorage[i].timestamp / 1000 % 60, // Seconds DTCStorage[i].timestamp / 1000 % 60, // Seconds
DTCStorage[i].timestamp % 1000); // milliseconds 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 + "</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) if (DTCStorage[i].active == DTC_ACTIVE)
temp = temp + "active"; temp = temp + "active";
@@ -156,39 +179,41 @@ String processor(const String &var)
return String(buff); return String(buff);
} }
if (var == "STATUS_FAC_1") if (var == "ACTIVE_FACTION")
return PersistenceData.activeFaction == FACTION_1 ? "ACTIVE" : "INACTIVE"; return String(PersistenceData.activeFaction);
if (var == "STATUS_FAC_2") if (var == "FACTION_1_ACTIVE")
return PersistenceData.activeFaction == FACTION_2 ? "ACTIVE" : "INACTIVE"; return String(PersistenceData.activeFaction == FACTION_1 ? "bg-primary" : "bg-secondary");
if (var == "FACTION_2_ACTIVE")
if (var == "STATUS_FAC_3") return String(PersistenceData.activeFaction == FACTION_2 ? "bg-primary" : "bg-secondary");
return PersistenceData.activeFaction == FACTION_3 ? "ACTIVE" : "INACTIVE"; if (var == "FACTION_3_ACTIVE")
return String(PersistenceData.activeFaction == FACTION_3 ? "bg-primary" : "bg-secondary");
if (var == "NAME_FAC_1") if (var == "NAME_FAC_1")
return FACTION_1_NAME; return String(ConfigData.Faction_1_Name);
if (var == "NAME_FAC_2") if (var == "NAME_FAC_2")
return FACTION_2_NAME; return String(ConfigData.Faction_2_Name);
if (var == "NAME_FAC_3") if (var == "NAME_FAC_3")
return FACTION_3_NAME; return String(ConfigData.Faction_3_Name);
if (var == "TITLE") if (var == "BATTERY_SELECT_OPTIONS")
return DEVICE_NAME; {
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") if (var == "FACTIONREBOOT_CHECKED")
{ return String(ConfigData.active_faction_on_reboot == true ? "checked" : "");
return String(globals.battery_level);
} if (var == "FACTION_RECOVERY")
if (var == "BATTERY_TYPE") return String(ConfigData.active_faction_on_reboot);
{
return String(BatteryString[ConfigData.batteryType]);
}
if (var == "BATTERY_VOLTAGE")
{
return String((float)globals.loadvoltage_mV / 1000.0);
}
return String(); return String();
} }
@@ -196,19 +221,84 @@ String processor(const String &var)
void Webserver_Callback(AsyncWebServerRequest *request) void Webserver_Callback(AsyncWebServerRequest *request)
{ {
request->send(LittleFS, "/index.htm", "text/html", false, processor); request->send(LittleFS, "/index.htm", "text/html", false, processor);
StatusResponseMessage_Type = RESPMSG_HIDE;
} }
void WebserverPOST_Callback(AsyncWebServerRequest *request) void WebserverPOST_Callback(AsyncWebServerRequest *request)
{ {
request->send(LittleFS, "/post.htm", "text/html", false, processor);
Debug_pushMessage("POST:\n");
int paramsNr = request->params(); int paramsNr = request->params();
for (int i = 0; i < paramsNr; i++) for (int i = 0; i < paramsNr; i++)
{ {
AsyncWebParameter *p = request->getParam(i); AsyncWebParameter *p = request->getParam(i);
if (p->name() == "commandInput") Debug_pushMessage("%s : %s\n", p->name().c_str(), p->value().c_str());
WebserverCommands_Callback(p->value());
// 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) void WebserverNotFound_Callback(AsyncWebServerRequest *request)
@@ -216,41 +306,6 @@ void WebserverNotFound_Callback(AsyncWebServerRequest *request)
request->send(404, "text/html", "Not found"); 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) void GetFlashVersion(char *buff, size_t buff_size)
{ {
File this_file = LittleFS.open("version", "r"); File this_file = LittleFS.open("version", "r");
@@ -273,7 +328,7 @@ void WebserverFirmwareUpdate_Callback(AsyncWebServerRequest *request, const Stri
if (!index) if (!index)
{ {
Serial.println("Update"); Debug_pushMessage("Update");
size_t content_len = request->contentLength(); size_t content_len = request->contentLength();
int cmd = (filename.indexOf(".fs") > -1) ? U_FS : U_FLASH; int cmd = (filename.indexOf(".fs") > -1) ? U_FS : U_FLASH;
Update.runAsync(true); Update.runAsync(true);
@@ -289,7 +344,7 @@ void WebserverFirmwareUpdate_Callback(AsyncWebServerRequest *request, const Stri
} }
else else
{ {
Serial.printf("Progress: %d%%\n", (Update.progress() * 100) / Update.size()); Debug_pushMessage("Progress: %d%%\n", (Update.progress() * 100) / Update.size());
} }
if (final) if (final)
@@ -304,8 +359,7 @@ void WebserverFirmwareUpdate_Callback(AsyncWebServerRequest *request, const Stri
} }
else else
{ {
Serial.println("Update complete"); Debug_pushMessage("Update complete\n");
Serial.flush();
globals.systemStatus = sysStat_Shutdown; 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) void WebserverEERestore_Callback(AsyncWebServerRequest *request, const String &filename, size_t index, uint8_t *data, size_t len, bool final)
{ {
bool ee_done = false; 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) if (!index)
{ {
Serial.println("EEPROM restore");
validext = (filename.indexOf(".ee.json") > -1); validext = (filename.indexOf(".ee.json") > -1);
}
if (validext) if (validext)
{ {
Serial.println("Restoring EEPROM-Stuff"); buffer = (char *)malloc(1536);
read_ptr = 0;
if (buffer == NULL)
Debug_pushMessage("malloc() failed for EEPROM-Restore");
}
}
if (buffer != NULL)
{
memcpy(buffer + read_ptr, data, len);
read_ptr = read_ptr + len;
} }
if (final) 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"); AsyncWebServerResponse *response = request->beginResponse(302, "text/plain", "Please wait while the device reboots");
response->addHeader("Refresh", "20"); response->addHeader("Refresh", "20");
response->addHeader("Location", "/"); response->addHeader("Location", "/");
request->send(response); request->send(response);
if (ee_done) if (ee_done)
{ {
Serial.println("Update complete"); Debug_pushMessage("Update complete");
Serial.flush();
globals.systemStatus = sysStat_Shutdown; globals.systemStatus = sysStat_Shutdown;
} }
else else
@@ -355,13 +449,19 @@ void WebServerEEJSON_Callback(AsyncWebServerRequest *request)
char buffer[16]; char buffer[16];
fwinfo["DeviceName"] = globals.DeviceName; 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; fwinfo["FS-Version"] = globals.FlashVersion;
snprintf_P(buffer, sizeof(buffer), "%s", constants.GitHash);
fwinfo["Git-Hash"] = buffer;
JsonObject config = json.createNestedObject("config"); JsonObject config = json.createNestedObject("config");
config["EEPROM_Version"] = ConfigData.EEPROM_Version; 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); sprintf(buffer, "0x%08X", ConfigData.checksum);
config["checksum"] = buffer; config["checksum"] = buffer;
@@ -373,7 +473,10 @@ void WebServerEEJSON_Callback(AsyncWebServerRequest *request)
JsonObject persis = json.createNestedObject("persis"); JsonObject persis = json.createNestedObject("persis");
persis["writeCycleCounter"] = PersistenceData.writeCycleCounter; 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); sprintf(buffer, "0x%08X", PersistenceData.checksum);
persis["checksum"] = buffer; persis["checksum"] = buffer;
@@ -383,3 +486,51 @@ void WebServerEEJSON_Callback(AsyncWebServerRequest *request)
request->send(response); 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,6 +1,6 @@
[wifi_cred] [wifi_cred]
wifi_ap_ssid = wifi-ap-ssid wifi_ap_ssid = wifi-ap-ssid
wifi_ap_password = wifiappass wifi_ap_password = wifiappass
wifi_ssid = wifi-ssid wifi_client_ssid = wifi-ssid
wifi_password = wifi-pass wifi_client_password = wifi-pass
admin_password = ota-password ota_password = ota-password