16 Commits

22 changed files with 617 additions and 538 deletions

View File

@@ -1,8 +0,0 @@
import subprocess
revision = (
subprocess.check_output(["git", "rev-parse", "--short=10", "HEAD"])
.strip()
.decode("utf-8")
)
print("-DGIT_REV='\"%s\"'" % revision)

View File

@@ -1,13 +1,10 @@
# SCRIPT TO GZIP CRITICAL FILES FOR ACCELERATED WEBSERVING
# see also https://community.platformio.org/t/question-esp32-compress-files-in-data-to-gzip-before-upload-possible-to-spiffs/6274/10
import glob import glob
import shutil import shutil
import gzip import gzip
import os import os
import subprocess import subprocess
import platform import platform
from os import popen
Import("env") Import("env")
Import("projenv") Import("projenv")
@@ -169,8 +166,13 @@ def gzip_webfiles(source, target, env):
return return
def gzip_binffiles(source, target, env): def gzip_binffiles(source, target, env):
git_revision = popen('git rev-parse --short HEAD').read().strip()
custom_flash_version = env.GetProjectOption("custom_flash_version", "0.99")
# Format the target file name
target_filename = f"filesystem_{custom_flash_version}_{git_revision}.fs"
littlefsbin = target[0].get_abspath() littlefsbin = target[0].get_abspath()
targetbin = os.path.join(os.path.dirname(littlefsbin), 'filesystem.fs') targetbin = os.path.join(os.path.dirname(littlefsbin), target_filename)
shutil.copyfile(littlefsbin, targetbin) shutil.copyfile(littlefsbin, targetbin)
gzip_file(targetbin, os.path.join(str(targetbin) + '.gz')) gzip_file(targetbin, os.path.join(str(targetbin) + '.gz'))
os.remove(targetbin) os.remove(targetbin)

View File

@@ -3,6 +3,31 @@ env.Execute("\"$PYTHONEXE\" -m pip install jinja2")
import struct2json import struct2json
import dtcs import dtcs
from os import popen
git_revision = popen('git rev-parse --short HEAD').read().strip()
# Versionsnummern aus platformio.ini holen
custom_firmware_version = env.GetProjectOption("custom_firmware_version", "0.99")
custom_flash_version = env.GetProjectOption("custom_flash_version", "0.99")
# Versionsnummern aufteilen in Major und Minor
fw_major, fw_minor = custom_firmware_version.split('.')
fl_major, fl_minor = custom_flash_version.split('.')
# Version in Datei "version" im Ordner "data_src" überschreiben
with open('data_src/version', 'w') as version_file:
version_file.write(custom_flash_version)
# Build-Flags setzen
env.Replace(PROGNAME="firmware_%s_%s.fw" % (custom_firmware_version, git_revision))
env.Append(CPPDEFINES=[
('GIT_REV', '\\"{}\\"'.format(git_revision)),
('FW_MAJOR', fw_major),
('FW_MINOR', fw_minor),
('FL_MAJOR', fl_major),
('FL_MINOR', fl_minor)
])
struct2json.struct2json() struct2json.struct2json()
dtcs.build_dtcs() dtcs.build_dtcs()

View File

