77 Commits

Author SHA1 Message Date
367a41527d Updated FW-Version 2023-02-28 10:12:18 +01:00
5460a70f6d Added STL_Files for Case 2023-02-28 10:11:33 +01:00
3b4a22bff7 corrected some DTC-Stuff 2023-02-24 19:28:06 +01:00
df209a788b fixed Debug-Output in WebserverCallback (this time for real) 2023-02-24 19:25:59 +01:00
a6031798da moved DTC Processing to own File 2023-02-24 19:24:26 +01:00
00cba7b5ac DTC-Severity was not correctly set on new DTCs 2023-02-24 19:23:31 +01:00
034b6c918b fixed sysStat-Behaviour 2023-02-24 19:22:51 +01:00
3af678f3f8 fixed DebugOutput in WebserverCallback 2023-02-24 19:22:33 +01:00
32107a45db removed RemoteDebug-Library Stuff 2023-02-24 00:52:51 +01:00
a446a51c07 updated FastLED-Lib 2023-02-24 00:06:31 +01:00
5b41090add reworked debugger enabling 2023-02-24 00:05:51 +01:00
2376d14b5d fixed warning 2023-02-24 00:05:21 +01:00
77a94de2eb new debugger and websockets 2023-02-23 23:14:58 +01:00
c9a6e4c870 fixed warning 2023-02-23 17:46:36 +01:00
9ac161ee4c fixed Display-Bug with Remain Distance 2023-02-23 17:46:28 +01:00
1f8b085598 small improvement of DTC-Handling for CAN 2023-02-20 09:18:14 +01:00
46f98b1244 fixes... 2023-02-19 14:42:40 +01:00
9e87a05418 replaced var-name bc. encoding Issues with special char 2023-02-19 14:29:38 +01:00
140414ee8b minor FormatTweaks for DTC-DebugVal in WebUI 2022-09-02 00:10:21 +02:00
371e21429d WebUI adjusted and prepared EE-Backup-Stuff 2022-09-01 23:46:20 +02:00
64f9e102a5 Disabled autocorrect of Config after SanityCheck 2022-09-01 23:00:19 +02:00
dc4dbb05ca Format-Fixes and DTC-Debgval in WebUI visible 2022-09-01 22:47:25 +02:00
8c0db2ffd9 Implemented DebugVal for DTCs and SanityCheck 2022-09-01 22:46:00 +02:00
c6b47fffaf changed color of Bargraph-Text on WebUI 2022-09-01 21:31:27 +02:00
1b49ed4a2e Sanity-Check for ConfigValues 2022-09-01 21:29:07 +02:00
4167a222d7 ATOMIC_FS_UPDATE now Projecte-Define 2022-08-28 23:27:28 +02:00
f9498dac7d made FW-Version same Format as FS.Version 2022-08-28 23:27:01 +02:00
b9f658b111 FlashFS now gzip-Updatefiles & FS-Versioning imp. 2022-08-28 23:26:09 +02:00
4e34aaa24a Added Documentation 2022-08-24 23:13:27 +02:00
084925b844 missed include 2022-08-24 23:10:11 +02:00
e6a861185c Purging now also possible from WebUI 2022-08-24 23:09:26 +02:00
e12971b971 some debugging 2022-08-24 23:08:57 +02:00
4f5fdb7af4 corrected Tank-Lvel-Calculation 2022-08-24 23:08:29 +02:00
730f020f41 Updated DTC-Descriptions 2022-08-24 22:13:30 +02:00
3af1cfcb1b unimportant Serial Format Fix 2022-08-24 21:00:17 +02:00
685832cff8 Improved EEPROM-Formatting 2022-08-24 20:59:00 +02:00
3811834927 json now gets also gzipped 2022-08-24 20:58:12 +02:00
0025f8b0be DTC-Description now via Modal-Dialog 2022-08-24 16:49:40 +02:00
a30f56ff58 small fix 2022-08-24 07:30:51 +02:00
26942dd946 fixed missing name-tag in index.html 2022-08-24 07:27:53 +02:00
c997949c5b disabled Serial-debugging 2022-08-23 21:43:04 +02:00
1b0498ee5a fixed icons in manifest-File 2022-08-23 21:42:45 +02:00
82043ed9be re-added Firmware-Upload-Button after BS4-Update 2022-08-23 01:11:53 +02:00
f67817adb5 Format-Tweaks on WebUI 2022-08-23 00:50:52 +02:00
da19ebcc09 changed FlashVersion and incereased Buffer-Size 2022-08-23 00:48:00 +02:00
eaf2c9d8a8 DTC-Icon-fix 2022-08-23 00:12:03 +02:00
9072f2b3e2 added Google-Based Font locally 2022-08-23 00:11:44 +02:00
7d669dc04f updated .gitignore 2022-08-22 23:39:57 +02:00
79a7ca6fc1 renamed data-folder to data_src 2022-08-22 23:39:33 +02:00
821e94eec8 Updated WebUI to Bootstrap 4 2022-08-22 23:36:27 +02:00
0d9acaf43e preparing utility-script for gzip-littlefs 2022-08-22 23:32:51 +02:00
35361449eb some Fixes on Webui 2022-08-22 21:25:14 +02:00
45363b10fe missed ) on if-statement 2022-08-22 14:53:56 +02:00
c7f26bee32 made EEPROM-Format on WebUI more "secure" 2022-08-22 14:49:14 +02:00
984affb5a7 missed adjust of declaration for GetFlashVersion 2022-08-22 14:45:44 +02:00
d78c73d61f fixed missed define-change for WiFi-Clientmode 2022-08-22 14:29:40 +02:00
812a094e50 prevent Lube if Tank is empty (DryRun-Protection) 2022-08-22 14:29:01 +02:00
2ada3d9a61 EEPROM reset-Function added to WebUI 2022-08-22 14:28:32 +02:00
6ffe239cae Added DTC for LittleFS-Image Version mismatch 2022-08-22 14:26:37 +02:00
bd4c1d9d53 DTCs now hav severity and improved DTCMaintenance 2022-08-22 14:13:55 +02:00
808709f5c2 sanity-check now functional 2022-08-22 09:23:01 +02:00
080742c88c Math error ! -.- 2022-08-21 20:31:48 +02:00
38185e9056 improved DTC-Handling for EEPROM 2022-08-21 19:57:20 +02:00
17ed1ff7fa Added define to disable flashing of LED 2022-08-21 15:47:58 +02:00
0e34e7121f changed PurgePulse Vars to uint16_t 2022-08-21 15:47:22 +02:00
4ce550c668 start of sanitycheck-header 2022-08-21 11:28:58 +02:00
a6f5b4ef65 HTML5-compliance fix 2022-08-19 12:30:21 +02:00
7c38d02bf8 Fixed crash bc Stackoverflow from within Webserver 2022-08-19 11:25:26 +02:00
01ba4b7333 WebUI improvement to prevent empty fields 2022-08-19 08:34:37 +02:00
3048c6c2a1 changed restart behaviour after Firmware-Update 2022-08-19 08:16:33 +02:00
a6ae30d655 WebUI-improvements 2022-08-19 00:15:40 +02:00
01af8cba3c Improved Feature Control 2022-08-19 00:10:42 +02:00
4843cc15c9 Merge branches 'master' and 'master' of ssh://git.hiabuto.net:2222/souko/Kettenoeler 2022-08-14 17:38:49 +02:00
0b9ef67c39 multiple changes 2022-08-14 17:38:45 +02:00
94e34fb593 Bugfix in DTC and SystemStatus Handling 2022-05-27 13:33:44 +02:00
ad6332acd4 Restructured Folders 2022-05-07 23:24:42 +02:00
f514ee62fc Updated BOM-Excel for PCB Rev 1.4 2022-05-07 23:23:11 +02:00
80 changed files with 20974 additions and 1353 deletions

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
Bestellung.xlsx

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

BIN
Hardware/BOM_Reichelt.xlsx Normal file

Binary file not shown.

View File

@@ -1,3 +1,4 @@
data/
.pio
.vscode/.browse.c_cpp.db*
.vscode/c_cpp_properties.json

View File

@@ -1,484 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>KTM CAN Chain Oiler</title>
<meta http-equiv="content-type" content="text/html;charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="static/css/bootstrap.min.css">
<link rel="stylesheet" href="static/css/custom.css">
<script src="static/js/jquery.min.js"></script>
<script src="static/js/bootstrap.min.js"></script>
<link rel="apple-touch-icon" sizes="180x180" href="static/img/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="static/img/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="static/img/favicon-16x16.png">
<link rel="manifest" href="static/img/site.webmanifest">
</head>
<body>
<nav class="navbar navbar-expand-md navbar-default fixed-top">
<div class="navbar-header">
<a class="navbar-brand" href="#">
<img src="static/img/logo.png" width="30" height="30" class="d-inline-block align-top" alt="">
KTM CAN ChainLube
</a>
<button type="button" data-target="#navbarCollapse" data-toggle="collapse" class="navbar-toggle">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
</div>
<!-- Collection of nav links, forms, and other content for toggling -->
<div id="navbarCollapse" class="collapse navbar-collapse">
<ul class="nav navbar-nav">
<li class="active"><a data-toggle="tab" href="#tab_home">Home</a></li>
<li><a data-toggle="tab" href="#tab_source">Wegstrecke</a></li>
<li><a data-toggle="tab" href="#tab_lube">Schmierung</a></li>
<li><a data-toggle="tab" href="#tab_tank">Öltank</a></li>
<li><a data-toggle="tab" href="#tab_maintenance">Wartung</a></li>
<li><a data-toggle="tab" href="#tab_sysinfo">Systeminfo</a></li>
</ul>
</div>
</nav>
<main role="main" class="container">
<!-- Tabs Content -->
<div class="tab-content">
<!-- Div Tab Home-->
<div id="tab_home" class="tab-pane fade in active">
<div class="col text-center">
<div class="jumbotron">
<img src="static/img/logo.png" width="120" height="120" class="img-fluid" alt="">
<h3>KTM CAN Chain Lube</h3>
</div>
</div>
<p>
<h4>Tankinhalt verbleibend</h4>
<div class="progress">
<div class="progress-bar" role="progressbar" aria-valuenow="%TANK_REMAIN_CAPACITY%" aria-valuemin="0"
aria-valuemax="100" style="width: %TANK_REMAIN_CAPACITY%&#37;">
%TANK_REMAIN_CAPACITY%&#37;
</div>
</div>
<h4>aktueller Modus</h4>
<input class="form-control" type="text" placeholder="%SYSTEM_STATUS%" readonly>
<div %SHOW_DTC_TABLE%>
<h4>Fehlercodes</h4>
<table class="table">
<tbody>
<tr>
<th class="col-md-4" scope="col">Timestamp</td>
<th class="col-md-4" scope="col">DTC</td>
<th class="col-md-4" scope="col">active</td>
</tr>
%DTC_TABLE%
</tbody>
</table>
</div>
</p>
</div>
<!-- Div Tab Home-->
<!-- Div Tab Source Settings-->
<div id="tab_source" class="tab-pane fade">
<h3>Erfassung Wegstrecke</h3>
<hr>
<p>
<form action="\post.htm" method="POST" class="form-horizontal">
<div class="form-group">
<label for="sourceselect" class="control-label col-xs-5">Wegstrecke Quelle</label>
<div class="col-xs-7">
<select id="sourceselect" name="sourceselect" class="select form-control">
%SOURCE_SELECT_OPTIONS%
</select>
</div>
</div>
<div class="form-group row">
<div class="col-xs-offset-5 col-xs-7">
<button name="sourcesave" type="submit" class="btn btn-primary">&Uuml;bernehmen</button>
</div>
</div>
</form>
</p>
<div class="alert alert-warning">
<strong>Achtung!</strong><br>
Bei Änderung der Wegstrecken-Quelle wird der CAN-Oiler neu gestartet.
Dadurch wird die WiFi-Verbindung getrennt und muss neu aufgebaut werden.
</div>
<!-- Div Source:Impulse Settings-->
<div %SHOW_IMPULSE_SETTINGS%>
<h4>Einstellungen Impuls</h4>
<p>
<form action="\post.htm" method="POST" class="form-horizontal">
<div class="form-group">
<label for="tirewidth" class="control-label col-xs-5">Reifenbreite</label>
<div class="col-xs-7">
<div class="input-group">
<input id="tirewidth" name="tirewidth" type="text" required="required" class="form-control"
value="%TIRE_WIDTH_MM%">
<div class="input-group-addon">mm</div>
</div>
</div>
</div>
<div class="form-group">
<label for="tireratio" class="control-label col-xs-5">Höhe/Breite-Verhältniss</label>
<div class="col-xs-7">
<div class="input-group">
<input id="tireratio" name="tireratio" type="text" required="required" class="form-control"
value="%TIRE_RATIO%">
<div class="input-group-addon"></div>
</div>
</div>
</div>
<div class="form-group">
<label for="tiredia" class="control-label col-xs-5">Felgendurchmesser</label>
<div class="col-xs-7">
<div class="input-group">
<input id="tiredia" name="tiredia" type="text" required="required" class="form-control"
value="%RIM_DIAMETER%">
<div class="input-group-addon">"</div>
</div>
</div>
</div>
<div class="form-group">
<label for="pulserev" class="control-label col-xs-5">Pulse pro Umdrehung</label>
<div class="col-xs-7">
<div class="input-group">
<input id="pulserev" name="pulserev" type="text" required="required" class="form-control"
value="%PULSE_PER_REV%">
<div class="input-group-addon"></div>
</div>
</div>
</div>
<div class="form-group row">
<div class="col-xs-offset-5 col-xs-7">
<button name="pulsesave" type="submit" class="btn btn-primary">Speichern</button>
</div>
</div>
</form>
</p>
</div>
<!-- Div Source:Impulse Settings-->
<!-- Div Source:CAN Settings-->
<div %SHOW_CAN_SETTINGS%>
<h4>Einstellungen CAN-Bus</h4>
<p>
<form action="\post.htm" method="POST" class="form-horizontal">
<div class="form-group">
<label for="cansource" class="control-label col-xs-5">Model</label>
<div class="col-xs-7">
<select id="cansource" name="cansource" class="select form-control">
%CANSOURCE_SELECT_OPTIONS%
</select>
</div>
</div>
<div class="form-group row">
<div class="col-xs-offset-5 col-xs-7">
<button name="cansave" type="submit" class="btn btn-primary">Speichern</button>
</div>
</div>
</form>
</p>
</div>
<!-- Div Source:CAN Settings-->
<!-- Div Source:GPS Settings-->
<div %SHOW_GPS_SETTINGS%>
<h4>Einstellungen GPS</h4>
<p>
<form action="\post.htm" method="POST" class="form-horizontal">
<div class="form-group">
<label for="gpsbaud" class="control-label col-xs-5">Baudrate</label>
<div class="col-xs-7">
<select id="gpsbaud" name="gpsbaud" class="select form-control">
%GPSBAUD_SELECT_OPTIONS%
</select>
</div>
</div>
<div class="form-group row">
<div class="col-xs-offset-5 col-xs-7">
<button name="gpssave" type="submit" class="btn btn-primary">Speichern</button>
</div>
</div>
</form>
</p>
</div>
<!-- Div Source:GPS Settings-->
</div>
<!-- Div Tab Source Settings-->
<!-- Div Tab Lube -->
<div id="tab_lube" class="tab-pane fade">
<h3>Schmierung</h3>
<hr>
<p>
<form action="\post.htm" method="POST" class="form-horizontal">
<div class="form-group">
<label for="lubedistancenormal" class="control-label col-xs-5">Modus:normal</label>
<div class="col-xs-7">
<div class="input-group">
<input id="lubedistancenormal" name="lubedistancenormal" value="%LUBE_DISTANCE_NORMAL%" type="text"
class="form-control" required="required">
<div class="input-group-addon">m</div>
</div>
</div>
</div>
<div class="form-group">
<label for="lubedistancerain" class="control-label col-xs-5">Modus:rain</label>
<div class="col-xs-7">
<div class="input-group">
<input id="lubedistancerain" name="lubedistancerain" value="%LUBE_DISTANCE_RAIN%" type="text"
class="form-control" required="required">
<div class="input-group-addon">m</div>
</div>
</div>
</div>
<div class="form-group row">
<div class="col-xs-offset-5 col-xs-7">
<button name="oilsave" type="submit" class="btn btn-primary">Speichern</button>
</div>
</div>
</form>
</p>
</div>
<!-- Div Tab Lube -->
<!-- Div Tab Maintenance -->
<div id="tab_maintenance" class="tab-pane fade">
<h3>Wartung</h3>
<hr>
<p>
<form action="\post.htm" method="POST" class="form-horizontal">
<div class="form-group">
<label for="purgepulse" class="control-label col-xs-5">Entl&uuml;ftung Impulse</label>
<div class="col-xs-7">
<div class="input-group">
<input id="purgepulse" name="purgepulse" value="%BLEEDING_PULSES%" type="text" class="form-control">
<div class="input-group-addon"></div>
</div>
</div>
</div>
<div class="form-group row">
<div class="col-xs-offset-5 col-xs-7">
<button name="maintsave" type="submit" class="btn btn-primary">Speichern</button>
</div>
</div>
</form>
</p>
<p>
<form action="\post.htm" method="POST" class="form-horizontal">
<div class="form-group">
<label for="tankremain_maint" class="control-label col-xs-5">Tankinhalt verbleibend</label>
<div class="col-xs-7">
<div class="progress">
<div id="tankremain_maint" class="progress-bar" role="progressbar"
aria-valuenow="%TANK_REMAIN_CAPACITY%" aria-valuemin="0" aria-valuemax="100"
style="width: %TANK_REMAIN_CAPACITY%&#37;">
%TANK_REMAIN_CAPACITY%&#37;
</div>
</div>
</div>
</div>
<div class="form-group row">
<div class="col-xs-offset-5 col-xs-7">
<button name="resettank" type="submit" class="btn btn-primary">Tank zurücksetzen</button>
</div>
</div>
</form>
</p>
</div>
<!-- Div Tab Maintenance -->
<!-- Div Tank Settings-->
<div id="tab_tank" class="tab-pane fade">
<h3>Öltank</h3>
<hr>
<p>
<form action="\post.htm" method="POST" class="form-horizontal">
<div class="form-group">
<label for="tankcap" class="control-label col-xs-5">Tankkapazität</label>
<div class="col-xs-7">
<div class="input-group">
<input id="tankcap" name="tankcap" value="%TANK_CAPACITY%" type="text" class="form-control"
required="required">
<div class="input-group-addon">ml</div>
</div>
</div>
</div>
<div class="form-group">
<label for="tankwarn" class="control-label col-xs-5">Leer-Warnung</label>
<div class="col-xs-7">
<div class="input-group">
<input id="tankwarn" name="tankwarn" value="%TANK_REMIND%" type="text" class="form-control"
required="required">
<div class="input-group-addon">&#37;</div>
</div>
</div>
</div>
<div class="form-group">
<label for="pumppulse" class="control-label col-xs-5">Menge pro Puls</label>
<div class="col-xs-7">
<div class="input-group">
<input id="pumppulse" name="pumppulse" value="%AMOUNT_PER_DOSE%" type="text" class="form-control"
required="required">
<div class="input-group-addon">µl</div>
</div>
</div>
</div>
<div class="form-group row">
<div class="col-xs-offset-5 col-xs-7">
<button name="oilsave" type="submit" class="btn btn-primary">Speichern</button>
</div>
</div>
</form>
</p>
</div>
<!-- Div Tank Settings-->
<!-- Div Tab SystemInfo -->
<div id="tab_sysinfo" class="tab-pane fade">
<h3>Systeminfo</h3>
<hr>
<h4>Firmware-Info</h4>
<p>
<table class="table">
<tbody>
<tr>
<th class="col-md-8" scope="col">Parameter</td>
<th class="col-md-4" scope="col">Value</td>
</tr>
<tr>
<td>Version</td>
<td>%SW_VERSION%</td>
</tr>
</table>
</p>
<h4>Einstellungen</h4>
<p>
<table class="table">
<tbody>
<tr>
<th class="col-md-8" scope="col">Parameter</td>
<th class="col-md-4" scope="col">Value</td>
</tr>
<tr>
<td>DistancePerLube_Default</td>
<td>%LUBE_DISTANCE_NORMAL%</td>
</tr>
<tr>
<td>DistancePerLube_Rain</td>
<td>%LUBE_DISTANCE_RAIN%</td>
</tr>
<tr>
<td>tankCapacity_ml</td>
<td>%TANK_CAPACITY%</td>
</tr>
<tr>
<td>amountPerDose_&micro;l</td>
<td>%AMOUNT_PER_DOSE%</td>
</tr>
<tr>
<td>TankRemindAtPercentage</td>
<td>%TANK_REMIND%</td>
</tr>
<tr>
<td>PulsePerRevolution</td>
<td>%PULSE_PER_REV%</td>
</tr>
<tr>
<td>TireWidth_mm</td>
<td>%TIRE_WIDTH_MM%</td>
</tr>
<tr>
<td>TireWidthHeight_Ratio</td>
<td>%TIRE_RATIO%</td>
</tr>
<tr>
<td>RimDiameter_Inch</td>
<td>%RIM_DIAMETER%</td>
</tr>
<tr>
<td>DistancePerRevolution_mm</td>
<td>%DISTANCE_PER_REV%</td>
</tr>
<tr>
<td>BleedingPulses</td>
<td>%BLEEDING_PULSES%</td>
</tr>
<tr>
<td>SpeedSource</td>
<td>%SPEED_SOURCE%</td>
</tr>
<tr>
<td>GPSBaudRate</td>
<td>%GPS_BAUD%</td>
</tr>
<tr>
<td>CANSource</td>
<td>%CAN_SOURCE%</td>
</tr>
<tr>
<td>Checksum</td>
<td>%CONFIG_CHECKSUM%</td>
</tr>
</tbody>
</table>
</p>
<h4>Betriebsdaten</h4>
<p>
<table class="table">
<tbody>
<tr>
<th class="col-md-8" scope="col">Parameter</td>
<th class="col-md-4" 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>tankRemain_µl</td>
<td>%TANK_REMAIN_UL%</td>
</tr>
<tr>
<td>TravelDistance_highRes</td>
<td>%TRAVEL_DISTANCE_HIGHRES%</td>
</tr>
<tr>
<td>Odometer</td>
<td>%ODOMETER%,%ODOMETER_M%</td>
</tr>
<tr>
<td>checksum</td>
<td>%PERSISTANCE_CHECKSUM%</td>
</tr>
</table>
</p>
</div>
<!-- Div Tab SystemInfo -->
</div>
<!-- Tabs Content -->
</main>
<!-- Footer -->
<footer class="navbar-default navbar-fixed-bottom">
<div class="container-fluid">
<!-- Copyright -->
<div class="col text-center">
© 2022 Copyright:
<a class="text-reset fw-bold" href="https://eventronics.de/">Marcel Peterkau</a>
</div>
<!-- Copyright -->
</div>
</footer>
<!-- Footer -->
</body>
</html>