@@ -3,7 +3,7 @@
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<title>%DEVICENAME%</title> <title>Dark Emergency Timer</title>
<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">
@@ -11,6 +11,8 @@
<script src="static/js/jquery.min.js"></script> <script src="static/js/jquery.min.js"></script>
<script src="static/js/bootstrap.min.js"></script> <script src="static/js/bootstrap.min.js"></script>
<script src="static/js/websocket.js"></script> <script src="static/js/websocket.js"></script>
<script src="static/js/dtc_table.js"></script>
<script src="static/js/script.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">
@@ -18,11 +20,22 @@
</head> </head>
<body> <body>
<!-- Connection-Overlay -->
<div id="overlay">
<div class="overlay-content">
<p>Verbinde...</p>
<span class="loader"></span>
</div>
</div>
<!-- Connection-Overlay -->
<!-- Notification-Container -->
<div id="notification-container" class="notification-container"></div>
<!-- Notification-Container -->
<nav class="navbar fixed-top navbar-dark bg-primary" id="navbar1"> <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 mr-1" alt=""> <img src="static/img/logo.png" width="30" height="30" class="d-inline-block align-top mr-1" alt="">
%DEVICENAME% <span class="data-devicename">DE Airsoft Timer</span>
</a> </a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#collapsingNavbar" <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#collapsingNavbar"
aria-controls="collapsingNavbar" aria-expanded="false" aria-label="Toggle navigation"> aria-controls="collapsingNavbar" aria-expanded="false" aria-label="Toggle navigation">
@@ -35,7 +48,6 @@
<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 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_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_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> <li class="nav-item"><a class="nav-link" role="tab" data-toggle="tab" href="#tab_fwupdate">Update</a></li>
</ul> </ul>
@@ -51,17 +63,17 @@
<div class="col text-center"> <div class="col text-center">
<div class="jumbotron"> <div class="jumbotron">
<img src="static/img/logo.png" width="120" height="120" class="img-fluid" alt=""> <img src="static/img/logo.png" width="120" height="120" class="img-fluid" alt="">
<h3 class="pt-3">%DEVICENAME%</h3> <h3 class="pt-3"><span class="data-devicename">DE Airsoft Timer</span></h3>
</div> </div>
</div> </div>
<!-- Div Group Battery remain --> <!-- Div Group Battery remain -->
<hr /> <hr />
<p> <p>
<h4>Akku Ladestand</h4> <h4>Akkuladestand</h4>
<div class="progress"> <div class="progress">
<div class="progress-bar text-light" role="progressbar" aria-valuenow="%BAT_REMAIN_CAPACITY%" <div id="battery_level" class="data-battery_level progress-bar text-light" role="progressbar" aria-valuenow="0"
aria-valuemin="0" aria-valuemax="100" style="width: %BAT_REMAIN_CAPACITY%&#37;"> aria-valuemin="0" aria-valuemax="100" style="width: 0%">
%BAT_REMAIN_CAPACITY%&#37; 0
</div> </div>
</div> </div>
</p> </p>
@@ -70,7 +82,7 @@
<hr /> <hr />
<p> <p>
<h4>aktueller Modus</h4> <h4>aktueller Modus</h4>
<input class="form-control" type="text" placeholder="%SYSTEM_STATUS%" readonly> <input class="data-systemstatus form-control" type="text" id="sysstatus" readonly>
</p> </p>
<!-- Div Group current Mode --> <!-- Div Group current Mode -->
<!-- Div Group Faction Points --> <!-- Div Group Faction Points -->
@@ -79,35 +91,35 @@
<h4>aktueller Punktestand</h4> <h4>aktueller Punktestand</h4>
<div class="container-fluid"> <div class="container-fluid">
<div class="row"> <div class="row">
<div class="col text-center %FACTION_1_ACTIVE% text-white p-3">%NAME_FAC_1%</div> <div id="header_faction1" class="col text-center data-name_faction1 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 id="header_faction2" class="col text-center data-name_faction2 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 id="header_faction3" class="col text-center data-name_faction3 text-white p-3">%NAME_FAC_3%</div>
</div> </div>
<div class="row"> <div class="row">
<div class="col bg-dark text-white p-3"><img src="static/img/logo_fac1.png" <div class="col bg-dark text-white p-3 data-activefaction faction-logo faction1">
class="rounded mx-auto img-fluid d-block" alt="..."> <img src="static/img/logo_fac1.png" class="rounded mx-auto img-fluid d-block" alt="...">
</div> </div>
<div class="col bg-dark text-white p-3"><img src="static/img/logo_fac2.png" <div class="col bg-dark text-white p-3 data-activefaction faction-logo faction2">
class="rounded mx-auto img-fluid d-block" alt="..."> <img src="static/img/logo_fac2.png" class="rounded mx-auto img-fluid d-block" alt="...">
</div> </div>
<div class="col bg-dark text-white p-3"><img src="static/img/logo_fac3.png" <div class="col bg-dark text-white p-3 data-activefaction faction-logo faction3">
class="rounded mx-auto img-fluid d-block" alt="..."> <img src="static/img/logo_fac3.png" class="rounded mx-auto img-fluid d-block" alt="...">
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="col text-center bg-secondary text-white p-3">%POINTS_FAC_1%</div> <div id="time_faction1" class="data-time_faction1 col text-center bg-secondary text-white p-3 format-time">0</div>
<div class="col text-center bg-secondary text-white p-3">%POINTS_FAC_2%</div> <div id="time_faction2" class="data-time_faction2 col text-center bg-secondary text-white p-3 format-time">0</div>
<div class="col text-center bg-secondary text-white p-3">%POINTS_FAC_3%</div> <div id="time_faction3" class="data-time_faction3 col text-center bg-secondary text-white p-3 format-time">0</div>
</div> </div>
</div> </div>
</p> </p>
<!-- Div GroupFaction Points --> <!-- Div GroupFaction Points -->
<!-- Div Group DTC Table --> <!-- Div Group DTC Table -->
<div %SHOW_DTC_TABLE%> <div id="dtc_container" hidden>
<hr /> <hr />
<p> <p>
<h4>Fehlercodes</h4> <h4>Fehlercodes</h4>
<table class="table"> <table class="table" id="dtc_table">
<tbody> <tbody>
<tr> <tr>
<th class="col-6" scope="col">Zeitstempel</th> <th class="col-6" scope="col">Zeitstempel</th>
@@ -115,7 +127,6 @@
<th class="col-2" scope="col">Schwere</th> <th class="col-2" scope="col">Schwere</th>
<th class="col-2" scope="col">Aktiv</th> <th class="col-2" scope="col">Aktiv</th>
</tr> </tr>
%DTC_TABLE%
</tbody> </tbody>
</table> </table>
</p> </p>
@@ -131,254 +142,13 @@
<hr /> <hr />
<p> <p>
<h4>Punkte zur&uuml;cksetzen</h4> <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">
<div class="col text-center"> <div class="col text-center">
<button name="resetpoints" type="submit" class="btn btn-outline-primary">Reset</button> <button id="reset-timer" class="btn-wsevent btn btn-outline-primary ml-2">Timer zurücksetzen</button>
</div> </div>
</div> </div>
</form>
</p> </p>
<!-- Div Group Reset Timers --> <!-- Div Group Reset Timers -->
<!-- Div Group EEPROM formatting -->
<hr />
<p>
<h4>EEPROM formatieren</h4>
<div class="alert alert-primary alert-dismissable show fade" role="alert">
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
<strong>Achtung!</strong><br>
Das Formatieren der EEPROM-Bereiche sollte nur ausgeführt werden wenn es unbedingt erforderlich ist!
Hierdurch werden alle Einstellungen zurück gesetzt bzw. alle Betriebsdaten gehen verloren.
Folgende Situationen erfordern unter anderem eine Formatierung:
- Erstinitialisierung (bei neu aufgebautem Gerät)
- Firmware-Update (nur wenn es die Release-Notes fordern)
</div>
<form action="post.htm" method="POST" class="form-horizontal">
<div class="form-group row">
<div class="offset-4 col-8">
<div class="form-check">
<input class="form-check-input" type="checkbox" name="reset_ee_cfg" id="reset_ee_cfg">
<label class="form-check-label" for="reset_ee_cfg">
Bereich "CFG"
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" name="reset_ee_pds" id="reset_ee_pds">
<label class="form-check-label" for="reset_ee_pds">
Bereich "PDS"
</label>
</div>
</div>
</div>
<div class="form-group row">
<div class="col text-center">
<button name="reset_ee_btn" type="submit" class="btn btn-outline-primary">EEPROM formatieren</button>
</div>
</div>
</form>
</p>
<!-- Div Group EEPROM formatting -->
<!-- Div Group Device Reboot -->
<hr />
<p>
<h4>Ger&auml;t neustarten</h4>
<form action="post.htm" method="POST" class="form-horizontal">
<div class="form-group row">
<div class="col text-center">
<button name="reboot" type="submit" class="btn btn-outline-primary">Reboot</button>
</div>
</div>
</form>
</p>
<!-- Div Group Device Reboot -->
</div>
<!-- Div Tab Maintenance -->
<!-- Div Tab Settings-->
<div id="tab_source" class="tab-pane fade" role="tabpanel">
<h3>Einstellungen</h3>
<!-- Div Group Battery Type -->
<hr />
<p>
<form action="post.htm" method="POST" class="form-horizontal">
<h4>Akku-Variante</h4>
<div class="form-group row">
<label for="battery_select" class="control-label col-4">Akku</label>
<div class="col-8">
<select id="battery_select" name="battery_select" class="select form-control">
%BATTERY_SELECT_OPTIONS%
</select>
</div>
</div>
<h4>Timer-Einstellungen</h4>
<div class="form-group row">
<label for="factionreboot_cont" class="control-label col-4">active Faction Recovery</label>
<div class="col-8">
<div class="form-check">
<input class="form-check-input" type="checkbox" name="factionreboot_cont" id="factionreboot_cont"
%FACTIONREBOOT_CHECKED%>
<label class="form-check-label" for="factionreboot_cont">
aktive Faktion beim booten wiederherstellen ?
</label>
</div>
</div>
</div>
<h4>Faktionsbezeichnungen</h4>
<div class="alert alert-primary alert-dismissable show fade" role="alert">
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
<strong>Achtung!</strong><br>
Faktionsbezeichnungen können nur aus ASCII-Zeichen bestehen, also A-Z, a-z und 0-9
</div>
<div class="form-group row">
<label for="faction_1_name" class="control-label col-4">Faktion 1</label>
<div class="col-8">
<div class="input-group">
<input id="faction_1_name" name="faction_1_name" value="%NAME_FAC_1%" type="text" class="form-control" pattern="[A-Za-z0-9 _-]{1,32}">
<div class="input-group-append">
<span class="input-group-text">max 32 Zeichen</span>
</div>
</div>
</div>
</div>
<div class="form-group row">
<label for="faction_2_name" class="control-label col-4">Faktion 2</label>
<div class="col-8">
<div class="input-group">
<input id="faction_2_name" name="faction_2_name" value="%NAME_FAC_2%" type="text" class="form-control" pattern="[A-Za-z0-9 _-]{1,32}">
<div class="input-group-append">
<span class="input-group-text">max 32 Zeichen</span>
</div>
</div>
</div>
</div>
<div class="form-group row">
<label for="faction_3_name" class="control-label col-4">Faktion 3</label>
<div class="col-8">
<div class="input-group">
<input id="faction_3_name" name="faction_3_name" value="%NAME_FAC_3%" type="text" class="form-control" pattern="[A-Za-z0-9 _-]{1,32}">
<div class="input-group-append">
<span class="input-group-text">max 32 Zeichen</span>
</div>
</div>
</div>
</div>
<div class="form-group row">
<div class="col text-center">
<button name="settingssave" type="submit" class="btn btn-outline-primary">&Uuml;bernehmen</button>
</div>
</div>
</form>
</p>
<!-- Div Group Battery Type -->
</div>
<!-- Div Tab Settings -->
<!-- Div Tab SystemInfo -->
<div id="tab_sysinfo" class="tab-pane fade" role="tabpanel">
<h3>Systeminfo</h3>
<!-- Div Group Sysinfo:Geraeteinfo -->
<hr />
<p>
<h4>Ger&auml;t</h4>
<table class="table">
<tbody>
<tr>
<th class="col-7" scope="col">Parameter</td>
<th class="col-5" scope="col">Value</td>
</tr>
<tr>
<td>Hostname</td>
<td>%HOSTNAME%</td>
</tr>
<tr>
<td>Device-ID</td>
<td>%DEVICENAME_ID%</td>
</tr>
<tr>
<td>Battery Voltage</td>
<td>%BAT_VOLTAGE%V</td>
</tr>
<tr>
<td>Battery Remain</td>
<td>%BAT_REMAIN_CAPACITY%&#37;</td>
</tr>
</table>
</p>
<!-- Div Group Sysinfo:Geraeteinfo -->
<!-- Div Group Sysinfo:Settings -->
<hr />
<p>
<h4>Einstellungen</h4>
<table class="table">
<tbody>
<tr>
<th class="col-7" scope="col">Parameter</td>
<th class="col-5" scope="col">Value</td>
</tr>
<tr>
<td>Battery_type</td>
<td>%BATTERY_TYPE%</td>
</tr>
<tr>
<td>Faction_recovery</td>
<td>%FACTION_RECOVERY%</td>
</tr>
<tr>
<td>EEPROM Version</td>
<td>%EEPROM_VERSION%</td>
</tr>
<tr>
<td>Checksum</td>
<td>%CONFIG_CHECKSUM%</td>
</tr>
</tbody>
</table>
</p>
<!-- Div Group Sysinfo:Settings -->
<!-- Div Group Sysinfo:Persistance -->
<hr />
<p>
<h4>Betriebsdaten</h4>
<table class="table">
<tbody>
<tr>
<th class="col-7" scope="col">Parameter</td>
<th class="col-5" scope="col">Value</td>
</tr>
<tr>
<td>writeCycleCounter</td>
<td>%WRITE_CYCLE_COUNT%</td>
</tr>
<tr>
<td>PersistenceMarker</td>
<td>%PERSISTENCE_MARKER%</td>
</tr>
<tr>
<td>activeFaction</td>
<td>%ACTIVE_FACTION%</td>
</tr>
<tr>
<td>faction_1_timer</td>
<td>%POINTS_FAC_1%</td>
</tr>
<tr>
<td>faction_2_timer</td>
<td>%POINTS_FAC_2%</td>
</tr>
<tr>
<td>faction_3_timer</td>
<td>%POINTS_FAC_3%</td>
</tr>
<tr>
<td>checksum</td>
<td>%PERSISTANCE_CHECKSUM%</td>
</tr>
</table>
</p>
<!-- Div Group Sysinfo:Persistance -->
<!-- Div Group LiveDebug --> <!-- Div Group LiveDebug -->
<hr /> <hr />
<p> <p>
@@ -388,14 +158,99 @@
</div> </div>
<div class="form-group row"> <div class="form-group row">
<div class="col text-center"> <div class="col text-center">
<button id="btn-ws-start" class="btn btn-outline-primary">Start</button> <button id="debugstart" class="btn-wsevent btn btn-outline-primary ml-2">Start</button>
<button id="btn-ws-stop" class="btn btn-outline-primary ml-2">Stop</button> <button id="debugstop" class="btn-wsevent btn btn-outline-primary ml-2">Stop</button>
</div> </div>
</div> </div>
</p> </p>
<!-- Div Group LiveDebug --> <!-- Div Group LiveDebug -->
<!-- Div Group Device Reboot -->
<hr />
<p>
<h4>Ger&auml;t neustarten</h4>
<div class="form-group row">
<div class="col text-center">
<button id="reboot" class="btn-wsevent confirm btn btn-outline-primary">Reboot</button>
</div> </div>
<!-- Div Tab SystemInfo --> </div>
</p>
<!-- Div Group Device Reboot -->
</div>
<!-- Div Tab Maintenance -->
<!-- Div Tab Settings-->
<div id="tab_source" class="tab-pane fade" role="tabpanel">
<h3>Einstellungen</h3>
<!-- Div Group Battery Type -->
<hr />
<p>
<h4>Akku</h4>
<div class="form-group row">
<label for="batterytype" class="control-label col-4">Akku-Variante</label>
<div class="col-8">
<select id="batterytype" class="set-wsevent data-batterytype select form-control">
<option value="Undefined">Undefined</option>
<option value="LiPo3S">LiPo 3S</option>
<option value="LiPo2S">LiPo 2S</option>
</select>
</div>
</div>
</p>
<!-- Div Group Battery Type -->
<!-- Div Group Timer Settings -->
<hr />
<p>
<h4>Timer Einstellungen</h4>
<div class="form-group row">
<label for="active_faction_on_reboot" class="control-label col-4">Aktive Fraktion wiederherstellen</label>
<div class="col-8">
<div class="form-check">
<input class="set-wsevent data-active_faction_on_reboot form-check-input" type="checkbox" id="active_faction_on_reboot">
<label class="form-check-label" for="active_faction_on_reboot">
aktivieren
</label>
</div>
</div>
</div>
<div class="form-group row">
<label for="name_faction1" class="control-label col-4">Faktion 1</label>
<div class="col-8">
<input id="name_faction1" type="text" class="set-wsevent data-name_faction1 form-control" required="required">
<div class="input-group-append">
<span class="input-group-text">max. 32 Zeichen</span>
</div>
</div>
</div>
<div class="form-group row">
<label for="name_faction2" class="control-label col-4">Faktion 2</label>
<div class="col-8">
<input id="name_faction2" type="text" class="set-wsevent data-name_faction2 form-control" required="required">
<div class="input-group-append">
<span class="input-group-text">max. 32 Zeichen</span>
</div>
</div>
</div>
<div class="form-group row">
<label for="name_faction3" class="control-label col-4">Faktion 3</label>
<div class="col-8">
<input id="name_faction3" type="text" class="set-wsevent data-name_faction3 form-control" required="required">
<div class="input-group-append">
<span class="input-group-text">max. 32 Zeichen</span>
</div>
</div>
</div>
<!-- Div Group Timer Settings -->
<!-- Div Group Save Button-->
<hr />
<p>
<div class="form-group row">
<div class="col text-center">
<button id="settingssave" class="btn-wsevent btn btn-outline-primary">Speichern</button>
</div>
</div>
</p>
</div>
<!-- Div Tab Settings -->
<!-- Div Tab Firmware Update--> <!-- Div Tab Firmware Update-->
<div id="tab_fwupdate" class="tab-pane fade" role="tabpanel"> <div id="tab_fwupdate" class="tab-pane fade" role="tabpanel">
@@ -482,14 +337,13 @@
<!-- Tabs Content --> <!-- Tabs Content -->
</main> </main>
<!-- Footer --> <!-- Footer -->
<footer class="page-footer navbar-dark bg-primary font-small fixed-bottom"> <footer class="page-footer navbar-dark bg-primary font-small fixed-bottom">
<div class="container-fluid text-center"> <div class="container-fluid text-center">
<div class="footer-copyright text-center py-3"> <div class="footer-copyright text-center py-3">
<span class="text-muted">© 2023 - <span class="text-muted">© 2023 -
<a class="text-reset fw-bold" href="https://hiabuto.de/">Hiabuto Defense Systems</a></span> <a class="text-reset fw-bold" href="https://eventronics.de/">Marcel Peterkau</a></span>
</div> </div>
</div> </div>
</footer> </footer>
@@ -520,46 +374,7 @@
<!-- Modal Dialog --> <!-- 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>