File diff suppressed because one or more lines are too long

View File

@@ -1 +0,0 @@
kbd{border:1px solid #333}.btn-default:focus,.btn-default:active,.btn-default.active,.open .dropdown-toggle.btn-default{background-color:#6a6a6a;border-color:#636363}.btn-default:hover{background-color:#6a6a6a}.btn-primary:hover{background-color:#404040}.btn-success:hover{background-color:#3d8b3d}.btn-info:hover{background-color:#28a1c5}.btn-danger:hover{background-color:#b52b27}.btn-warning:hover{background-color:#df8a13}.navbar-default .navbar-nav>li.active>a:hover{background-color:#222}.navbar-inverse .navbar-nav>li.active>a:hover{background-color:#444}.table{color:#fff}.table .primary,.table .info,.table .success,.table .warning,.table .danger{color:#fff}.table-hover tr:hover{cursor:pointer}.input-group-addon{color:#fff}.nav>li>a:hover{color:#fff}.pager>li>a:hover{color:#fff}a:focus{outline:0}a.list-group-item.active:hover{background-color:#4d4d4d}a.list-group-item-success,a.list-group-item-info,a.list-group-item-warning,a.list-group-item-danger,a.list-group-item-success:hover,a.list-group-item-info:hover,a.list-group-item-warning:hover,a.list-group-item-danger:hover{color:#fff}a.active.list-group-item-success,a.active.list-group-item-info,a.active.list-group-item-warning,a.active.list-group-item-danger,a.active.list-group-item-success:hover,a.active.list-group-item-info:hover,a.active.list-group-item-warning:hover,a.active.list-group-item-danger:hover{border-color:#666}a.active.list-group-item-success:hover{background-color:#3d8b3d}a.active.list-group-item-info:hover{background-color:#28a1c5}a.active.list-group-item-warning:hover{background-color:#df8a13}a.active.list-group-item-danger:hover{background-color:#b52b27}.list-group-item-success,.list-group-item-info,.list-group-item-warning,.list-group-item-danger{color:#fff}.alert-info,.alert-primary,.alert-warning,.alert-danger,.alert-success{color:#fff}.alert-info .alert-link,.alert-primary .alert-link,.alert-warning .alert-link,.alert-danger .alert-link,.alert-success .alert-link{color:#fff}

View File

@@ -1 +0,0 @@
{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"}

File diff suppressed because one or more lines are too long

View File

@@ -1,37 +0,0 @@
#ifndef _COMMON_H_
#define _COMMON_H_
#define Q(x) #x
#define QUOTE(x) Q(x)
#define GPIO_BUTTON D4
#define GPIO_LED D3
#define GPIO_TRIGGER D6
#define GPIO_PUMP D0
#define GPIO_CS_CAN D8
#ifndef HOST_NAME
#define HOST_NAME "ChainLube_%06X" // Use printf-Formatting - Chip-ID (uin32_t) will be added
#endif
#define SW_VERSION_MAJOR 1
#define SW_VERSION_MINOR 0
#ifndef OTA_DELAY
#define OTA_DELAY 50 // ticks -> 10ms / tick
#endif
#ifndef ADMIN_PASSWORD
#error "You need to define ADMIN_PASSWORD for OTA-Update"
#endif
#ifndef WIFI_PASSWORD
#error "You must define an WIFI_PASSWORD for OTA-Update"
#endif
#ifndef WIFI_SSID
#error "You must define an WIFI_SSID for OTA-Update"
#endif
#ifndef WIFI_AP_PASSWORD
#error "You must define an WIFI_AP_PASSWORD for Standalone AP-Mode"
#endif
#endif

View File

@@ -1,226 +0,0 @@
#include "config.h"
I2C_eeprom ee(0x50, EEPROM_SIZE_BYTES);
LubeConfig_t LubeConfig;
persistenceData_t PersistenceData;
uint16_t eePersistenceMarker = 0;
const uint16_t eeVersion = 1; // inc
boolean eeAvailable = false;
const uint16_t startofLubeConfig = 16;
const uint16_t startofPersistence = 16 + sizeof(LubeConfig) + (sizeof(LubeConfig) % 16);
boolean checkEEPROMavailable();
void InitEEPROM()
{
ee.begin();
if (!checkEEPROMavailable())
{
globals.systemStatus = sysStat_Error;
MaintainDTC(DTC_NO_EEPROM_FOUND, true);
return;
}
GetConfig_EEPROM();
if (LubeConfig.EEPROM_Version != eeVersion)
{
FormatConfig_EEPROM();
globals.systemStatus = sysStat_Error;
MaintainDTC(DTC_EEPROM_VERSION_BAD, true);
return;
}
}
void EEPROM_Process()
{
switch (globals.requestEEAction)
{
case EE_CFG_SAVE:
StoreConfig_EEPROM();
globals.requestEEAction = EE_IDLE;
break;
case EE_CFG_LOAD:
GetConfig_EEPROM();
globals.requestEEAction = EE_IDLE;
break;
case EE_PDS_SAVE:
StorePersistence_EEPROM();
globals.requestEEAction = EE_IDLE;
break;
case EE_PDS_LOAD:
GetPersistence_EEPROM();
globals.requestEEAction = EE_IDLE;
break;
case EE_IDLE:
default:
globals.requestEEAction = EE_IDLE;
}
}
void StoreConfig_EEPROM()
{
LubeConfig.checksum = 0;
LubeConfig.checksum = Checksum_EEPROM((uint8_t *)&LubeConfig, sizeof(LubeConfig));
if (!checkEEPROMavailable())
return;
ee.updateBlock(startofLubeConfig, (uint8_t *)&LubeConfig, sizeof(LubeConfig));
}
void GetConfig_EEPROM()
{
if (!checkEEPROMavailable())
return;
ee.readBlock(startofLubeConfig, (uint8_t *)&LubeConfig, sizeof(LubeConfig));
uint32_t checksum = LubeConfig.checksum;
LubeConfig.checksum = 0;
if (Checksum_EEPROM((uint8_t *)&LubeConfig, sizeof(LubeConfig)) != checksum)
{
MaintainDTC(DTC_EEPROM_CFG_BAD, true);
FormatConfig_EEPROM();
}
LubeConfig.checksum = checksum;
}
uint16_t getPersistanceAddress()
{
return startofPersistence + eePersistenceMarker;
}
void StorePersistence_EEPROM()
{
if (PersistenceData.writeCycleCounter >= 0xFFF0)
MovePersistencePage_EEPROM(false);
else
PersistenceData.writeCycleCounter++;
PersistenceData.checksum = 0;
PersistenceData.checksum = Checksum_EEPROM((uint8_t *)&PersistenceData, sizeof(PersistenceData));
if (!checkEEPROMavailable())
return;
ee.updateBlock(getPersistanceAddress(), (uint8_t *)&PersistenceData, sizeof(PersistenceData));
}
void GetPersistence_EEPROM()
{
if (!checkEEPROMavailable())
return;
eePersistenceMarker = (ee.readByte(0) << 8) | ee.readByte(1);
ee.readBlock(getPersistanceAddress(), (uint8_t *)&PersistenceData, sizeof(PersistenceData));
uint32_t checksum = PersistenceData.checksum;
PersistenceData.checksum = 0;
if (Checksum_EEPROM((uint8_t *)&PersistenceData, sizeof(PersistenceData)) != checksum)
{
MaintainDTC(DTC_EEPROM_PDS_BAD, true);
FormatPersistence_EEPROM();
}
PersistenceData.checksum = checksum;
}
void FormatConfig_EEPROM()
{
LubeConfig_t defaults;
LubeConfig = defaults;
LubeConfig.EEPROM_Version = eeVersion;
StoreConfig_EEPROM();
}
void FormatPersistence_EEPROM()
{
persistenceData_t defaults;
PersistenceData = defaults;
eePersistenceMarker = 0;
StorePersistence_EEPROM();
}
void MovePersistencePage_EEPROM(boolean reset)
{
if (!checkEEPROMavailable())
return;
eePersistenceMarker = eePersistenceMarker + sizeof(PersistenceData);
PersistenceData.writeCycleCounter = 0;
// check if we reached the End of the EEPROM and Startover at the beginning
// if ((startofPersistence + eePersistenceMarker + sizeof(PersistenceData)) > ee.getDeviceSize() || reset)
// {
// eePersistenceMarker = 0;
// }
ee.updateByte(0, (uint8_t)(eePersistenceMarker >> 8));
ee.updateByte(1, (uint8_t)(eePersistenceMarker & 0xFF));
}
uint32_t Checksum_EEPROM(uint8_t const *data, size_t len)
{
if (data == NULL)
return 0;
uint32_t crc, mask;
crc = 0xFFFFFFFF;
while (len--)
{
crc ^= *data++;
for (uint8_t k = 0; k < 8; k++)
{
mask = -(crc & 1);
crc = (crc >> 1) ^ (0xEDB88320 & mask);
}
}
return ~crc;
}
void dumpEEPROM(uint16_t memoryAddress, uint16_t length)
{
#define BLOCK_TO_LENGTH 16
if (!checkEEPROMavailable())
return;
char ascii_buf[BLOCK_TO_LENGTH + 1];
sprintf(ascii_buf, "%*s", BLOCK_TO_LENGTH, "ASCII");
Serial.print(PSTR("\nAddress "));
for (int x = 0; x < BLOCK_TO_LENGTH; x++)
Serial.printf("%3d", x);
memoryAddress = memoryAddress / BLOCK_TO_LENGTH * BLOCK_TO_LENGTH;
length = (length + BLOCK_TO_LENGTH - 1) / BLOCK_TO_LENGTH * BLOCK_TO_LENGTH;
for (unsigned int i = 0; i < length; i++)
{
int blockpoint = memoryAddress % BLOCK_TO_LENGTH;
if (blockpoint == 0)
{
ascii_buf[BLOCK_TO_LENGTH] = 0;
Serial.printf(" %s", ascii_buf);
Serial.printf("\n0x%05X:", memoryAddress);
}
ascii_buf[blockpoint] = ee.readByte(memoryAddress);
Serial.printf(" %02X", ascii_buf[blockpoint]);
if (ascii_buf[blockpoint] < 0x20 || ascii_buf[blockpoint] > 0x7E)
ascii_buf[blockpoint] = '.';
memoryAddress++;
}
Serial.println();
}
boolean checkEEPROMavailable()
{
if (!ee.isConnected())
{
MaintainDTC(DTC_NO_EEPROM_FOUND, true);
return false;
}
return true;
}

View File

@@ -1,278 +0,0 @@
#include "webui.h"
AsyncWebServer webServer(80);
const char *PARAM_MESSAGE = "message";
String processor(const String &var);
void WebserverPOST_Callback(AsyncWebServerRequest *request);
void WebserverNotFound_Callback(AsyncWebServerRequest *request);
void Webserver_Callback(AsyncWebServerRequest *request);
void initWebUI()
{
if (!LittleFS.begin())
{
Serial.println("An Error has occurred while mounting LittleFS");
return;
}
webServer.serveStatic("/static/", LittleFS, "/static/").setCacheControl("max-age=360000");
webServer.on("/", HTTP_GET, [](AsyncWebServerRequest *request)
{ request->redirect("/index.htm"); });
webServer.onNotFound(WebserverNotFound_Callback);
webServer.on("/index.htm", HTTP_GET, Webserver_Callback);
webServer.on("/post.htm", HTTP_POST, WebserverPOST_Callback);
webServer.begin();
}
String processor(const String &var)
{
if (var == "TANK_REMAIN_CAPACITY")
return String((PersistenceData.tankRemain_µl / 10) / LubeConfig.tankCapacity_ml);
if (var == "LUBE_DISTANCE_NORMAL")
return String(LubeConfig.DistancePerLube_Default);
if (var == "LUBE_DISTANCE_RAIN")
return String(LubeConfig.DistancePerLube_Rain);
if (var == "TANK_CAPACITY")
return String(LubeConfig.tankCapacity_ml);
if (var == "AMOUNT_PER_DOSE")
return String(LubeConfig.amountPerDose_µl);
if (var == "TANK_REMIND")
return String(LubeConfig.TankRemindAtPercentage);
if (var == "PULSE_PER_REV")
return String(LubeConfig.PulsePerRevolution);
if (var == "TIRE_WIDTH_MM")
return String(LubeConfig.TireWidth_mm);
if (var == "TIRE_RATIO")
return String(LubeConfig.TireWidthHeight_Ratio);
if (var == "RIM_DIAMETER")
return String(LubeConfig.RimDiameter_Inch);
if (var == "DISTANCE_PER_REV")
return String(LubeConfig.DistancePerRevolution_mm);
if (var == "BLEEDING_PULSES")
return String(LubeConfig.BleedingPulses);
if (var == "SPEED_SOURCE")
return String(SpeedSourceString[LubeConfig.SpeedSource]);
#ifdef FEATURE_ENABLE_GPS
if (var == "GPS_BAUD")
return String(GPSBaudRateString[LubeConfig.GPSBaudRate]);
#endif
#ifdef FEATURE_ENABLE_CAN
if (var == "CAN_SOURCE")
return String(CANSourceString[LubeConfig.CANSource]);
#endif
if (var == "CONFIG_CHECKSUM")
{
char buffer[7];
sprintf(buffer, "0x%04X", LubeConfig.checksum);
return String(buffer);
}
if (var == "WRITE_CYCLE_COUNT")
return String(PersistenceData.writeCycleCounter);
if (var == "PERSISTENCE_MARKER")
return String(getPersistanceAddress());
if (var == "TANK_REMAIN_UL")
return String(PersistenceData.tankRemain_µl);
if (var == "TRAVEL_DISTANCE_HIGHRES")
return String(PersistenceData.TravelDistance_highRes_mm);
if (var == "ODOMETER")
return String(PersistenceData.odometer);
if (var == "ODOMETER_M")
return String(PersistenceData.odometer_mm / 1000);
if (var == "PERSISTANCE_CHECKSUM")
{
char buffer[7];
sprintf(buffer, "0x%04X", PersistenceData.checksum);
return String(buffer);
}
if (var == "SHOW_IMPULSE_SETTINGS")
return LubeConfig.SpeedSource == SOURCE_IMPULSE ? "" : "hidden";
#ifdef FEATURE_ENABLE_CAN
if (var == "SHOW_CAN_SETTINGS")
return LubeConfig.SpeedSource == SOURCE_CAN ? "" : "hidden";
#endif
#ifdef FEATURE_ENABLE_GPS
if (var == "SHOW_GPS_SETTINGS")
return LubeConfig.SpeedSource == SOURCE_GPS ? "" : "hidden";
#endif
if (var == "SHOW_DTC_TABLE")
return globals.systemStatus == sysStat_Error ? "" : "hidden";
if (var == "DTC_TABLE")
{
String temp;
char buff_timestamp[16]; // Format: DD-hh:mm:ss:xxx
for (uint32_t i = 0; i < MAX_DTC_STORAGE; i++)
{
if (DTCStorage[i].Number < 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
temp = "<tr><td>" + String(buff_timestamp);
temp = temp + "</td><td>" + String(DTCStorage[i].Number) + "</td><td>";
if (DTCStorage[i].active == DTC_ACTIVE)
temp = temp + "active";
else if (DTCStorage[i].active == DTC_PREVIOUS)
temp = temp + "previous";
else
temp = temp + "none";
temp = temp + "</td></tr>";
}
}
return temp;
}
if (var == "SOURCE_SELECT_OPTIONS")
{
String temp;
for (uint32_t i = 0; i < SpeedSourceString_Elements; i++)
{
String selected = LubeConfig.SpeedSource == i ? " selected " : "";
temp = temp + "<option value=\"" + i + "\"" + selected + ">" + SpeedSourceString[i] + "</option>";
}
return temp;
}
#ifdef FEATURE_ENABLE_CAN
if (var == "CANSOURCE_SELECT_OPTIONS")
{
String temp;
for (uint32_t i = 0; i < CANSourceString_Elements; i++)
{
String selected = LubeConfig.CANSource == i ? " selected " : "";
temp = temp + "<option value=\"" + i + "\"" + selected + ">" + CANSourceString[i] + "</option>";
}
return temp;
}
#endif
#ifdef FEATURE_EABLE_GPS
if (var == "GPSBAUD_SELECT_OPTIONS")
{
String temp;
for (uint32_t i = 0; i < GPSBaudRateString_Elements; i++)
{
String selected = LubeConfig.GPSBaudRate == i ? " selected " : "";
temp = temp + "<option value=\"" + i + "\"" + selected + ">" + GPSBaudRateString[i] + "</option>";
}
return temp;
}
#endif
if (var == "SYSTEM_STATUS")
return String(globals.systemStatustxt);
if (var == "SW_VERSION")
{
char buffer[7];
sprintf(buffer, "%d.%02d", SW_VERSION_MAJOR, SW_VERSION_MINOR);
return String(buffer);
}
if (var == "PLACEHOLDER")
return "placeholder";
return String();
}
void Webserver_Callback(AsyncWebServerRequest *request)
{
request->send(LittleFS, "/index.htm", "text/html", false, processor);
}
void WebserverPOST_Callback(AsyncWebServerRequest *request)
{
request->send(LittleFS, "/post.htm", "text/html", false, processor);
Serial.print("POST:\n");
int paramsNr = request->params();
for (int i = 0; i < paramsNr; i++)
{
AsyncWebParameter *p = request->getParam(i);
Serial.printf("%s : %s\n", p->name().c_str(), p->value().c_str());
// begin: POST Form Source Changed
if (p->name() == "sourceselect")
{
SpeedSource_t temp = (SpeedSource_t)p->value().toInt();
Serial.printf("temp: %d", temp);
Serial.printf("SpeedSource: %d", LubeConfig.SpeedSource);
if (LubeConfig.SpeedSource != temp)
{
LubeConfig.SpeedSource = temp;
globals.systemStatus = sysStat_Shutdown;
}
}
// end: POST Form Source Changed
// begin: POST Form Source Pulse Settings
if (p->name() == "tirewidth")
LubeConfig.TireWidth_mm = p->value().toInt();
if (p->name() == "tireratio")
LubeConfig.TireWidthHeight_Ratio = p->value().toInt();
if (p->name() == "tiredia")
LubeConfig.RimDiameter_Inch = p->value().toInt();
if (p->name() == "pulserev")
LubeConfig.PulsePerRevolution = p->value().toInt();
if (p->name() == "pulsesave")
globals.requestEEAction = EE_CFG_SAVE;
// end: POST Form Source Pulse Settings
#ifdef FEATURE_EABLE_GPS
// begin: POST Form Source GPS Settings
if (p->name() == "gpsbaud")
LubeConfig.GPSBaudRate = (GPSBaudRate_t)p->value().toInt();
if (p->name() == "gpssave")
globals.requestEEAction = EE_CFG_SAVE;
// end: POST Form Source GPS Settings
#endif
#ifdef FEATURE_EABLE_CAN
// begin: POST Form Source CAN Settings
if (p->name() == "cansource")
LubeConfig.CANSource = (CANSource_t)p->value().toInt();
if (p->name() == "cansave")
globals.requestEEAction = EE_CFG_SAVE;
// end: POST Form Source CAN Settings
#endif
// begin: POST Form Lubrication
if (p->name() == "lubedistancenormal")
LubeConfig.DistancePerLube_Default = p->value().toInt();
if (p->name() == "lubedistancerain")
LubeConfig.DistancePerLube_Rain = p->value().toInt();
if (p->name() == "lubesave")
globals.requestEEAction = EE_CFG_SAVE;
// end: POST Form Lubrication
// begin: POST Form Oiltank
if (p->name() == "tankcap")
LubeConfig.tankCapacity_ml = p->value().toInt();
if (p->name() == "tankwarn")
LubeConfig.TankRemindAtPercentage = p->value().toInt();
if (p->name() == "pumppulse")
LubeConfig.amountPerDose_µl = p->value().toInt();
if (p->name() == "oilsave")
globals.requestEEAction = EE_CFG_SAVE;
// end: POST Form Oiltank
// begin: POST Form Maintenance
if (p->name() == "purgepulse")
LubeConfig.BleedingPulses = p->value().toInt();
if (p->name() == "maintsave")
globals.requestEEAction = EE_CFG_SAVE;
if (p->name() == "resettank")
{
PersistenceData.tankRemain_µl = LubeConfig.tankCapacity_ml * 1000;
globals.requestEEAction = EE_PDS_SAVE;
}
// end: POST Form Maintenance
}
}
void WebserverNotFound_Callback(AsyncWebServerRequest *request)
{
request->send(404, "text/html", "Not found");
}

View File

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

696
Software/data_src/index.htm Normal file
View File

@@ -0,0 +1,696 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>KTM CAN Chain Oiler</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="static/css/bootstrap.min.css">
<link rel="stylesheet" href="static/css/custom.css">
<link rel="stylesheet" href="static/css/tweaks.css">
<script src="static/js/jquery.min.js"></script>
<script src="static/js/bootstrap.min.js"></script>
<script src="static/js/websocket.js"></script>
<link rel="apple-touch-icon" sizes="180x180" href="static/img/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="static/img/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="static/img/favicon-16x16.png">
<link rel="manifest" href="static/img/site.webmanifest">
</head>
<body>
<nav class="navbar fixed-top navbar-dark bg-primary" id="navbar1">
<a class="navbar-brand" href="#">
<img src="static/img/logo.png" width="30" height="30" class="d-inline-block align-top mr-1" alt="">
KTM CAN ChainLube
</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#collapsingNavbar"
aria-controls="collapsingNavbar" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="collapsingNavbar">
<ul class="navbar-nav nav mr-auto mt-2 mt-lg-0">
<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_source">Wegstrecke</a></li>
<li class="nav-item"><a class="nav-link" role="tab" data-toggle="tab" href="#tab_lube">Schmierung</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_sysinfo">Systeminfo</a></li>
<li class="nav-item"><a class="nav-link" role="tab" data-toggle="tab" href="#tab_fwupdate">Update</a></li>
</ul>
</div>
</nav>
<main class="container">
<!-- Tabs Content -->
<div class="tab-content">
<!-- Div Tab Home-->
<div id="tab_home" class="tab-pane fade show active" role="tabpanel">
<div class="col text-center">
<div class="jumbotron">
<img src="static/img/logo.png" width="120" height="120" class="img-fluid" alt="">
<h3 class="pt-3">KTM CAN Chain Lube</h3>
</div>
</div>
<hr />
<p>
<h4>Tankinhalt verbleibend</h4>
<div class="progress">
<div class="progress-bar text-light" role="progressbar" aria-valuenow="%TANK_REMAIN_CAPACITY%"
aria-valuemin="0" aria-valuemax="100" style="width: %TANK_REMAIN_CAPACITY%&#37;">
%TANK_REMAIN_CAPACITY%&#37;
</div>
</div>
</p>
<hr />
<p>
<h4>aktueller Modus</h4>
<input class="form-control" type="text" placeholder="%SYSTEM_STATUS%" readonly>
</p>
<hr />
<div %SHOW_DTC_TABLE%>
<p>
<h4>Fehlercodes</h4>
<table class="table">
<tbody>
<tr>
<th class="col-6" scope="col">Zeitstempel</th>
<th class="col-2" scope="col">Fehlercode</th>
<th class="col-2" scope="col">Schwere</th>
<th class="col-2" scope="col">Aktiv</th>
</tr>
%DTC_TABLE%
</tbody>
</table>
</p>
<hr />
</div>
</div>
<!-- Div Tab Home-->
<!-- Div Tab Source Settings-->
<div id="tab_source" class="tab-pane fade" role="tabpanel">
<h3>Wegstreckenerfassung</h3>
<hr />
<p>
<h4>Signalquelle</h4>
<form action="post.htm" method="POST" class="form-horizontal">
<div class="form-group row">
<label for="sourceselect" class="control-label col-4">Schnittstelle</label>
<div class="col-8">
<select id="sourceselect" name="sourceselect" class="select form-control">
%SOURCE_SELECT_OPTIONS%
</select>
</div>
</div>
<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>
Bei Änderung der Signalquelle wird der CAN-Oiler neu gestartet.
Dadurch wird die WiFi-Verbindung getrennt und muss neu aufgebaut werden.
</div>
<div class="form-group row">
<div class="col text-center">
<button name="sourcesave" type="submit" class="btn btn-outline-primary">&Uuml;bernehmen</button>
</div>
</div>
</form>
</p>
<!-- Div Source:Impulse Settings-->
<div %SHOW_IMPULSE_SETTINGS%>
<hr />
<p>
<h4>Einstellungen Impulseingang</h4>
<form action="post.htm" method="POST" class="form-horizontal">
<div class="form-group row">
<label for="tirewidth" class="control-label col-4">Reifenbreite</label>
<div class="col-8">
<div class="input-group">
<input id="tirewidth" name="tirewidth" type="text" required="required" class="form-control"
value="%TIRE_WIDTH_MM%">
<div class="input-group-append">
<span class="input-group-text">mm</span>
</div>
</div>
</div>
</div>
<div class="form-group row">
<label for="tireratio" class="control-label col-4">Höhe/Breite-Verhältniss</label>
<div class="col-8">
<div class="input-group">
<input id="tireratio" name="tireratio" type="text" required="required" class="form-control"
value="%TIRE_RATIO%">
<div class="input-group-append">
<span class="input-group-text">mm</span>
</div>
</div>
</div>
</div>
<div class="form-group row">
<label for="tiredia" class="control-label col-4">Felgendurchmesser</label>
<div class="col-8">
<div class="input-group">
<input id="tiredia" name="tiredia" type="text" required="required" class="form-control"
value="%RIM_DIAMETER%">
<div class="input-group-append">
<span class="input-group-text">"</span>
</div>
</div>
</div>
</div>
<div class="form-group row">
<label for="pulserev" class="control-label col-4">Pulse pro Umdrehung</label>
<div class="col-8">
<div class="input-group">
<input id="pulserev" name="pulserev" type="text" required="required" class="form-control"
value="%PULSE_PER_REV%">
<div class="input-group-addon"></div>
</div>
</div>
</div>
<div class="form-group row">
<div class="col text-center">
<button name="pulsesave" type="submit" class="btn btn-outline-primary">Speichern</button>
</div>
</div>
</form>
</p>
<hr />
</div>
<!-- Div Source:Impulse Settings-->
<!-- Div Source:CAN Settings-->
<div %SHOW_CAN_SETTINGS%>
<hr />
<p>
<h4>Einstellungen CAN-Bus</h4>
<form action="post.htm" method="POST" class="form-horizontal">
<div class="form-group row">
<label for="cansource" class="control-label col-4">Model</label>
<div class="col-8">
<select id="cansource" name="cansource" class="select form-control">
%CANSOURCE_SELECT_OPTIONS%
</select>
</div>
</div>
<div class="form-group row">
<div class="col text-center">
<button name="cansave" type="submit" class="btn btn-outline-primary">Speichern</button>
</div>
</div>
</form>
</p>
<hr />
</div>
<!-- Div Source:CAN Settings-->
<!-- Div Source:GPS Settings-->
<div %SHOW_GPS_SETTINGS%>
<hr />
<p>
<h4>Einstellungen GPS</h4>
<form action="post.htm" method="POST" class="form-horizontal">
<div class="form-group row">
<label for="gpsbaud" class="control-label col-4">Baudrate</label>
<div class="col-8">
<select id="gpsbaud" name="gpsbaud" class="select form-control">
%GPSBAUD_SELECT_OPTIONS%
</select>
</div>
</div>
<div class="form-group row">
<div class="col text-center">
<button name="gpssave" type="submit" class="btn btn-outline-primary">Speichern</button>
</div>
</div>
</form>
</p>
<hr />
</div>
<!-- Div Source:GPS Settings-->
</div>
<!-- Div Tab Source Settings-->
<!-- Div Tab Lube -->
<div id="tab_lube" class="tab-pane fade" role="tabpanel">
<h3>Schmierung</h3>
<hr />
<p>
<h4>Dosierung</h4>
<form action="post.htm" method="POST" class="form-horizontal">
<div class="form-group row">
<label for="lubedistancenormal" class="control-label col-4">Normal (gr&uuml;n)</label>
<div class="col-8">
<div class="input-group">
<input id="lubedistancenormal" name="lubedistancenormal" value="%LUBE_DISTANCE_NORMAL%" type="text"
class="form-control" required="required">
<div class="input-group-append">
<span class="input-group-text">m</span>
</div>
</div>
</div>
</div>
<div class="form-group row">
<label for="lubedistancerain" class="control-label col-4">Regen (blau)</label>
<div class="col-8">
<div class="input-group">
<input id="lubedistancerain" name="lubedistancerain" value="%LUBE_DISTANCE_RAIN%" type="text"
class="form-control" required="required">
<div class="input-group-append">
<span class="input-group-text">m</span>
</div>
</div>
</div>
</div>
<div class="form-group row">
<div class="col text-center">
<button name="oilsave" type="submit" class="btn btn-outline-primary">Speichern</button>
</div>
</div>
</form>
</p>
<hr />
</div>
<!-- Div Tab Lube -->
<!-- Div Tab Maintenance -->
<div id="tab_maintenance" class="tab-pane fade" role="tabpanel">
<h3>Wartung</h3>
<hr />
<p>
<h4>&Ouml;lvorrat</h4>
<form action="post.htm" method="POST" class="form-horizontal">
<div class="form-group row">
<label for="tankcap" class="control-label col-4">Tankkapazität</label>
<div class="col-8">
<div class="input-group">
<input id="tankcap" name="tankcap" value="%TANK_CAPACITY%" type="text" class="form-control"
required="required">
<div class="input-group-append">
<span class="input-group-text">ml</span>
</div>
</div>
</div>
</div>
<div class="form-group row">
<label for="tankwarn" class="control-label col-4">Leer-Warnung</label>
<div class="col-8">
<div class="input-group">
<input id="tankwarn" name="tankwarn" value="%TANK_REMIND%" type="text" class="form-control"
required="required">
<div class="input-group-append">
<span class="input-group-text">&#37;</span>
</div>
</div>
</div>
</div>
<div class="form-group row">
<label for="pumppulse" class="control-label col-4">Menge pro Puls</label>
<div class="col-8">
<div class="input-group">
<input id="pumppulse" name="pumppulse" value="%AMOUNT_PER_DOSE%" type="text" class="form-control"
required="required">
<div class="input-group-append">
<span class="input-group-text">µl</span>
</div>
</div>
</div>
</div>
<div class="form-group row">
<label for="tankremain_maint" class="control-label col-4">Tankinhalt verbleibend</label>
<div class="col-8">
<div class="progress">
<div id="tankremain_maint" class="progress-bar text-light" role="progressbar"
aria-valuenow="%TANK_REMAIN_CAPACITY%" aria-valuemin="0" aria-valuemax="100"
style="width: %TANK_REMAIN_CAPACITY%&#37;">
%TANK_REMAIN_CAPACITY%&#37;
</div>
</div>
</div>
</div>
<div class="form-group row">
<div class="col text-center">
<button name="oilsave" type="submit" class="btn btn-outline-primary">Speichern</button>
<button name="resettank" type="submit" class="btn btn-outline-primary ml-2">Tank zurücksetzen</button>
</div>
</div>
</form>
</p>
<hr />
<p>
<h4>Entl&uuml;ftung</h4>
<form action="post.htm" method="POST" class="form-horizontal">
<div class="form-group row">
<label for="purgepulse" class="control-label col-4">Entl&uuml;ftung Dosierung</label>
<div class="col-8">
<div class="input-group">
<input id="purgepulse" name="purgepulse" value="%BLEEDING_PULSES%" type="text" class="form-control">
<div class="input-group-append">
<span class="input-group-text">Pulse</span>
</div>
</div>
</div>
</div>
<div class="form-group row">
<div class="col text-center">
<button name="maintsave" type="submit" class="btn btn-outline-primary">Speichern</button>
<button name="purgenow" type="submit" class="btn btn-outline-primary ml-2">Entlüftung starten</button>
</div>
</div>
</form>
</p>
<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>
<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>
<hr />
</div>
<!-- Div Tab Maintenance -->
<!-- Div Tab SystemInfo -->
<div id="tab_sysinfo" class="tab-pane fade" role="tabpanel">
<h3>Systeminfo</h3>
<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>DistancePerLube_Default</td>
<td>%LUBE_DISTANCE_NORMAL%</td>
</tr>
<tr>
<td>DistancePerLube_Rain</td>
<td>%LUBE_DISTANCE_RAIN%</td>
</tr>
<tr>
<td>tankCapacity_ml</td>
<td>%TANK_CAPACITY%</td>
</tr>
<tr>
<td>amountPerDose_&micro;l</td>
<td>%AMOUNT_PER_DOSE%</td>
</tr>
<tr>
<td>TankRemindAtPercentage</td>
<td>%TANK_REMIND%</td>
</tr>
<tr>
<td>PulsePerRevolution</td>
<td>%PULSE_PER_REV%</td>
</tr>
<tr>
<td>TireWidth_mm</td>
<td>%TIRE_WIDTH_MM%</td>
</tr>
<tr>
<td>TireWidthHeight_Ratio</td>
<td>%TIRE_RATIO%</td>
</tr>
<tr>
<td>RimDiameter_Inch</td>
<td>%RIM_DIAMETER%</td>
</tr>
<tr>
<td>DistancePerRevolution_mm</td>
<td>%DISTANCE_PER_REV%</td>
</tr>
<tr>
<td>BleedingPulses</td>
<td>%BLEEDING_PULSES%</td>
</tr>
<tr>
<td>SpeedSource</td>
<td>%SPEED_SOURCE%</td>
</tr>
<tr>
<td>GPSBaudRate</td>
<td>%GPS_BAUD%</td>
</tr>
<tr>
<td>CANSource</td>
<td>%CAN_SOURCE%</td>
</tr>
<tr>
<td>Checksum</td>
<td>%CONFIG_CHECKSUM%</td>
</tr>
</tbody>
</table>
</p>
<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>tankRemain_µl</td>
<td>%TANK_REMAIN_UL%</td>
</tr>
<tr>
<td>TravelDistance_highRes</td>
<td>%TRAVEL_DISTANCE_HIGHRES%</td>
</tr>
<tr>
<td>Odometer</td>
<td>%ODOMETER%,%ODOMETER_M%</td>
</tr>
<tr>
<td>checksum</td>
<td>%PERSISTANCE_CHECKSUM%</td>
</tr>
</table>
</p>
<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>
<hr />
</div>
<!-- Div Tab SystemInfo -->
<!-- Div Tab Firmware Update-->
<div id="tab_fwupdate" class="tab-pane fade" role="tabpanel">
<h3>Firmware</h3>
<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>
</table>
</p>
<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>
<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>
<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>
<hr />
</div>
<!-- Div Tab Firmware Update-->
</div>
<!-- Tabs Content -->
</main>
<!-- Footer -->
<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">© 2022 -
<a class="text-reset fw-bold" href="https://eventronics.de/">Marcel Peterkau</a></span>
</div>
</div>
</footer>
<!-- Footer -->
<!-- Modal Dialog -->
<div class="modal fade" id="dtcModal" tabindex="-1" role="dialog" aria-labelledby="dtcModalLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="dtcModalLabel">DTC-Description</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<p class="dtc-desc">DTC Description</p>
<p class="dtc-debugval">DTC DebugVal</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-outline-secondary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
<!-- Modal Dialog -->
<script>
$('.navbar-nav>li>a').on('click', function () {
$('.navbar-collapse').collapse('hide');
});
document.querySelector('.custom-file-input').addEventListener('change', function (e) {
var fileName = document.getElementById("fw-update-file").files[0].name;
var nextSibling = e.target.nextElementSibling
nextSibling.innerText = fileName
});
$(document).ready(function () {
$("tr[data-dtc]").each(function (i) {
$(this).attr('data-toggle', "modal");
$(this).attr('data-target', "#dtcModal");
});
});
$('#dtcModal').on('show.bs.modal', function (event) {
var dtctr = $(event.relatedTarget)
var dtc = dtctr.data('dtc')
var debugval = dtctr.data('debugval')
var modal = $(this)
$.getJSON('static/tt_dtc/dtc_' + dtc + '.json', function (data) {
modal.find('.modal-title').text(data.title)
modal.find('.dtc-desc').text(data.description)
if (debugval > 0) {
modal.find('.dtc-debugval').text("Debugvalue: " + debugval)
}
else {
modal.find('.dtc-debugval').remove()
}
}).fail(function () {
console.log("An error has occurred.");
modal.find('.modal-title').text("Fehler")
modal.find('.dtc-desc').text("DTC-Beschreibung konnte nicht geladen werden")
});
});
</script>
</body>
</html>

View File

@@ -14,7 +14,7 @@
<link rel="icon" type="image/png" sizes="32x32" href="static/img/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="static/img/favicon-16x16.png">
<link rel="manifest" href="static/img/site.webmanifest">
<meta http-equiv="refresh" content="3; url='/index.htm'" />
<meta http-equiv="refresh" content="3; url='index.htm'" />
</head>
<body>

File diff suppressed because it is too large Load Diff

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.

View File

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View File

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 39 KiB

View File

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

View File

Before

Width:  |  Height:  |  Size: 545 B

After

Width:  |  Height:  |  Size: 545 B

View File

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

View File

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 5.6 KiB

View File

@@ -0,0 +1 @@
{"name":"","short_name":"","icons":[{"src":"/static/img/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/static/img/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"}

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,68 @@
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;
}

View File

@@ -0,0 +1,4 @@
{
"title": "Ölvorrat leer",
"description": "Ölvorrat ist komplett leer. Den Ölvorrat auffüllen und im Menu 'Wartung' zurück setzen"
}

View File

@@ -0,0 +1,4 @@
{
"title": "Keine GPS-Verbindung",
"description": "Es wurde kein GPS-Signal über die serielle Schnittstelle empfangen, Prüfen sie die Verbindung und das GPS-Modul"
}

View File

@@ -0,0 +1,4 @@
{
"title": "CAN-Transceiver Error",
"description": "Es konnte keine Verbindung zum CAN-Transceiver hergestellt werden. Prüfen Sie die Hardware auf Defekte"
}

View File

@@ -0,0 +1,4 @@
{
"title": "Keine CAN-Verbindung",
"description": "Es konnte kein CAN-Signal empfangen werden. Prüfen sie die Verbindung und die Einstellungen"
}

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": "Ölvorrat niedrig",
"description": "Ölvorrat ist unter der Warnschwelle. Den Ölvorrat demnächst auffüllen und im Menu 'Wartung' zurück setzen"
}

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": "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 @@
1.3

View File

@@ -26,17 +26,24 @@ upload_speed = 921600
build_flags =
!python git_rev_macro.py
-DWIFI_SSID=${wifi_cred.wifi_ssid}
-DWIFI_PASSWORD=${wifi_cred.wifi_password}
-DWIFI_SSID_CLIENT=${wifi_cred.wifi_ssid_client}
-DWIFI_PASSWORD_CLIENT=${wifi_cred.wifi_password_client}
-DADMIN_PASSWORD=${wifi_cred.admin_password}
-DWIFI_AP_PASSWORD=${wifi_cred.wifi_ap_password}
-DWIFI_AP_IP_GW=10,0,0,1
;-DFEATURE_ENABLE_WIFI_CLIENT
-DFEATURE_ENABLE_REMOTE_DEBUG
-DATOMIC_FS_UPDATE
-DFEATURE_ENABLE_WIFI_CLIENT
-DFEATURE_ENABLE_OLED
-DFEATURE_ENABLE_CAN
-DFEATURE_ENABLE_GPS
;-DFEATURE_ENABLE_GPS
-DFEATURE_ENABLE_WEBSOCKETS
-DPCB_REV=4
;-DNO_MODE_FLASH
;build_type = debug
board_build.filesystem = littlefs
extra_scripts = post:prepare_littlefs.py
monitor_filters = esp8266_exception_decoder
monitor_speed = 115200
@@ -45,10 +52,10 @@ board_build.ldscript = eagle.flash.4m1m.ld
lib_ldf_mode = deep
lib_deps =
olikraus/U8g2 @ ^2.28.8
joaolopesf/RemoteDebug @ ^2.1.2
fastled/FastLED @ ^3.5.0
https://github.com/FastLED/FastLED.git#3d2ab78 ;fastled/FastLED @ ^3.5.0
sstaub/Ticker @ ^4.2.0
coryjfowler/mcp_can @ ^1.5.0
robtillaart/I2C_EEPROM @ ^1.5.2
mikalhart/TinyGPSPlus @ ^1.0.3
me-no-dev/ESP Async WebServer @ ^1.2.3
bblanchon/ArduinoJson @ ^6.19.4

View File

@@ -0,0 +1,116 @@
# 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 shutil
import gzip
import os
Import("env")
Import("projenv")
def gzip_file(src_path, dst_path):
with open(src_path, 'rb') as src, gzip.open(dst_path, 'wb') as dst:
for chunk in iter(lambda: src.read(4096), b""):
dst.write(chunk)
def getListOfFiles(dirName):
# create a list of file and sub directories
# names in the given directory
listOfFile = os.listdir(dirName)
allFiles = list()
# Iterate over all the entries
for entry in listOfFile:
# Create full path
fullPath = os.path.join(dirName, entry)
# If entry is a directory then get the list of files in this directory
if os.path.isdir(fullPath):
allFiles = allFiles + getListOfFiles(fullPath)
else:
allFiles.append(fullPath)
return allFiles
def remove_prefix(text, prefix):
if text.startswith(prefix):
return text[len(prefix):]
return text # or whatever
# Compress files from 'data_src/' to 'data/'
def gzip_webfiles(source, target, env):
# Filetypes to compress
filetypes_to_gzip = ['.css', '.png', '.js', '.ico', '.woff2', '.json']
print('\nGZIP: Starting gzip-Process for LittleFS-Image...\n')
data_src_dir_path = os.path.join(env.get('PROJECT_DIR'), 'data_src')
data_dir_path = env.get('PROJECT_DATA_DIR')
# check if data and datasrc exist. If the first exists and not the second, it renames it
if(os.path.exists(data_dir_path) and not os.path.exists(data_src_dir_path)):
print('GZIP: Directory "'+data_dir_path +
'" exists, "'+data_src_dir_path+'" is not found.')
print('GZIP: Renaming "' + data_dir_path +
'" to "' + data_src_dir_path + '"')
os.rename(data_dir_path, data_src_dir_path)
# Delete the 'data' directory
if(os.path.exists(data_dir_path)):
print('GZIP: Deleting the "data" directory ' + data_dir_path)
shutil.rmtree(data_dir_path)
# Recreate empty 'data' directory
print('GZIP: Re-creating an empty data directory ' + data_dir_path)
os.mkdir(data_dir_path)
# Determine the files to compress
files_to_copy = []
files_to_gzip = []
all_data_src = getListOfFiles(data_src_dir_path)
for file in all_data_src:
file_name, file_extension = os.path.splitext(file)
print(file_name + " has filetype " + file_extension)
if file_extension in filetypes_to_gzip:
files_to_gzip.append(file)
else:
filename_subdir = remove_prefix(file, data_src_dir_path)
files_to_copy.append(filename_subdir)
for file in files_to_copy:
print('GZIP: Copying file from: ' + data_src_dir_path + file + ' to: ' + data_dir_path + file)
os.makedirs(os.path.dirname(data_dir_path + file), exist_ok=True)
shutil.copy(data_src_dir_path + file, data_dir_path + file)
# Compress and move files
was_error = False
try:
for source_file_path in files_to_gzip:
print('GZIP: compressing... ' + source_file_path)
filename_subdir = remove_prefix(source_file_path, data_src_dir_path)
target_file_path = data_dir_path + filename_subdir
os.makedirs(os.path.dirname(target_file_path), exist_ok=True)
print('GZIP: Compressed... ' + target_file_path)
gzip_file(source_file_path, target_file_path + ".gz")
except IOError as e:
was_error = True
print('GZIP: Failed to compress file: ' + source_file_path)
# print( 'GZIP: EXCEPTION... {}'.format( e ) )
if was_error:
print('GZIP: Failure/Incomplete.\n')
else:
print('GZIP: Compressed correctly.\n')
return
def gzip_binffiles(source, target, env):
littlefsbin = target[0].get_abspath()
targetbin = os.path.join(os.path.dirname(littlefsbin), 'filesystem.fs')
shutil.copyfile(littlefsbin, targetbin)
gzip_file(targetbin, os.path.join(str(targetbin) + '.gz'))
os.remove(targetbin)
return
# IMPORTANT, this needs to be added to call the routine
env.AddPreAction('$BUILD_DIR/littlefs.bin', gzip_webfiles)
env.AddPostAction('$BUILD_DIR/littlefs.bin', gzip_binffiles)

View File

@@ -7,7 +7,7 @@ void Init_CAN()
{
if (CAN0.begin(MCP_STDEXT, CAN_500KBPS, MCP_16MHZ) != CAN_OK)
MaintainDTC(DTC_CAN_TRANSCEIVER_FAILED, true);
MaintainDTC(DTC_CAN_TRANSCEIVER_FAILED, DTC_CRITICAL, true);
CAN0.init_Mask(0, 0, 0x07FF0000); // Init first mask...
CAN0.init_Mask(1, 0, 0x07FF0000); // Init second mask...
@@ -23,9 +23,11 @@ uint32_t Process_CAN_WheelSpeed()
can_frame canMsg;
static uint32_t lastRecTimestamp = 0;
uint16_t RearWheelSpeed_raw;
uint32_t milimeters_to_add = 0;
if (CAN0.readMsgBuf(&canMsg.can_id, &canMsg.can_dlc, canMsg.data) == CAN_OK)
{
RearWheelSpeed_raw = (uint16_t)canMsg.data[5] << 8 | canMsg.data[6];
// raw / FACTOR_RWP_KMH_890ADV -> km/h * 100000 -> cm/h / 3600 -> cm/s
// raw * 500 -> cm/s
@@ -34,13 +36,14 @@ uint32_t Process_CAN_WheelSpeed()
uint32_t timesincelast = millis() - lastRecTimestamp;
lastRecTimestamp = millis();
uint32_t milimeters_to_add = (RWP_millimeter_per_second * timesincelast) / 1000;
return milimeters_to_add;
milimeters_to_add = (RWP_millimeter_per_second * timesincelast) / 1000;
}
MaintainDTC(DTC_NO_CAN_SIGNAL, (millis() > lastRecTimestamp + 10000 ? true : false));
if (lastRecTimestamp != 0)
{
MaintainDTC(DTC_NO_CAN_SIGNAL, DTC_CRITICAL, (millis() > lastRecTimestamp + 10000 ? true : false));
}
return 0;
return milimeters_to_add;
}
#endif

52
Software/src/common.h Normal file
View File

@@ -0,0 +1,52 @@
#ifndef _COMMON_H_
#define _COMMON_H_
#define Q(x) #x
#define QUOTE(x) Q(x)
#if PCB_REV == 2
#define GPIO_BUTTON D7
#define GPIO_LED D8
#define GPIO_TRIGGER D6
#define GPIO_PUMP D5
#elif PCB_REV == 1 || PCB_REV == 3
#define GPIO_BUTTON D5
#define GPIO_LED D6
#define GPIO_TRIGGER D4
#define GPIO_PUMP D3
#elif PCB_REV == 4
#define GPIO_BUTTON D4
#define GPIO_LED D3
#define GPIO_TRIGGER D6
#define GPIO_PUMP D0
#define GPIO_CS_CAN D8
#endif
#ifndef HOST_NAME
#define HOST_NAME "ChainLube_%06X" // Use printf-Formatting - Chip-ID (uin32_t) will be added
#endif
#define SW_VERSION 1.4
#define FLASH_FS_VERSION 1.4
#ifndef OTA_DELAY
#define OTA_DELAY 50 // ticks -> 10ms / tick
#endif
#define LUBE_PULSE_LENGHT_MS 160
#define LUBE_PULSE_PAUSE_MS 340
// -> 2Hz PumpPulse
// -> 49,7cc / h @ 2Hz
// -> 49,7 ml / h @ 2Hz
// -> 828,4µl / min @ 2Hz
// -> 828,3µl / 60s
// -> 13,81µl / 1s
// -> 6,90µl / Pulse
#define DEFAULT_PUMP_DOSE 7
#define STARTUP_DELAY 5000
#define SHUTDOWN_DELAY_MS 5000
#endif

358
Software/src/config.cpp Normal file
View File

@@ -0,0 +1,358 @@
#include "config.h"
#include "debugger.h"
I2C_eeprom ee(0x50, EEPROM_SIZE_BYTES);
LubeConfig_t LubeConfig;
persistenceData_t PersistenceData;
const uint16_t eeVersion = 2; // inc
boolean eeAvailable = false;
const uint16_t startofLubeConfig = 16;
const uint16_t startofPersistence = 16 + sizeof(LubeConfig) + (sizeof(LubeConfig) % 16);
boolean checkEEPROMavailable();
void InitEEPROM()
{
ee.begin();
checkEEPROMavailable();
}
void EEPROM_Process()
{
switch (globals.requestEEAction)
{
case EE_CFG_SAVE:
StoreConfig_EEPROM();
globals.requestEEAction = EE_IDLE;
Debug_pushMessage("Stored EEPROM CFG\n");
break;
case EE_CFG_LOAD:
GetConfig_EEPROM();
globals.requestEEAction = EE_IDLE;
Debug_pushMessage("Loaded EEPROM CFG\n");
break;
case EE_CFG_FORMAT:
FormatConfig_EEPROM();
globals.requestEEAction = EE_IDLE;
globals.systemStatus = sysStat_Shutdown;
Debug_pushMessage("Formated EEPROM CFG\n");
break;
case EE_PDS_SAVE:
StorePersistence_EEPROM();
globals.requestEEAction = EE_IDLE;
Debug_pushMessage("Stored EEPROM PDS\n");
break;
case EE_PDS_LOAD:
GetPersistence_EEPROM();
globals.requestEEAction = EE_IDLE;
Debug_pushMessage("Loaded EEPROM PDS\n");
break;
case EE_PDS_FORMAT:
FormatPersistence_EEPROM();
globals.requestEEAction = EE_IDLE;
Debug_pushMessage("Formated EEPROM PDS\n");
break;
case EE_FORMAT_ALL:
FormatConfig_EEPROM();
FormatPersistence_EEPROM();
globals.requestEEAction = EE_IDLE;
Debug_pushMessage("Formated EEPROM ALL\n");
break;
case EE_ALL_SAVE:
StorePersistence_EEPROM();
StoreConfig_EEPROM();
globals.requestEEAction = EE_IDLE;
Debug_pushMessage("Stored EEPROM ALL\n");
break;
case EE_IDLE:
default:
globals.requestEEAction = EE_IDLE;
}
}
void StoreConfig_EEPROM()
{
LubeConfig.checksum = 0;
LubeConfig.checksum = Checksum_EEPROM((uint8_t *)&LubeConfig, sizeof(LubeConfig));
if (!checkEEPROMavailable())
return;
ee.updateBlock(startofLubeConfig, (uint8_t *)&LubeConfig, sizeof(LubeConfig));
}
void GetConfig_EEPROM()
{
if (!checkEEPROMavailable())
return;
ee.readBlock(startofLubeConfig, (uint8_t *)&LubeConfig, sizeof(LubeConfig));
uint32_t checksum = LubeConfig.checksum;
LubeConfig.checksum = 0;
if (Checksum_EEPROM((uint8_t *)&LubeConfig, sizeof(LubeConfig)) != checksum)
{
MaintainDTC(DTC_EEPROM_CFG_BAD, DTC_CRITICAL, true);
}
LubeConfig.checksum = checksum;
uint32_t ConfigSanityCheckResult = ConfigSanityCheck(false);
if (ConfigSanityCheckResult > 0)
{
MaintainDTC(DTC_EEPROM_CFG_SANITY, DTC_WARN, true, ConfigSanityCheckResult);
globals.requestEEAction = EE_CFG_SAVE;
}
}
void StorePersistence_EEPROM()
{
if (PersistenceData.writeCycleCounter >= 0xFFF0)
MovePersistencePage_EEPROM(false);
else
PersistenceData.writeCycleCounter++;
PersistenceData.checksum = 0;
PersistenceData.checksum = Checksum_EEPROM((uint8_t *)&PersistenceData, sizeof(PersistenceData));
if (!checkEEPROMavailable())
return;
ee.updateBlock(globals.eePersistanceAdress, (uint8_t *)&PersistenceData, sizeof(PersistenceData));
}
void GetPersistence_EEPROM()
{
if (!checkEEPROMavailable())
return;
ee.readBlock(0, (uint8_t *)&globals.eePersistanceAdress, sizeof(globals.eePersistanceAdress));
// if we got the StartAdress of Persistance and it's out of Range - we Reset it and store defaults
// otherwise we Read from eeprom and check if everything is correct
if (globals.eePersistanceAdress < startofPersistence || globals.eePersistanceAdress > ee.getDeviceSize())
{
MovePersistencePage_EEPROM(true);
FormatPersistence_EEPROM();
MaintainDTC(DTC_EEPROM_PDSADRESS_BAD, DTC_CRITICAL, true);
}
else
{
ee.readBlock(globals.eePersistanceAdress, (uint8_t *)&PersistenceData, sizeof(PersistenceData));
uint32_t checksum = PersistenceData.checksum;
PersistenceData.checksum = 0;
if (Checksum_EEPROM((uint8_t *)&PersistenceData, sizeof(PersistenceData)) != checksum)
{
MaintainDTC(DTC_EEPROM_PDS_BAD, DTC_CRITICAL, true);
}
PersistenceData.checksum = checksum;
}
}
void FormatConfig_EEPROM()
{
Debug_pushMessage("Formatting Config-Partition\n");
LubeConfig = LubeConfig_defaults;
LubeConfig.EEPROM_Version = eeVersion;
StoreConfig_EEPROM();
}
void FormatPersistence_EEPROM()
{
Debug_pushMessage("Formatting Persistance-Partition\n");
PersistenceData = {0};
// memset(&PersistenceData, 0, sizeof(PersistenceData));
StorePersistence_EEPROM();
}
void MovePersistencePage_EEPROM(boolean reset)
{
if (!checkEEPROMavailable())
return;
globals.eePersistanceAdress = +sizeof(PersistenceData);
PersistenceData.writeCycleCounter = 0;
// check if we reached the End of the EEPROM and Startover at the beginning
if ((globals.eePersistanceAdress + sizeof(PersistenceData)) > ee.getDeviceSize() || reset)
{
globals.eePersistanceAdress = startofPersistence;
}
ee.updateBlock(0, (uint8_t *)&globals.eePersistanceAdress, sizeof(globals.eePersistanceAdress));
}
uint32_t Checksum_EEPROM(uint8_t const *data, size_t len)
{
if (data == NULL)
return 0;
uint32_t crc, mask;
crc = 0xFFFFFFFF;
while (len--)
{
crc ^= *data++;
for (uint8_t k = 0; k < 8; k++)
{
mask = -(crc & 1);
crc = (crc >> 1) ^ (0xEDB88320 & mask);
}
}
return ~crc;
}
void dumpEEPROM(uint16_t memoryAddress, uint16_t length)
{
#define BLOCK_TO_LENGTH 16
if (!checkEEPROMavailable())
return;
char ascii_buf[BLOCK_TO_LENGTH + 1];
sprintf(ascii_buf, "%*s", BLOCK_TO_LENGTH, "ASCII");
Debug_pushMessage(PSTR("\nAddress "));
for (int x = 0; x < BLOCK_TO_LENGTH; x++)
Debug_pushMessage("%3d", x);
memoryAddress = memoryAddress / BLOCK_TO_LENGTH * BLOCK_TO_LENGTH;
length = (length + BLOCK_TO_LENGTH - 1) / BLOCK_TO_LENGTH * BLOCK_TO_LENGTH;
for (unsigned int i = 0; i < length; i++)
{
int blockpoint = memoryAddress % BLOCK_TO_LENGTH;
if (blockpoint == 0)
{
ascii_buf[BLOCK_TO_LENGTH] = 0;
Debug_pushMessage(" %s", ascii_buf);
Debug_pushMessage("\n0x%05X:", memoryAddress);
}
ascii_buf[blockpoint] = ee.readByte(memoryAddress);
Debug_pushMessage(" %02X", ascii_buf[blockpoint]);
if (ascii_buf[blockpoint] < 0x20 || ascii_buf[blockpoint] > 0x7E)
ascii_buf[blockpoint] = '.';
memoryAddress++;
}
Debug_pushMessage("\n");
}
boolean checkEEPROMavailable()
{
if (!ee.isConnected())
{
MaintainDTC(DTC_NO_EEPROM_FOUND, DTC_CRITICAL, true);
return false;
}
MaintainDTC(DTC_NO_EEPROM_FOUND, DTC_CRITICAL, false);
return true;
}
uint32_t ConfigSanityCheck(bool autocorrect)
{
uint32_t setting_reset_bits = 0;
if (!(LubeConfig.DistancePerLube_Default > 0) || !(LubeConfig.DistancePerLube_Default < 50000))
{
setting_reset_bits = setting_reset_bits | (1 << 0);
if (autocorrect)
LubeConfig.DistancePerLube_Default = LubeConfig_defaults.DistancePerLube_Default;
}
if (!(LubeConfig.DistancePerLube_Rain > 0) || !(LubeConfig.DistancePerLube_Rain < 50000))
{
setting_reset_bits = setting_reset_bits | (1 << 1);
if (autocorrect)
LubeConfig.DistancePerLube_Rain = LubeConfig_defaults.DistancePerLube_Rain;
}
if (!(LubeConfig.tankCapacity_ml > 0) || !(LubeConfig.tankCapacity_ml < 5000))
{
setting_reset_bits = setting_reset_bits | (1 << 2);
if (autocorrect)
LubeConfig.tankCapacity_ml = LubeConfig_defaults.tankCapacity_ml;
}
if (!(LubeConfig.amountPerDose_microL > 0) || !(LubeConfig.amountPerDose_microL < 100))
{
setting_reset_bits = setting_reset_bits | (1 << 3);
if (autocorrect)
LubeConfig.amountPerDose_microL = LubeConfig_defaults.amountPerDose_microL;
}
if (!(LubeConfig.TankRemindAtPercentage >= 0) || !(LubeConfig.TankRemindAtPercentage <= 100))
{
setting_reset_bits = setting_reset_bits | (1 << 4);
if (autocorrect)
LubeConfig.TankRemindAtPercentage = LubeConfig_defaults.TankRemindAtPercentage;
}
if (!(LubeConfig.PulsePerRevolution > 0) || !(LubeConfig.PulsePerRevolution < 1000))
{
setting_reset_bits = setting_reset_bits | (1 << 5);
if (autocorrect)
LubeConfig.PulsePerRevolution = LubeConfig_defaults.PulsePerRevolution;
}
if (!(LubeConfig.TireWidth_mm > 0) || !(LubeConfig.TireWidth_mm < 500))
{
setting_reset_bits = setting_reset_bits | (1 << 6);
if (autocorrect)
LubeConfig.TireWidth_mm = LubeConfig_defaults.TireWidth_mm;
}
if (!(LubeConfig.TireWidthHeight_Ratio > 0) || !(LubeConfig.TireWidthHeight_Ratio < 150))
{
setting_reset_bits = setting_reset_bits | (1 << 7);
if (autocorrect)
LubeConfig.TireWidthHeight_Ratio = LubeConfig_defaults.TireWidthHeight_Ratio;
}
if (!(LubeConfig.RimDiameter_Inch > 0) || !(LubeConfig.RimDiameter_Inch < 30))
{
setting_reset_bits = setting_reset_bits | (1 << 8);
if (autocorrect)
LubeConfig.RimDiameter_Inch = LubeConfig_defaults.RimDiameter_Inch;
}
if (!(LubeConfig.DistancePerRevolution_mm > 0) || !(LubeConfig.DistancePerRevolution_mm < 10000))
{
setting_reset_bits = setting_reset_bits | (1 << 9);
if (autocorrect)
LubeConfig.DistancePerRevolution_mm = LubeConfig_defaults.DistancePerRevolution_mm;
}
if (!(LubeConfig.BleedingPulses > 0) || !(LubeConfig.BleedingPulses < 1001))
{
setting_reset_bits = setting_reset_bits | (1 << 10);
if (autocorrect)
LubeConfig.BleedingPulses = LubeConfig_defaults.BleedingPulses;
}
if (!(LubeConfig.SpeedSource >= 0) || !(LubeConfig.SpeedSource < SpeedSourceString_Elements))
{
setting_reset_bits = setting_reset_bits | (1 << 11);
if (autocorrect)
LubeConfig.SpeedSource = LubeConfig_defaults.SpeedSource;
}
#ifdef FEATURE_ENABLE_GPS
if (!(LubeConfig.GPSBaudRate >= 0) || !(LubeConfig.GPSBaudRate < GPSBaudRateString_Elements))
{
setting_reset_bits = setting_reset_bits | (1 << 12);
if (autocorrect)
LubeConfig.GPSBaudRate = LubeConfig_defaults.GPSBaudRate;
}
#endif
#ifdef FEATURE_ENABLE_CAN
if (!(LubeConfig.CANSource >= 0) || !(LubeConfig.CANSource < CANSourceString_Elements))
{
setting_reset_bits = setting_reset_bits | (1 << 13);
if (autocorrect)
LubeConfig.CANSource = LubeConfig_defaults.CANSource;
}
#endif
return setting_reset_bits;
}

View File

@@ -6,8 +6,13 @@
#include <I2C_eeprom.h>
#include "globals.h"
#include "dtc.h"
#include "common.h"
#if PCB_REV == 1 || PCB_REV == 2 || PCB_REV == 3
#define EEPROM_SIZE_BYTES I2C_DEVICESIZE_24LC64
#elif PCB_REV == 4
#define EEPROM_SIZE_BYTES I2C_DEVICESIZE_24LC256
#endif
typedef enum SpeedSource_e
{
@@ -63,7 +68,7 @@ const size_t SpeedSourceString_Elements = sizeof(SpeedSourceString) / sizeof(Spe
typedef struct
{
uint16_t writeCycleCounter = 0;
uint32_t tankRemain_µl = 0;
uint32_t tankRemain_microL = 0;
uint32_t TravelDistance_highRes_mm = 0;
uint32_t odometer_mm = 0;
uint32_t odometer = 0;
@@ -76,14 +81,14 @@ typedef struct
uint32_t DistancePerLube_Default = 8000;
uint32_t DistancePerLube_Rain = 4000;
uint32_t tankCapacity_ml = 320;
uint32_t amountPerDose_µl = 72;
uint32_t amountPerDose_microL = DEFAULT_PUMP_DOSE;
uint8_t TankRemindAtPercentage = 30;
uint8_t PulsePerRevolution = 1;
uint32_t TireWidth_mm = 150;
uint32_t TireWidthHeight_Ratio = 70;
uint32_t RimDiameter_Inch = 18;
uint32_t DistancePerRevolution_mm = 2000;
uint8_t BleedingPulses = 25;
uint16_t BleedingPulses = 25;
SpeedSource_t SpeedSource = SOURCE_IMPULSE;
#ifdef FEATURE_ENABLE_GPS
GPSBaudRate_t GPSBaudRate = BAUD_115200;
@@ -94,6 +99,16 @@ typedef struct
uint32_t checksum = 0;
} LubeConfig_t;
const LubeConfig_t LubeConfig_defaults = {
0, 8000, 4000, 320, DEFAULT_PUMP_DOSE, 30, 1, 150, 70, 18, 2000, 25, SOURCE_IMPULSE,
#ifdef FEATURE_ENABLE_GPS
BAUD_115200,
#endif
#ifdef FEATURE_ENABLE_CAN
KTM_890_ADV_R_2021,
#endif
0};
void InitEEPROM();
void EEPROM_Process();
void StoreConfig_EEPROM();
@@ -105,7 +120,7 @@ void FormatPersistence_EEPROM();
uint32_t Checksum_EEPROM(uint8_t const *data, size_t len);
void dumpEEPROM(uint16_t memoryAddress, uint16_t length);
void MovePersistencePage_EEPROM(boolean reset);
uint16_t getPersistanceAddress();
uint32_t ConfigSanityCheck(bool autocorrect = false);
extern LubeConfig_t LubeConfig;
extern persistenceData_t PersistenceData;

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

@@ -0,0 +1,253 @@
#include "debugger.h"
DebugStatus_t DebuggerStatus[dbg_cntElements];
String IpAddress2String(const IPAddress &ipAddress);
void processCmdDebug();
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 initDebugger()
{
DebuggerStatus[dbg_Serial] = disabled;
DebuggerStatus[dbg_Webui] = disabled;
Serial.setDebugOutput(false);
}
void SetDebugportStatus(DebugPorts_t port, DebugStatus_t status)
{
if (status == disabled)
Debug_pushMessage("disable DebugPort %s", sDebugPorts[port]);
DebuggerStatus[port] = status;
if (status == enabled)
Debug_pushMessage("enabled DebugPort %s", 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 pushCANDebug(uint32_t id, uint8_t dlc, uint8_t *data)
{
if ((DebuggerStatus[dbg_Serial] == enabled) || (DebuggerStatus[dbg_Webui] == enabled))
{
char buff[100];
char *p = buff;
p += snprintf(p, sizeof(buff), "CAN: 0x%08X | %d | ", id, dlc);
for (int i = 0; i < dlc; i++)
{
p += snprintf(p, sizeof(buff) - (p - buff), "%02X ", data[i]);
}
*(p++) = '\n';
*p = '\0';
if (DebuggerStatus[dbg_Serial] == enabled)
{
Serial.print(buff);
}
if (DebuggerStatus[dbg_Webui] == enabled)
{
Websocket_PushLiveDebug(String(buff));
}
}
}
void processCmdDebug(String command)
{
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();
}
void Debug_formatCFG()
{
Debug_pushMessage("Formatting Config-EEPROM and reseting to default");
FormatConfig_EEPROM();
}
void Debug_formatPersistence()
{
Debug_pushMessage("Formatting Persistence-EEPROM and reseting to default");
FormatPersistence_EEPROM();
}
void RemotDebug_printSystemInfo()
{
Debug_pushMessage("Souko's ChainOiler Mk1");
Debug_pushMessage("Hostname: %s", globals.DeviceName);
FlashMode_t ideMode = ESP.getFlashChipMode();
Debug_pushMessage("Sdk version: %s", ESP.getSdkVersion());
Debug_pushMessage("Core Version: %s", ESP.getCoreVersion().c_str());
Debug_pushMessage("Boot Version: %u", ESP.getBootVersion());
Debug_pushMessage("Boot Mode: %u", ESP.getBootMode());
Debug_pushMessage("CPU Frequency: %u MHz", ESP.getCpuFreqMHz());
Debug_pushMessage("Reset reason: %s", ESP.getResetReason().c_str());
Debug_pushMessage("Flash Size: %d", ESP.getFlashChipRealSize());
Debug_pushMessage("Flash Size IDE: %d", ESP.getFlashChipSize());
Debug_pushMessage("Flash ide mode: %s", (ideMode == FM_QIO ? "QIO" : ideMode == FM_QOUT ? "QOUT"
: ideMode == FM_DIO ? "DIO"
: ideMode == FM_DOUT ? "DOUT"
: "UNKNOWN"));
Debug_pushMessage("OTA-Pass: %s", QUOTE(ADMIN_PASSWORD));
Debug_pushMessage("Git-Revison: %s", GIT_REV);
Debug_pushMessage("Sw-Version: %s", QUOTE(SW_VERSION));
}
void Debug_dumpConfig()
{
Debug_pushMessage("DistancePerLube_Default: %d", LubeConfig.DistancePerLube_Default);
Debug_pushMessage("DistancePerLube_Rain: %d", LubeConfig.DistancePerLube_Rain);
Debug_pushMessage("tankCapacity_ml: %d", LubeConfig.tankCapacity_ml);
Debug_pushMessage("amountPerDose_microL: %d", LubeConfig.amountPerDose_microL);
Debug_pushMessage("TankRemindAtPercentage: %d", LubeConfig.TankRemindAtPercentage);
Debug_pushMessage("PulsePerRevolution: %d", LubeConfig.PulsePerRevolution);
Debug_pushMessage("TireWidth_mm: %d", LubeConfig.TireWidth_mm);
Debug_pushMessage("TireWidthHeight_Ratio: %d", LubeConfig.TireWidth_mm);
Debug_pushMessage("RimDiameter_Inch: %d", LubeConfig.RimDiameter_Inch);
Debug_pushMessage("DistancePerRevolution_mm: %d", LubeConfig.DistancePerRevolution_mm);
Debug_pushMessage("BleedingPulses: %d", LubeConfig.BleedingPulses);
Debug_pushMessage("SpeedSource: %d", LubeConfig.SpeedSource);
#ifdef FEATURE_ENABLE_GPS
Debug_pushMessage("GPSBaudRate: %d", LubeConfig.GPSBaudRate);
#endif
#ifdef FEATURE_ENABLE_CAN
Debug_pushMessage("CANSource: %d", LubeConfig.CANSource);
#endif
Debug_pushMessage("checksum: 0x%08X", LubeConfig.checksum);
}
void Debug_dumpGlobals()
{
Debug_pushMessage("systemStatus: %d", globals.systemStatus);
Debug_pushMessage("resumeStatus: %d", globals.resumeStatus);
Debug_pushMessage("systemStatustxt: %s", globals.systemStatustxt);
Debug_pushMessage("purgePulses: %d", globals.purgePulses);
Debug_pushMessage("requestEEAction: %d", globals.requestEEAction);
Debug_pushMessage("DeviceName: %s", globals.DeviceName);
Debug_pushMessage("FlashVersion: %s", globals.FlashVersion);
Debug_pushMessage("eePersistanceAdress: %d", globals.eePersistanceAdress);
Debug_pushMessage("TankPercentage: %d", globals.TankPercentage);
Debug_pushMessage("hasDTC: %d", globals.hasDTC);
}
void Debug_dumpPersistance()
{
Debug_pushMessage("writeCycleCounter: %d", PersistenceData.writeCycleCounter);
Debug_pushMessage("tankRemain_microL: %d", PersistenceData.tankRemain_microL);
Debug_pushMessage("TravelDistance_highRes_mm: %d", PersistenceData.TravelDistance_highRes_mm);
Debug_pushMessage("checksum: %d", PersistenceData.checksum);
Debug_pushMessage("PSD Adress: 0x%04X", 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 = LubeConfig.checksum;
LubeConfig.checksum = 0;
if (Checksum_EEPROM((uint8_t *)&LubeConfig, sizeof(LubeConfig)) == checksum)
{
Debug_pushMessage("LubeConfig EEPROM Checksum OK\n");
}
else
{
Debug_pushMessage("LubeConfig EEPROM Checksum BAD\n");
}
LubeConfig.checksum = checksum;
}
void Debug_ShowDTCs()
{
char buff_timestamp[16]; // Format: DD-hh:mm:ss:xxx
char buff_active[9];
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 \t %6d \t %s \t %d", buff_timestamp, DTCStorage[i].Number, buff_active, DTCStorage[i].severity);
}
}
}

View File

@@ -1,3 +1,9 @@
#ifndef _DEBUGGER_H_
#define _DEBUGGER_H_
#include <Arduino.h>
#include "webui.h"
const char helpCmd[] = "sysinfo - System Info\r\n"
"netinfo - WiFi Info\r\n"
"formatPDS - Format Persistence EEPROM Data\r\n"
@@ -9,4 +15,31 @@ const char helpCmd[] = "sysinfo - System Info\r\n"
"dumpCFG - print Config struct\r\n"
"dumpPDS - print PersistanceStruct\r\n"
"saveEE - save EE-Data\r\n"
"showdtc - Show all DTCs\r\n";
"showdtc - Show all DTCs\r\n"
"dumpGlobals - print globals\r\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);
#endif

View File

@@ -1,8 +1,9 @@
#include "dtc.h"
#include "debugger.h"
DTCEntry_s DTCStorage[MAX_DTC_STORAGE];
void MaintainDTC(DTCNums_t DTC_no, boolean active)
void MaintainDTC(DTCNums_t DTC_no, DTCSeverity_t DTC_severity, boolean active, uint32_t DebugValue)
{
for (int i = 0; i < MAX_DTC_STORAGE; i++)
{
@@ -10,13 +11,15 @@ void MaintainDTC(DTCNums_t DTC_no, boolean active)
{
if (active && DTCStorage[i].active != DTC_ACTIVE)
{
Serial.printf("DTC gone active: %d\n", DTC_no);
Debug_pushMessage("DTC gone active: %d, DebugVal: %d\n", DTC_no, DebugValue);
DTCStorage[i].timestamp = millis();
DTCStorage[i].active = DTC_ACTIVE;
DTCStorage[i].severity = DTC_severity;
DTCStorage[i].debugVal = DebugValue;
}
if (!active && DTCStorage[i].active == DTC_ACTIVE)
{
Serial.printf("DTC gone previous: %d\n", DTC_no);
Debug_pushMessage("DTC gone previous: %d\n", DTC_no);
DTCStorage[i].active = DTC_PREVIOUS;
}
return;
@@ -31,10 +34,12 @@ void MaintainDTC(DTCNums_t DTC_no, boolean active)
{
if (DTCStorage[i].Number == DTC_LAST_DTC)
{
Serial.printf("new DTC registered: %d\n", DTC_no);
Debug_pushMessage("new DTC registered: %d, DebugVal: %d\n", DTC_no, DebugValue);
DTCStorage[i].Number = DTC_no;
DTCStorage[i].timestamp = millis();
DTCStorage[i].active = DTC_ACTIVE;
DTCStorage[i].debugVal = DebugValue;
DTCStorage[i].severity = DTC_severity;
return;
}
}
@@ -82,4 +87,53 @@ DTCNums_t getlastDTC(boolean only_active)
}
return pointer >= 0 ? DTCStorage[pointer].Number : DTC_LAST_DTC;
}
DTCNums_t getlastDTC_Severity(boolean only_active, DTCSeverity_t severity)
{
int8_t pointer = -1;
uint32_t lasttimestamp = 0;
for (int i = 0; i < MAX_DTC_STORAGE; i++)
{
if (DTCStorage[i].Number > 0 && DTCStorage[i].timestamp > lasttimestamp)
{
if ((only_active == false || DTCStorage[i].active == DTC_ACTIVE) && DTCStorage[i].severity == severity)
{
pointer = i;
lasttimestamp = DTCStorage[i].timestamp;
}
}
}
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)
{
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

@@ -8,10 +8,14 @@
typedef enum DTCNums_e
{
DTC_TANK_EMPTY = 1,
DTC_TANK_LOW,
DTC_NO_EEPROM_FOUND,
DTC_EEPROM_CFG_BAD,
DTC_EEPROM_PDS_BAD,
DTC_EEPROM_PDSADRESS_BAD,
DTC_EEPROM_VERSION_BAD,
DTC_FLASHFS_ERROR,
DTC_FLASHFS_VERSION_ERROR,
#ifdef FEATURE_ENABLE_GPS
DTC_NO_GPS_SERIAL,
#endif
@@ -19,6 +23,7 @@ typedef enum DTCNums_e
DTC_CAN_TRANSCEIVER_FAILED,
DTC_NO_CAN_SIGNAL,
#endif
DTC_EEPROM_CFG_SANITY,
DTC_LAST_DTC
} DTCNums_t;
@@ -29,17 +34,28 @@ typedef enum DTCActive_e
DTC_PREVIOUS
} DTCActive_t;
typedef enum DTCSeverity_e
{
DTC_INFO,
DTC_WARN,
DTC_CRITICAL
} DTCSeverity_t;
typedef struct DTCEntry_s
{
DTCNums_t Number;
uint32_t timestamp;
DTCActive_t active;
DTCSeverity_t severity;
uint32_t debugVal;
} DTCEntry_t;
void MaintainDTC(DTCNums_t DTC_no, boolean active);
void MaintainDTC(DTCNums_t DTC_no, DTCSeverity_t DTC_severity, boolean active, uint32_t DebugValue = 0);
void ClearDTC(DTCNums_t DTC_no);
void ClearAllDTC();
DTCNums_t getlastDTC(boolean only_active);
DTCNums_t getlastDTC_Severity(boolean only_active, DTCSeverity_t severity);
void DTC_Process();
extern DTCEntry_s DTCStorage[MAX_DTC_STORAGE];
#endif

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

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

View File

@@ -18,8 +18,13 @@ typedef enum eEERequest
EE_IDLE,
EE_CFG_SAVE,
EE_CFG_LOAD,
EE_CFG_FORMAT,
EE_PDS_SAVE,
EE_PDS_LOAD
EE_PDS_LOAD,
EE_PDS_FORMAT,
EE_FORMAT_ALL,
EE_ALL_SAVE
} tEERequest;
typedef struct Globals_s
@@ -27,10 +32,17 @@ typedef struct Globals_s
tSystem_Status systemStatus = sysStat_Startup;
tSystem_Status resumeStatus = sysStat_Startup;
char systemStatustxt[16] = "";
uint8_t purgePulses = 0;
uint16_t purgePulses = 0;
eEERequest requestEEAction = EE_IDLE;
char DeviceName[33];
char FlashVersion[10];
uint16_t eePersistanceAdress;
uint8_t TankPercentage;
bool hasDTC;
} Globals_t;
extern Globals_t globals;
void initGlobals();
#endif

View File

@@ -19,7 +19,7 @@ void Init_GPS()
break;
}
Serial.printf(PSTR("Init GPS with Baud %d\n"), baudrate);
Debug_pushMessage(PSTR("Init GPS with Baud %d\n"), baudrate);
Serial.begin(baudrate);
}
@@ -51,7 +51,7 @@ uint32_t Process_GPS_WheelSpeed()
}
}
MaintainDTC(DTC_NO_GPS_SERIAL, (millis() > lastRecTimestamp + 10000));
MaintainDTC(DTC_NO_GPS_SERIAL,DTC_CRITICAL, (millis() > lastRecTimestamp + 10000));
return 0;
}

View File

@@ -5,20 +5,10 @@ uint32_t lubePulseTimestamp = 0;
void RunLubeApp(uint32_t add_milimeters)
{
MaintainDTC(DTC_TANK_EMPTY, (PersistenceData.tankRemain_µl < LubeConfig.amountPerDose_µl));
globals.TankPercentage = PersistenceData.tankRemain_microL / (LubeConfig.tankCapacity_ml * 10);
static tSystem_Status preserverSysStatusError;
if (getlastDTC(true) < DTC_LAST_DTC)
{
if (globals.systemStatus != sysStat_Error)
preserverSysStatusError = globals.systemStatus;
globals.systemStatus = sysStat_Error;
}
else
{
globals.systemStatus = preserverSysStatusError;
}
MaintainDTC(DTC_TANK_EMPTY, DTC_CRITICAL, (PersistenceData.tankRemain_microL < LubeConfig.amountPerDose_microL));
MaintainDTC(DTC_TANK_LOW, DTC_WARN, (globals.TankPercentage < LubeConfig.TankRemindAtPercentage));
// Add traveled Distance in mm
PersistenceData.TravelDistance_highRes_mm += add_milimeters;
@@ -77,22 +67,22 @@ void RunLubeApp(uint32_t add_milimeters)
switch (globals.systemStatus)
{
case sysStat_Normal:
strcpy(globals.systemStatustxt, PSTR("Normal"));
strcpy_P(globals.systemStatustxt, PSTR("Normal"));
break;
case sysStat_Purge:
strcpy(globals.systemStatustxt, PSTR("Purge"));
strcpy_P(globals.systemStatustxt, PSTR("Purge"));
break;
case sysStat_Rain:
strcpy(globals.systemStatustxt, PSTR("Rain"));
strcpy_P(globals.systemStatustxt, PSTR("Rain"));
break;
case sysStat_Startup:
strcpy(globals.systemStatustxt, PSTR("Startup"));
strcpy_P(globals.systemStatustxt, PSTR("Startup"));
break;
case sysStat_Error:
strcpy(globals.systemStatustxt, PSTR("Error"));
strcpy_P(globals.systemStatustxt, PSTR("Error"));
break;
case sysStat_Shutdown:
strcpy(globals.systemStatustxt, PSTR("Shutdown"));
strcpy_P(globals.systemStatustxt, PSTR("Shutdown"));
break;
}
@@ -105,9 +95,13 @@ void RunLubeApp(uint32_t add_milimeters)
void LubePulse()
{
lubePulseTimestamp = millis() + LUBE_PULSE_LENGHT_MS;
if (PersistenceData.tankRemain_µl < LubeConfig.amountPerDose_µl)
PersistenceData.tankRemain_µl = 0;
else
PersistenceData.tankRemain_µl = PersistenceData.tankRemain_µl - LubeConfig.amountPerDose_µl;
if (PersistenceData.tankRemain_microL > 0) // Only Lube if theres Oil remaining!
{
lubePulseTimestamp = millis() + LUBE_PULSE_LENGHT_MS;
if (PersistenceData.tankRemain_microL < LubeConfig.amountPerDose_microL) // Prevent underrun and shiftover
PersistenceData.tankRemain_microL = 0;
else
PersistenceData.tankRemain_microL = PersistenceData.tankRemain_microL - LubeConfig.amountPerDose_microL;
}
}

View File

@@ -8,10 +8,6 @@
#include "globals.h"
#include "dtc.h"
#define LUBE_PULSE_LENGHT_MS 160
#define LUBE_PULSE_PAUSE_MS 100
#define STARTUP_DELAY 5000
void RunLubeApp(uint32_t add_milimeters);
void LubePulse();

View File

@@ -1,8 +1,9 @@
#include <Arduino.h>
#include <Wire.h>
#ifdef FEATURE_ENABLE_OLED
#include <U8g2lib.h>
#endif
#include <ESP8266WiFi.h>
#include <ESP8266mDNS.h>
#include <ArduinoOTA.h>
#include <FastLED.h>
@@ -10,10 +11,13 @@
#include "common.h"
#include "sanitycheck.h"
#include "lubeapp.h"
#include "webui.h"
#include "config.h"
#include "globals.h"
#include "debugger.h"
#ifdef FEATURE_ENABLE_CAN
#include "can.h"
#endif
@@ -22,58 +26,33 @@
#endif
#include "dtc.h"
#ifdef FEATURE_ENABLE_REMOTE_DEBUG
#include <RemoteDebug.h>
#include "rmtdbghelp.h"
#else
#define debugV Serial.println
#define debugE Serial.println
#endif
#ifdef FEATURE_ENABLE_WIFI_CLIENT
#include <ESP8266WiFiMulti.h>
const char *ssid = QUOTE(WIFI_SSID);
const char *password = QUOTE(WIFI_PASSWORD);
const char *ssid = QUOTE(WIFI_SSID_CLIENT);
const char *password = QUOTE(WIFI_PASSWORD_CLIENT);
const uint32_t connectTimeoutMs = 5000;
ESP8266WiFiMulti wifiMulti;
#endif
bool startSetupMode = false;
char DeviceName[33];
Globals_t globals;
uint32_t TravelDistance_highRes;
volatile uint32_t wheel_pulse = 0;
U8X8_SSD1306_128X64_NONAME_HW_I2C u8x8(-1);
CRGB leds[1];
// Function-Prototypes
void IRAM_ATTR trigger_ISR();
void LED_Process(uint8_t override = false, CRGB setColor = CRGB::White);
#ifdef FEATURE_ENABLE_OLED
U8X8_SSD1306_128X64_NONAME_HW_I2C u8x8(-1);
void Display_Process();
#endif
void Button_Process();
void toggleWiFiAP(boolean shutdown = false);
void SystemShutdown();
uint32_t Process_Impulse_WheelSpeed();
void EEPROMCyclicPDS_callback();
void initGlobals();
#ifdef FEATURE_ENABLE_REMOTE_DEBUG
RemoteDebug Debug;
String IpAddress2String(const IPAddress &ipAddress);
void processCmdRemoteDebug();
void RemoteDebug_formatCFG();
void RemoteDebug_formatPersistence();
void RemotDebug_printSystemInfo();
void RemoteDebug_printWifiInfo();
void RemoteDebug_CheckEEPOM();
void RemoteDebug_dumpConfig();
void RemoteDebug_dumpPersistance();
void RemoteDebug_ShowDTCs();
#endif
#ifdef FEATURE_ENABLE_WIFI_CLIENT
void wifiMaintainConnectionTicker_callback();
@@ -84,34 +63,32 @@ Ticker EEPROMCyclicPDSTicker(EEPROMCyclicPDS_callback, 60000, 0, MILLIS);
void setup()
{
system_update_cpu_freq(SYS_CPU_80MHZ);
snprintf(DeviceName, 32, HOST_NAME, ESP.getChipId());
snprintf(globals.DeviceName, 32, HOST_NAME, ESP.getChipId());
WiFi.persistent(false);
ClearAllDTC(); // Init DTC-Storage
#ifdef FEATURE_ENABLE_WIFI_CLIENT
WiFi.mode(WIFI_STA);
WiFi.setHostname(DeviceName);
wifiMulti.addAP(QUOTE(WIFI_SSID), QUOTE(WIFI_PASSWORD));
WiFi.setHostname(globals.DeviceName);
wifiMulti.addAP(QUOTE(WIFI_SSID_CLIENT), QUOTE(WIFI_PASSWORD_CLIENT));
WiFiMaintainConnectionTicker.start();
#else
WiFi.mode(WIFI_OFF);
#endif
Serial.begin(115200);
Serial.setDebugOutput(true);
Serial.println("Souko's ChainLube Mk1");
Serial.println(DeviceName);
Serial.println("\n\nSouko's ChainLube Mk1");
Serial.println(globals.DeviceName);
InitEEPROM();
GetConfig_EEPROM();
GetPersistence_EEPROM();
#ifdef FEATURE_ENABLE_OLED
u8x8.begin();
u8x8.setFont(u8x8_font_chroma48medium8_r);
FastLED.addLeds<WS2811, GPIO_LED, GRB>(leds, 1); // GRB ordering is assumed
#endif
FastLED.addLeds<WS2811, GPIO_LED, RGB>(leds, 1); // GRB ordering is assumed
switch (LubeConfig.SpeedSource)
{
@@ -133,33 +110,17 @@ void setup()
break;
#endif
default:
debugE("Source Setting N/A");
Debug_pushMessage("Source Setting N/A");
break;
}
pinMode(GPIO_BUTTON, INPUT_PULLUP);
pinMode(GPIO_PUMP, OUTPUT);
#ifdef FEATURE_ENABLE_REMOTE_DEBUG
if (MDNS.begin(DeviceName))
MDNS.addService("telnet", "tcp", 23);
Debug.begin(DeviceName);
Debug.setResetCmdEnabled(true);
Debug.showProfiler(false);
Debug.showColors(true);
Debug.setPassword(QUOTE(ADMIN_PASSWORD));
Debug.setSerialEnabled(true);
Debug.showDebugLevel(true);
Debug.setHelpProjectsCmds(helpCmd);
Debug.setCallBackProjectCmds(&processCmdRemoteDebug);
#endif
ArduinoOTA.setPort(8266);
ArduinoOTA.setHostname(DeviceName);
ArduinoOTA.setHostname(globals.DeviceName);
ArduinoOTA.setPassword(QUOTE(ADMIN_PASSWORD));
#ifdef FEATURE_ENABLE_OLED
ArduinoOTA.onStart([]()
{
u8x8.clearDisplay();
@@ -185,12 +146,14 @@ void setup()
u8x8.clearDisplay();
u8x8.drawString(0, 0, "OTA-Restart");
u8x8.refreshDisplay(); });
#endif
ArduinoOTA.begin();
#ifdef FEATURE_ENABLE_OLED
u8x8.clearDisplay();
u8x8.drawString(0, 0, "KTM ChainLube V1");
u8x8.refreshDisplay();
#endif
initWebUI();
initGlobals();
@@ -222,16 +185,17 @@ void loop()
}
RunLubeApp(wheelDistance);
EEPROMCyclicPDSTicker.update();
#ifdef FEATURE_ENABLE_OLED
Display_Process();
#endif
Button_Process();
LED_Process();
EEPROM_Process();
Webserver_Process();
DTC_Process();
ArduinoOTA.handle();
#ifdef FEATURE_ENABLE_REMOTE_DEBUG
Debug.handle();
#endif
EEPROMCyclicPDSTicker.update();
#ifdef FEATURE_ENABLE_WIFI_CLIENT
WiFiMaintainConnectionTicker.update();
#endif
@@ -248,147 +212,6 @@ String IpAddress2String(const IPAddress &ipAddress)
String(ipAddress[3]);
}
void initGlobals()
{
globals.purgePulses = 0;
globals.requestEEAction = EE_IDLE;
globals.resumeStatus = sysStat_Normal;
globals.systemStatus = sysStat_Startup;
}
#ifdef FEATURE_ENABLE_REMOTE_DEBUG
void processCmdRemoteDebug()
{
String lastCmd = Debug.getLastCommand();
if (lastCmd == "sysinfo")
RemotDebug_printSystemInfo();
else if (lastCmd == "netinfo")
RemoteDebug_printWifiInfo();
else if (lastCmd == "formatCFG")
RemoteDebug_formatCFG();
else if (lastCmd == "formatPDS")
RemoteDebug_formatPersistence();
else if (lastCmd == "checkEE")
RemoteDebug_CheckEEPOM();
else if (lastCmd == "dumpEE1k")
dumpEEPROM(0, 1024);
else if (lastCmd == "dumpEE")
dumpEEPROM(0, EEPROM_SIZE_BYTES);
else if (lastCmd == "resetPageEE")
MovePersistencePage_EEPROM(true);
else if (lastCmd == "dumpCFG")
RemoteDebug_dumpConfig();
else if (lastCmd == "dumpPDS")
RemoteDebug_dumpPersistance();
else if (lastCmd == "saveEE")
StoreConfig_EEPROM();
else if (lastCmd == "showdtc")
RemoteDebug_ShowDTCs();
}
void RemoteDebug_formatCFG()
{
debugA("Formatting Config-EEPROM and reseting to default");
FormatConfig_EEPROM();
}
void RemoteDebug_formatPersistence()
{
debugA("Formatting Persistence-EEPROM and reseting to default");
FormatPersistence_EEPROM();
}
void RemotDebug_printSystemInfo()
{
debugA("Souko's ChainOiler Mk1");
debugA("Hostname: %s", DeviceName);
FlashMode_t ideMode = ESP.getFlashChipMode();
debugA("Sdk version: %s", ESP.getSdkVersion());
debugA("Core Version: %s", ESP.getCoreVersion().c_str());
debugA("Boot Version: %u", ESP.getBootVersion());
debugA("Boot Mode: %u", ESP.getBootMode());
debugA("CPU Frequency: %u MHz", ESP.getCpuFreqMHz());
debugA("Reset reason: %s", ESP.getResetReason().c_str());
debugA("Flash Size: %d", ESP.getFlashChipRealSize());
debugA("Flash Size IDE: %d", ESP.getFlashChipSize());
debugA("Flash ide mode: %s", (ideMode == FM_QIO ? "QIO" : ideMode == FM_QOUT ? "QOUT"
: ideMode == FM_DIO ? "DIO"
: ideMode == FM_DOUT ? "DOUT"
: "UNKNOWN"));
debugA("OTA-Pass: %s", QUOTE(ADMIN_PASSWORD));
debugA("Git-Revison: %s", GIT_REV);
debugA("Sw-Version: %d.%02d", SW_VERSION_MAJOR, SW_VERSION_MINOR);
}
void RemoteDebug_dumpConfig()
{
debugA("DistancePerLube_Default: %d", LubeConfig.DistancePerLube_Default);
debugA("DistancePerLube_Rain: %d", LubeConfig.DistancePerLube_Rain);
debugA("tankCapacity_ml: %d", LubeConfig.tankCapacity_ml);
debugA("amountPerDose_µl: %d", LubeConfig.amountPerDose_µl);
debugA("TankRemindAtPercentage: %d", LubeConfig.TankRemindAtPercentage);
debugA("PulsePerRevolution: %d", LubeConfig.PulsePerRevolution);
debugA("TireWidth_mm: %d", LubeConfig.TireWidth_mm);
debugA("TireWidthHeight_Ratio: %d", LubeConfig.TireWidth_mm);
debugA("RimDiameter_Inch: %d", LubeConfig.RimDiameter_Inch);
debugA("DistancePerRevolution_mm: %d", LubeConfig.DistancePerRevolution_mm);
debugA("BleedingPulses: %d", LubeConfig.BleedingPulses);
debugA("SpeedSource: %d", LubeConfig.SpeedSource);
#ifdef FEATURE_ENABLE_GPS
debugA("GPSBaudRate: %d", LubeConfig.GPSBaudRate);
#endif
#ifdef FEATURE_ENABLE_CAN
debugA("CANSource: %d", LubeConfig.CANSource);
#endif
debugA("checksum: 0x%08X", LubeConfig.checksum);
}
void RemoteDebug_dumpPersistance()
{
debugA("writeCycleCounter: %d", PersistenceData.writeCycleCounter);
debugA("tankRemain_µl: %d", PersistenceData.tankRemain_µl);
debugA("TravelDistance_highRes_mm: %d", PersistenceData.TravelDistance_highRes_mm);
debugA("checksum: %d", PersistenceData.checksum);
debugA("PSD Adress: 0x%04X", getPersistanceAddress());
}
void RemoteDebug_printWifiInfo()
{
}
void RemoteDebug_CheckEEPOM()
{
uint32_t checksum = PersistenceData.checksum;
PersistenceData.checksum = 0;
if (Checksum_EEPROM((uint8_t *)&PersistenceData, sizeof(PersistenceData)) == checksum)
{
debugA("PersistenceData EEPROM Checksum OK\n");
}
else
{
debugA("PersistenceData EEPROM Checksum BAD\n");
}
PersistenceData.checksum = checksum;
checksum = LubeConfig.checksum;
LubeConfig.checksum = 0;
if (Checksum_EEPROM((uint8_t *)&LubeConfig, sizeof(LubeConfig)) == checksum)
{
debugA("LubeConfig EEPROM Checksum OK\n");
}
else
{
debugA("LubeConfig EEPROM Checksum BAD\n");
}
LubeConfig.checksum = checksum;
}
#endif
#ifdef FEATURE_ENABLE_WIFI_CLIENT
void wifiMaintainConnectionTicker_callback()
{
@@ -407,7 +230,7 @@ void wifiMaintainConnectionTicker_callback()
}
else
{
debugV("WiFi not connected! - Start AP");
Debug_pushMessage("WiFi not connected! - Start AP");
toggleWiFiAP();
}
}
@@ -453,7 +276,7 @@ void LED_Process(uint8_t override, CRGB SetColor)
if (LED_Status != LED_Override)
{
LED_ResumeOverrideStatus = LED_Status;
debugV("Override LED_Status");
Debug_pushMessage("Override LED_Status");
}
LED_Status = LED_Override;
LED_override_color = SetColor;
@@ -464,7 +287,7 @@ void LED_Process(uint8_t override, CRGB SetColor)
if (LED_Status == LED_Override)
{
LED_Status = LED_ResumeOverrideStatus;
debugV("Resume LED_Status");
Debug_pushMessage("Resume LED_Status");
}
}
@@ -474,25 +297,25 @@ void LED_Process(uint8_t override, CRGB SetColor)
{
case sysStat_Startup:
LED_Status = LED_Startup;
debugV("sysStat: Startup");
Debug_pushMessage("sysStat: Startup");
break;
case sysStat_Normal:
timestamp = timer + 3500;
LED_Status = LED_Confirm_Normal;
debugV("sysStat: Normal");
Debug_pushMessage("sysStat: Normal");
break;
case sysStat_Rain:
timestamp = timer + 3500;
LED_Status = LED_Confirm_Rain;
debugV("sysStat: Rain");
Debug_pushMessage("sysStat: Rain");
break;
case sysStat_Purge:
LED_Status = LED_Purge;
debugV("sysStat: Purge");
Debug_pushMessage("sysStat: Purge");
break;
case sysStat_Error:
LED_Status = LED_Error;
debugV("sysStat: Error");
Debug_pushMessage("sysStat: Error");
break;
case sysStat_Shutdown:
default:
@@ -501,14 +324,12 @@ void LED_Process(uint8_t override, CRGB SetColor)
oldSysStatus = globals.systemStatus;
}
uint32_t percentage = PersistenceData.tankRemain_µl / (LubeConfig.tankCapacity_ml * 10);
switch (LED_Status)
{
case LED_Startup:
FastLED.setBrightness(255);
if (percentage < LubeConfig.TankRemindAtPercentage)
if (globals.TankPercentage < LubeConfig.TankRemindAtPercentage)
leds[0] = CRGB::OrangeRed;
else
leds[0] = CRGB::White;
@@ -521,14 +342,18 @@ void LED_Process(uint8_t override, CRGB SetColor)
{
LED_Status = LED_Normal;
FastLED.setBrightness(64);
debugV("LED_Status: Confirm -> Normal");
Debug_pushMessage("LED_Status: Confirm -> Normal");
}
break;
case LED_Normal:
#ifndef NO_MODE_FLASH
if (timer % 2000 > 1950)
leds[0] = CRGB(0, 255, 0);
else if (WiFi.getMode() != WIFI_OFF && timer % 2000 > 1800 && timer % 2000 < 1850)
#else
if (WiFi.getMode() != WIFI_OFF && timer % 2000 > 1950)
#endif
leds[0] = CRGB(255, 128, 0);
else
leds[0] = CRGB(0, 4, 0);
@@ -541,14 +366,18 @@ void LED_Process(uint8_t override, CRGB SetColor)
{
LED_Status = LED_Rain;
FastLED.setBrightness(64);
debugV("LED_Status: Confirm -> Rain");
Debug_pushMessage("LED_Status: Confirm -> Rain");
}
break;
case LED_Rain:
#ifndef NO_MODE_FLASH
if (timer % 2000 > 1950)
leds[0] = CRGB(0, 0, 255);
else if (WiFi.getMode() != WIFI_OFF && timer % 2000 > 1800 && timer % 2000 < 1850)
#else
if (WiFi.getMode() != WIFI_OFF && timer % 2000 > 1950)
#endif
leds[0] = CRGB(255, 128, 0);
else
leds[0] = CRGB(0, 0, 4);
@@ -577,7 +406,7 @@ void LED_Process(uint8_t override, CRGB SetColor)
}
FastLED.show();
}
#ifdef FEATURE_ENABLE_OLED
void Display_Process()
{
static tSystem_Status oldSysStatus = sysStat_Startup;
@@ -591,7 +420,7 @@ void Display_Process()
u8x8.setCursor(0, 1);
uint32_t DistRemain = globals.systemStatus == sysStat_Normal ? LubeConfig.DistancePerLube_Default : LubeConfig.DistancePerLube_Rain;
DistRemain -= TravelDistance_highRes / 1000;
DistRemain = DistRemain - (PersistenceData.TravelDistance_highRes_mm / 1000);
u8x8.printf(PSTR("Mode: %10s\n"), globals.systemStatustxt);
if (globals.systemStatus == sysStat_Error)
{
@@ -600,7 +429,7 @@ void Display_Process()
else
{
u8x8.printf(PSTR("next Lube: %4dm\n"), DistRemain);
u8x8.printf(PSTR("Tank: %8dml\n"), PersistenceData.tankRemain_µl / 1000);
u8x8.printf(PSTR("Tank: %8dml\n"), PersistenceData.tankRemain_microL / 1000);
u8x8.printf(PSTR("WiFi: %10s\n"), (WiFi.getMode() == WIFI_AP ? "AP" : WiFi.getMode() == WIFI_OFF ? "OFF"
: WiFi.getMode() == WIFI_STA ? "CLIENT"
: "UNKNOWN"));
@@ -609,6 +438,7 @@ void Display_Process()
}
u8x8.refreshDisplay();
}
#endif
void Button_Process()
{
@@ -666,13 +496,13 @@ void Button_Process()
{
case BTN_TOGGLEWIFI:
toggleWiFiAP();
debugV("Starting WiFi AP");
Debug_pushMessage("Starting WiFi AP");
break;
case BTN_STARTPURGE:
globals.systemStatus = sysStat_Purge;
globals.purgePulses = LubeConfig.BleedingPulses;
debugV("Starting Purge");
Debug_pushMessage("Starting Purge");
break;
case BTN_TOGGLEMODE:
@@ -690,12 +520,12 @@ void Button_Process()
default:
break;
}
debugV("Toggling Mode");
Debug_pushMessage("Toggling Mode");
break;
case BTN_NOTHING:
default:
debugV("Nothing or invalid");
Debug_pushMessage("Nothing or invalid");
break;
}
LED_Process(2);
@@ -710,7 +540,7 @@ void toggleWiFiAP(boolean shutdown)
if (WiFi.getMode() != WIFI_OFF)
{
WiFi.mode(WIFI_OFF);
debugV("WiFi turned off");
Debug_pushMessage("WiFi turned off");
#ifdef FEATURE_ENABLE_WIFI_CLIENT
WiFiMaintainConnectionTicker.stop();
#endif
@@ -719,20 +549,31 @@ void toggleWiFiAP(boolean shutdown)
{
WiFi.mode(WIFI_AP);
WiFi.softAPConfig(IPAddress(WIFI_AP_IP_GW), IPAddress(WIFI_AP_IP_GW), IPAddress(255, 255, 255, 0));
WiFi.softAP(DeviceName, QUOTE(WIFI_AP_PASSWORD));
WiFi.softAP(globals.DeviceName, QUOTE(WIFI_AP_PASSWORD));
#ifdef FEATURE_ENABLE_WIFI_CLIENT
WiFiMaintainConnectionTicker.stop();
debugV("WiFi AP started, stopped Maintain-Timer");
Debug_pushMessage("WiFi AP started, stopped Maintain-Timer");
#else
debugV("WiFi AP started");
Debug_pushMessage("WiFi AP started");
#endif
}
}
void SystemShutdown()
{
StoreConfig_EEPROM();
ESP.restart();
static uint32_t shutdown_delay = 0;
if (shutdown_delay == 0)
{
shutdown_delay = millis() + SHUTDOWN_DELAY_MS;
Serial.printf("Shutdown requested - Restarting in %d seconds\n", SHUTDOWN_DELAY_MS / 1000);
}
if (shutdown_delay < millis())
{
StoreConfig_EEPROM();
StorePersistence_EEPROM();
ESP.restart();
}
}
uint32_t Process_Impulse_WheelSpeed()
@@ -745,30 +586,3 @@ uint32_t Process_Impulse_WheelSpeed()
return add_milimeters;
}
void RemoteDebug_ShowDTCs()
{
char buff_timestamp[16]; // Format: DD-hh:mm:ss:xxx
char buff_active[9];
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");
debugA("%s \t %6d \t %s", buff_timestamp, DTCStorage[i].Number, buff_active);
}
}
}