View File

@@ -8439,3 +8439,22 @@ a.text-dark:hover {
.navbar-dark.bg-primary { .navbar-dark.bg-primary {
background-color: #111 !important background-color: #111 !important
} }
.glow-active-faction {
border: 3px solid #FFD700; /* Goldene Umrandung */
box-shadow: 0 0 20px #FFD700; /* Leuchtender Glüheffekt */
animation: glow 1.5s infinite alternate;
border-radius: 10px; /* Abgerundete Ecken */
margin-bottom: 10px; /* Abstand nach unten */
}
@keyframes glow {
from {
box-shadow: 0 0 10px #FFD700;
}
to {
box-shadow: 0 0 20px #FFD700;
}
}

View File

@@ -3,6 +3,13 @@ const jsonFilePath = "static/dtc_table.json";
var dtcState = {}; var dtcState = {};
async function processDTCNotifications(dtcArray) { async function processDTCNotifications(dtcArray) {
// Entferne DTCs aus dtcState, die nicht im dtcArray enthalten sind
for (var key in dtcState) {
if (!dtcArray.some((dtc) => parseInt(dtc.split(",")[1]) == key)) {
delete dtcState[key];
}
}
if (dtcArray.length === 0 || dtcArray[0] == "0") { if (dtcArray.length === 0 || dtcArray[0] == "0") {
dtcState = {}; dtcState = {};
return; return;
@@ -31,14 +38,14 @@ async function processDTCNotifications(dtcArray) {
if (dtcState[errorCode]) { if (dtcState[errorCode]) {
// Überprüfen, ob sich der Zustand von "previous" auf "active" geändert hat // Überprüfen, ob sich der Zustand von "previous" auf "active" geändert hat
if (activity !== dtcState[errorCode]) { if (activity !== dtcState[errorCode].activity) {
dtcState[errorCode] = activity; dtcState[errorCode].activity = activity;
if (activity === 1) showNotification(description, severity); if (activity === 1) showNotification(description, severity);
} }
} else { } else {
// DTC ist neu, Zustand speichern und Benachrichtigung anzeigen // DTC ist neu, Zustand speichern und wenn active, Benachrichtigung anzeigen
dtcState[errorCode] = activity; dtcState[errorCode] = { activity: activity };
showNotification(description, severity); if (activity === 1) showNotification(description, severity);
} }
} catch (error) { } catch (error) {
console.error("Error processing DTC:", error); console.error("Error processing DTC:", error);
@@ -89,14 +96,15 @@ async function showDTCModal(event) {
} catch (error) { } catch (error) {
console.error("Fehler beim Abrufen der Beschreibung:", error); console.error("Fehler beim Abrufen der Beschreibung:", error);
modal.find(".modal-title").text("Fehler"); modal.find(".modal-title").text("Fehler");
modal.find(".dtc-desc").text("DTC-Beschreibung konnte nicht geladen werden"); modal
.find(".dtc-desc")
.text("DTC-Beschreibung konnte nicht geladen werden");
} }
// Modal anzeigen // Modal anzeigen
modal.modal("show"); modal.modal("show");
} }
function fillDTCTable(dtcArray) { function fillDTCTable(dtcArray) {
// Referenz auf das Tabellen-Element // Referenz auf das Tabellen-Element
var table = document.getElementById("dtc_table"); var table = document.getElementById("dtc_table");
@@ -108,10 +116,27 @@ function fillDTCTable(dtcArray) {
tablediv.hidden = true; tablediv.hidden = true;
table.innerHTML = ""; table.innerHTML = "";
return; return;
} else { }
// Prüfen, ob sich der Inhalt der Tabelle geändert hat
var tableContentChanged = false;
for (var i = 0; i < dtcArray.length; i++) {
var dtcInfo = dtcArray[i].split(",");
var errorCode = parseInt(dtcInfo[1]);
var activity = parseInt(dtcInfo[3]);
if (!dtcState[errorCode] || dtcState[errorCode].activity !== activity) {
tableContentChanged = true;
break;
}
}
if (!tableContentChanged) {
return;
}
// Zeige das Tabellen-Div, wenn DTC vorhanden sind // Zeige das Tabellen-Div, wenn DTC vorhanden sind
tablediv.hidden = false; tablediv.hidden = false;
}
// Tabelle leeren, bevor sie neu gefüllt wird // Tabelle leeren, bevor sie neu gefüllt wird
table.innerHTML = ""; table.innerHTML = "";

View File

@@ -84,7 +84,6 @@ function onMessage(event) {
processDTCNotifications(dtcArray); processDTCNotifications(dtcArray);
fillDTCTable(dtcArray); fillDTCTable(dtcArray);
} else if (data.startsWith("MAPPING_STATUS:")) { } else if (data.startsWith("MAPPING_STATUS:")) {
const data_sliced = data.slice(15); const data_sliced = data.slice(15);
statusMapping = createMapping(data_sliced); statusMapping = createMapping(data_sliced);
@@ -179,14 +178,57 @@ function fillValuesToHTML(dataset) {
// Wenn das Element ein Settingsabschnitt-div ist // Wenn das Element ein Settingsabschnitt-div ist
if (dataset[key] == 0) element.style.display = "none"; if (dataset[key] == 0) element.style.display = "none";
else element.style.display = ""; else element.style.display = "";
} else if (element.tagName === "DIV" || element.tagName === "SPAN") {
if (element.classList.contains("format-time")) {
element.innerText = formatTime(dataset[key]);
} else if (element.classList.contains("faction-logo")) {
// Faction-Logo-Logik
updateFactionLogo(element, dataset[key]);
} else {
element.innerText = dataset[key];
}
} else { } else {
// Standardmäßig für Textfelder und andere Elemente // Standardmäßig für Textfelder und andere Elemente
element.value = dataset[key]; element.value = dataset[key];
} }
} }
} }
// Aktualisiere den <title>-Tag, wenn der Schlüssel 'devicename' im dataset vorhanden ist
if (key === "devicename") {
document.title = dataset[key];
} }
} }
}
function formatTime(seconds) {
var hrs = Math.floor(seconds / 3600);
var mins = Math.floor((seconds % 3600) / 60);
var secs = seconds % 60;
return (
String(hrs).padStart(2, "0") +
":" +
String(mins).padStart(2, "0") +
":" +
String(secs).padStart(2, "0")
);
}
function updateFactionLogo(element, faction) {
const glowClass = "glow-active-faction";
const factionClasses = ["faction1", "faction2", "faction3"];
factionClasses.forEach((factionClass) => {
if (
factionClass === "faction" + faction &&
element.classList.contains(factionClass)
) {
element.classList.add(glowClass);
} else {
element.classList.remove(glowClass);
}
});
}
// Funktion zum Setzen des ausgewählten Werts für Dropdowns // Funktion zum Setzen des ausgewählten Werts für Dropdowns
function setDropdownValue(selectElement, value) { function setDropdownValue(selectElement, value) {

View File

@@ -1 +1 @@
1.05 1.06

View File

@@ -12,8 +12,10 @@
#define TRUE 1 #define TRUE 1
#define FALSE 0 #define FALSE 0
#ifndef HOST_NAME #ifndef DEVICE_NAME
#define HOST_NAME "AirsoftTimer_%08X" #define HOST_NAME "AirsoftTimer"
#else
#define HOST_NAME DEVICE_NAME
#endif #endif
#define SHUTDOWN_DELAY_MS 5000 #define SHUTDOWN_DELAY_MS 5000
@@ -50,14 +52,24 @@
typedef enum eSystem_Status typedef enum eSystem_Status
{ {
sysStat_Init,
sysStat_Startup, sysStat_Startup,
sysStat_Normal, sysStat_Normal,
sysStat_Rain,
sysStat_Purge,
sysStat_Error, sysStat_Error,
sysStat_Shutdown sysStat_Shutdown
} tSystem_Status; } tSystem_Status;
typedef enum batteryType_e
{
BATTERY_UNDEFINED,
BATTERY_LIPO_2S,
BATTERY_LIPO_3S
} batteryType_t;
// String representation of SpeedSource enum
extern const char *BatteryString[];
extern const size_t BatteryString_Elements;
#define STARTUP_DELAY 2500 #define STARTUP_DELAY 2500
#define SHUTDOWN_DELAY_MS 2500 #define SHUTDOWN_DELAY_MS 2500

View File

@@ -17,12 +17,15 @@
#include <Arduino.h> #include <Arduino.h>
#include "webui.h" #include "webui.h"
const char PROGMEM helpCmd[] = "sysinfo - System Info\n" const char PROGMEM helpCmd[] = "sysinfo - System Info\n"
"reboot - System Reboot\n"
"netinfo - WiFi Info\n" "netinfo - WiFi Info\n"
"formatPDS - Format Persistence EEPROM Data\n" "formatPDS - Format Persistence EEPROM Data\n"
"formatCFG - Format Configuration EEPROM Data\n" "formatCFG - Format Configuration EEPROM Data\n"
"checkEE - Check EEPROM with checksum\n" "checkEE - Check EEPROM with checksum\n"
"dumpEE1k - dump the first 1kb of EEPROM to Serial\n" "dumpEE1k - dump the first 1kb of EEPROM to Serial\n"
"dumpEE - dump the whole EPPROM to Serial\n" "dumpEE - dump the whole EPPROM to Serial\n"
"killEE - kill the first 1024 byte of EEPROM\n"
"zeroEE - zero the first 1024 byte of EEPROM\n"
"resetPageEE - Reset the PersistenceData Page\n" "resetPageEE - Reset the PersistenceData Page\n"
"dumpCFG - print Config struct\n" "dumpCFG - print Config struct\n"
"dumpPDS - print PersistanceStruct\n" "dumpPDS - print PersistanceStruct\n"

View File

@@ -57,20 +57,6 @@ typedef struct
uint32_t checksum; uint32_t checksum;
} persistenceData_t; } persistenceData_t;
typedef enum
{
BATTERY_UNDEFINED,
BATTERY_LIPO_2S,
BATTERY_LIPO_3S
} batteryType_t;
const char BatteryString[][10]{
"Undefined",
"LiPo 2S",
"LiPo 3S"};
const size_t BatteryString_Elements = sizeof(BatteryString) / sizeof(BatteryString[0]);
// Structure for configuration settings stored in EEPROM // Structure for configuration settings stored in EEPROM
typedef struct typedef struct
{ {
@@ -104,7 +90,7 @@ const configData_t ConfigData_defaults = {
0 // checksum 0 // checksum
}; };
void InitEEPROM(); boolean InitEEPROM();
void EEPROM_Process(); void EEPROM_Process();
void StoreConfig_EEPROM(); void StoreConfig_EEPROM();
void GetConfig_EEPROM(); void GetConfig_EEPROM();
@@ -117,6 +103,8 @@ 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);
bool validateWiFiString(char *string, size_t size); bool validateWiFiString(char *string, size_t size);
void writeSequentialToEEPROM(uint16_t memoryAddress, uint16_t length);
void writeZeroToEEPROM(uint16_t memoryAddress, uint16_t length);
extern configData_t ConfigData; extern configData_t ConfigData;
extern persistenceData_t PersistenceData; extern persistenceData_t PersistenceData;

View File

@@ -11,6 +11,7 @@ typedef struct Globals_s
char systemStatustxt[16] = ""; /**< Text representation of system status */ char systemStatustxt[16] = ""; /**< Text representation of system status */
EERequest_t requestEEAction = EE_IDLE; /**< EEPROM-related request */ EERequest_t requestEEAction = EE_IDLE; /**< EEPROM-related request */
char DeviceName[33]; /**< Device name */ char DeviceName[33]; /**< Device name */
char DeviceNameId[sizeof(DeviceName) + 8]; /**< Device name plus 8 chars chipID */
char FlashVersion[10]; /**< Flash version */ char FlashVersion[10]; /**< Flash version */
uint16_t eePersistanceAdress; /**< EEPROM persistence address */ uint16_t eePersistanceAdress; /**< EEPROM persistence address */
bool hasDTC; bool hasDTC;
@@ -31,8 +32,8 @@ typedef struct Constants_s
} Constants_t; } Constants_t;
const Constants_t constants PROGMEM = { const Constants_t constants PROGMEM = {
1, 5, // Firmware_Version FW_MAJOR, FW_MINOR, // Firmware_Version
1, 5, // Required Flash Version FL_MAJOR, FL_MINOR, // Required Flash Version
GIT_REV // Git-Hash-String GIT_REV // Git-Hash-String
}; };