View File

@@ -0,0 +1,37 @@
#ifndef _SANITYCHECK_H_
#define _SANITYCHECK_H_
#ifndef PCB_REV
#error "You must define PCB_REV"
#else
#if PCB_REV < 1 || PCB_REV > 4
#error "Unsupported PCB-Revision"
#endif
#if PCB_REV < 4 && defined(FEATURE_ENABLE_CAN)
#error "CAN-Feature unsupported with this PCB-Rev"
#endif
#if PCB_REV < 4 && defined(DFEATURE_ENABLE_GPS)
#error "CAN-Feature unsupported with this PCB-Rev"
#endif
#endif
#ifndef ADMIN_PASSWORD
#error "You need to define ADMIN_PASSWORD for OTA-Update"
#endif
#ifdef FEATURE_ENABLE_WIFI_CLIENT
#ifndef WIFI_PASSWORD_CLIENT
#error "You must define an WIFI_PASSWORD for Client-Mode"
#endif
#ifndef WIFI_SSID_CLIENT
#error "You must define an WIFI_SSID for Client-Mode"
#endif
#endif
#ifndef WIFI_AP_PASSWORD
#error "You must define an WIFI_AP_PASSWORD for Standalone AP-Mode"
#endif
#endif //_SANITYCHECK_H_