View File

@@ -19,10 +19,10 @@
#endif #endif
#ifdef FEATURE_ENABLE_WIFI_CLIENT #ifdef FEATURE_ENABLE_WIFI_CLIENT
#ifndef WIFI_CLIENT_PASSWORD #ifndef WIFI_PASSWORD_CLIENT
#error "You must define an WIFI_PASSWORD for OTA-Update" #error "You must define an WIFI_PASSWORD for OTA-Update"
#endif #endif
#ifndef WIFI_CLIENT_SSID #ifndef WIFI_SSID_CLIENT
#error "You must define an WIFI_SSID for OTA-Update" #error "You must define an WIFI_SSID for OTA-Update"
#endif #endif
#endif #endif

View File

@@ -17,24 +17,26 @@ platform = espressif8266
framework = arduino framework = arduino
board = d1_mini board = d1_mini
custom_firmware_version = 1.06
custom_flash_version = 1.06
upload_protocol = esptool upload_protocol = esptool
upload_speed = 921600 upload_speed = 921600
;upload_port = 10.0.1.48 ;upload_port = 10.0.1.48
;upload_protocol = espota
;upload_flags = ;upload_flags =
; --auth=${wifi_cred.ota_password} ; --port=8266
; --auth=${wifi_cred.admin_password}
build_flags= build_flags=
!python codegen/git_rev_macro.py
-DATOMIC_FS_UPDATE -DATOMIC_FS_UPDATE
-DFEATURE_ENABLE_WIFI_CLIENT -DFEATURE_ENABLE_WIFI_CLIENT
;-DFEATURE_ENABLE_LORA ;-DFEATURE_ENABLE_LORA
-DFEATURE_ENABLE_UARTLORA -DFEATURE_ENABLE_UARTLORA
-DWIFI_AP_IP_GW=10,0,0,1 -DWIFI_AP_IP_GW=10,0,0,1
-DADMIN_PASSWORD=${wifi_cred.ota_password} -DADMIN_PASSWORD=${wifi_cred.admin_password}
-DWIFI_CLIENT_SSID=${wifi_cred.wifi_client_ssid} -DWIFI_SSID_CLIENT=${wifi_cred.wifi_ssid_client}
-DWIFI_CLIENT_PASSWORD=${wifi_cred.wifi_client_password} -DWIFI_PASSWORD_CLIENT=${wifi_cred.wifi_password_client}
-DWIFI_AP_SSID=${wifi_cred.wifi_ap_ssid} -DADMIN_PASSWORD=${wifi_cred.admin_password}
-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"'

8
Software/src/common.cpp Normal file
View File

@@ -0,0 +1,8 @@
#include "common.h"
const char *BatteryString[] = {
"Undefined",
"LiPo 2S",
"LiPo 3S"};
const size_t BatteryString_Elements = sizeof(BatteryString) / sizeof(BatteryString[0]);

View File

@@ -179,7 +179,6 @@ void Debug_pushMessage(const char *format, ...)
} }
} }
/** /**
* @brief Processes a debug command and performs corresponding actions. * @brief Processes a debug command and performs corresponding actions.
* *
@@ -190,6 +189,8 @@ void processCmdDebug(String command)
// Check the received command and execute corresponding actions // Check the received command and execute corresponding actions
if (command == "help") if (command == "help")
Debug_printHelp(); Debug_printHelp();
else if (command == "reboot")
globals.systemStatus = sysStat_Shutdown;
else if (command == "sysinfo") else if (command == "sysinfo")
Debug_printSystemInfo(); Debug_printSystemInfo();
else if (command == "netinfo") else if (command == "netinfo")
@@ -206,6 +207,10 @@ void processCmdDebug(String command)
dumpEEPROM(0, 1024); dumpEEPROM(0, 1024);
else if (command == "dumpEE") else if (command == "dumpEE")
dumpEEPROM(0, EEPROM_SIZE_BYTES); dumpEEPROM(0, EEPROM_SIZE_BYTES);
else if (command == "killEE")
writeSequentialToEEPROM(0, 1024);
else if (command == "zeroEE")
writeZeroToEEPROM(0, 1024);
else if (command == "resetPageEE") else if (command == "resetPageEE")
MovePersistencePage_EEPROM(true); MovePersistencePage_EEPROM(true);
else if (command == "dumpCFG") else if (command == "dumpCFG")
@@ -283,6 +288,18 @@ void Debug_printSystemInfo()
Debug_pushMessage("OTA-Pass: %s\n", QUOTE(ADMIN_PASSWORD)); Debug_pushMessage("OTA-Pass: %s\n", QUOTE(ADMIN_PASSWORD));
Debug_pushMessage("Git-Revision: %s\n", constants.GitHash); Debug_pushMessage("Git-Revision: %s\n", constants.GitHash);
Debug_pushMessage("Sw-Version: %d.%02d\n", constants.FW_Version_major, constants.FW_Version_minor); Debug_pushMessage("Sw-Version: %d.%02d\n", constants.FW_Version_major, constants.FW_Version_minor);
Debug_pushMessage("globals.systemStatus: %d\n", globals.systemStatus);
Debug_pushMessage("globals.resumeStatus: %d\n", globals.resumeStatus);
Debug_pushMessage("globals.systemStatustxt: %s\n", globals.systemStatustxt);
Debug_pushMessage("globals.requestEEAction: %d\n", globals.requestEEAction);
Debug_pushMessage("globals.DeviceName: %s\n", globals.DeviceName);
Debug_pushMessage("globals.FlashVersion: %s\n", globals.FlashVersion);
Debug_pushMessage("globals.eePersistanceAdress: %u\n", globals.eePersistanceAdress);
Debug_pushMessage("globals.hasDTC: %d\n", globals.hasDTC);
Debug_pushMessage("globals.loadvoltage_mV: %d\n", globals.loadvoltage_mV);
Debug_pushMessage("globals.battery_level: %d\n", globals.battery_level);
Debug_pushMessage("globals.timer_disabled: %d\n", globals.timer_disabled);
} }
/** /**
@@ -291,6 +308,15 @@ void Debug_printSystemInfo()
void Debug_dumpConfig() void Debug_dumpConfig()
{ {
Debug_pushMessage("batteryType: %d\n", ConfigData.batteryType); Debug_pushMessage("batteryType: %d\n", ConfigData.batteryType);
Debug_pushMessage("Faction_1_Name: %s\n", ConfigData.Faction_1_Name);
Debug_pushMessage("Faction_1_Name: %s\n", ConfigData.Faction_2_Name);
Debug_pushMessage("Faction_1_Name: %s\n", ConfigData.Faction_3_Name);
Debug_pushMessage("active_faction_on_reboot: %d\n", ConfigData.active_faction_on_reboot);
Debug_pushMessage("wifi_autoconnect: %d\n", ConfigData.wifi_autoconnect);
Debug_pushMessage("wifi_ap_password: %s\n", ConfigData.wifi_ap_password);
Debug_pushMessage("wifi_ap_ssid: %s\n", ConfigData.wifi_ap_ssid);
Debug_pushMessage("wifi_client_ssid: %s\n", ConfigData.wifi_client_ssid);
Debug_pushMessage("wifi_client_password: %s\n", ConfigData.wifi_client_password);
Debug_pushMessage("EEPROM_Version: %d\n", ConfigData.EEPROM_Version); Debug_pushMessage("EEPROM_Version: %d\n", ConfigData.EEPROM_Version);
Debug_pushMessage("checksum: 0x%08X\n", ConfigData.checksum); Debug_pushMessage("checksum: 0x%08X\n", ConfigData.checksum);
} }
@@ -451,12 +477,15 @@ void Debug_printHelp()
* @return A pointer to a const char string containing the binary representation * @return A pointer to a const char string containing the binary representation
* of the input number with nibbles separated by a space. * of the input number with nibbles separated by a space.
*/ */
const char* uint32_to_binary_string(uint32_t num) { const char *uint32_to_binary_string(uint32_t num)
{
static char binary_str[65]; // 32 bits + 31 spaces + null terminator static char binary_str[65]; // 32 bits + 31 spaces + null terminator
int i, j; int i, j;
for (i = 31, j = 0; i >= 0; i--, j++) { for (i = 31, j = 0; i >= 0; i--, j++)
{
binary_str[j] = ((num >> i) & 1) ? '1' : '0'; binary_str[j] = ((num >> i) & 1) ? '1' : '0';
if (i % 4 == 0 && i != 0) { if (i % 4 == 0 && i != 0)
{
binary_str[++j] = ' '; // Insert space after every nibble binary_str[++j] = ' '; // Insert space after every nibble
} }
} }

View File

@@ -35,12 +35,13 @@ boolean checkEEPROMavailable();
* *
* This function initializes the EEPROM using the I2C_eeprom instance and checks if it's available. * This function initializes the EEPROM using the I2C_eeprom instance and checks if it's available.
*/ */
void InitEEPROM() boolean InitEEPROM()
{ {
Wire.begin();
ConfigData = ConfigData_defaults; ConfigData = ConfigData_defaults;
PersistenceData = {0}; PersistenceData = {0};
ee.begin(); ee.begin();
checkEEPROMavailable(); return checkEEPROMavailable();
} }
/** /**
@@ -113,16 +114,23 @@ void EEPROM_Process()
*/ */
void StoreConfig_EEPROM() void StoreConfig_EEPROM()
{ {
// Berechnung der Prüfsumme
ConfigData.checksum = 0; ConfigData.checksum = 0;
ConfigData.checksum = Checksum_EEPROM((uint8_t *)&ConfigData, sizeof(ConfigData)); ConfigData.checksum = Checksum_EEPROM((uint8_t *)&ConfigData, sizeof(ConfigData));
// Überprüfung, ob der EEPROM verfügbar ist
if (!checkEEPROMavailable()) if (!checkEEPROMavailable())
return; return;
ee.updateBlock(startofConfigData, (uint8_t *)&ConfigData, sizeof(ConfigData)); // Byteweise in den EEPROM schreiben
uint8_t *dataPtr = (uint8_t *)&ConfigData;
for (uint16_t i = 0; i < sizeof(ConfigData); i++)
{
ee.writeByte(startofConfigData + i, dataPtr[i]);
}
// Sanity Check der Konfiguration
uint32_t ConfigSanityCheckResult = ConfigSanityCheck(false); uint32_t ConfigSanityCheckResult = ConfigSanityCheck(false);
if (ConfigSanityCheckResult > 0) if (ConfigSanityCheckResult > 0)
{ {
MaintainDTC(DTC_EEPROM_CFG_SANITY, true, ConfigSanityCheckResult); MaintainDTC(DTC_EEPROM_CFG_SANITY, true, ConfigSanityCheckResult);
@@ -152,7 +160,6 @@ void GetConfig_EEPROM()
uint32_t ConfigSanityCheckResult = ConfigSanityCheck(false); uint32_t ConfigSanityCheckResult = ConfigSanityCheck(false);
MaintainDTC(DTC_EEPROM_CFG_SANITY, (ConfigSanityCheckResult > 0), ConfigSanityCheckResult); MaintainDTC(DTC_EEPROM_CFG_SANITY, (ConfigSanityCheckResult > 0), ConfigSanityCheckResult);
} }
/** /**
@@ -174,7 +181,12 @@ void StorePersistence_EEPROM()
if (!checkEEPROMavailable()) if (!checkEEPROMavailable())
return; return;
ee.updateBlock(globals.eePersistanceAdress, (uint8_t *)&PersistenceData, sizeof(PersistenceData)); // Byteweise in den EEPROM schreiben
uint8_t *dataPtr = (uint8_t *)&PersistenceData;
for (uint16_t i = 0; i < sizeof(PersistenceData); i++)
{
ee.writeByte(globals.eePersistanceAdress + i, dataPtr[i]);
}
} }
/** /**
@@ -306,7 +318,7 @@ void dumpEEPROM(uint16_t memoryAddress, uint16_t length)
if (!checkEEPROMavailable()) if (!checkEEPROMavailable())
return; return;
char ascii_buf[BLOCK_TO_LENGTH + 1]; char ascii_buf[BLOCK_TO_LENGTH + 1] = {0};
sprintf(ascii_buf, "%*s", BLOCK_TO_LENGTH, "ASCII"); sprintf(ascii_buf, "%*s", BLOCK_TO_LENGTH, "ASCII");
// Print column headers // Print column headers
@@ -325,25 +337,27 @@ void dumpEEPROM(uint16_t memoryAddress, uint16_t length)
// Print ASCII representation header for each block // Print ASCII representation header for each block
if (blockpoint == 0) if (blockpoint == 0)
{
if (i > 0) // Ensure we don't print an empty ASCII buffer on the first iteration
{ {
ascii_buf[BLOCK_TO_LENGTH] = 0; ascii_buf[BLOCK_TO_LENGTH] = 0;
Debug_pushMessage(" %s", ascii_buf); Debug_pushMessage(" %s", ascii_buf);
}
Debug_pushMessage("\n0x%05X:", memoryAddress); Debug_pushMessage("\n0x%05X:", memoryAddress);
memset(ascii_buf, ' ', BLOCK_TO_LENGTH); // Clear the ASCII buffer with spaces
} }
// Read and print each byte // Read and print each byte
ascii_buf[blockpoint] = ee.readByte(memoryAddress); uint8_t byte = ee.readByte(memoryAddress);
Debug_pushMessage(" %02X", ascii_buf[blockpoint]); ascii_buf[blockpoint] = (byte >= 0x20 && byte <= 0x7E) ? byte : '.';
Debug_pushMessage(" %02X", byte);
// Replace non-printable characters with dots in ASCII representation
if (ascii_buf[blockpoint] < 0x20 || ascii_buf[blockpoint] > 0x7E)
ascii_buf[blockpoint] = '.';
memoryAddress++; memoryAddress++;
} }
// Print a new line at the end of the dump // Print remaining ASCII buffer
Debug_pushMessage("\n"); ascii_buf[BLOCK_TO_LENGTH] = 0;
Debug_pushMessage(" %s\n", ascii_buf); // Final ASCII line
} }
/** /**
@@ -459,3 +473,43 @@ bool validateWiFiString(char *string, size_t size)
return false; return false;
} }
/**
* @brief Write sequential numbers to a portion of EEPROM.
*
* This function writes sequential numbers starting from 0 to a specified portion of EEPROM.
* If the number reaches 255, it wraps around and starts again from 1.
*
* @param memoryAddress Starting address in EEPROM.
* @param length Number of bytes to write.
*/
void writeSequentialToEEPROM(uint16_t memoryAddress, uint16_t length)
{
if (!checkEEPROMavailable())
return;
uint8_t value = 0;
for (uint16_t i = 0; i < length; i++)
{
ee.writeByte(memoryAddress + i, value);
value = (value == 255) ? 1 : value + 1;
}
}
/**
* @brief Write 0 to a portion of EEPROM.
*
* This function writes 0 to a specified portion of EEPROM.
*
* @param memoryAddress Starting address in EEPROM.
* @param length Number of bytes to write.
*/
void writeZeroToEEPROM(uint16_t memoryAddress, uint16_t length)
{
if (!checkEEPROMavailable())
return;
for (uint16_t i = 0; i < length; i++)
{
ee.writeByte(memoryAddress + i, 0);
}
}

View File

@@ -6,4 +6,5 @@ void initGlobals()
{ {
globals.systemStatus = sysStat_Startup; globals.systemStatus = sysStat_Startup;
globals.requestEEAction = EE_IDLE; globals.requestEEAction = EE_IDLE;
globals.systemStatustxt[0] = 0;
} }

View File

@@ -79,7 +79,7 @@ void LoRa_Process()
if (e220ttl.available() > 1) if (e220ttl.available() > 1)
{ {
ResponseContainer rc = e220ttl.receiveMessageRSSI(); ResponseContainer rc = e220ttl.receiveMessageRSSI();
// Is something goes wrong print error // If something goes wrong, print error
if (rc.status.code != 1) if (rc.status.code != 1)
{ {
Serial.println(rc.status.getResponseDescription()); Serial.println(rc.status.getResponseDescription());
@@ -96,34 +96,45 @@ void LoRa_Process()
#elif defined(FEATURE_ENABLE_UARTLORA) #elif defined(FEATURE_ENABLE_UARTLORA)
static char packageInput[32]; static char packageInput[32];
static bool packageRecieved = false; static bool packageReceived = false;
static unsigned int bufferPtr = 0; static unsigned int bufferPtr = 0;
int recievedSize = 0; int receivedSize = 0;
while (SerialLoRa.available() && packageRecieved == false) while (SerialLoRa.available() && !packageReceived)
{ {
if (bufferPtr < sizeof(packageInput) - 1) if (bufferPtr < sizeof(packageInput) - 1)
{ {
packageInput[bufferPtr] = SerialLoRa.read(); char c = SerialLoRa.read();
packageInput[bufferPtr + 1] = 0; // always terminate String packageInput[bufferPtr] = c;
packageInput[bufferPtr + 1] = '\0'; // always terminate string
if (packageInput[bufferPtr] == '\n') if (c == '\n')
{ {
packageRecieved = true; packageReceived = true;
recievedSize = bufferPtr; receivedSize = bufferPtr;
bufferPtr = 0; bufferPtr = 0;
Debug_pushMessage("Got LoRa UART: %s\n", packageInput); 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 else if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c == ' ' || c == ',' || c == '.')) // Accept numbers, uppercase letters, and some special chars
{ {
bufferPtr++; bufferPtr++;
} }
else
{
Debug_pushMessage("Invalid character received: %c\n", c);
}
}
else
{
Debug_pushMessage("Buffer overflow. Resetting buffer.\n");
bufferPtr = 0;
} }
} }
if (packageRecieved) { if (packageReceived)
Parse_LoRa_UartCommand(packageInput, recievedSize); {
packageRecieved = false; Parse_LoRa_UartCommand(packageInput, receivedSize);
packageReceived = false;
} }
#endif #endif

View File

@@ -84,7 +84,8 @@ void setup()
system_update_cpu_freq(SYS_CPU_80MHZ); system_update_cpu_freq(SYS_CPU_80MHZ);
// Generate a unique device name based on ESP chip ID // Generate a unique device name based on ESP chip ID
snprintf(globals.DeviceName, 32, HOST_NAME, ESP.getChipId()); strncpy(globals.DeviceName, HOST_NAME, sizeof(globals.DeviceName));
snprintf(globals.DeviceNameId, sizeof(globals.DeviceNameId), "%s_%08X", globals.DeviceName, ESP.getChipId());
// Disable WiFi persistent storage // Disable WiFi persistent storage
WiFi.persistent(false); WiFi.persistent(false);
@@ -95,7 +96,7 @@ void setup()
#ifdef FEATURE_ENABLE_WIFI_CLIENT #ifdef FEATURE_ENABLE_WIFI_CLIENT
// Configure WiFi settings for client mode if enabled // Configure WiFi settings for client mode if enabled
WiFi.mode(WIFI_STA); WiFi.mode(WIFI_STA);
WiFi.setHostname(globals.DeviceName); WiFi.setHostname(globals.DeviceNameId);
wifiMulti.addAP(QUOTE(WIFI_SSID_CLIENT), QUOTE(WIFI_PASSWORD_CLIENT)); wifiMulti.addAP(QUOTE(WIFI_SSID_CLIENT), QUOTE(WIFI_PASSWORD_CLIENT));
tmrWiFiMaintainConnection.start(); tmrWiFiMaintainConnection.start();
#else #else
@@ -108,14 +109,20 @@ void setup()
Serial.setDebugOutput(false); Serial.setDebugOutput(false);
Serial.print("\n\n-------------------START-------------------\n"); Serial.print("\n\n-------------------START-------------------\n");
Serial.print(globals.DeviceName); Serial.print(globals.DeviceNameId);
Serial.print("\nby Hiabuto Defense\n"); Serial.print("\nby Hiabuto Defense\n\n");
// Initialize EEPROM, load configuration, and persistence data from EEPROM // Initialize EEPROM, load configuration, and persistence data from EEPROM
InitEEPROM(); if (InitEEPROM())
{
GetConfig_EEPROM(); GetConfig_EEPROM();
GetPersistence_EEPROM(); GetPersistence_EEPROM();
Serial.print("\nEE-Init done"); Serial.printf("Initialized EEPROM at Address 0x%02X\n", I2C_EE_ADDRESS);
}
else
{
Serial.print("EEPROM not Initialized\n");
}
if (i2c_io.begin()) if (i2c_io.begin())
{ {
@@ -150,7 +157,7 @@ void setup()
// Set up OTA updates // Set up OTA updates
ArduinoOTA.setPort(8266); ArduinoOTA.setPort(8266);
ArduinoOTA.setHostname(globals.DeviceName); ArduinoOTA.setHostname(globals.DeviceNameId);
ArduinoOTA.setPassword(QUOTE(ADMIN_PASSWORD)); ArduinoOTA.setPassword(QUOTE(ADMIN_PASSWORD));
ArduinoOTA.onStart([]() ArduinoOTA.onStart([]()
@@ -208,7 +215,6 @@ void setup()
// Start cyclic EEPROM updates for Persistence Data Structure (PDS) // Start cyclic EEPROM updates for Persistence Data Structure (PDS)
tmrEEPROMCyclicPDS.start(); tmrEEPROMCyclicPDS.start();
Serial.print("\nSetup Done\n");
disp_FAC_1.init(); disp_FAC_1.init();
disp_FAC_1.setBrightness(5); disp_FAC_1.setBrightness(5);
@@ -217,7 +223,6 @@ void setup()
disp_FAC_3.init(); disp_FAC_3.init();
disp_FAC_3.setBrightness(5); disp_FAC_3.setBrightness(5);
tmrEEPROMCyclicPDS.start();
tmrFactionTicker.start(); tmrFactionTicker.start();
tmrInputGetter.start(); tmrInputGetter.start();
@@ -251,7 +256,7 @@ void loop()
tmrWiFiMaintainConnection.update(); tmrWiFiMaintainConnection.update();
#endif #endif
static tSystem_Status lastStatus = sysStat_Error; static tSystem_Status lastStatus = sysStat_Init;
// Handle different system statuses // Handle different system statuses
switch (globals.systemStatus) switch (globals.systemStatus)
@@ -293,7 +298,12 @@ void loop()
} }
SystemShutdown(false); SystemShutdown(false);
break; break;
case sysStat_Error:
if (lastStatus != globals.systemStatus)
{
strcpy_P(globals.systemStatustxt, PSTR("Error"));
lastStatus = globals.systemStatus;
}
default: default:
break; break;
} }
@@ -578,7 +588,7 @@ void toggleWiFiAP(bool shutdown)
// Start WiFi in Access Point (AP) mode // Start WiFi in Access Point (AP) mode
WiFi.mode(WIFI_AP); WiFi.mode(WIFI_AP);
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(globals.DeviceName, QUOTE(WIFI_AP_PASSWORD)); WiFi.softAP(globals.DeviceNameId, QUOTE(WIFI_AP_PASSWORD));
// Stop WiFi maintenance connection ticker if enabled and display debug messages // Stop WiFi maintenance connection ticker if enabled and display debug messages
#ifdef FEATURE_ENABLE_WIFI_CLIENT #ifdef FEATURE_ENABLE_WIFI_CLIENT

View File

@@ -17,6 +17,8 @@ AsyncWebServer webServer(80);
const char *PARAM_MESSAGE = "message"; const char *PARAM_MESSAGE = "message";
batteryType_t batterytypePreselect; /**< Preselect Memory for change Batterytype */
String processor(const String &var); String processor(const String &var);
void WebserverNotFound_Callback(AsyncWebServerRequest *request); void WebserverNotFound_Callback(AsyncWebServerRequest *request);
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);
@@ -69,7 +71,7 @@ void initWebUI()
} }
// Initialize mDNS and add service // Initialize mDNS and add service
MDNS.begin(globals.DeviceName); MDNS.begin(globals.DeviceNameId);
MDNS.addService("http", "tcp", 80); MDNS.addService("http", "tcp", 80);
// Set up WebSocket event handler and attach to web server // Set up WebSocket event handler and attach to web server
@@ -340,7 +342,7 @@ void WebServerEEJSON_Callback(AsyncWebServerRequest *request)
char buffer[16]; char buffer[16];
info["DeviceName"] = globals.DeviceName; info["DeviceNameId"] = globals.DeviceNameId;
sprintf(buffer, "%d.%02d", constants.Required_Flash_Version_major, constants.Required_Flash_Version_minor); sprintf(buffer, "%d.%02d", constants.Required_Flash_Version_major, constants.Required_Flash_Version_minor);
info["FW-Version"] = buffer; info["FW-Version"] = buffer;
info["FS-Version"] = globals.FlashVersion; info["FS-Version"] = globals.FlashVersion;
@@ -446,8 +448,14 @@ void Websocket_HandleButtons(uint8_t *data)
char value[32]; char value[32];
parseWebsocketString((char *)data, identifier, sizeof(identifier), value, sizeof(value)); parseWebsocketString((char *)data, identifier, sizeof(identifier), value, sizeof(value));
if (strcmp(identifier, "reset-timer") == 0)
if (strcmp(identifier, "debugstart") == 0) {
PersistenceData.activeFaction = NONE;
PersistenceData.faction_1_timer = 0;
PersistenceData.faction_2_timer = 0;
PersistenceData.faction_3_timer = 0;
}
else if (strcmp(identifier, "debugstart") == 0)
{ {
SetDebugportStatus(dbg_Webui, enabled); SetDebugportStatus(dbg_Webui, enabled);
} }
@@ -457,6 +465,7 @@ void Websocket_HandleButtons(uint8_t *data)
} }
else if (strcmp(identifier, "settingssave") == 0) else if (strcmp(identifier, "settingssave") == 0)
{ {
ConfigData.batteryType = batterytypePreselect;
globals.requestEEAction = EE_CFG_SAVE; globals.requestEEAction = EE_CFG_SAVE;
} }
else if (strcmp(identifier, "reboot") == 0) else if (strcmp(identifier, "reboot") == 0)
@@ -484,7 +493,33 @@ void Websocket_HandleSettings(uint8_t *data)
parseWebsocketString((char *)data, identifier, sizeof(identifier), value, sizeof(value)); parseWebsocketString((char *)data, identifier, sizeof(identifier), value, sizeof(value));
if (strcmp(identifier, "wifi-ssid") == 0) if (strcmp(identifier, "active_faction_on_reboot") == 0)
{
ConfigData.active_faction_on_reboot = value[0] == '1' ? true : false;
}
else if (strcmp(identifier, "name_faction1") == 0)
{
strncpy(ConfigData.Faction_1_Name, value, sizeof(ConfigData.Faction_1_Name));
}
else if (strcmp(identifier, "name_faction2") == 0)
{
strncpy(ConfigData.Faction_2_Name, value, sizeof(ConfigData.Faction_2_Name));
}
else if (strcmp(identifier, "name_faction3") == 0)
{
strncpy(ConfigData.Faction_3_Name, value, sizeof(ConfigData.Faction_3_Name));
}
else if (strcmp(identifier, "batterytype") == 0)
{
strncpy(ConfigData.wifi_client_ssid, value, sizeof(ConfigData.wifi_client_ssid));
}
else if (strcmp(identifier, "batterytype") == 0)
{
int index = findIndexByString(value, BatteryString, BatteryString_Elements);
batterytypePreselect = (batteryType_t)index;
}
else if (strcmp(identifier, "wifi-ssid") == 0)
{ {
strncpy(ConfigData.wifi_client_ssid, value, sizeof(ConfigData.wifi_client_ssid)); strncpy(ConfigData.wifi_client_ssid, value, sizeof(ConfigData.wifi_client_ssid));
} }
@@ -568,6 +603,7 @@ void Websocket_RefreshClientData_Status(uint32_t client_id, bool send_mapping)
if (send_mapping) if (send_mapping)
{ {
const char mapping[] = "MAPPING_STATUS:" const char mapping[] = "MAPPING_STATUS:"
"batterylevel;"
"systemstatus;" "systemstatus;"
"activefaction;" "activefaction;"
"time_faction1;" "time_faction1;"
@@ -578,10 +614,13 @@ void Websocket_RefreshClientData_Status(uint32_t client_id, bool send_mapping)
webSocket.text(client_id, mapping); webSocket.text(client_id, mapping);
else else
webSocket.textAll(mapping); webSocket.textAll(mapping);
Debug_pushMessage("send MAPPING_STATUS WS-Client Data\n");
} }
String temp = "STATUS:"; String temp = "STATUS:";
temp.concat(String(globals.battery_level) + ";");
temp.concat(String(globals.systemStatustxt) + ";"); temp.concat(String(globals.systemStatustxt) + ";");
temp.concat(String(PersistenceData.activeFaction) + ";"); temp.concat(String(PersistenceData.activeFaction) + ";");
temp.concat(String(PersistenceData.faction_1_timer) + ";"); temp.concat(String(PersistenceData.faction_1_timer) + ";");
@@ -614,6 +653,7 @@ void Websocket_RefreshClientData_Static(uint32_t client_id, bool send_mapping)
if (send_mapping) if (send_mapping)
{ {
const char mapping[] = "MAPPING_STATIC:" const char mapping[] = "MAPPING_STATIC:"
"devicename;"
"active_faction_on_reboot;" "active_faction_on_reboot;"
"batteryType;" "batteryType;"
"name_faction1;" "name_faction1;"
@@ -630,6 +670,7 @@ void Websocket_RefreshClientData_Static(uint32_t client_id, bool send_mapping)
String temp = "STATIC:"; String temp = "STATIC:";
temp.concat(String(globals.DeviceName) + ";");
temp.concat(String(ConfigData.active_faction_on_reboot) + ";"); temp.concat(String(ConfigData.active_faction_on_reboot) + ";");
temp.concat(String(ConfigData.batteryType) + ";"); temp.concat(String(ConfigData.batteryType) + ";");
temp.concat(String(ConfigData.Faction_1_Name) + ";"); temp.concat(String(ConfigData.Faction_1_Name) + ";");

View File

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