571
Software/src/webui.cpp Normal file
View File

@@ -0,0 +1,571 @@
#include "webui.h"
AsyncWebServer webServer(80);
const char *PARAM_MESSAGE = "message";
String processor(const String &var);
void WebserverPOST_Callback(AsyncWebServerRequest *request);
void WebserverNotFound_Callback(AsyncWebServerRequest *request);
void Webserver_Callback(AsyncWebServerRequest *request);
void WebserverFirmwareUpdate_Callback(AsyncWebServerRequest *request, const String &filename, size_t index, uint8_t *data, size_t len, bool final);
void WebserverEERestore_Callback(AsyncWebServerRequest *request, const String &filename, size_t index, uint8_t *data, size_t len, bool final);
void WebServerEEJSON_Callback(AsyncWebServerRequest *request);
void GetFlashVersion(char *buff, size_t buff_size);
#ifdef FEATURE_ENABLE_WEBSOCKETS
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);
#endif
void initWebUI()
{
if (!LittleFS.begin())
{
Debug_pushMessage("An Error has occurred while mounting LittleFS\n");
MaintainDTC(DTC_FLASHFS_ERROR, DTC_CRITICAL, true);
return;
}
GetFlashVersion(globals.FlashVersion, sizeof(globals.FlashVersion));
if (strcmp(globals.FlashVersion, QUOTE(FLASH_FS_VERSION)))
{
MaintainDTC(DTC_FLASHFS_VERSION_ERROR, DTC_WARN, true);
}
MDNS.begin(globals.DeviceName);
MDNS.addService("http", "tcp", 80);
#ifdef FEATURE_ENABLE_WEBSOCKETS
webSocket.onEvent(WebsocketEvent_Callback);
webServer.addHandler(&webSocket);
#endif
webServer.serveStatic("/static/", LittleFS, "/static/").setCacheControl("max-age=360000");
webServer.on("/", HTTP_GET, [](AsyncWebServerRequest *request)
{ request->redirect("/index.htm"); });
webServer.onNotFound(WebserverNotFound_Callback);
webServer.on("/index.htm", HTTP_GET, Webserver_Callback);
webServer.on("/post.htm", HTTP_POST, WebserverPOST_Callback);
webServer.on("/eejson", HTTP_GET, WebServerEEJSON_Callback);
webServer.on(
"/doUpdate", HTTP_POST, [](AsyncWebServerRequest *request) {}, WebserverFirmwareUpdate_Callback);
webServer.on(
"/eeRestore", HTTP_POST, [](AsyncWebServerRequest *request) {}, WebserverEERestore_Callback);
webServer.begin();
}
void Webserver_Process()
{
#ifdef FEATURE_ENABLE_WEBSOCKETS
webSocket.cleanupClients();
#endif
}
String processor(const String &var)
{
if (var == "TANK_REMAIN_CAPACITY")
return String((PersistenceData.tankRemain_microL / 10) / LubeConfig.tankCapacity_ml);
if (var == "LUBE_DISTANCE_NORMAL")
return String(LubeConfig.DistancePerLube_Default);
if (var == "LUBE_DISTANCE_RAIN")
return String(LubeConfig.DistancePerLube_Rain);
if (var == "TANK_CAPACITY")
return String(LubeConfig.tankCapacity_ml);
if (var == "AMOUNT_PER_DOSE")
return String(LubeConfig.amountPerDose_microL);
if (var == "TANK_REMIND")
return String(LubeConfig.TankRemindAtPercentage);
if (var == "PULSE_PER_REV")
return String(LubeConfig.PulsePerRevolution);
if (var == "TIRE_WIDTH_MM")
return String(LubeConfig.TireWidth_mm);
if (var == "TIRE_RATIO")
return String(LubeConfig.TireWidthHeight_Ratio);
if (var == "RIM_DIAMETER")
return String(LubeConfig.RimDiameter_Inch);
if (var == "DISTANCE_PER_REV")
return String(LubeConfig.DistancePerRevolution_mm);
if (var == "BLEEDING_PULSES")
return String(LubeConfig.BleedingPulses);
if (var == "SPEED_SOURCE")
return String(SpeedSourceString[LubeConfig.SpeedSource]);
if (var == "GPS_BAUD")
#ifdef FEATURE_ENABLE_GPS
return String(GPSBaudRateString[LubeConfig.GPSBaudRate]);
#else
return "Feature N/A";
#endif
if (var == "CAN_SOURCE")
#ifdef FEATURE_ENABLE_CAN
return String(CANSourceString[LubeConfig.CANSource]);
#else
return "Feature N/A";
#endif
if (var == "CONFIG_CHECKSUM")
{
char buffer[7];
sprintf(buffer, "0x%04X", LubeConfig.checksum);
return String(buffer);
}
if (var == "WRITE_CYCLE_COUNT")
return String(PersistenceData.writeCycleCounter);
if (var == "PERSISTENCE_MARKER")
return String(globals.eePersistanceAdress);
if (var == "TANK_REMAIN_UL")
return String(PersistenceData.tankRemain_microL);
if (var == "TRAVEL_DISTANCE_HIGHRES")
return String(PersistenceData.TravelDistance_highRes_mm);
if (var == "ODOMETER")
return String(PersistenceData.odometer);
if (var == "ODOMETER_M")
return String(PersistenceData.odometer_mm / 1000);
if (var == "PERSISTANCE_CHECKSUM")
{
char buffer[7];
sprintf(buffer, "0x%04X", PersistenceData.checksum);
return String(buffer);
}
if (var == "SHOW_IMPULSE_SETTINGS")
return LubeConfig.SpeedSource == SOURCE_IMPULSE ? "" : "hidden";
if (var == "SHOW_CAN_SETTINGS")
#ifdef FEATURE_ENABLE_CAN
return LubeConfig.SpeedSource == SOURCE_CAN ? "" : "hidden";
#else
return "hidden";
#endif
if (var == "SHOW_GPS_SETTINGS")
#ifdef FEATURE_ENABLE_GPS
return LubeConfig.SpeedSource == SOURCE_GPS ? "" : "hidden";
#else
return "hidden";
#endif
if (var == "SHOW_DTC_TABLE")
return globals.hasDTC ? "" : "hidden";
if (var == "DTC_TABLE")
{
String temp = "";
char buff_timestamp[16]; // Format: DD-hh:mm:ss:xxx
for (uint32_t i = 0; i < MAX_DTC_STORAGE; i++)
{
if (DTCStorage[i].Number < 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
temp = temp + "<tr data-dtc=" + String(DTCStorage[i].Number);
temp = temp + " data-debugval=" + String(DTCStorage[i].debugVal) + "><td>" + String(buff_timestamp);
temp = temp + "</td><td>" + String(DTCStorage[i].Number) + "</td><td>";
temp = temp + "<img src=static/img/";
switch (DTCStorage[i].severity)
{
case DTC_CRITICAL:
temp = temp + "critical";
break;
case DTC_WARN:
temp = temp + "warn";
break;
case DTC_INFO:
temp = temp + "info";
break;
}
temp = temp + ".png></td><td>";
if (DTCStorage[i].active == DTC_ACTIVE)
temp = temp + "active";
else if (DTCStorage[i].active == DTC_PREVIOUS)
temp = temp + "previous";
else
temp = temp + "none";
temp = temp + "</td></tr>";
}
}
return temp;
}
if (var == "SOURCE_SELECT_OPTIONS")
{
String temp;
for (uint32_t i = 0; i < SpeedSourceString_Elements; i++)
{
String selected = LubeConfig.SpeedSource == i ? " selected " : "";
temp = temp + "<option value=\"" + i + "\"" + selected + ">" + SpeedSourceString[i] + "</option>";
}
return temp;
}
#ifdef FEATURE_ENABLE_CAN
if (var == "CANSOURCE_SELECT_OPTIONS")
{
String temp;
for (uint32_t i = 0; i < CANSourceString_Elements; i++)
{
String selected = LubeConfig.CANSource == i ? " selected " : "";
temp = temp + "<option value=\"" + i + "\"" + selected + ">" + CANSourceString[i] + "</option>";
}
return temp;
}
#endif
#ifdef FEATURE_EABLE_GPS
if (var == "GPSBAUD_SELECT_OPTIONS")
{
String temp;
for (uint32_t i = 0; i < GPSBaudRateString_Elements; i++)
{
String selected = LubeConfig.GPSBaudRate == i ? " selected " : "";
temp = temp + "<option value=\"" + i + "\"" + selected + ">" + GPSBaudRateString[i] + "</option>";
}
return temp;
}
#endif
if (var == "SYSTEM_STATUS")
return String(globals.systemStatustxt);
if (var == "SW_VERSION")
{
return String(QUOTE(SW_VERSION));
}
if (var == "FS_VERSION")
return String(globals.FlashVersion);
if (var == "PLACEHOLDER")
return "placeholder";
return String();
}
void Webserver_Callback(AsyncWebServerRequest *request)
{
request->send(LittleFS, "/index.htm", "text/html", false, processor);
}
void WebserverPOST_Callback(AsyncWebServerRequest *request)
{
request->send(LittleFS, "/post.htm", "text/html", false, processor);
Debug_pushMessage("POST:\n");
int paramsNr = request->params();
for (int i = 0; i < paramsNr; i++)
{
AsyncWebParameter *p = request->getParam(i);
Debug_pushMessage("%s : %s\n", p->name().c_str(), p->value().c_str());
// begin: POST Form Source Changed
if (p->name() == "sourceselect")
{
SpeedSource_t temp = (SpeedSource_t)p->value().toInt();
Debug_pushMessage("temp: %d", temp);
Debug_pushMessage("SpeedSource: %d", LubeConfig.SpeedSource);
if (LubeConfig.SpeedSource != temp)
{
LubeConfig.SpeedSource = temp;
globals.systemStatus = sysStat_Shutdown;
}
}
// end: POST Form Source Changed
// begin: POST Form Source Pulse Settings
if (p->name() == "tirewidth")
LubeConfig.TireWidth_mm = p->value().toInt();
if (p->name() == "tireratio")
LubeConfig.TireWidthHeight_Ratio = p->value().toInt();
if (p->name() == "tiredia")
LubeConfig.RimDiameter_Inch = p->value().toInt();
if (p->name() == "pulserev")
LubeConfig.PulsePerRevolution = p->value().toInt();
if (p->name() == "pulsesave")
globals.requestEEAction = EE_CFG_SAVE;
// end: POST Form Source Pulse Settings
#ifdef FEATURE_EABLE_GPS
// begin: POST Form Source GPS Settings
if (p->name() == "gpsbaud")
LubeConfig.GPSBaudRate = (GPSBaudRate_t)p->value().toInt();
if (p->name() == "gpssave")
globals.requestEEAction = EE_CFG_SAVE;
// end: POST Form Source GPS Settings
#endif
#ifdef FEATURE_EABLE_CAN
// begin: POST Form Source CAN Settings
if (p->name() == "cansource")
LubeConfig.CANSource = (CANSource_t)p->value().toInt();
if (p->name() == "cansave")
globals.requestEEAction = EE_CFG_SAVE;
// end: POST Form Source CAN Settings
#endif
// begin: POST Form Lubrication
if (p->name() == "lubedistancenormal")
LubeConfig.DistancePerLube_Default = p->value().toInt();
if (p->name() == "lubedistancerain")
LubeConfig.DistancePerLube_Rain = p->value().toInt();
if (p->name() == "lubesave")
globals.requestEEAction = EE_CFG_SAVE;
// end: POST Form Lubrication
// begin: POST Form Oiltank
if (p->name() == "tankcap")
LubeConfig.tankCapacity_ml = p->value().toInt();
if (p->name() == "tankwarn")
LubeConfig.TankRemindAtPercentage = p->value().toInt();
if (p->name() == "pumppulse")
LubeConfig.amountPerDose_microL = p->value().toInt();
if (p->name() == "oilsave")
globals.requestEEAction = EE_CFG_SAVE;
// end: POST Form Oiltank
// begin: POST Form Maintenance
if (p->name() == "purgepulse")
LubeConfig.BleedingPulses = p->value().toInt();
if (p->name() == "maintsave")
globals.requestEEAction = EE_CFG_SAVE;
if (p->name() == "resettank")
{
PersistenceData.tankRemain_microL = LubeConfig.tankCapacity_ml * 1000;
globals.requestEEAction = EE_PDS_SAVE;
}
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() == "purgenow")
{
globals.systemStatus = sysStat_Purge;
globals.purgePulses = LubeConfig.BleedingPulses;
}
if (p->name() == "reboot")
{
globals.systemStatus = sysStat_Shutdown;
}
// end: POST Form Maintenance
}
}
void WebserverNotFound_Callback(AsyncWebServerRequest *request)
{
request->send(404, "text/html", "Not found");
}
void GetFlashVersion(char *buff, size_t buff_size)
{
File this_file = LittleFS.open("version", "r");
if (!this_file)
{ // failed to open the file, retrn empty result
buff[0] = '\0';
return;
}
if (this_file.available())
{
int bytes_read;
bytes_read = this_file.readBytesUntil('\r', buff, buff_size - 1);
buff[bytes_read] = '\0';
}
this_file.close();
}
void WebserverFirmwareUpdate_Callback(AsyncWebServerRequest *request, const String &filename, size_t index, uint8_t *data, size_t len, bool final)
{
if (!index)
{
Debug_pushMessage("Update");
size_t content_len = request->contentLength();
int cmd = (filename.indexOf(".fs") > -1) ? U_FS : U_FLASH;
Update.runAsync(true);
if (!Update.begin(content_len, cmd))
{
Update.printError(Serial);
}
}
if (Update.write(data, len) != len)
{
Update.printError(Serial);
}
else
{
Debug_pushMessage("Progress: %d%%\n", (Update.progress() * 100) / Update.size());
}
if (final)
{
AsyncWebServerResponse *response = request->beginResponse(302, "text/plain", "Please wait while the device reboots");
response->addHeader("Refresh", "20");
response->addHeader("Location", "/");
request->send(response);
if (!Update.end(true))
{
Update.printError(Serial);
}
else
{
Debug_pushMessage("Update complete\n");
globals.systemStatus = sysStat_Shutdown;
}
}
}
void WebserverEERestore_Callback(AsyncWebServerRequest *request, const String &filename, size_t index, uint8_t *data, size_t len, bool final)
{
bool ee_done = false;
bool validext = false;
if (!index)
{
Debug_pushMessage("EEPROM restore\n");
// size_t content_len = request->contentLength();
validext = (filename.indexOf(".ee.json") > -1);
}
if (validext)
{
Debug_pushMessage("Restoring EEPROM-Stuff\n");
}
if (final)
{
AsyncWebServerResponse *response = request->beginResponse(302, "text/plain", "Please wait while the device reboots");
response->addHeader("Refresh", "20");
response->addHeader("Location", "/");
request->send(response);
if (ee_done)
{
Debug_pushMessage("Update complete");
globals.systemStatus = sysStat_Shutdown;
}
else
{
}
}
}
void WebServerEEJSON_Callback(AsyncWebServerRequest *request)
{
AsyncResponseStream *response = request->beginResponseStream("application/json");
DynamicJsonDocument json(1024);
JsonObject fwinfo = json.createNestedObject("info");
char buffer[16];
fwinfo["DeviceName"] = globals.DeviceName;
fwinfo["FW-Version"] = QUOTE(SW_VERSION);
fwinfo["FS-Version"] = globals.FlashVersion;
JsonObject config = json.createNestedObject("config");
config["EEPROM_Version"] = LubeConfig.EEPROM_Version;
config["DistancePerLube_Default"] = LubeConfig.DistancePerLube_Default;
config["DistancePerLube_Rain"] = LubeConfig.DistancePerLube_Rain;
config["tankCapacity_ml"] = LubeConfig.tankCapacity_ml;
config["amountPerDose_microL"] = LubeConfig.amountPerDose_microL;
config["TankRemindAtPercentage"] = LubeConfig.TankRemindAtPercentage;
config["PulsePerRevolution"] = LubeConfig.PulsePerRevolution;
config["TireWidth_mm"] = LubeConfig.TireWidth_mm;
config["TireWidthHeight_Ratio"] = LubeConfig.TireWidthHeight_Ratio;
config["RimDiameter_Inch"] = LubeConfig.RimDiameter_Inch;
config["DistancePerRevolution_mm"] = LubeConfig.DistancePerRevolution_mm;
config["BleedingPulses"] = LubeConfig.BleedingPulses;
config["SpeedSource"] = LubeConfig.SpeedSource;
config["SpeedSource_Str"] = SpeedSourceString[LubeConfig.SpeedSource];
#ifdef FEATURE_ENABLE_GPS
config["GPSBaudRate"] = LubeConfig.GPSBaudRate;
config["GPSBaudRate_Str"] = GPSBaudRateString[LubeConfig.GPSBaudRate];
#endif
#ifdef FEATURE_ENABLE_CAN
config["CANSource"] = LubeConfig.CANSource;
config["CANSource_Str"] = CANSourceString[LubeConfig.CANSource];
#endif
sprintf(buffer, "0x%08X", LubeConfig.checksum);
config["checksum"] = buffer;
JsonObject eepart = json.createNestedObject("eepart");
sprintf(buffer, "0x%04X", globals.eePersistanceAdress);
eepart["PersistanceAddress"] = buffer;
JsonObject persis = json.createNestedObject("persis");
persis["writeCycleCounter"] = PersistenceData.writeCycleCounter;
persis["tankRemain_microL"] = PersistenceData.tankRemain_microL;
persis["TravelDistance_highRes_mm"] = PersistenceData.TravelDistance_highRes_mm;
persis["odometer_mm"] = PersistenceData.odometer_mm;
persis["odometer"] = PersistenceData.odometer;
sprintf(buffer, "0x%08X", PersistenceData.checksum);
persis["checksum"] = buffer;
serializeJsonPretty(json, *response);
response->addHeader("Content-disposition", "attachment; filename=backup.ee.json");
request->send(response);
}
#ifdef FEATURE_ENABLE_WEBSOCKETS
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");
}
#endif

View File

@@ -6,11 +6,22 @@
#include <LittleFS.h>
#include <ESPAsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <Updater.h>
#include <ESP8266mDNS.h>
#include <AsyncJson.h>
#include <ArduinoJson.h>
#include "config.h"
#include "globals.h"
#include "dtc.h"
#include "common.h"
#include "debugger.h"
void initWebUI();
void Webserver_Process();
#ifdef FEATURE_ENABLE_WEBSOCKETS
void Websocket_PushLiveDebug(String Message);
#endif
#endif

View File

@@ -1,5 +1,5 @@
[wifi_cred]
admin_password = adminpass
wifi_ap_password = wifiappass
wifi_ssid = wifi-ssid
wifi_password = wifi-pass
wifi_ssid_client = wifi-ssid
wifi_password_client = wifi-pass