44 Commits

Author SHA1 Message Date
8cf310e634 added OBD2-KLine Interface 2025-05-05 00:05:56 +02:00
1ee326fd57 added first code for OBD2 via CAN and K-Line 2025-05-04 12:03:52 +02:00
b627f52272 some debugger-commands added 2025-05-04 11:53:38 +02:00
d723290e57 updated platformio.ini 2025-05-04 11:53:03 +02:00
fbe5f0b202 added debug-Function for EE-Sanity-Check 2024-02-12 00:46:26 +01:00
f92f6a23c7 reworked some DTC-Handling 2024-02-12 00:45:34 +01:00
ac8be93faf changed Capture-Functions to FunctionPointer 2024-02-07 22:52:28 +01:00
059b693889 some small changes 2024-01-30 22:05:50 +01:00
b723a80d46 added Wifi-Settings to WebUI and Config 2024-01-30 21:31:49 +01:00
26ec46eb0e missed one import on python generator scripts 2024-01-26 22:00:08 +01:00
d01953409e made buildscripts running under Linux 2024-01-26 21:41:27 +01:00
8ef469b9f1 added Wifi-Config to EEPROM Layout 2024-01-25 14:33:40 +01:00
88b572f408 codegenerator now supports char-arrays 2024-01-25 14:33:09 +01:00
75ed8e6308 made enviroment buildable again 2024-01-25 11:27:58 +01:00
bbd76e77fa reset purgePulses if system goes to error 2024-01-16 09:56:31 +01:00
dcaf56074e Removed some unnecessary log outputs. 2024-01-16 00:10:33 +01:00
bc2c19dad1 reworked dtc-javascript and colors of notifications 2024-01-15 23:57:43 +01:00
8f494dfa05 added echo for serial debugger and some more commands 2024-01-15 23:57:00 +01:00
e913ce6e1b reworked DTC-notification and clearing 2024-01-15 22:57:08 +01:00
d994fd25a0 added websocket-driven notification-overlay 2024-01-15 22:56:08 +01:00
cebf0db60c added remaining settings to websocket-functionality 2024-01-15 22:55:08 +01:00
d524b919fd added Animation to Connection-overlay 2024-01-12 19:53:10 +01:00
eac5dd243b fixed missed \n in Debug Messages 2024-01-12 19:52:25 +01:00
f1defa98f2 added an overlay to the WebUI and some ConnectionHandling 2024-01-12 13:29:22 +01:00
94e407208e most settings working via Websocket 2024-01-11 22:06:32 +01:00
5df69bcdb7 incereased debugger-Buffer size 2024-01-11 22:05:09 +01:00
a449c04cf4 removed EEPROM-Format from WebUI (use JSON-Upload) 2024-01-11 21:20:35 +01:00
ed6f4e488a rearragned some code 2024-01-11 21:19:31 +01:00
0aae5a742c repaired collapsible menu 2024-01-11 17:42:25 +01:00
b79c4bd60f repaired Modal-Window of DTC-Table in WebUI 2024-01-11 17:18:00 +01:00
286ba1fe6c some buttons are now websocket-handled 2024-01-11 14:55:33 +01:00
6a9d09ddf3 updated .gitignore to exclude vscode-stuff 2024-01-11 12:43:49 +01:00
ef8f27e495 updated also the remaining libs 2024-01-11 12:42:24 +01:00
eee7baaece Updated some Libraries (Json and Webserver) 2024-01-11 10:41:20 +01:00
58c6bc820a added checksum to auto-generated files 2024-01-10 19:09:18 +01:00
925167ec3c small Layout-change of OLED during OTA 2024-01-09 22:52:28 +01:00
c236322667 reworked the WebUI-Websocket-Comm 2024-01-09 22:51:45 +01:00
157d59963c updated CodeGeneration 2024-01-09 20:47:28 +01:00
ac28ab21d4 missed to add comments for webui.cpp 2024-01-09 13:12:20 +01:00
a7ea17ef05 changed Config-Default-code 2024-01-09 13:12:09 +01:00
f52f4103f6 used ChatGPT to add comments and proper Headers to all SourceFiles 2024-01-09 12:54:05 +01:00
62cc2bf982 made index.html static - websocket everywhere 2024-01-09 12:17:13 +01:00
e375fab048 make restart chooseable in SystemShutdown 2024-01-09 12:15:39 +01:00
16d6aee420 fixed Bug in EEPROM-Page Handling 2024-01-09 10:46:36 +01:00
58 changed files with 33665 additions and 19717 deletions

24
Hardware/MC33660.lib Normal file
View File

@@ -0,0 +1,24 @@
EESchema-LIBRARY Version 2.4
#encoding utf-8
#
# MC33660
#
DEF MC33660 U 0 40 Y Y 1 F N
F0 "U" 0 0 50 H V C CNN
F1 "MC33660" 0 -100 50 H V C CNN
F2 "" 0 0 50 H I C CNN
F3 "" 0 0 50 H I C CNN
DRAW
S -400 250 400 -350 0 1 0 N
X VBB 1 50 450 200 D 50 50 1 1 W
X NC 2 -50 -550 200 U 50 50 1 1 W
X GND 3 50 -550 200 U 50 50 1 1 W
X ISO 4 600 -50 200 L 50 50 1 1 B
X TX 5 -600 -200 200 R 50 50 1 1 O
X RX 6 -600 -50 200 R 50 50 1 1 I
X VDD 7 -50 450 200 D 50 50 1 1 W
X CEN 8 -600 100 200 R 50 50 1 1 I
ENDDRAW
ENDDEF
#
#End Library

File diff suppressed because it is too large Load Diff

View File

@@ -1,15 +1,19 @@
{
"board": {
"3dviewports": [],
"design_settings": {
"defaults": {
"board_outline_line_width": 0.049999999999999996,
"copper_line_width": 0.19999999999999998,
"apply_defaults_to_fp_fields": false,
"apply_defaults_to_fp_shapes": false,
"apply_defaults_to_fp_text": false,
"board_outline_line_width": 0.05,
"copper_line_width": 0.2,
"copper_text_italic": false,
"copper_text_size_h": 1.5,
"copper_text_size_v": 1.5,
"copper_text_thickness": 0.3,
"copper_text_upright": false,
"courtyard_line_width": 0.049999999999999996,
"courtyard_line_width": 0.05,
"dimension_precision": 4,
"dimension_units": 3,
"dimensions": {
@@ -20,13 +24,13 @@
"text_position": 0,
"units_format": 1
},
"fab_line_width": 0.09999999999999999,
"fab_line_width": 0.1,
"fab_text_italic": false,
"fab_text_size_h": 1.0,
"fab_text_size_v": 1.0,
"fab_text_thickness": 0.15,
"fab_text_upright": false,
"other_line_width": 0.09999999999999999,
"other_line_width": 0.1,
"other_text_italic": false,
"other_text_size_h": 1.0,
"other_text_size_v": 1.0,
@@ -45,11 +49,100 @@
"silk_text_upright": false,
"zones": {
"45_degree_only": false,
"min_clearance": 0.19999999999999998
"min_clearance": 0.2
}
},
"diff_pair_dimensions": [],
"drc_exclusions": [],
"drc_exclusions": [
[
"courtyards_overlap|118511500|75177000|1553c88f-2adb-4497-8788-967b865e436a|b792e1a3-e773-46cb-bdd0-cca64b65c21c",
""
],
[
"courtyards_overlap|123007000|75355000|00000000-0000-0000-0000-000061d28ad3|1553c88f-2adb-4497-8788-967b865e436a",
""
],
[
"lib_footprint_issues|141478000|85575000|00000000-0000-0000-0000-000061d2ae4b|00000000-0000-0000-0000-000000000000",
""
],
[
"lib_footprint_mismatch|115824000|80772000|1553c88f-2adb-4497-8788-967b865e436a|00000000-0000-0000-0000-000000000000",
""
],
[
"lib_footprint_mismatch|124460000|93980000|f3127aa8-4fa0-47de-9985-06be44bbdf06|00000000-0000-0000-0000-000000000000",
""
],
[
"lib_footprint_mismatch|125984000|82296000|00000000-0000-0000-0000-000061d2caf2|00000000-0000-0000-0000-000000000000",
""
],
[
"lib_footprint_mismatch|129032000|77978000|00000000-0000-0000-0000-000061de69e4|00000000-0000-0000-0000-000000000000",
""
],
[
"lib_footprint_mismatch|129540000|88900000|479edbfe-22e9-482f-abe6-e8a9ee4f8095|00000000-0000-0000-0000-000000000000",
""
],
[
"lib_footprint_mismatch|132842000|93218000|00000000-0000-0000-0000-000061d28984|00000000-0000-0000-0000-000000000000",
""
],
[
"lib_footprint_mismatch|139700000|89916000|0b7b6b80-ae94-4b1b-a38e-a90a7895e1d0|00000000-0000-0000-0000-000000000000",
""
],
[
"lib_footprint_mismatch|145703000|65864500|00000000-0000-0000-0000-000061d2f827|00000000-0000-0000-0000-000000000000",
""
],
[
"malformed_courtyard|124128000|98140000|00000000-0000-0000-0000-000061d2ae4b|00000000-0000-0000-0000-000000000000",
""
],
[
"malformed_courtyard|124178000|72040000|00000000-0000-0000-0000-000061d2ae4b|00000000-0000-0000-0000-000000000000",
""
],
[
"malformed_courtyard|158828000|72040000|00000000-0000-0000-0000-000061d2ae4b|00000000-0000-0000-0000-000000000000",
""
],
[
"silk_edge_clearance|108458000|61861000|ccc4cc25-ac17-45ef-825c-e079951ffb21|dc75368d-0996-4249-8abb-dc4cf7e8b3a4",
""
],
[
"silk_edge_clearance|108458000|74901000|ccc4cc25-ac17-45ef-825c-e079951ffb21|53b3d478-aede-49e5-a9c6-af0d51081e6b",
""
],
[
"silk_edge_clearance|131953000|99060000|626679e8-6101-4722-ac57-5b8d9dab4c8b|0ceda40c-021b-4e82-b42f-da6ab60c2da7",
""
],
[
"silk_over_copper|124256491|96080000|5918385d-932b-42f5-93dc-b50c4d404527|00000000-0000-0000-0000-000000000000",
""
],
[
"silk_over_copper|126686000|72160000|c0c7c21a-5ba8-4e1a-b19c-dd42f87b5e73|00000000-0000-0000-0000-000000000000",
""
],
[
"silk_overlap|114722000|93418819|2389429b-e330-41bd-ae02-ffdf7f42affb|277dc3b2-ee65-405f-ac52-614baa7cb1bf",
""
],
[
"silk_overlap|114807618|80226819|2cde46e7-b5a2-4709-b127-bb84cc090edc|d0190ea1-2eb5-4019-a426-876a8032a9c9",
""
],
[
"silk_overlap|125118537|76007746|ba335760-ecfa-408d-9aa6-aeeaddbba1a7|d65dbdcd-4994-45be-8af9-98fc61c06e09",
""
]
],
"meta": {
"filename": "board_design_settings.json",
"version": 2
@@ -57,35 +150,56 @@
"rule_severities": {
"annular_width": "error",
"clearance": "error",
"connection_width": "warning",
"copper_edge_clearance": "error",
"copper_sliver": "warning",
"courtyards_overlap": "error",
"creepage": "error",
"diff_pair_gap_out_of_range": "error",
"diff_pair_uncoupled_length_too_long": "error",
"drill_out_of_range": "error",
"duplicate_footprints": "warning",
"extra_footprint": "warning",
"footprint": "error",
"footprint_filters_mismatch": "ignore",
"footprint_symbol_mismatch": "warning",
"footprint_type_mismatch": "error",
"hole_clearance": "error",
"hole_near_hole": "error",
"hole_to_hole": "error",
"holes_co_located": "warning",
"invalid_outline": "error",
"isolated_copper": "warning",
"item_on_disabled_layer": "error",
"items_not_allowed": "error",
"length_out_of_range": "error",
"lib_footprint_issues": "warning",
"lib_footprint_mismatch": "warning",
"malformed_courtyard": "error",
"microvia_drill_out_of_range": "error",
"mirrored_text_on_front_layer": "warning",
"missing_courtyard": "ignore",
"missing_footprint": "warning",
"net_conflict": "warning",
"nonmirrored_text_on_back_layer": "warning",
"npth_inside_courtyard": "ignore",
"padstack": "error",
"pth_inside_courtyard": "ignore",
"shorting_items": "error",
"silk_edge_clearance": "warning",
"silk_over_copper": "warning",
"silk_overlap": "warning",
"skew_out_of_range": "error",
"solder_mask_bridge": "error",
"starved_thermal": "error",
"text_height": "warning",
"text_on_edge_cuts": "error",
"text_thickness": "warning",
"through_hole_pad_without_hole": "error",
"too_many_vias": "error",
"track_angle": "error",
"track_dangling": "warning",
"track_segment_length": "error",
"track_width": "error",
"tracks_crossing": "error",
"unconnected_items": "error",
@@ -101,24 +215,100 @@
"allow_microvias": false,
"max_error": 0.005,
"min_clearance": 0.0,
"min_copper_edge_clearance": 0.049999999999999996,
"min_connection": 0.0,
"min_copper_edge_clearance": 0.05,
"min_groove_width": 0.0,
"min_hole_clearance": 0.25,
"min_hole_to_hole": 0.25,
"min_microvia_diameter": 0.19999999999999998,
"min_microvia_drill": 0.09999999999999999,
"min_microvia_diameter": 0.2,
"min_microvia_drill": 0.1,
"min_resolved_spokes": 2,
"min_silk_clearance": 0.0,
"min_text_height": 0.8,
"min_text_thickness": 0.08,
"min_through_hole_diameter": 0.3,
"min_track_width": 0.19999999999999998,
"min_via_annular_width": 0.049999999999999996,
"min_via_diameter": 0.39999999999999997,
"min_track_width": 0.2,
"min_via_annular_width": 0.05,
"min_via_diameter": 0.4,
"solder_mask_to_copper_clearance": 0.005,
"use_height_for_length_calcs": true
},
"teardrop_options": [
{
"td_onpthpad": true,
"td_onroundshapesonly": false,
"td_onsmdpad": true,
"td_ontrackend": false,
"td_onvia": true
}
],
"teardrop_parameters": [
{
"td_allow_use_two_tracks": true,
"td_curve_segcount": 0,
"td_height_ratio": 1.0,
"td_length_ratio": 0.5,
"td_maxheight": 2.0,
"td_maxlen": 1.0,
"td_on_pad_in_zone": false,
"td_target_name": "td_round_shape",
"td_width_to_size_filter_ratio": 0.9
},
{
"td_allow_use_two_tracks": true,
"td_curve_segcount": 0,
"td_height_ratio": 1.0,
"td_length_ratio": 0.5,
"td_maxheight": 2.0,
"td_maxlen": 1.0,
"td_on_pad_in_zone": false,
"td_target_name": "td_rect_shape",
"td_width_to_size_filter_ratio": 0.9
},
{
"td_allow_use_two_tracks": true,
"td_curve_segcount": 0,
"td_height_ratio": 1.0,
"td_length_ratio": 0.5,
"td_maxheight": 2.0,
"td_maxlen": 1.0,
"td_on_pad_in_zone": false,
"td_target_name": "td_track_end",
"td_width_to_size_filter_ratio": 0.9
}
],
"track_widths": [
0.0,
0.5,
1.0,
2.0
],
"tuning_pattern_settings": {
"diff_pair_defaults": {
"corner_radius_percentage": 80,
"corner_style": 1,
"max_amplitude": 1.0,
"min_amplitude": 0.2,
"single_sided": false,
"spacing": 1.0
},
"diff_pair_skew_defaults": {
"corner_radius_percentage": 80,
"corner_style": 1,
"max_amplitude": 1.0,
"min_amplitude": 0.2,
"single_sided": false,
"spacing": 0.6
},
"single_track_defaults": {
"corner_radius_percentage": 80,
"corner_style": 1,
"max_amplitude": 1.0,
"min_amplitude": 0.2,
"single_sided": false,
"spacing": 0.6
}
},
"via_dimensions": [
{
"diameter": 0.0,
@@ -140,7 +330,16 @@
"zones_allow_external_fillets": false,
"zones_use_no_outline": true
},
"layer_presets": []
"ipc2581": {
"dist": "",
"distpn": "",
"internal_id": "",
"mfg": "",
"mpn": ""
},
"layer_pairs": [],
"layer_presets": [],
"viewports": []
},
"boards": [],
"cvpcb": {
@@ -331,11 +530,21 @@
"different_unit_net": "error",
"duplicate_reference": "error",
"duplicate_sheet_names": "error",
"endpoint_off_grid": "warning",
"extra_units": "error",
"footprint_filter": "ignore",
"footprint_link_issues": "warning",
"four_way_junction": "ignore",
"global_label_dangling": "warning",
"hier_label_mismatch": "error",
"label_dangling": "error",
"label_multiple_wires": "warning",
"lib_symbol_issues": "warning",
"lib_symbol_mismatch": "warning",
"missing_bidi_pin": "warning",
"missing_input_pin": "warning",
"missing_power_pin": "error",
"missing_unit": "warning",
"multiple_net_names": "warning",
"net_not_bus_member": "warning",
"no_connect_connected": "warning",
@@ -344,8 +553,14 @@
"pin_not_driven": "error",
"pin_to_pin": "warning",
"power_pin_not_driven": "error",
"same_local_global_label": "warning",
"similar_label_and_power": "warning",
"similar_labels": "warning",
"similar_power": "warning",
"simulation_model_issue": "ignore",
"single_global_label": "ignore",
"unannotated": "error",
"unconnected_wire_endpoint": "warning",
"unit_value_mismatch": "error",
"unresolved_variable": "error",
"wire_dangling": "error"
@@ -357,12 +572,12 @@
},
"meta": {
"filename": "oiler SMD.kicad_pro",
"version": 1
"version": 3
},
"net_settings": {
"classes": [
{
"bus_width": 12.0,
"bus_width": 12,
"clearance": 0.2,
"diff_pair_gap": 0.25,
"diff_pair_via_gap": 0.25,
@@ -372,32 +587,112 @@
"microvia_drill": 0.1,
"name": "Default",
"pcb_color": "rgba(0, 0, 0, 0.000)",
"priority": 2147483647,
"schematic_color": "rgba(0, 0, 0, 0.000)",
"track_width": 0.25,
"via_diameter": 0.8,
"via_drill": 0.4,
"wire_width": 6.0
"wire_width": 6
}
],
"meta": {
"version": 2
"version": 4
},
"net_colors": null
"net_colors": null,
"netclass_assignments": null,
"netclass_patterns": []
},
"pcbnew": {
"last_paths": {
"gencad": "",
"idf": "",
"netlist": "Rehoiler SMD.net",
"plot": "",
"pos_files": "",
"specctra_dsn": "",
"step": "",
"svg": "",
"vrml": ""
},
"page_layout_descr_file": ""
},
"schematic": {
"annotate_start_num": 0,
"bom_export_filename": "${PROJECTNAME}.csv",
"bom_fmt_presets": [],
"bom_fmt_settings": {
"field_delimiter": ",",
"keep_line_breaks": false,
"keep_tabs": false,
"name": "CSV",
"ref_delimiter": ",",
"ref_range_delimiter": "",
"string_delimiter": "\""
},
"bom_presets": [],
"bom_settings": {
"exclude_dnp": false,
"fields_ordered": [
{
"group_by": false,
"label": "Reference",
"name": "Reference",
"show": true
},
{
"group_by": false,
"label": "Qty",
"name": "${QUANTITY}",
"show": true
},
{
"group_by": true,
"label": "Value",
"name": "Value",
"show": true
},
{
"group_by": true,
"label": "DNP",
"name": "${DNP}",
"show": true
},
{
"group_by": true,
"label": "Exclude from BOM",
"name": "${EXCLUDE_FROM_BOM}",
"show": true
},
{
"group_by": true,
"label": "Exclude from Board",
"name": "${EXCLUDE_FROM_BOARD}",
"show": true
},
{
"group_by": true,
"label": "Footprint",
"name": "Footprint",
"show": true
},
{
"group_by": false,
"label": "Datasheet",
"name": "Datasheet",
"show": true
}
],
"filter_string": "",
"group_symbols": true,
"include_excluded_from_bom": true,
"name": "Default Editing",
"sort_asc": true,
"sort_field": "Referenz"
},
"connection_grid_size": 50.0,
"drawing": {
"dashed_lines_dash_length_ratio": 12.0,
"dashed_lines_gap_length_ratio": 3.0,
"default_line_thickness": 6.0,
"default_text_size": 50.0,
"field_names": [],
@@ -408,6 +703,11 @@
"intersheets_ref_suffix": "",
"junction_size_choice": 3,
"label_size_ratio": 0.25,
"operating_point_overlay_i_precision": 3,
"operating_point_overlay_i_range": "~A",
"operating_point_overlay_v_precision": 3,
"operating_point_overlay_v_range": "~V",
"overbar_offset_ratio": 1.23,
"pin_symbol_size": 25.0,
"text_offset_ratio": 0.08
},
@@ -423,20 +723,26 @@
"meta": {
"version": 0
},
"model_mode": 0,
"model_mode": 4,
"workbook_filename": ""
},
"page_layout_descr_file": "",
"plot_directory": "",
"space_save_all_events": true,
"spice_adjust_passive_values": false,
"spice_current_sheet_as_root": false,
"spice_external_command": "spice \"%I\"",
"spice_model_current_sheet_as_root": true,
"spice_save_all_currents": false,
"spice_save_all_dissipations": false,
"spice_save_all_voltages": false,
"subpart_first_id": 65,
"subpart_id_separator": 0
},
"sheets": [
[
"b1ddb058-f7b2-429c-9489-f4e2242ad7e5",
""
"Root"
]
],
"text_variables": {}

File diff suppressed because it is too large Load Diff

View File

@@ -1,257 +0,0 @@
update=03.01.2022 00:33:13
version=1
last_client=kicad
[general]
version=1
RootSch=
BoardNm=
[cvpcb]
version=1
NetIExt=net
[eeschema]
version=1
LibDir=
[eeschema/libraries]
[schematic_editor]
version=1
PageLayoutDescrFile=
PlotDirectoryName=
SubpartIdSeparator=0
SubpartFirstId=65
NetFmtName=Pcbnew
SpiceAjustPassiveValues=0
LabSize=50
ERC_TestSimilarLabels=1
[pcbnew]
version=1
PageLayoutDescrFile=
LastNetListRead=Rehoiler SMD.net
CopperLayerCount=2
BoardThickness=1.6
AllowMicroVias=0
AllowBlindVias=0
RequireCourtyardDefinitions=0
ProhibitOverlappingCourtyards=1
MinTrackWidth=0.2
MinViaDiameter=0.4
MinViaDrill=0.3
MinMicroViaDiameter=0.2
MinMicroViaDrill=0.09999999999999999
MinHoleToHole=0.25
TrackWidth1=0.25
TrackWidth2=0.5
TrackWidth3=1
TrackWidth4=2
ViaDiameter1=0.8
ViaDrill1=0.4
ViaDiameter2=0.7
ViaDrill2=0.35
ViaDiameter3=1
ViaDrill3=0.6
ViaDiameter4=2
ViaDrill4=1
dPairWidth1=0.2
dPairGap1=0.25
dPairViaGap1=0.25
SilkLineWidth=0.12
SilkTextSizeV=1
SilkTextSizeH=1
SilkTextSizeThickness=0.15
SilkTextItalic=0
SilkTextUpright=1
CopperLineWidth=0.2
CopperTextSizeV=1.5
CopperTextSizeH=1.5
CopperTextThickness=0.3
CopperTextItalic=0
CopperTextUpright=1
EdgeCutLineWidth=0.05
CourtyardLineWidth=0.05
OthersLineWidth=0.15
OthersTextSizeV=1
OthersTextSizeH=1
OthersTextSizeThickness=0.15
OthersTextItalic=0
OthersTextUpright=1
SolderMaskClearance=0
SolderMaskMinWidth=0
SolderPasteClearance=0
SolderPasteRatio=-0
[pcbnew/Layer.F.Cu]
Name=F.Cu
Type=0
Enabled=1
[pcbnew/Layer.In1.Cu]
Name=In1.Cu
Type=0
Enabled=0
[pcbnew/Layer.In2.Cu]
Name=In2.Cu
Type=0
Enabled=0
[pcbnew/Layer.In3.Cu]
Name=In3.Cu
Type=0
Enabled=0
[pcbnew/Layer.In4.Cu]
Name=In4.Cu
Type=0
Enabled=0
[pcbnew/Layer.In5.Cu]
Name=In5.Cu
Type=0
Enabled=0
[pcbnew/Layer.In6.Cu]
Name=In6.Cu
Type=0
Enabled=0
[pcbnew/Layer.In7.Cu]
Name=In7.Cu
Type=0
Enabled=0
[pcbnew/Layer.In8.Cu]
Name=In8.Cu
Type=0
Enabled=0
[pcbnew/Layer.In9.Cu]
Name=In9.Cu
Type=0
Enabled=0
[pcbnew/Layer.In10.Cu]
Name=In10.Cu
Type=0
Enabled=0
[pcbnew/Layer.In11.Cu]
Name=In11.Cu
Type=0
Enabled=0
[pcbnew/Layer.In12.Cu]
Name=In12.Cu
Type=0
Enabled=0
[pcbnew/Layer.In13.Cu]
Name=In13.Cu
Type=0
Enabled=0
[pcbnew/Layer.In14.Cu]
Name=In14.Cu
Type=0
Enabled=0
[pcbnew/Layer.In15.Cu]
Name=In15.Cu
Type=0
Enabled=0
[pcbnew/Layer.In16.Cu]
Name=In16.Cu
Type=0
Enabled=0
[pcbnew/Layer.In17.Cu]
Name=In17.Cu
Type=0
Enabled=0
[pcbnew/Layer.In18.Cu]
Name=In18.Cu
Type=0
Enabled=0
[pcbnew/Layer.In19.Cu]
Name=In19.Cu
Type=0
Enabled=0
[pcbnew/Layer.In20.Cu]
Name=In20.Cu
Type=0
Enabled=0
[pcbnew/Layer.In21.Cu]
Name=In21.Cu
Type=0
Enabled=0
[pcbnew/Layer.In22.Cu]
Name=In22.Cu
Type=0
Enabled=0
[pcbnew/Layer.In23.Cu]
Name=In23.Cu
Type=0
Enabled=0
[pcbnew/Layer.In24.Cu]
Name=In24.Cu
Type=0
Enabled=0
[pcbnew/Layer.In25.Cu]
Name=In25.Cu
Type=0
Enabled=0
[pcbnew/Layer.In26.Cu]
Name=In26.Cu
Type=0
Enabled=0
[pcbnew/Layer.In27.Cu]
Name=In27.Cu
Type=0
Enabled=0
[pcbnew/Layer.In28.Cu]
Name=In28.Cu
Type=0
Enabled=0
[pcbnew/Layer.In29.Cu]
Name=In29.Cu
Type=0
Enabled=0
[pcbnew/Layer.In30.Cu]
Name=In30.Cu
Type=0
Enabled=0
[pcbnew/Layer.B.Cu]
Name=B.Cu
Type=0
Enabled=1
[pcbnew/Layer.B.Adhes]
Enabled=1
[pcbnew/Layer.F.Adhes]
Enabled=1
[pcbnew/Layer.B.Paste]
Enabled=1
[pcbnew/Layer.F.Paste]
Enabled=1
[pcbnew/Layer.B.SilkS]
Enabled=1
[pcbnew/Layer.F.SilkS]
Enabled=1
[pcbnew/Layer.B.Mask]
Enabled=1
[pcbnew/Layer.F.Mask]
Enabled=1
[pcbnew/Layer.Dwgs.User]
Enabled=1
[pcbnew/Layer.Cmts.User]
Enabled=1
[pcbnew/Layer.Eco1.User]
Enabled=1
[pcbnew/Layer.Eco2.User]
Enabled=1
[pcbnew/Layer.Edge.Cuts]
Enabled=1
[pcbnew/Layer.Margin]
Enabled=1
[pcbnew/Layer.B.CrtYd]
Enabled=1
[pcbnew/Layer.F.CrtYd]
Enabled=1
[pcbnew/Layer.B.Fab]
Enabled=1
[pcbnew/Layer.F.Fab]
Enabled=1
[pcbnew/Layer.Rescue]
Enabled=0
[pcbnew/Netclasses]
[pcbnew/Netclasses/Default]
Name=Default
Clearance=0.2
TrackWidth=0.25
ViaDiameter=0.8
ViaDrill=0.4
uViaDiameter=0.3
uViaDrill=0.1
dPairWidth=0.2
dPairGap=0.25
dPairViaGap=0.25

View File

@@ -1,698 +0,0 @@
EESchema Schematic File Version 4
EELAYER 30 0
EELAYER END
$Descr A4 11693 8268
encoding utf-8
Sheet 1 1
Title ""
Date ""
Rev ""
Comp ""
Comment1 ""
Comment2 ""
Comment3 ""
Comment4 ""
$EndDescr
$Comp
L MCU_Module:WeMos_D1_mini U1
U 1 1 61D21889
P 6500 3150
F 0 "U1" H 6500 2261 50 0000 C CNN
F 1 "WeMos_D1_mini" H 6500 2170 50 0000 C CNN
F 2 "Module:WEMOS_D1_mini_light" H 6500 2000 50 0001 C CNN
F 3 "https://wiki.wemos.cc/products:d1:d1_mini#documentation" H 4650 2000 50 0001 C CNN
1 6500 3150
1 0 0 -1
$EndComp
$Comp
L Transistor_FET:IRLZ44N Q1
U 1 1 61D22C04
P 9400 3750
F 0 "Q1" H 9604 3796 50 0000 L CNN
F 1 "IRLZ44N" H 9604 3705 50 0000 L CNN
F 2 "Package_TO_SOT_THT:TO-220-3_Vertical" H 9650 3675 50 0001 L CIN
F 3 "http://www.irf.com/product-info/datasheets/data/irlz44n.pdf" H 9400 3750 50 0001 L CNN
1 9400 3750
1 0 0 -1
$EndComp
$Comp
L Device:R R3
U 1 1 61D23437
P 9050 4000
F 0 "R3" H 9120 4046 50 0000 L CNN
F 1 "4k7" H 9120 3955 50 0000 L CNN
F 2 "Resistor_SMD:R_0805_2012Metric_Pad1.20x1.40mm_HandSolder" V 8980 4000 50 0001 C CNN
F 3 "~" H 9050 4000 50 0001 C CNN
1 9050 4000
1 0 0 -1
$EndComp
$Comp
L Device:R R2
U 1 1 61D23883
P 8750 3750
F 0 "R2" V 8543 3750 50 0000 C CNN
F 1 "100" V 8634 3750 50 0000 C CNN
F 2 "Resistor_SMD:R_0805_2012Metric_Pad1.20x1.40mm_HandSolder" V 8680 3750 50 0001 C CNN
F 3 "~" H 8750 3750 50 0001 C CNN
1 8750 3750
0 1 1 0
$EndComp
$Comp
L power:GND #PWR0101
U 1 1 61D23AAC
P 9050 4200
F 0 "#PWR0101" H 9050 3950 50 0001 C CNN
F 1 "GND" H 9055 4027 50 0000 C CNN
F 2 "" H 9050 4200 50 0001 C CNN
F 3 "" H 9050 4200 50 0001 C CNN
1 9050 4200
1 0 0 -1
$EndComp
$Comp
L power:GND #PWR0102
U 1 1 61D240D1
P 9500 4200
F 0 "#PWR0102" H 9500 3950 50 0001 C CNN
F 1 "GND" H 9505 4027 50 0000 C CNN
F 2 "" H 9500 4200 50 0001 C CNN
F 3 "" H 9500 4200 50 0001 C CNN
1 9500 4200
1 0 0 -1
$EndComp
$Comp
L power:GND #PWR0103
U 1 1 61D2429A
P 6500 4200
F 0 "#PWR0103" H 6500 3950 50 0001 C CNN
F 1 "GND" H 6505 4027 50 0000 C CNN
F 2 "" H 6500 4200 50 0001 C CNN
F 3 "" H 6500 4200 50 0001 C CNN
1 6500 4200
1 0 0 -1
$EndComp
Wire Wire Line
6500 4200 6500 3950
Wire Wire Line
8450 3750 8600 3750
Wire Wire Line
8900 3750 9050 3750
Wire Wire Line
9050 3850 9050 3750
Connection ~ 9050 3750
Wire Wire Line
9050 3750 9200 3750
Wire Wire Line
9050 4200 9050 4150
Wire Wire Line
9500 4200 9500 3950
$Comp
L Connector_Generic:Conn_01x02 J4
U 1 1 61D24E27
P 9800 3350
F 0 "J4" H 9880 3342 50 0000 L CNN
F 1 "PUMP" H 9880 3251 50 0000 L CNN
F 2 "Connector_Phoenix_MC:PhoenixContact_MC_1,5_2-G-3.5_1x02_P3.50mm_Horizontal" H 9800 3350 50 0001 C CNN
F 3 "~" H 9800 3350 50 0001 C CNN
1 9800 3350
1 0 0 -1
$EndComp
$Comp
L Connector_Generic:Conn_01x02 J3
U 1 1 61D2549D
P 9800 2750
F 0 "J3" H 9880 2742 50 0000 L CNN
F 1 "POWER" H 9880 2651 50 0000 L CNN
F 2 "Connector_Phoenix_MC:PhoenixContact_MC_1,5_2-G-3.5_1x02_P3.50mm_Horizontal" H 9800 2750 50 0001 C CNN
F 3 "~" H 9800 2750 50 0001 C CNN
1 9800 2750
1 0 0 -1
$EndComp
Wire Wire Line
9500 3550 9500 3500
Wire Wire Line
9500 3450 9600 3450
Wire Wire Line
9600 3350 9500 3350
Wire Wire Line
9500 3350 9500 3200
Wire Wire Line
9500 2750 9600 2750
$Comp
L power:GND #PWR0104
U 1 1 61D25EA9
P 9600 2900
F 0 "#PWR0104" H 9600 2650 50 0001 C CNN
F 1 "GND" H 9605 2727 50 0000 C CNN
F 2 "" H 9600 2900 50 0001 C CNN
F 3 "" H 9600 2900 50 0001 C CNN
1 9600 2900
1 0 0 -1
$EndComp
Wire Wire Line
9600 2850 9600 2900
Connection ~ 9500 2750
$Comp
L power:GND #PWR0105
U 1 1 61D27601
P 10100 2350
F 0 "#PWR0105" H 10100 2100 50 0001 C CNN
F 1 "GND" H 10105 2177 50 0000 C CNN
F 2 "" H 10100 2350 50 0001 C CNN
F 3 "" H 10100 2350 50 0001 C CNN
1 10100 2350
1 0 0 -1
$EndComp
$Comp
L power:+3.3V #PWR0106
U 1 1 61D282EA
P 6600 2350
F 0 "#PWR0106" H 6600 2200 50 0001 C CNN
F 1 "+3.3V" H 6615 2523 50 0000 C CNN
F 2 "" H 6600 2350 50 0001 C CNN
F 3 "" H 6600 2350 50 0001 C CNN
1 6600 2350
1 0 0 -1
$EndComp
$Comp
L Regulator_Switching:R-78C5.0-1.0 U2
U 1 1 61D28955
P 10100 2050
F 0 "U2" H 10100 2292 50 0000 C CNN
F 1 "R-78C5.0-1.0" H 10100 2201 50 0000 C CNN
F 2 "Converter_DCDC:Converter_DCDC_RECOM_R-78E-0.5_THT" H 10150 1800 50 0001 L CIN
F 3 "https://www.recom-power.com/pdf/Innoline/R-78Cxx-1.0.pdf" H 10100 2050 50 0001 C CNN
1 10100 2050
1 0 0 -1
$EndComp
$Comp
L power:+5V #PWR0107
U 1 1 61D2BC64
P 6400 2350
F 0 "#PWR0107" H 6400 2200 50 0001 C CNN
F 1 "+5V" H 6415 2523 50 0000 C CNN
F 2 "" H 6400 2350 50 0001 C CNN
F 3 "" H 6400 2350 50 0001 C CNN
1 6400 2350
1 0 0 -1
$EndComp
$Comp
L power:+5V #PWR0108
U 1 1 61D2C166
P 10550 1900
F 0 "#PWR0108" H 10550 1750 50 0001 C CNN
F 1 "+5V" H 10565 2073 50 0000 C CNN
F 2 "" H 10550 1900 50 0001 C CNN
F 3 "" H 10550 1900 50 0001 C CNN
1 10550 1900
1 0 0 -1
$EndComp
Wire Wire Line
10400 2050 10550 2050
Wire Wire Line
10550 2050 10550 1900
$Comp
L Diode:BAT42 D2
U 1 1 61D2CD57
P 8250 4400
F 0 "D2" V 8296 4320 50 0000 R CNN
F 1 "BAT42" V 8205 4320 50 0000 R CNN
F 2 "Diode_SMD:D_SOD-123" H 8250 4225 50 0001 C CNN
F 3 "http://www.vishay.com/docs/85660/bat42.pdf" H 8250 4400 50 0001 C CNN
F 4 "BAT 42" H 8250 4400 50 0001 C CNN "Reichelt Order No."
1 8250 4400
0 -1 -1 0
$EndComp
$Comp
L Connector_Generic:Conn_01x02 J2
U 1 1 61D2DCEE
P 8550 4700
F 0 "J2" H 8630 4692 50 0000 L CNN
F 1 "SIGNAL" H 8630 4601 50 0000 L CNN
F 2 "Connector_PinHeader_2.54mm:PinHeader_1x02_P2.54mm_Horizontal" H 8550 4700 50 0001 C CNN
F 3 "~" H 8550 4700 50 0001 C CNN
1 8550 4700
1 0 0 -1
$EndComp
Wire Wire Line
8350 4700 8250 4700
Wire Wire Line
8250 4700 8250 4550
Wire Wire Line
8250 4250 8250 3350
$Comp
L Device:C C1
U 1 1 61D2F740
P 7400 3700
F 0 "C1" H 7515 3746 50 0000 L CNN
F 1 "10n" H 7515 3655 50 0000 L CNN
F 2 "Capacitor_SMD:C_0805_2012Metric_Pad1.18x1.45mm_HandSolder" H 7438 3550 50 0001 C CNN
F 3 "~" H 7400 3700 50 0001 C CNN
1 7400 3700
1 0 0 -1
$EndComp
$Comp
L Device:C C2
U 1 1 61D32638
P 8000 3700
F 0 "C2" H 8115 3746 50 0000 L CNN
F 1 "10n" H 8115 3655 50 0000 L CNN
F 2 "Capacitor_SMD:C_0805_2012Metric_Pad1.18x1.45mm_HandSolder" H 8038 3550 50 0001 C CNN
F 3 "~" H 8000 3700 50 0001 C CNN
1 8000 3700
1 0 0 -1
$EndComp
$Comp
L power:GND #PWR0109
U 1 1 61D32EB9
P 8000 3850
F 0 "#PWR0109" H 8000 3600 50 0001 C CNN
F 1 "GND" H 8005 3677 50 0000 C CNN
F 2 "" H 8000 3850 50 0001 C CNN
F 3 "" H 8000 3850 50 0001 C CNN
1 8000 3850
1 0 0 -1
$EndComp
$Comp
L power:GND #PWR0110
U 1 1 61D331A8
P 7400 3850
F 0 "#PWR0110" H 7400 3600 50 0001 C CNN
F 1 "GND" H 7405 3677 50 0000 C CNN
F 2 "" H 7400 3850 50 0001 C CNN
F 3 "" H 7400 3850 50 0001 C CNN
1 7400 3850
1 0 0 -1
$EndComp
$Comp
L Diode:BAT42 D1
U 1 1 61D35ED1
P 7750 4400
F 0 "D1" V 7796 4320 50 0000 R CNN
F 1 "BAT42" V 7705 4320 50 0000 R CNN
F 2 "Diode_SMD:D_SOD-123" H 7750 4225 50 0001 C CNN
F 3 "http://www.vishay.com/docs/85660/bat42.pdf" H 7750 4400 50 0001 C CNN
F 4 "BAT 42" H 7750 4400 50 0001 C CNN "Reichelt Order No."
1 7750 4400
0 -1 -1 0
$EndComp
$Comp
L Diode:1N4001 D3
U 1 1 61D36E68
P 9100 2750
F 0 "D3" H 9100 2967 50 0000 C CNN
F 1 "1N4001" H 9100 2876 50 0000 C CNN
F 2 "Diode_THT:D_DO-35_SOD27_P7.62mm_Horizontal" H 9100 2575 50 0001 C CNN
F 3 "http://www.vishay.com/docs/88503/1n4001.pdf" H 9100 2750 50 0001 C CNN
1 9100 2750
1 0 0 -1
$EndComp
Wire Wire Line
9250 2750 9500 2750
Wire Wire Line
8950 2050 8950 2750
Wire Wire Line
8950 2050 9450 2050
$Comp
L Device:CP C3
U 1 1 61D3892A
P 9450 2200
F 0 "C3" H 9568 2246 50 0000 L CNN
F 1 "470µF" H 9568 2155 50 0000 L CNN
F 2 "Capacitor_SMD:CP_Elec_8x10" H 9488 2050 50 0001 C CNN
F 3 "~" H 9450 2200 50 0001 C CNN
F 4 "ECC MZS350ARA471" H 9450 2200 50 0001 C CNN "Reichelt Order No."
1 9450 2200
1 0 0 -1
$EndComp
Connection ~ 9450 2050
Wire Wire Line
9450 2050 9800 2050
$Comp
L power:GND #PWR0111
U 1 1 61D3952C
P 9450 2350
F 0 "#PWR0111" H 9450 2100 50 0001 C CNN
F 1 "GND" H 9455 2177 50 0000 C CNN
F 2 "" H 9450 2350 50 0001 C CNN
F 3 "" H 9450 2350 50 0001 C CNN
1 9450 2350
1 0 0 -1
$EndComp
$Comp
L Device:CP C4
U 1 1 61D39810
P 10550 2200
F 0 "C4" H 10668 2246 50 0000 L CNN
F 1 "100µ" H 10668 2155 50 0000 L CNN
F 2 "Capacitor_SMD:CP_Elec_6.3x7.7" H 10588 2050 50 0001 C CNN
F 3 "~" H 10550 2200 50 0001 C CNN
F 4 "ECC HXE250ARA101" H 10550 2200 50 0001 C CNN "Reichelt Order No."
1 10550 2200
1 0 0 -1
$EndComp
Connection ~ 10550 2050
$Comp
L power:GND #PWR0112
U 1 1 61D39D32
P 10550 2350
F 0 "#PWR0112" H 10550 2100 50 0001 C CNN
F 1 "GND" H 10555 2177 50 0000 C CNN
F 2 "" H 10550 2350 50 0001 C CNN
F 3 "" H 10550 2350 50 0001 C CNN
1 10550 2350
1 0 0 -1
$EndComp
$Comp
L power:GND #PWR0113
U 1 1 61D3BF4D
P 7850 5450
F 0 "#PWR0113" H 7850 5200 50 0001 C CNN
F 1 "GND" H 7855 5277 50 0000 C CNN
F 2 "" H 7850 5450 50 0001 C CNN
F 3 "" H 7850 5450 50 0001 C CNN
1 7850 5450
1 0 0 -1
$EndComp
$Comp
L power:+5V #PWR0114
U 1 1 61D3C31B
P 7850 5050
F 0 "#PWR0114" H 7850 4900 50 0001 C CNN
F 1 "+5V" H 7865 5223 50 0000 C CNN
F 2 "" H 7850 5050 50 0001 C CNN
F 3 "" H 7850 5050 50 0001 C CNN
1 7850 5050
1 0 0 -1
$EndComp
Wire Wire Line
7900 5100 7850 5100
Wire Wire Line
7850 5100 7850 5050
$Comp
L Device:R R1
U 1 1 61D3DA39
P 7450 5300
F 0 "R1" V 7243 5300 50 0000 C CNN
F 1 "100" V 7334 5300 50 0000 C CNN
F 2 "Resistor_SMD:R_0805_2012Metric_Pad1.20x1.40mm_HandSolder" V 7380 5300 50 0001 C CNN
F 3 "~" H 7450 5300 50 0001 C CNN
1 7450 5300
0 1 1 0
$EndComp
$Comp
L Diode:1N4001 D4
U 1 1 61D3DFDC
P 9300 3350
F 0 "D4" V 9254 3430 50 0000 L CNN
F 1 "1N4001" V 9345 3430 50 0000 L CNN
F 2 "Diode_THT:D_DO-35_SOD27_P7.62mm_Horizontal" H 9300 3175 50 0001 C CNN
F 3 "http://www.vishay.com/docs/88503/1n4001.pdf" H 9300 3350 50 0001 C CNN
1 9300 3350
0 1 1 0
$EndComp
Wire Wire Line
9300 3500 9500 3500
Connection ~ 9500 3500
Wire Wire Line
9500 3500 9500 3450
Wire Wire Line
9300 3200 9500 3200
Connection ~ 9500 3200
Wire Wire Line
9500 3200 9500 2750
$Comp
L Connector_Generic:Conn_01x04 J1
U 1 1 61D4071E
P 8100 5200
F 0 "J1" H 8180 5192 50 0000 L CNN
F 1 "COCKPIT" H 8180 5101 50 0000 L CNN
F 2 "Connector_PinHeader_2.54mm:PinHeader_1x04_P2.54mm_Horizontal" H 8100 5200 50 0001 C CNN
F 3 "~" H 8100 5200 50 0001 C CNN
1 8100 5200
1 0 0 -1
$EndComp
Wire Wire Line
7900 5400 7850 5400
Wire Wire Line
7850 5400 7850 5450
Wire Wire Line
7150 5300 7300 5300
Wire Wire Line
7750 4550 7750 5200
Wire Wire Line
7900 5200 7750 5200
Wire Wire Line
7600 5300 7900 5300
$Comp
L power:GND #PWR0115
U 1 1 61D47EEA
P 8250 4850
F 0 "#PWR0115" H 8250 4600 50 0001 C CNN
F 1 "GND" H 8255 4677 50 0000 C CNN
F 2 "" H 8250 4850 50 0001 C CNN
F 3 "" H 8250 4850 50 0001 C CNN
1 8250 4850
1 0 0 -1
$EndComp
Wire Wire Line
8250 4850 8250 4800
Wire Wire Line
8250 4800 8350 4800
$Comp
L Connector_Generic:Conn_01x04 J5
U 1 1 61E12B85
P 8450 2500
F 0 "J5" H 8530 2492 50 0000 L CNN
F 1 "I2C" H 8530 2401 50 0000 L CNN
F 2 "Connector_PinHeader_2.54mm:PinHeader_1x04_P2.54mm_Horizontal" H 8450 2500 50 0001 C CNN
F 3 "~" H 8450 2500 50 0001 C CNN
1 8450 2500
1 0 0 -1
$EndComp
$Comp
L power:+3.3V #PWR0116
U 1 1 61E137AF
P 8050 1550
F 0 "#PWR0116" H 8050 1400 50 0001 C CNN
F 1 "+3.3V" H 8065 1723 50 0000 C CNN
F 2 "" H 8050 1550 50 0001 C CNN
F 3 "" H 8050 1550 50 0001 C CNN
1 8050 1550
1 0 0 -1
$EndComp
$Comp
L power:GND #PWR0117
U 1 1 61E147DB
P 8200 2750
F 0 "#PWR0117" H 8200 2500 50 0001 C CNN
F 1 "GND" H 8205 2577 50 0000 C CNN
F 2 "" H 8200 2750 50 0001 C CNN
F 3 "" H 8200 2750 50 0001 C CNN
1 8200 2750
1 0 0 -1
$EndComp
Wire Wire Line
8250 2700 8200 2700
Wire Wire Line
8200 2700 8200 2750
Wire Wire Line
8050 2950 8050 2400
Wire Wire Line
8050 2400 8250 2400
Wire Wire Line
7950 2850 7950 2500
Wire Wire Line
7950 2500 8250 2500
$Comp
L Device:R R4
U 1 1 61E189A2
P 7950 1850
F 0 "R4" H 7880 1804 50 0000 R CNN
F 1 "4k7" H 7880 1895 50 0000 R CNN
F 2 "Resistor_SMD:R_0805_2012Metric_Pad1.20x1.40mm_HandSolder" V 7880 1850 50 0001 C CNN
F 3 "~" H 7950 1850 50 0001 C CNN
1 7950 1850
-1 0 0 1
$EndComp
$Comp
L Device:R R5
U 1 1 61E1955B
P 8050 2150
F 0 "R5" H 7980 2104 50 0000 R CNN
F 1 "4k7" H 7980 2195 50 0000 R CNN
F 2 "Resistor_SMD:R_0805_2012Metric_Pad1.20x1.40mm_HandSolder" V 7980 2150 50 0001 C CNN
F 3 "~" H 8050 2150 50 0001 C CNN
1 8050 2150
-1 0 0 1
$EndComp
Wire Wire Line
8250 2600 7850 2600
Wire Wire Line
7850 2600 7850 1600
Wire Wire Line
7850 1600 7950 1600
Wire Wire Line
8050 1600 8050 1550
Connection ~ 7950 1600
Wire Wire Line
7950 1600 8050 1600
Wire Wire Line
8050 2000 8050 1600
Connection ~ 8050 1600
Wire Wire Line
7950 1600 7950 1700
Wire Wire Line
8050 2300 8050 2400
Connection ~ 8050 2400
Wire Wire Line
7950 2000 7950 2500
Connection ~ 7950 2500
Wire Wire Line
6900 3550 7150 3550
Wire Wire Line
7150 3550 7150 5300
Wire Wire Line
6900 3450 7400 3450
Connection ~ 7400 3450
Wire Wire Line
7400 3450 7400 3550
Wire Wire Line
7400 3450 7750 3450
Wire Wire Line
7750 3450 7750 4250
Wire Wire Line
6900 3350 8000 3350
Wire Wire Line
8000 3350 8000 3550
Wire Wire Line
8000 3350 8250 3350
Connection ~ 8000 3350
Wire Wire Line
8450 3250 8450 3750
Wire Wire Line
6900 3250 8450 3250
$Comp
L Memory_EEPROM:24LC64 U3
U 1 1 61DDD4E7
P 6750 1550
F 0 "U3" H 6750 2031 50 0000 C CNN
F 1 "24LC64" H 6750 1940 50 0000 C CNN
F 2 "Package_SO:SOIC-8_3.9x4.9mm_P1.27mm" H 6750 1550 50 0001 C CNN
F 3 "http://ww1.microchip.com/downloads/en/DeviceDoc/21189f.pdf" H 6750 1550 50 0001 C CNN
1 6750 1550
1 0 0 -1
$EndComp
$Comp
L power:+3.3V #PWR0118
U 1 1 61DDE198
P 6750 1250
F 0 "#PWR0118" H 6750 1100 50 0001 C CNN
F 1 "+3.3V" H 6765 1423 50 0000 C CNN
F 2 "" H 6750 1250 50 0001 C CNN
F 3 "" H 6750 1250 50 0001 C CNN
1 6750 1250
1 0 0 -1
$EndComp
$Comp
L power:GND #PWR0119
U 1 1 61DDE4C0
P 6750 1850
F 0 "#PWR0119" H 6750 1600 50 0001 C CNN
F 1 "GND" H 6755 1677 50 0000 C CNN
F 2 "" H 6750 1850 50 0001 C CNN
F 3 "" H 6750 1850 50 0001 C CNN
1 6750 1850
1 0 0 -1
$EndComp
$Comp
L power:GND #PWR0120
U 1 1 61DDE71F
P 6300 1850
F 0 "#PWR0120" H 6300 1600 50 0001 C CNN
F 1 "GND" H 6305 1677 50 0000 C CNN
F 2 "" H 6300 1850 50 0001 C CNN
F 3 "" H 6300 1850 50 0001 C CNN
1 6300 1850
1 0 0 -1
$EndComp
Wire Wire Line
6350 1650 6300 1650
Wire Wire Line
6300 1650 6300 1850
Wire Wire Line
6350 1450 6300 1450
Wire Wire Line
6300 1450 6300 1550
Connection ~ 6300 1650
Wire Wire Line
6350 1550 6300 1550
Connection ~ 6300 1550
Wire Wire Line
6300 1550 6300 1650
Wire Wire Line
6900 2850 7400 2850
Wire Wire Line
6900 2950 7500 2950
Wire Wire Line
7150 1550 7400 1550
Wire Wire Line
7400 1550 7400 2850
Connection ~ 7400 2850
Wire Wire Line
7400 2850 7950 2850
Wire Wire Line
7500 1450 7500 2950
Wire Wire Line
7150 1450 7500 1450
Connection ~ 7500 2950
Wire Wire Line
7500 2950 8050 2950
$Comp
L power:GND #PWR0121
U 1 1 61DFBD18
P 7250 1850
F 0 "#PWR0121" H 7250 1600 50 0001 C CNN
F 1 "GND" H 7255 1677 50 0000 C CNN
F 2 "" H 7250 1850 50 0001 C CNN
F 3 "" H 7250 1850 50 0001 C CNN
1 7250 1850
1 0 0 -1
$EndComp
Wire Wire Line
7150 1650 7250 1650
Wire Wire Line
7250 1650 7250 1850
$Comp
L power:GND #PWR0122
U 1 1 61DEAC05
P 6000 1700
F 0 "#PWR0122" H 6000 1450 50 0001 C CNN
F 1 "GND" H 6005 1527 50 0000 C CNN
F 2 "" H 6000 1700 50 0001 C CNN
F 3 "" H 6000 1700 50 0001 C CNN
1 6000 1700
1 0 0 -1
$EndComp
$Comp
L Device:C C5
U 1 1 61DEA081
P 6000 1550
F 0 "C5" H 6115 1596 50 0000 L CNN
F 1 "10n" H 6115 1505 50 0000 L CNN
F 2 "Capacitor_SMD:C_0805_2012Metric_Pad1.18x1.45mm_HandSolder" H 6038 1400 50 0001 C CNN
F 3 "~" H 6000 1550 50 0001 C CNN
1 6000 1550
1 0 0 -1
$EndComp
$Comp
L power:+3.3V #PWR0123
U 1 1 61DEAFE2
P 6000 1400
F 0 "#PWR0123" H 6000 1250 50 0001 C CNN
F 1 "+3.3V" H 6015 1573 50 0000 C CNN
F 2 "" H 6000 1400 50 0001 C CNN
F 3 "" H 6000 1400 50 0001 C CNN
1 6000 1400
1 0 0 -1
$EndComp
$EndSCHEMATC

4
Hardware/sym-lib-table Normal file
View File

@@ -0,0 +1,4 @@
(sym_lib_table
(version 7)
(lib (name "MC33660")(type "Legacy")(uri "MC33660.lib")(options "")(descr ""))
)

8
Software/.gitignore vendored
View File

@@ -1,7 +1,5 @@
data/
.pio
.vscode/.browse.c_cpp.db*
.vscode/c_cpp_properties.json
.vscode/launch.json
.vscode/ipch
wifi_credentials.ini
.vscode
wifi_credentials.ini
__pycache__

View File

@@ -1,10 +0,0 @@
{
// See http://go.microsoft.com/fwlink/?LinkId=827846
// for the documentation about the extensions.json format
"recommendations": [
"platformio.platformio-ide"
],
"unwantedRecommendations": [
"ms-vscode.cpptools-extension-pack"
]
}

View File

@@ -1,127 +0,0 @@
Import("env") # pylint: disable=undefined-variable
env.Execute("\"$PYTHONEXE\" -m pip install jinja2")
import os
import time
from jinja2 import Environment, FileSystemLoader
import json
# Pfad zur Eingabedatei und Ausgabedatei
input_file = "src/dtc_defs.txt"
output_file = "include/dtc_defs.h"
json_output_file = "data_src/static/dtc_table.json"
# Überprüfen, ob das Verzeichnis existiert, andernfalls erstellen
json_output_dir = os.path.dirname(json_output_file)
if not os.path.exists(json_output_dir):
os.makedirs(json_output_dir)
# Mehrdimensionales Array zum Speichern der Zeilen aus der Eingabedatei
dtc_lines = []
# Lesen und analysieren der Eingabedatei
with open(input_file, "r", encoding="utf-8") as f:
for line in f:
line = line.strip()
if not line or line.startswith("#"):
continue
parts = line.split(";")
if len(parts) == 5:
num, dtc_name, dtc_severity, title, description = [part.strip() for part in parts]
dtc_lines.append([int(num), dtc_name, dtc_severity, title, description])
# Überprüfen auf Duplikate in den DTC-Nummern und DTC-Namen
num_set = set()
dtc_name_set = set()
duplicates = []
for line in dtc_lines:
num, dtc_name, _, _, _ = line
if num in num_set:
duplicates.append(f"DTC-Nummer {num} ist ein Duplikat.")
else:
num_set.add(num)
if dtc_name in dtc_name_set:
duplicates.append(f"DTC-Name '{dtc_name}' ist ein Duplikat.")
else:
dtc_name_set.add(dtc_name)
if duplicates:
for duplicate in duplicates:
print(f"Fehler: {duplicate}")
raise ValueError("Duplicate DTC Data detected")
# Suchen nach DTC_NO_DTC und DTC_LAST_DTC
dtc_no_dtc_added = False
dtc_last_dtc_line = None
for line in dtc_lines:
_, dtc_name, _, _, _ = line
if dtc_name == "DTC_NO_DTC":
dtc_no_dtc_added = True
elif dtc_name == "DTC_LAST_DTC":
dtc_last_dtc_line = line
# Einen DTC für DTC_NO_DTC hinzufügen (wenn nicht vorhanden)
if not dtc_no_dtc_added:
dtc_lines.insert(0, [0, "DTC_NO_DTC", "DTC_NONE", "No Error", "No Error"])
# Falls DTC_LAST_DTC existiert, lösche es
if dtc_last_dtc_line:
dtc_lines.remove(dtc_last_dtc_line)
# Einen DTC für DTC_LAST_DTC hinzufügen (mit der höchsten Nummer)
if dtc_lines:
highest_num = max([line[0] for line in dtc_lines])
else:
highest_num = 0
dtc_lines.append([highest_num + 1, "DTC_LAST_DTC", "DTC_NONE", "Last Error", "Last Error"])
# Sortieren der Zeilen nach der Nummer aufsteigend
dtc_lines.sort(key=lambda x: x[0])
# DTC_NAME_CONSTANT-Makros initialisieren
dtc_macros = []
dtc_structs = []
dtc_table_data = []
# Verarbeiten der sortierten Zeilen
for i, line in enumerate(dtc_lines):
num, dtc_name, dtc_severity, title, description = line
dtc_macros.append(f"#define {dtc_name:<30} {num}")
comma = "," if i < len(dtc_lines) - 1 else " "
dtc_structs.append(f" {{ {dtc_name:<30}, {dtc_severity:<12} }}{comma} // {description}")
dtc_table_data.append({"num": num, "title": title, "description": description})
# Unix-Zeitstempel hinzufügen
timestamp = int(time.time())
env = Environment(loader=FileSystemLoader('include', encoding='utf-8'))
# Lade das Jinja2-Template aus der Datei
template = env.get_template('dtc_defs.h.j2')
# Erstelle ein Context-Dictionary mit den erforderlichen Daten
context = {
'timestamp_unix': timestamp,
'timestamp' : time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(timestamp)),
'dtc_macros': dtc_macros, # Übergebe die dtc_macros-Liste direkt
'dtc_structs': dtc_structs, # Übergebe die dtc_structs-Liste direkt
}
# Rendere das Template mit den Werten und erhalte den Header-Text
header_text = template.render(context)
# Schreibe den generierten Header-Text in die Header-Datei
with open(output_file, "w", encoding='utf-8') as f:
f.write(header_text)
print(f"Header-Datei wurde erstellt: {output_file}")
# JSON-Datei mit UTF-8-Zeichencodierung erstellen
with open(json_output_file, 'w', encoding='utf-8') as json_f:
json.dump(dtc_table_data, json_f, ensure_ascii=False, indent=4, separators=(',', ': '))
print(f"JSON-Datei wurde erstellt: {json_output_file}")

145
Software/codegen/dtcs.py Normal file
View File

@@ -0,0 +1,145 @@
import os
import time
from jinja2 import Environment, FileSystemLoader
import json
import sys
import filechecksum as fcs
def build_dtcs():
# Pfad zur Eingabedatei und Ausgabedatei
input_file = "src/dtc_defs.txt"
output_file = "include/dtc_defs.h"
json_output_file = "data_src/static/dtc_table.json"
# Überprüfen, ob das Verzeichnis existiert, andernfalls erstellen
json_output_dir = os.path.dirname(json_output_file)
if not os.path.exists(json_output_dir):
os.makedirs(json_output_dir)
# Mehrdimensionales Array zum Speichern der Zeilen aus der Eingabedatei
dtc_lines = []
# Lesen und analysieren der Eingabedatei
with open(input_file, "r", encoding="utf-8") as f:
for line in f:
line = line.strip()
if not line or line.startswith("#"):
continue
parts = line.split(";")
if len(parts) == 5:
num, dtc_name, dtc_severity, title, description = [part.strip() for part in parts]
dtc_lines.append([int(num), dtc_name, dtc_severity, title, description])
# Überprüfen auf Duplikate in den DTC-Nummern und DTC-Namen
num_set = set()
dtc_name_set = set()
duplicates = []
for line in dtc_lines:
num, dtc_name, _, _, _ = line
if num in num_set:
duplicates.append(f"DTC-Nummer {num} ist ein Duplikat.")
else:
num_set.add(num)
if dtc_name in dtc_name_set:
duplicates.append(f"DTC-Name '{dtc_name}' ist ein Duplikat.")
else:
dtc_name_set.add(dtc_name)
if duplicates:
for duplicate in duplicates:
print(f"Fehler: {duplicate}")
raise ValueError("Duplicate DTC Data detected")
# Suchen nach DTC_NO_DTC und DTC_LAST_DTC
dtc_no_dtc_added = False
dtc_last_dtc_line = None
for line in dtc_lines:
_, dtc_name, _, _, _ = line
if dtc_name == "DTC_NO_DTC":
dtc_no_dtc_added = True
elif dtc_name == "DTC_LAST_DTC":
dtc_last_dtc_line = line
# Einen DTC für DTC_NO_DTC hinzufügen (wenn nicht vorhanden)
if not dtc_no_dtc_added:
dtc_lines.insert(0, [0, "DTC_NO_DTC", "DTC_NONE", "No Error", "No Error"])
# Falls DTC_LAST_DTC existiert, lösche es
if dtc_last_dtc_line:
dtc_lines.remove(dtc_last_dtc_line)
# Einen DTC für DTC_LAST_DTC hinzufügen (mit der höchsten Nummer)
if dtc_lines:
highest_num = max([line[0] for line in dtc_lines])
else:
highest_num = 0
dtc_lines.append([highest_num + 1, "DTC_LAST_DTC", "DTC_NONE", "Last Error", "Last Error"])
# Sortieren der Zeilen nach der Nummer aufsteigend
dtc_lines.sort(key=lambda x: x[0])
checksum = fcs.calculate_checksum(dtc_lines)
timestamp = int(time.time())
if fcs.read_and_compare_checksum(output_file, checksum):
print("Keine Änderungen im DTC-Headerfile erforderlich.")
else:
# DTC_NAME_CONSTANT-Makros initialisieren
dtc_macros = []
dtc_structs = []
# Verarbeiten der sortierten Zeilen
for i, line in enumerate(dtc_lines):
num, dtc_name, dtc_severity, title, description = line
dtc_macros.append(f"#define {dtc_name:<30} {num}")
comma = "," if i < len(dtc_lines) - 1 else " "
dtc_structs.append(f" {{ {dtc_name:<30}, {dtc_severity:<12} }}{comma} // {description}")
env = Environment(loader=FileSystemLoader('codegen/templates', encoding='utf-8'))
# Lade das Jinja2-Template aus der Datei
template = env.get_template('dtc_defs.h.j2')
# Erstelle ein Context-Dictionary mit den erforderlichen Daten
context = {
'timestamp_unix': timestamp,
'timestamp' : time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(timestamp)),
'date' : time.strftime('%d.%m.%Y', time.localtime(timestamp)),
'dtc_macros': dtc_macros, # Übergebe die dtc_macros-Liste direkt
'dtc_structs': dtc_structs, # Übergebe die dtc_structs-Liste direkt
'checksum' : checksum
}
# Rendere das Template mit den Werten und erhalte den Header-Text
header_text = template.render(context)
# Schreibe den generierten Header-Text in die Header-Datei
with open(output_file, "w", encoding='utf-8') as f:
f.write(header_text)
print(f"Header-Datei wurde erstellt: {output_file}")
if fcs.read_and_compare_json_checksum(json_output_file, checksum):
print("Keine Änderungen im DTC-JSON-file erforderlich.")
else:
dtc_info = {
"codegenerator_checksum": checksum,
'timestamp' : time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(timestamp)),
"dtc_table_data": []
}
# Verarbeiten der sortierten Zeilen
for i, line in enumerate(dtc_lines):
num, dtc_name, dtc_severity, title, description = line
dtc_info["dtc_table_data"].append({"num": num, "title": title, "description": description})
# JSON-Datei mit UTF-8-Zeichencodierung erstellen
with open(json_output_file, 'w', encoding='utf-8') as json_f:
json.dump(dtc_info, json_f, ensure_ascii=False, indent=4, separators=(',', ': '))
print(f"JSON-Datei wurde erstellt: {json_output_file}")

View File

@@ -0,0 +1,45 @@
import hashlib
import json
# Funktion zum Berechnen der SHA-256-Checksumme
def calculate_checksum(data):
sha256 = hashlib.sha256()
sha256.update(str(data).encode('utf-8'))
return sha256.hexdigest()
# Funktion zum Lesen und Vergleichen der Checksumme in einer Datei
def read_and_compare_checksum(file_path, expected_checksum):
try:
with open(file_path, 'r') as file:
content = file.read()
# Suche nach der Zeile mit der Checksumme
checksum_line_start = content.find("// CODEGENERATOR_CHECKSUM:")
if checksum_line_start != -1:
# Extrahiere die Checksumme aus der Zeile
existing_checksum = content[checksum_line_start + len("// CODEGENERATOR_CHECKSUM:"):].strip()
# Vergleiche die Checksummen
if existing_checksum == expected_checksum:
return True
except FileNotFoundError:
pass # Datei existiert nicht, was nicht schlimm ist
return False
def read_and_compare_json_checksum(json_file_path, expected_checksum):
try:
with open(json_file_path, 'r') as json_file:
# Lade das JSON aus der Datei
data = json.load(json_file)
# Überprüfe, ob "codegenerator_checksum" im JSON vorhanden ist
if "codegenerator_checksum" in data:
existing_checksum = data["codegenerator_checksum"]
# Vergleiche die Checksummen
if existing_checksum == expected_checksum:
return True
except FileNotFoundError:
pass # Datei existiert nicht, was nicht schlimm ist
return False

View File

@@ -7,14 +7,26 @@ import shutil
import gzip
import os
import subprocess
import platform
Import("env")
Import("projenv")
# Setze die Pfade zu den Tools als Variablen
html_minifier_path = os.path.join(os.getenv("APPDATA"), "npm", "html-minifier.cmd")
uglifyjs_path = os.path.join(os.getenv("APPDATA"), "npm", "uglifyjs.cmd")
terser_path = os.path.join(os.getenv("APPDATA"), "npm", "terser.cmd")
cssnano_path = os.path.join(os.getenv("APPDATA"), "npm", "cssnano.cmd")
# Überprüfe die Betriebssystemplattform
if platform.system() == "Windows":
# Setze die Pfade zu den Tools für Windows
html_minifier_path = os.path.join(os.getenv("APPDATA"), "npm", "html-minifier.cmd")
uglifyjs_path = os.path.join(os.getenv("APPDATA"), "npm", "uglifyjs.cmd")
terser_path = os.path.join(os.getenv("APPDATA"), "npm", "terser.cmd")
cssnano_path = os.path.join(os.getenv("APPDATA"), "npm", "cssnano.cmd")
elif platform.system() == "Linux":
# Setze die Namen der Tools für Linux
html_minifier_path = "html-minifier"
uglifyjs_path = "uglifyjs"
terser_path = "terser"
cssnano_path = "cssnano"
else:
# Hier könntest du weitere Bedingungen für andere Betriebssysteme hinzufügen
raise Exception("Unterstütztes Betriebssystem nicht erkannt")
def minify_html(input_path, output_path):

View File

@@ -0,0 +1,9 @@
Import("env") # pylint: disable=undefined-variable
env.Execute("\"$PYTHONEXE\" -m pip install jinja2")
env.Replace(PROGNAME="firmware_pcb_1.%s.fw" % env.GetProjectOption("custom_pcb_revision"))
import struct2json
import dtcs
struct2json.struct2json()
dtcs.build_dtcs()

View File

@@ -0,0 +1,113 @@
import os
import time
from jinja2 import Environment, FileSystemLoader
import re
import filechecksum as fcs
# Pfad zur Eingabedatei und Ausgabedatei
input_file = "include/config.h"
output_sourcefile = "src/struct2json.cpp"
output_headerfile = "include/struct2json.h"
# Liste der zu suchenden Variablen/Structs
variable_names = ['LubeConfig', 'PersistenceData']
def get_types(file_content, variable_names):
result = {}
# Entferne Kommentare, um unerwünschte Störungen zu vermeiden
file_content = re.sub(r'\/\*.*?\*\/', '', file_content, flags=re.DOTALL)
file_content = re.sub(r'\/\/.*', '', file_content)
for var_name in variable_names:
# Erstelle ein reguläres Ausdrucksmuster, um den Typ der Variable zu extrahieren
pattern = re.compile(r'\b(?:extern\s+)?(\w+)\s+' + re.escape(var_name) + r'\s*;')
match = pattern.search(file_content)
if match:
# Extrahiere den Typ aus dem Treffer
type_match = match.group(1)
result[var_name] = type_match
return result
def extract_struct_fields(file_content, variable_types):
result = {}
# Entferne Kommentare, um unerwünschte Störungen zu vermeiden
file_content = re.sub(r'\/\*.*?\*\/', '', file_content, flags=re.DOTALL)
file_content = re.sub(r'\/\/.*', '', file_content)
for var_name, var_type in variable_types.items():
# Erstelle ein reguläres Ausdrucksmuster, um das Strukturfeld zu extrahieren
pattern = re.compile(r'typedef\s+struct\s*{([^}]*)}\s*' + re.escape(var_type) + r'\s*;')
match = pattern.search(file_content)
if match:
# Extrahiere die Felder aus dem Treffer
fields_match = re.findall(r'\b(\w+)\s+(\w+)(?:\[(\d+)\])?\s*;', match.group(1))
if fields_match:
result[var_name] = {'type': var_type, 'fields': {}}
for field_type, field_name, array_size in fields_match:
if array_size:
result[var_name]['fields'][field_name] = {'type': field_type, 'size': int(array_size)}
else:
result[var_name]['fields'][field_name] = {'type': field_type}
return result
def struct2json():
# Überprüfen, ob die Verzeichnisse existieren, andernfalls erstellen
output_dir_source = os.path.dirname(output_sourcefile)
if not os.path.exists(output_dir_source):
os.makedirs(output_dir_source)
output_dir_header = os.path.dirname(output_headerfile)
if not os.path.exists(output_dir_header):
os.makedirs(output_dir_header)
# Unix-Zeitstempel hinzufügen
timestamp = int(time.time())
# Parse structs
with open(input_file, 'r') as file:
content = file.read()
variable_types = get_types(content, variable_names)
structs = extract_struct_fields(content, variable_types)
checksum = fcs.calculate_checksum(structs)
env = Environment(loader=FileSystemLoader('codegen/templates', encoding='utf-8'))
# Lade das Jinja2-Template aus der Datei
template_c = env.get_template('struct2json.cpp.j2')
template_h = env.get_template('struct2json.h.j2')
# Erstelle ein Context-Dictionary mit den erforderlichen Daten
context = {
'timestamp_unix': timestamp,
'timestamp' : time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(timestamp)),
'date' : time.strftime('%d.%m.%Y', time.localtime(timestamp)),
'structs': structs,
'checksum': checksum
}
# Überprüfe, ob die Checksummen übereinstimmen
if fcs.read_and_compare_checksum(output_sourcefile, checksum):
print("Keine Änderungen in der Source-Datei erforderlich.")
else:
# Rendere das Template mit den Werten und erhalte den Source-Text
source_text = template_c.render(context)
# Schreibe den generierten Source-Text in die Source-Datei
with open(output_sourcefile, "w", encoding='utf-8') as f:
f.write(source_text)
print(f"Source-Datei wurde erstellt: {output_sourcefile}")
# Überprüfe, ob die Checksummen übereinstimmen
if fcs.read_and_compare_checksum(output_headerfile, checksum):
print("Keine Änderungen in der Header-Datei erforderlich.")
else:
# Rendere das Template mit den Werten und erhalte den Header-Text
header_text = template_h.render(context)
# Schreibe den generierten Header-Text in die Header-Datei
with open(output_headerfile, "w", encoding='utf-8') as f:
f.write(header_text)
print(f"Header-Datei wurde erstellt: {output_headerfile}")

View File

@@ -0,0 +1,54 @@
/**
* @file dtc_defs.h
*
* @brief Header file for Diagnostic Trouble Code (DTC) definitions in the ChainLube application.
*
* This file contains definitions for Diagnostic Trouble Codes (DTC) in the ChainLube project.
* It includes enums for DTC active status, severity levels, and specific DTC codes.
* The file also defines an array of DTC definitions and a timestamp indicating the generation time.
*
* @note This file is auto-generated by a script on {{ timestamp }}.
*
* @author Marcel Peterkau
* @date {{ date }}
*/
#ifndef DTC_DEFS_H
#define DTC_DEFS_H
#include <stdint.h>
typedef uint32_t DTCNum_t;
typedef enum
{
DTC_INACTIVE,
DTC_ACTIVE,
DTC_PREVIOUS
} DTCActive_t;
typedef enum
{
DTC_NONE,
DTC_INFO,
DTC_WARN,
DTC_CRITICAL
} DTCSeverity_t;
typedef struct {
DTCNum_t code;
DTCSeverity_t severity;
} DTC_t;
{% for dtc in dtc_macros -%}
{{ dtc }}
{% endfor %}
const DTC_t dtc_definitions[] = {
{% for struct in dtc_structs -%}
{{ struct }}
{% endfor -%}
};
#endif // DTC_DEFS_H
// CODEGENERATOR_CHECKSUM: {{ checksum }}

View File

@@ -0,0 +1,25 @@
/**
* @file struct2json.cpp
*
* @brief Implementation file for converting structs to JSON objects.
*
* @note This file is auto-generated by a script on {{ timestamp }}.
*
* @author Marcel Peterkau
* @date {{ date }}
*/
#include "struct2json.h"
{% for var_name, var_info in structs.items() -%}
void generateJsonObject_{{ var_name }}(JsonObject data)
{
{% for field_name, field_type in var_info['fields'].items() -%}
data["{{ field_name }}"] = {{ var_name }}.{{ field_name }};
{% endfor -%}
}
{% endfor %}
// CODEGENERATOR_CHECKSUM: {{ checksum }}

View File

@@ -0,0 +1,26 @@
/**
* @file struct2json.h
*
* @brief Header file for converting structs to JSON objects.
*
* @note This file is auto-generated by a script on {{ timestamp }}.
*
* @author Marcel Peterkau
* @date {{ date }}
*/
#ifndef _STRUCT2JSON_H_
#define _STRUCT2JSON_H_
#include <Arduino.h>
#include <ArduinoJson.h>
#include "config.h"
{% for var_name, var_info in structs.items() -%}
void generateJsonObject_{{ var_name }}(JsonObject data);
{% endfor %}
#endif /* _STRUCT2JSON_H_ */
// CODEGENERATOR_CHECKSUM: {{ checksum }}

View File

@@ -12,7 +12,7 @@
<script src="static/js/bootstrap.min.js"></script>
<script src="static/js/websocket.js"></script>
<script src="static/js/dtc_table.js"></script>
<script src="static/js/script.js" type="text/javascript"></script>
<script src="static/js/script.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">
@@ -20,7 +20,17 @@
</head>
<body>
<!-- Connection-Overlay -->
<div id="overlay">
<div class="overlay-content">
<p>Verbinde...</p>
<span class="loader"></span>
</div>
</div>
<!-- Connection-Overlay -->
<!-- Notification-Container -->
<div id="notification-container" class="notification-container"></div>
<!-- Notification-Container -->
<nav class="navbar fixed-top navbar-dark bg-primary" id="navbar1">
<a class="navbar-brand" href="#">
<img src="static/img/logo.png" width="30" height="30" class="d-inline-block align-top mr-1" alt="">
@@ -37,7 +47,6 @@
<li class="nav-item"><a class="nav-link active" role="tab" data-toggle="tab" href="#tab_home">Home</a></li>
<li class="nav-item"><a class="nav-link" role="tab" data-toggle="tab" href="#tab_maintenance">Wartung</a></li>
<li class="nav-item"><a class="nav-link" role="tab" data-toggle="tab" href="#tab_source">Einstellungen</a></li>
<li class="nav-item"><a class="nav-link" role="tab" data-toggle="tab" href="#tab_sysinfo">Systeminfo</a></li>
<li class="nav-item"><a class="nav-link" role="tab" data-toggle="tab" href="#tab_fwupdate">Update</a></li>
</ul>
@@ -61,9 +70,9 @@
<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 id="tankremain" class="data-tankremain progress-bar text-light" role="progressbar" aria-valuenow="0"
aria-valuemin="0" aria-valuemax="100" style="width: 0%">
0
</div>
</div>
</p>
@@ -72,7 +81,7 @@
<hr />
<p>
<h4>aktueller Modus</h4>
<input class="form-control" type="text" id="SystemStatus" readonly>
<input class="data-systemstatus form-control" type="text" id="sysstatus" readonly>
</p>
<!-- Div Group current Mode -->
<!-- Div Group DTC Table -->
@@ -103,37 +112,33 @@
<hr />
<p>
<h4>&Ouml;lvorrat</h4>
<form action="post.htm" method="POST" class="form-horizontal">
<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 id="tankremain_maint" class="data-tankremain progress-bar text-light" role="progressbar"
aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"
style="width: 0%">0%
</div>
</div>
</div>
</div>
<div class="form-group row">
<div class="col text-center">
<button name="resettank" type="submit" class="btn btn-outline-primary ml-2">Tank zurücksetzen</button>
<button id="resettank" class="btn-wsevent confirm btn btn-outline-primary ml-2">Tank zurücksetzen</button>
</div>
</div>
</form>
</p>
<!-- Div Group Tank remain -->
<!-- Div Group Purging -->
<hr />
<p>
<h4>Entl&uuml;ftung</h4>
<form action="post.htm" method="POST" class="form-horizontal">
<div class="form-group row">
<label for="BleedingPulses" class="control-label col-4">Entl&uuml;ftung Dosierung</label>
<label for="bleedingpulses" class="control-label col-4">Entl&uuml;ftung Dosierung</label>
<div class="col-8">
<div class="input-group">
<input id="BleedingPulses" name="BleedingPulses" value="0" type="text" class="form-control">
<input id="bleedingpulses" value="0" type="text" class="set-wsevent data-bleedingpulses form-control">
<div class="input-group-append">
<span class="input-group-text">Pulse</span>
</div>
@@ -142,11 +147,9 @@
</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>
<button id="purgenow" class="btn-wsevent btn btn-outline-primary ml-2">Entlüftung starten</button>
</div>
</div>
</form>
</p>
<!-- Div Group Purging -->
<!-- Div Group Measure -->
@@ -154,13 +157,11 @@
<hr />
<p>
<h4>Einmessen</h4>
<form action="post.htm" method="POST" class="form-horizontal">
<div class="form-group row">
<label for="measuredpulses" class="control-label col-4">erfasste Pulse</label>
<div class="col-8">
<div class="input-group">
<input id="measuredpulses" name="measuredpulses" value="%MEASURED_PULSES%" type="text" readonly
class="form-control">
<input id="measuredpulses" name="measuredpulses" value="0" type="text" readonly class="form-control">
<div class="input-group-append">
<span class="input-group-text">Pulse</span>
</div>
@@ -169,65 +170,37 @@
</div>
<div class="form-group row">
<div class="col text-center">
<button name="measurestartstop" type="submit" class="btn btn-outline-primary">%MEASURE_BTN%</button>
<button name="measurereset" type="submit" class="btn btn-outline-primary ml-2">Reset</button>
<button id="measurestartstop" class="btn-wsevent btn btn-outline-primary">Start</button>
<button id="measurereset" class="btn-wsevent btn btn-outline-primary ml-2">Reset</button>
</div>
</div>
</form>
</p>
</div>
<!-- Div Group Purging -->
<!-- Div Group EEPROM formatting -->
<!-- Div Group LiveDebug -->
<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)
<h4>Live Debug</h4>
<div class="form-group row">
<textarea class="form-control" spellcheck="false" id="livedebug-out" rows="3" readonly></textarea>
</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 class="form-group row">
<div class="col text-center">
<button id="debugstart" class="btn-wsevent btn btn-outline-primary ml-2">Start</button>
<button id="debugstop" class="btn-wsevent btn btn-outline-primary ml-2">Stop</button>
</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>
</div>
</p>
<!-- Div Group EEPROM formatting -->
<!-- Div Group LiveDebug -->
<!-- Div Group Device Reboot -->
<hr />
<p>
<h4>Ger&auml;t neustarten</h4>
<form action="post.htm" method="POST" class="form-horizontal">
<div class="form-group row">
<div class="col text-center">
<button name="reboot" type="submit" class="btn btn-outline-primary">Reboot</button>
<button id="reboot" class="btn-wsevent confirm btn btn-outline-primary">Reboot</button>
</div>
</div>
</form>
</p>
<!-- Div Group Device Reboot -->
</div>
@@ -240,12 +213,13 @@
<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>
<label for="speedsource" class="control-label col-4">Schnittstelle</label>
<div class="col-8">
<select id="sourceselect" name="sourceselect" class="select form-control">
%SOURCE_SELECT_OPTIONS%
<select id="speedsource" class="set-wsevent data-speedsource select form-control">
<option value="Impuls">Impuls</option>
<option value="GPS">GPS</option>
<option value="CAN-Bus">CAN-Bus</option>
</select>
</div>
</div>
@@ -259,25 +233,21 @@
</div>
<div class="form-group row">
<div class="col text-center">
<button name="sourcesave" type="submit" class="btn btn-outline-primary">&Uuml;bernehmen</button>
<button id="sourcesave" class="btn-wsevent confirm btn btn-outline-primary">&Uuml;bernehmen</button>
</div>
</div>
</form>
</p>
<!-- Div Group Signal Source -->
<!-- Div Group Source:Impulse Settings-->
<div %SHOW_IMPULSE_SETTINGS%>
<div id="showimpulse" class="data-showimpulse hideable">
<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%">
<input id="tirewidth" type="text" required="required" class="set-wsevent data-tirewidth form-control">
<div class="input-group-append">
<span class="input-group-text">mm</span>
</div>
@@ -289,8 +259,7 @@
<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%">
<input id="tireratio" type="text" required="required" class="set-wsevent data-tireratio form-control">
<div class="input-group-append">
<span class="input-group-text">mm</span>
</div>
@@ -301,8 +270,7 @@
<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%">
<input id="tiredia" type="text" required="required" class="set-wsevent data-tiredia form-control">
<div class="input-group-append">
<span class="input-group-text">"</span>
</div>
@@ -313,64 +281,43 @@
<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%">
<input id="pulserev" type="text" required="required" class="set-wsevent data-pulserev form-control">
<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>
</div>
<!-- Div Group Source:Impulse Settings-->
<!-- Div Group Source:CAN Settings-->
<div %SHOW_CAN_SETTINGS%>
<div id="showcan" class="data-showcan hideable">
<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 id="cansource" class="set-wsevent data-cansource select form-control">
<option value="KTM 890 Adventure R (2021)">KTM 890 Adventure R (2021)</option>
<option value="KTM 1290 Superduke R (2023)">KTM 1290 Superduke R (2023)</option>
</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>
</div>
<!-- Div Group Source:CAN Settings-->
<!-- Div Group Source:GPS Settings-->
<div %SHOW_GPS_SETTINGS%>
<div id="showgps" class="data-showgps hideable">
<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 id="gpsbaud" class="set-wsevent data-gpsbaud select form-control">
</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>
</div>
<!-- Div Group Source:GPS Settings-->
@@ -378,13 +325,12 @@
<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">
<input id="lubedistancenormal" type="text"
class="set-wsevent data-lubedistancenormal form-control" required="required">
<div class="input-group-append">
<span class="input-group-text">m</span>
</div>
@@ -395,32 +341,25 @@
<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">
<input id="lubedistancerain" type="text"
class="set-wsevent data-lubedistancerain 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>
<!-- Div Group Lube Settings-->
<!-- Div Group Oiltank Settings -->
<hr />
<p>
<h4>&Ouml;ltank</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"
<input id="tankcap" type="text" class="set-wsevent data-tankcap form-control"
required="required">
<div class="input-group-append">
<span class="input-group-text">ml</span>
@@ -432,7 +371,7 @@
<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"
<input id="tankwarn" type="text" class="set-wsevent data-tankwarn form-control"
required="required">
<div class="input-group-append">
<span class="input-group-text">&#37;</span>
@@ -444,7 +383,7 @@
<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"
<input id="pumppulse" type="text" class="set-wsevent data-pumppulse form-control"
required="required">
<div class="input-group-append">
<span class="input-group-text">µl</span>
@@ -452,24 +391,17 @@
</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>
<!-- Div Group Oiltank Settings -->
<!-- Div Group LED Settings-->
<hr />
<p>
<h4>LED Einstellungen</h4>
<form action="post.htm" method="POST" class="form-horizontal">
<div class="form-group row">
<label for="ledmodeflash" class="control-label col-4">LED Modus blinken</label>
<div class="col-8">
<div class="form-check">
<input class="form-check-input" type="checkbox" name="ledmodeflash" id="ledmodeflash" %LEDFLASHCHECKED%>
<input class="set-wsevent data-ledmodeflash form-check-input" type="checkbox" id="ledmodeflash">
<label class="form-check-label" for="ledmodeflash">
LED blinken
</label>
@@ -480,8 +412,7 @@
<label for="ledmaxbrightness" class="control-label col-4">Max Helligkeit</label>
<div class="col-8">
<div class="input-group">
<input id="ledmaxbrightness" name="ledmaxbrightness" value="%LED_MAX_BRIGHTNESS%" type="text"
class="form-control" required="required">
<input id="ledmaxbrightness" type="text" class="set-wsevent data-ledmaxbrightness form-control" required="required">
</div>
</div>
</div>
@@ -489,187 +420,59 @@
<label for="ledminbrightness" class="control-label col-4">Min Helligkeit</label>
<div class="col-8">
<div class="input-group">
<input id="ledminbrightness" name="ledminbrightness" value="%LED_MIN_BRIGHTNESS%" type="text"
class="form-control" required="required">
<input id="ledminbrightness" type="text" class="set-wsevent data-ledminbrightness form-control" required="required">
</div>
</div>
</div>
</p>
<!-- Div Group LED Settings-->
<!-- Div Group WiFi Settings-->
<hr />
<p>
<h4>WiFi Einstellungen</h4>
<div class="form-group row">
<label for="wifi-ssid" class="control-label col-4">WiFi SSID</label>
<div class="col-8">
<select id="wifi-ssid" class="set-wsevent data-wifi-ssid select form-control">
</select>
</div>
</div>
<div class="form-group row">
<label for="wifi-pass" class="control-label col-4">WiFi Passwort</label>
<div class="col-8">
<div class="input-group" id="show_hide_password">
<input id="wifi-pass" type="password" minlength="8" maxlength="63" class="set-wsevent data-wifi-pass form-control">
<div class="input-group-addon">
<a href=""><i class="fa fa-eye-slash" aria-hidden="true"></i></a>
</div>
</div>
</div>
</div>
<div class="form-group row">
<div class="col text-center">
<button name="ledsave" type="submit" class="btn btn-outline-primary">Speichern</button>
<label for="wifi-conavailable" class="control-label col-4">automatisch verbinden</label>
<div class="col-8">
<div class="form-check">
<input class="set-wsevent data-wifi-conavailable form-check-input" type="checkbox" id="wifi-conavailable">
<label class="form-check-label" for="wifi-conavailable">
verbinden wenn verfügbar
</label>
</div>
</div>
</div>
</p>
<!-- Div Group WiFi Settings-->
<!-- Div Group Save Button-->
<hr />
<p>
<div class="form-group row">
<div class="col text-center">
<button id="settingssave" class="btn-wsevent btn btn-outline-primary">Speichern</button>
</div>
</div>
</form>
</p>
<!-- Div Group Lube Settings-->
</div>
<!-- Div Tab Settings -->
<!-- Div Tab SystemInfo -->
<div id="tab_sysinfo" class="tab-pane fade" role="tabpanel">
<h3>Systeminfo</h3>
<!-- Div Group Sysinfo:Geraeteinfo -->
<hr />
<p>
<h4>Ger&auml;t</h4>
<table class="table">
<tbody>
<tr>
<th class="col-7" scope="col">Parameter</td>
<th class="col-5" scope="col">Value</td>
</tr>
<tr>
<td>Hostname</td>
<td>%HOSTNAME%</td>
</tr>
</table>
</p>
<!-- Div Group Sysinfo:Geraeteinfo -->
<!-- Div Group Sysinfo:Settings -->
<hr />
<p>
<h4>Einstellungen</h4>
<table class="table">
<tbody>
<tr>
<th class="col-7" scope="col">Parameter</td>
<th class="col-5" scope="col">Value</td>
</tr>
<tr>
<td>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>LED Mode Flash</td>
<td>%LED_MODE_FLASH%</td>
</tr>
<tr>
<td>LED Max Brightness</td>
<td>%LED_MAX_BRIGHTNESS%</td>
</tr>
<tr>
<td>LED Min Brightness</td>
<td>%LED_MIN_BRIGHTNESS%</td>
</tr>
<tr>
<td>EEPROM Version</td>
<td>%EEPROM_VERSION%</td>
</tr>
<tr>
<td>Checksum</td>
<td>%CONFIG_CHECKSUM%</td>
</tr>
</tbody>
</table>
</p>
<!-- Div Group Sysinfo:Settings -->
<!-- Div Group Sysinfo:Persistance -->
<hr />
<p>
<h4>Betriebsdaten</h4>
<table class="table">
<tbody>
<tr>
<th class="col-7" scope="col">Parameter</td>
<th class="col-5" scope="col">Value</td>
</tr>
<tr>
<td>writeCycleCounter</td>
<td>%WRITE_CYCLE_COUNT%</td>
</tr>
<tr>
<td>PersistenceMarker</td>
<td>%PERSISTENCE_MARKER%</td>
</tr>
<tr>
<td>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 Group Sysinfo:Persistance -->
<!-- Div Group LiveDebug -->
<hr />
<p>
<h4>Live Debug</h4>
<div class="form-group row">
<textarea class="form-control" spellcheck="false" id="livedebug-out" rows="3" readonly></textarea>
</div>
<div class="form-group row">
<div class="col text-center">
<button id="btn-ws-start" class="btn btn-outline-primary">Start</button>
<button id="btn-ws-stop" class="btn btn-outline-primary ml-2">Stop</button>
</div>
</div>
</p>
<!-- Div Group LiveDebug -->
</div>
<!-- Div Tab SystemInfo -->
<!-- Div Tab Firmware Update-->
<div id="tab_fwupdate" class="tab-pane fade" role="tabpanel">
<h3>Firmware</h3>

View File

@@ -4075,9 +4075,9 @@ input[type=submit].btn-block {
}
.alert-success {
color: #012d36;
background-color: #ccdde1;
border-color: #b8d0d5
color: #002200;
background-color: #99ff99;
border-color: #20bb20
}
.alert-success hr {
@@ -4089,9 +4089,9 @@ input[type=submit].btn-block {
}
.alert-info {
color: #084367;
background-color: #cfe6f4;
border-color: #bcdcef
color: #000022;
background-color: #99ddff;
border-color: #2040FF
}
.alert-info hr {
@@ -4103,9 +4103,9 @@ input[type=submit].btn-block {
}
.alert-warning {
color: #07767a;
background-color: #cff9fb;
border-color: #bbf7f9
color: #222200;
background-color: #FFFF99;
border-color: #FFFF00
}
.alert-warning hr {
@@ -4117,9 +4117,9 @@ input[type=submit].btn-block {
}
.alert-danger {
color: #851929;
background-color: #ffd6dc;
border-color: #ffc5ce
color: #200000;
background-color: #ffcccc;
border-color: #AA2020
}
.alert-danger hr {

View File

@@ -25,3 +25,66 @@ hr {
padding: 10px;
}
#overlay {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.8); /* Dunkler Hintergrund mit Transparenz */
color: white; /* Textfarbe */
justify-content: center;
align-items: center;
z-index: 9999; /* Stellen Sie sicher, dass es über anderen Elementen liegt */
}
.overlay-content {
text-align: center;
font-size: 4rem;
}
.loader {
width: 96px;
height: 96px;
border: 12px solid #FFF;
border-radius: 50%;
display: inline-block;
position: relative;
box-sizing: border-box;
animation: rotation 1s linear infinite;
}
.loader::after {
content: '';
box-sizing: border-box;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
width: 120px;
height: 120px;
border-radius: 50%;
border: 12px solid transparent;
border-bottom-color: #FF3D00;
}
@keyframes rotation {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
.notification-container {
position: fixed;
top: 30%;
left: 50%;
transform: translateX(-50%);
z-index: 1000;
}
.notification {
margin-bottom: 20px; /* Fügen Sie bei Bedarf weitere Stile hinzu */
}

View File

@@ -1,92 +1,121 @@
[
{
"num": 0,
"title": "No Error",
"description": "No Error"
},
{
"num": 1,
"title": "Ölvorrat leer",
"description": "Ölvorrat ist komplett leer. Den Ölvorrat auffüllen und im Menu 'Wartung' zurück setzen"
},
{
"num": 2,
"title": "Ölvorrat niedrig",
"description": "Ölvorrat ist unter der Warnschwelle. Den Ölvorrat demnächst auffüllen und im Menu 'Wartung' zurück setzen"
},
{
"num": 3,
"title": "kein EEPROM erkannt",
"description": "Es wurde kein EEPROM gefunden. Dies lässt einen Hardware-Defekt vermuten."
},
{
"num": 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"
},
{
"num": 5,
"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"
},
{
"num": 6,
"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"
},
{
"num": 7,
"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"
},
{
"num": 8,
"title": "Flashspeicher Fehler",
"description": "Der Flashspeicher konnte nicht initialisiert werden. Aktualisieren sie Flash & Firmware"
},
{
"num": 9,
"title": "Flashversion falsch",
"description": "Die Version des Flashspeicher stimmt nicht mit der Firmware-Version überein. Aktualisieren sie den Flash mit der passenden Update-Datei"
},
{
"num": 10,
"title": "Keine GPS-Verbindung",
"description": "Es wurde kein GPS-Signal über die serielle Schnittstelle empfangen, Prüfen sie die Verbindung und das GPS-Modul"
},
{
"num": 11,
"title": "CAN-Transceiver Error",
"description": "Es konnte keine Verbindung zum CAN-Transceiver hergestellt werden. Prüfen Sie die Hardware auf Defekte"
},
{
"num": 12,
"title": "Keine CAN-Verbindung",
"description": "Es konnte kein CAN-Signal empfangen werden. Prüfen sie die Verbindung und die Einstellungen"
},
{
"num": 13,
"title": "Config-Validierung",
"description": "Ein oder mehrer Einstellungswerte sind ausserhalb plausibler Werte. Prüfen Sie Ihre Einstellungen"
},
{
"num": 14,
"title": "Dummy-DTC Info",
"description": "Ein Dummy-DTC der Schwere \"Info\" für Debugging-Zwecke"
},
{
"num": 15,
"title": "Dummy-DTC Warnung",
"description": "Ein Dummy-DTC der Schwere \"Warnung\" für Debugging-Zwecke"
},
{
"num": 16,
"title": "Dummy-DTC Kritisch",
"description": "Ein Dummy-DTC der Schwere \"Kritisch\" für Debugging-Zwecke"
},
{
"num": 17,
"title": "Last Error",
"description": "Last Error"
}
]
{
"codegenerator_checksum": "15e9152fb712bc6ed7c3353a05b1b54dc697f3e489a6e1ff42b7e57f0fa094d4",
"timestamp": "2025-05-04 12:01:55",
"dtc_table_data": [
{
"num": 0,
"title": "No Error",
"description": "No Error"
},
{
"num": 1,
"title": "Ölvorrat leer",
"description": "Ölvorrat ist komplett leer. Den Ölvorrat auffüllen und im Menu 'Wartung' zurück setzen"
},
{
"num": 2,
"title": "Ölvorrat niedrig",
"description": "Ölvorrat ist unter der Warnschwelle. Den Ölvorrat demnächst auffüllen und im Menu 'Wartung' zurück setzen"
},
{
"num": 3,
"title": "kein EEPROM erkannt",
"description": "Es wurde kein EEPROM gefunden. Dies lässt einen Hardware-Defekt vermuten."
},
{
"num": 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"
},
{
"num": 5,
"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"
},
{
"num": 6,
"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"
},
{
"num": 7,
"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"
},
{
"num": 8,
"title": "Flashspeicher Fehler",
"description": "Der Flashspeicher konnte nicht initialisiert werden. Aktualisieren sie Flash & Firmware"
},
{
"num": 9,
"title": "Flashversion falsch",
"description": "Die Version des Flashspeicher stimmt nicht mit der Firmware-Version überein. Aktualisieren sie den Flash mit der passenden Update-Datei"
},
{
"num": 10,
"title": "Keine GPS-Verbindung",
"description": "Es wurde kein GPS-Signal über die serielle Schnittstelle empfangen, Prüfen sie die Verbindung und das GPS-Modul"
},
{
"num": 11,
"title": "CAN-Transceiver Error",
"description": "Es konnte keine Verbindung zum CAN-Transceiver hergestellt werden. Prüfen Sie die Hardware auf Defekte"
},
{
"num": 12,
"title": "Keine CAN-Verbindung",
"description": "Es konnte kein CAN-Signal empfangen werden. Prüfen sie die Verbindung und die Einstellungen"
},
{
"num": 13,
"title": "Config-Validierung",
"description": "Ein oder mehrer Einstellungswerte sind ausserhalb plausibler Werte. Prüfen Sie Ihre Einstellungen"
},
{
"num": 14,
"title": "Dummy-DTC Info",
"description": "Ein Dummy-DTC der Schwere \"Info\" für Debugging-Zwecke"
},
{
"num": 15,
"title": "Dummy-DTC Warnung",
"description": "Ein Dummy-DTC der Schwere \"Warnung\" für Debugging-Zwecke"
},
{
"num": 16,
"title": "Dummy-DTC Kritisch",
"description": "Ein Dummy-DTC der Schwere \"Kritisch\" für Debugging-Zwecke"
},
{
"num": 17,
"title": "OBD2-KLine Timeout",
"description": "Die Anfrage über OBD2-KLine konnte nicht gesendet werden. Prüfen Sie den K-Line-Treiber (z.B. L9637D) und die Verkabelung."
},
{
"num": 18,
"title": "OBD2-CAN Timeout",
"description": "Die Anfrage an das Steuergerät über OBD2-CAN konnte nicht gesendet werden. Prüfen Sie die Verbindung zum CAN-Modul und die OBD2-Konfiguration."
},
{
"num": 19,
"title": "Keine OBD2-CAN Antwort",
"description": "Es wurde innerhalb der erwarteten Zeit keine Antwort vom Steuergerät über OBD2-CAN empfangen. Prüfen Sie, ob das Fahrzeug OBD2 unterstützt und die Verbindung korrekt ist."
},
{
"num": 20,
"title": "Keine OBD2-KLine Antwort",
"description": "Es wurde innerhalb der erwarteten Zeit keine Antwort über OBD2-KLine empfangen. Prüfen Sie die Verbindung zum Steuergerät und die Protokollkompatibilität."
},
{
"num": 21,
"title": "OBD2-KLine Antwort ungültig",
"description": "Das empfangene Frame war unvollständig oder entsprach nicht dem erwarteten OBD2-Format. Möglicherweise inkompatibles Steuergerät."
},
{
"num": 22,
"title": "Last Error",
"description": "Last Error"
}
]
}

View File

@@ -2,105 +2,100 @@ const jsonFilePath = "static/dtc_table.json";
var dtcState = {};
function processDTCNotifications(dtcArray) {
async function processDTCNotifications(dtcArray) {
if (dtcArray.length === 0 || dtcArray[0] == "0") {
dtcState = {};
return;
}
for (var i = 0; i < dtcArray.length; i++) {
var dtcInfo = dtcArray[i].split(",");
var errorCode = dtcInfo[1];
var errorCode = parseInt(dtcInfo[1]);
var activity = parseInt(dtcInfo[3]);
var severity = parseInt(dtcInfo[2]);
if (dtcState[errorCode]) {
// Überprüfen, ob sich der Zustand von "previous" auf "active" geändert hat
if (activity !== dtcState[errorCode]) {
dtcState[errorCode] = activity;
if (activity === 1) showDTCNotification(errorCode);
try {
var { title, description } = await getDescriptionForDTCNumber(errorCode);
switch (severity) {
case 1:
severity = "info";
break;
case 2:
severity = "warning";
break;
case 3:
severity = "danger";
break;
}
} else {
// DTC ist neu, Zustand speichern und Benachrichtigung anzeigen
dtcState[errorCode] = activity;
showDTCNotification(errorCode);
}
}
}
function showDTCNotification(dtctext, severity) {
// Überprüfen, ob der Browser die Notification API unterstützt
if ("Notification" in window) {
// Überprüfen, ob der Benutzer bereits Berechtigungen erteilt hat
if (Notification.permission === "granted") {
// Benachrichtigung anzeigen
showNotification(dtctext, severity);
} else if (Notification.permission !== "denied") {
// Aufforderung zur Erlaubnis einholen
Notification.requestPermission().then(function (permission) {
if (permission === "granted") {
// Benachrichtigung anzeigen
showNotification(dtctext, severity);
} else {
// Der Benutzer hat die Berechtigung abgelehnt oder das Dialogfeld geschlossen
console.log("Benachrichtigungsberechtigung wurde verweigert.");
if (dtcState[errorCode]) {
// Überprüfen, ob sich der Zustand von "previous" auf "active" geändert hat
if (activity !== dtcState[errorCode]) {
dtcState[errorCode] = activity;
if (activity === 1) showNotification(description, severity);
}
});
} else {
// Der Benutzer hat die Berechtigung bereits verweigert
console.log("Benachrichtigungsberechtigung wurde bereits verweigert.");
} else {
// DTC ist neu, Zustand speichern und Benachrichtigung anzeigen
dtcState[errorCode] = activity;
showNotification(description, severity);
}
} catch (error) {
console.error("Error processing DTC:", error);
}
}
}
// Funktion zum Anzeigen der Benachrichtigung
function showNotification(dtctext, severity) {
var severityIcon;
switch (severity) {
case 1:
severityIcon = "static/img/info.png";
break;
case 2:
severityIcon = "static/img/warn.png";
break;
case 3:
severityIcon = "static/img/critical.png";
break;
default:
severityIcon = "static/img/none.png";
function getDescriptionForDTCNumber(number) {
return new Promise((resolve, reject) => {
fetch(jsonFilePath)
.then((response) => response.json())
.then((data) => {
const dtcList = data.dtc_table_data;
const foundEntry = dtcList.find((entry) => entry.num === number);
if (foundEntry) {
const description = foundEntry.description;
const title = foundEntry.title;
resolve({ title, description });
} else {
// Wenn die Nummer nicht gefunden wurde, geben Sie einen Fehler zurück
reject(`Beschreibung für Nummer ${number} nicht gefunden.`);
}
})
.catch((error) => {
// Im Fehlerfall geben Sie den Fehler zurück
reject(error);
});
});
}
async function showDTCModal(event) {
var dtc = parseInt(event.currentTarget.getAttribute("data-dtc"));
var debugval = event.currentTarget.getAttribute("data-debugval");
var modal = $("#dtcModal");
try {
var { title, description } = await getDescriptionForDTCNumber(dtc);
modal.find(".modal-title").text(title);
modal.find(".dtc-desc").text(description);
if (debugval > 0) {
modal.find(".dtc-debugval").text("Debugvalue: " + debugval);
} else {
modal.find(".dtc-debugval").remove();
}
} catch (error) {
console.error("Fehler beim Abrufen der Beschreibung:", error);
modal.find(".modal-title").text("Fehler");
modal.find(".dtc-desc").text("DTC-Beschreibung konnte nicht geladen werden");
}
var options = {
body: dtctext,
icon: severityIcon,
};
var notification = new Notification("KTM Chain Oiler DTC", options);
// Optional: Handle Click-Event
notification.onclick = function () {
console.log("Benachrichtigung wurde angeklickt.");
};
// Modal anzeigen
modal.modal("show");
}
function getDescriptionForDTCNumber(number, callback) {
fetch(jsonFilePath)
.then((response) => response.json())
.then((data) => {
const foundEntry = data.find((entry) => entry.num === number);
if (foundEntry) {
const description = foundEntry.description;
const title = foundEntry.title;
callback(null, title, description);
} else {
// Wenn die Nummer nicht gefunden wurde, geben Sie einen Fehler zurück
callback(
`Beschreibung für Nummer ${number} nicht gefunden.`,
null,
null
);
}
})
.catch((error) => {
// Im Fehlerfall geben Sie den Fehler zurück
callback(error, null, null);
});
}
function fillDTCTable(dtcArray) {
// Referenz auf das Tabellen-Element
@@ -108,9 +103,10 @@ function fillDTCTable(dtcArray) {
var tablediv = document.getElementById("dtc_container");
// Prüfen, ob DTC vorhanden sind
if (dtcArray.length === 0) {
if (dtcArray.length === 0 || dtcArray[0] == "0") {
// Verstecke das Tabellen-Div, wenn keine DTC vorhanden sind
tablediv.hidden = true;
table.innerHTML = "";
return;
} else {
// Zeige das Tabellen-Div, wenn DTC vorhanden sind
@@ -176,6 +172,7 @@ function fillDTCTable(dtcArray) {
row.setAttribute("data-dtc", dtcInfo[1]);
row.setAttribute("data-debugval", dtcInfo[4]);
row.addEventListener("click", showDTCModal);
// Aktivität
var activityCell = row.insertCell(3);

View File

@@ -1,5 +1,20 @@
$(".navbar-nav>li>a").on("click", function () {
$(".navbar-collapse").collapse("hide");
$(document).ready(function () {
$(".navbar-nav a").on("click", function () {
$(".navbar-collapse").collapse("hide");
});
$("#show_hide_password a").on("click", function (event) {
event.preventDefault();
if ($("#show_hide_password input").attr("type") == "text") {
$("#show_hide_password input").attr("type", "password");
$("#show_hide_password i").addClass("fa-eye-slash");
$("#show_hide_password i").removeClass("fa-eye");
} else if ($("#show_hide_password input").attr("type") == "password") {
$("#show_hide_password input").attr("type", "text");
$("#show_hide_password i").removeClass("fa-eye-slash");
$("#show_hide_password i").addClass("fa-eye");
}
});
});
document
@@ -9,29 +24,3 @@ document
var nextSibling = e.target.nextElementSibling;
nextSibling.innerText = fileName;
});
$("table").on("click", "tr[data-dtc]", function () {
var dtc = $(this).data("dtc");
var debugval = $(this).data("debugval");
var modal = $("#dtcModal");
getDescriptionForDTCNumber(dtc, function (error, title, description) {
if (error) {
console.error("Fehler beim Abrufen der Beschreibung:", error);
modal.find(".modal-title").text("Fehler");
modal
.find(".dtc-desc")
.text("DTC-Beschreibung konnte nicht geladen werden");
} else {
modal.find(".modal-title").text(title);
modal.find(".dtc-desc").text(description);
if (debugval > 0) {
modal.find(".dtc-debugval").text("Debugvalue: " + debugval);
} else {
modal.find(".dtc-debugval").remove();
}
}
});
// Modal anzeigen
modal.modal("show");
});

View File

@@ -3,8 +3,13 @@ var websocket;
var statusMapping;
var staticMapping;
var overlay;
window.addEventListener("load", onLoad);
document.addEventListener("DOMContentLoaded", function () {
// Ihr JavaScript-Code hier, einschließlich der onLoad-Funktion
overlay = document.getElementById("overlay");
onLoad();
});
function initWebSocket() {
console.log("Trying to open a WebSocket connection...");
@@ -15,12 +20,27 @@ function initWebSocket() {
}
function initButtons() {
document
.getElementById("btn-ws-stop")
.addEventListener("click", livedebug_stop);
document
.getElementById("btn-ws-start")
.addEventListener("click", livedebug_start);
var elements = document.getElementsByClassName("btn-wsevent");
if (elements.length > 0) {
for (var i = 0; i < elements.length; i++) {
let element = elements[i];
element.addEventListener("click", sendButton);
}
}
}
function initSettingInputs() {
var elements = document.getElementsByClassName("set-wsevent");
if (elements.length > 0) {
for (var i = 0; i < elements.length; i++) {
let element = elements[i];
element.addEventListener("change", function () {
websocket_sendevent("set-" + element.id, element.value);
});
}
}
}
function onOpen(event) {
@@ -29,59 +49,59 @@ function onOpen(event) {
function onClose(event) {
console.log("Connection closed");
setTimeout(initWebSocket, 2000);
setTimeout(initWebSocket, 1000);
overlay.style.display = "flex";
}
function sendButton(event) {
var targetElement = event.target;
if (
targetElement.classList.contains("confirm") &&
window.confirm("Sicher?") == false
)
return;
websocket_sendevent("btn-" + targetElement.id, targetElement.value);
}
function onMessage(event) {
var data = event.data;
console.log("ws_msg:" + event.data + "\n");
if (data.startsWith("DEBUG:")) {
if (data.startsWith("NOTIFY:")) {
var notify_data = data.slice(7).split(";")[1];
var notify_type = data.slice(7).split(";")[0];
showNotification(notify_data, notify_type);
} else if (data.startsWith("DEBUG:")) {
var addtext = data.slice(6);
var livedebug_out = document.getElementById("livedebug-out");
livedebug_out.value += addtext;
livedebug_out.scrollTop = livedebug_out.scrollHeight;
do_resize(livedebug_out);
return;
}
if (data.startsWith("DTC:")) {
} else if (data.startsWith("DTC:")) {
const dtcs = data.slice(4);
const dtcArray = dtcs.trim() !== "" ? dtcs.split(";").filter(Boolean) : [];
if (dtcArray[0] != "0") {
processDTCNotifications(dtcArray);
fillDTCTable(dtcArray);
}
return;
}
processDTCNotifications(dtcArray);
fillDTCTable(dtcArray);
if (data.startsWith("MAPPING_STATUS:")) {
} else if (data.startsWith("MAPPING_STATUS:")) {
const data_sliced = data.slice(15);
statusMapping = createMapping(data_sliced);
}
if (data.startsWith("MAPPING_STATIC:")) {
} else if (data.startsWith("MAPPING_STATIC:")) {
const data_sliced = data.slice(15);
staticMapping = createMapping(data_sliced);
}
if (data.startsWith("STATUS:")) {
console.log(staticMapping);
} else if (data.startsWith("STATUS:")) {
const data_sliced = data.slice(7);
const result = processDataString(data_sliced, statusMapping);
console.log("STATUS:");
console.log(JSON.stringify(result, null, 2));
fillValuestoHTML(result);
return;
}
if (data.startsWith("STATIC:")) {
fillValuesToHTML(result);
} else if (data.startsWith("STATIC:")) {
const data_sliced = data.slice(7);
const result = processDataString(data_sliced, staticMapping);
console.log("STATIC:");
console.log(JSON.stringify(result, null, 2));
fillValuestoHTML(result);
return;
fillValuesToHTML(result);
console.log(result);
overlay.style.display = "none";
}
}
@@ -112,14 +132,12 @@ function processDataString(dataString, mapping) {
function onLoad(event) {
initWebSocket();
initButtons();
initSettingInputs();
overlay.style.display = "flex";
}
function livedebug_start() {
websocket.send("start");
}
function livedebug_stop() {
websocket.send("stop");
function websocket_sendevent(element_id, element_value) {
websocket.send(element_id + ":" + element_value);
}
function do_resize(textbox) {
@@ -139,11 +157,77 @@ function do_resize(textbox) {
else textbox.rows = rows;
}
function fillValuestoHTML(dataset) {
function fillValuesToHTML(dataset) {
for (var key in dataset) {
var inputElement = document.getElementById(key);
if (inputElement) {
inputElement.value = dataset[key];
var key_prefixed = "data-" + key;
var elements = document.getElementsByClassName(key_prefixed);
if (elements.length > 0) {
for (var i = 0; i < elements.length; i++) {
var element = elements[i];
if (element.type === "checkbox") {
// Wenn das Element ein Kontrollkästchen ist
element.checked = dataset[key] == 1 ? true : false;
} else if (element.tagName === "SELECT") {
// Wenn das Element ein Dropdown ist
setDropdownValue(element, dataset[key]);
} else if (element.classList.contains("progress-bar")) {
// Wenn das Element eine Fortschrittsleiste ist
updateProgressBar(element, dataset[key]);
} else if (element.classList.contains("hideable")) {
// Wenn das Element ein Settingsabschnitt-div ist
if (dataset[key] == 0) element.style.display = "none";
else element.style.display = "";
} else {
// Standardmäßig für Textfelder und andere Elemente
element.value = dataset[key];
}
}
}
}
}
// Funktion zum Setzen des ausgewählten Werts für Dropdowns
function setDropdownValue(selectElement, value) {
for (var i = 0; i < selectElement.options.length; i++) {
if (selectElement.options[i].value === value) {
selectElement.selectedIndex = i;
break;
}
}
}
// Funktion zum Aktualisieren der Fortschrittsleiste
function updateProgressBar(progressBar, value) {
// Wert in das aria-valuenow-Attribut einfügen
progressBar.setAttribute("aria-valuenow", value);
// Breite des Fortschrittsbalkens und inneren Text aktualisieren
progressBar.style.width = value + "%";
progressBar.textContent = value + "%";
}
function showNotification(message, type) {
// Erstellen Sie ein Bootstrap-Alert-Element
var alertElement = $(
'<div class="alert alert-' +
type +
' alert-dismissible fade show notification" role="alert">' +
"<strong>" +
message +
"</strong>" +
'<button type="button" class="close" data-dismiss="alert" aria-label="Close">' +
'<span aria-hidden="true">&times;</span>' +
"</button>" +
"</div>"
);
// Fügen Sie das Alert-Element dem Container hinzu
$("#notification-container").append(alertElement);
// Nach 5 Sekunden das Alert-Element ausblenden
setTimeout(function () {
alertElement.alert("close");
}, 5000);
}

View File

@@ -1,3 +1,16 @@
/**
* @file can.h
*
* @brief Header file for Controller Area Network (CAN) functionality in the ChainLube application.
*
* This file provides functions and structures related to Controller Area Network (CAN)
* communication for the ChainLube project. It includes functions for initializing CAN,
* processing CAN messages, and retrieving wheel speed from CAN data.
*
* @author Marcel Peterkau
* @date 09.01.2024
*/
#ifndef _CAN_H_
#define _CAN_H_
@@ -9,6 +22,7 @@
#include "dtc.h"
#include "debugger.h"
// CAN frame structure definition
struct can_frame
{
unsigned long can_id;
@@ -16,8 +30,8 @@ struct can_frame
uint8_t data[8] __attribute__((aligned(8)));
};
// Function prototypes
void Init_CAN();
void CAN_Process();
uint32_t Process_CAN_WheelSpeed();
#endif
#endif

View File

@@ -1,10 +1,26 @@
/**
* @file common.h
*
* @brief Header file for common definitions and macros in the ChainLube application.
*
* This file defines common macros, GPIO configurations, and other shared constants
* for the ChainLube project. It includes definitions for GPIO pins, OTA delays, pulse lengths,
* and other common settings used across the project.
*
* @author Marcel Peterkau
* @date 09.01.2024
*/
#ifndef _COMMON_H_
#define _COMMON_H_
#include <stddef.h>
#define Q(x) #x
#define QUOTE(x) Q(x)
#define SET_BIT(value, bitPosition) ((value) |= (1U << (bitPosition)))
// Conditional compilation based on PCB revision
#if PCB_REV == 1
#define GPIO_BUTTON D7
#define GPIO_LED D8
@@ -15,6 +31,7 @@
#define GPIO_LED D8
#define GPIO_TRIGGER D6
#define GPIO_PUMP D5
#define GPIO_CS_CAN -1
#elif PCB_REV == 3
#define GPIO_BUTTON D4
#define GPIO_LED D3
@@ -40,17 +57,70 @@
#define LUBE_PULSE_LENGHT_MS 160
#define LUBE_PULSE_PAUSE_MS 340
// Pump pulse parameters
// -> 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
// -> 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
typedef enum eSystem_Status
{
sysStat_Startup,
sysStat_Normal,
sysStat_Rain,
sysStat_Purge,
sysStat_Error,
sysStat_Shutdown
} tSystem_Status;
#endif
// Enum for different sources of speed input
typedef enum SpeedSource_e
{
#ifdef FEATURE_ENABLE_TIMER
SOURCE_TIME,
#endif
SOURCE_IMPULSE,
SOURCE_GPS,
SOURCE_CAN,
SOURCE_OBD2_KLINE,
SOURCE_OBD2_CAN
} SpeedSource_t;
// String representation of SpeedSource enum
extern const char *SpeedSourceString[];
extern const size_t SpeedSourceString_Elements;
// Enum for GPS baud rates
typedef enum GPSBaudRate_e
{
BAUD_4800,
BAUD_9600,
BAUD_19200,
BAUD_38400,
BAUD_57600,
BAUD_115200
} GPSBaudRate_t;
// String representation of GPSBaudRate enum
extern const char *GPSBaudRateString[];
extern const size_t GPSBaudRateString_Elements;
// Enum for CAN bus sources
typedef enum CANSource_e
{
KTM_890_ADV_R_2021,
KTM_1290_SD_R_2023
} CANSource_t;
// String representation of CANSource enum
extern const char *CANSourceString[];
extern const size_t CANSourceString_Elements;
#define STARTUP_DELAY 2500
#define SHUTDOWN_DELAY_MS 2500
#endif

View File

@@ -1,97 +1,89 @@
/**
* @file config.h
*
* @brief Header file for configuration settings and EEPROM operations in the ChainLube application.
*
* This file defines configuration settings for the ChainLube project, including default values,
* EEPROM structures, and functions for EEPROM operations. It also defines enums for different sources
* of speed input, GPS baud rates, and CAN bus sources. Additionally, it includes functions for EEPROM handling
* such as storing, retrieving, and formatting configuration data.
*
* @author Marcel Peterkau
* @date 09.01.2024
*/
#ifndef _CONFIG_H_
#define _CONFIG_H_
#include <Arduino.h>
#include <Wire.h>
#include <I2C_eeprom.h>
#include "globals.h"
#include "dtc.h"
#include "common.h"
#define EEPROM_STRUCTURE_REVISION 3 // Increment this version when changing EEPROM structures
#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
typedef enum EERequest_e
{
#ifdef FEATURE_ENABLE_TIMER
SOURCE_TIME,
#endif
SOURCE_IMPULSE,
SOURCE_GPS,
SOURCE_CAN
} SpeedSource_t;
EE_IDLE,
EE_CFG_SAVE,
EE_CFG_LOAD,
EE_CFG_FORMAT,
EE_PDS_SAVE,
EE_PDS_LOAD,
EE_PDS_FORMAT,
EE_FORMAT_ALL,
EE_ALL_SAVE
const char SpeedSourceString[][8] = {
#ifdef FEATURE_ENABLE_TIMER
"Timer",
#endif
"Impuls",
"GPS",
"CAN-Bus"
};
typedef enum GPSBaudRate_e
{
BAUD_9600,
BAUD_115200
} GPSBaudRate_t;
const char GPSBaudRateString[][7] = {
"9600",
"115200"};
const size_t GPSBaudRateString_Elements = sizeof(GPSBaudRateString) / sizeof(GPSBaudRateString[0]);
typedef enum CANSource_e
{
KTM_890_ADV_R_2021,
KTM_1290_SD_R_2023
} CANSource_t;
const char CANSourceString[][30] = {
"KTM 890 Adventure R (2021)",
"KTM 1290 Superduke R (2023)"};
const size_t CANSourceString_Elements = sizeof(CANSourceString) / sizeof(CANSourceString[0]);
const size_t SpeedSourceString_Elements = sizeof(SpeedSourceString) / sizeof(SpeedSourceString[0]);
} EERequest_t;
// Structure for persistence data stored in EEPROM
typedef struct
{
uint16_t writeCycleCounter = 0;
uint32_t tankRemain_microL = 0;
uint32_t TravelDistance_highRes_mm = 0;
uint32_t odometer_mm = 0;
uint32_t odometer = 0;
uint32_t checksum = 0;
uint16_t writeCycleCounter;
uint32_t tankRemain_microL;
uint32_t TravelDistance_highRes_mm;
uint32_t odometer_mm;
uint32_t odometer;
uint32_t checksum;
} persistenceData_t;
// Structure for configuration settings stored in EEPROM
typedef struct
{
uint8_t EEPROM_Version = 0;
uint32_t DistancePerLube_Default = 8000;
uint32_t DistancePerLube_Rain = 4000;
uint32_t tankCapacity_ml = 320;
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;
uint16_t BleedingPulses = 25;
SpeedSource_t SpeedSource = SOURCE_IMPULSE;
GPSBaudRate_t GPSBaudRate = BAUD_115200;
CANSource_t CANSource = KTM_890_ADV_R_2021;
bool LED_Mode_Flash = false;
uint8_t LED_Max_Brightness = 255;
uint8_t LED_Min_Brightness = 5;
uint32_t checksum = 0;
uint8_t EEPROM_Version;
uint32_t DistancePerLube_Default;
uint32_t DistancePerLube_Rain;
uint32_t tankCapacity_ml;
uint32_t amountPerDose_microL;
uint8_t TankRemindAtPercentage;
uint8_t PulsePerRevolution;
uint32_t TireWidth_mm;
uint32_t TireWidthHeight_Ratio;
uint32_t RimDiameter_Inch;
uint32_t DistancePerRevolution_mm;
uint16_t BleedingPulses;
SpeedSource_t SpeedSource;
GPSBaudRate_t GPSBaudRate;
CANSource_t CANSource;
bool LED_Mode_Flash;
uint8_t LED_Max_Brightness;
uint8_t LED_Min_Brightness;
char wifi_ap_ssid[33];
char wifi_ap_password[64];
char wifi_client_ssid[33];
char wifi_client_password[64];
bool wifi_autoconnect;
uint32_t checksum;
} LubeConfig_t;
// Default configuration settings
const LubeConfig_t LubeConfig_defaults = {
0, 8000, 4000, 320, DEFAULT_PUMP_DOSE, 30, 1, 150, 70, 18, 2000, 25, SOURCE_IMPULSE,
BAUD_115200,
@@ -99,6 +91,11 @@ const LubeConfig_t LubeConfig_defaults = {
false,
255,
5,
"ChainLube",
QUOTE(WIFI_AP_PASSWORD),
QUOTE(WIFI_SSID_CLIENT),
QUOTE(WIFI_PASSWORD_CLIENT),
true,
0};
void InitEEPROM();
@@ -113,8 +110,9 @@ uint32_t Checksum_EEPROM(uint8_t const *data, size_t len);
void dumpEEPROM(uint16_t memoryAddress, uint16_t length);
void MovePersistencePage_EEPROM(boolean reset);
uint32_t ConfigSanityCheck(bool autocorrect = false);
bool validateWiFiString(char *string, size_t size);
extern LubeConfig_t LubeConfig;
extern persistenceData_t PersistenceData;
extern uint16_t eePersistenceMarker;
#endif // _CONFIG_H_
#endif // _CONFIG_H_

View File

@@ -1,9 +1,21 @@
/**
* @file debugger.h
*
* @brief Header file for debugging functions and status in the ChainLube application.
*
* This file declares functions and status definitions for debugging purposes in the ChainLube project.
* It includes functions to print system information, WiFi information, format EEPROM data,
* handle debug messages, and manage the status of different debug ports.
*
* @author Marcel Peterkau
* @date 09.01.2024
*/
#ifndef _DEBUGGER_H_
#define _DEBUGGER_H_
#include <Arduino.h>
#include "webui.h"
const char PROGMEM helpCmd[] = "sysinfo - System Info\n"
"netinfo - WiFi Info\n"
"formatPDS - Format Persistence EEPROM Data\n"

View File

@@ -1,3 +1,16 @@
/**
* @file dtc.h
*
* @brief Header file for handling Diagnostic Trouble Codes (DTC) in the ChainLube application.
*
* This file provides definitions and functions for handling Diagnostic Trouble Codes (DTC)
* in the ChainLube project. It includes structures for DTC entries, severity levels,
* and functions for DTC maintenance and processing. DTCs are used to track system errors and issues.
*
* @author Marcel Peterkau
* @date 09.01.2024
*/
#ifndef _DTC_H_
#define _DTC_H_

View File

@@ -1,4 +1,18 @@
// Auto-generated by script on 2023-12-04 02:10:49
/**
* @file dtc_defs.h
*
* @brief Header file for Diagnostic Trouble Code (DTC) definitions in the ChainLube application.
*
* This file contains definitions for Diagnostic Trouble Codes (DTC) in the ChainLube project.
* It includes enums for DTC active status, severity levels, and specific DTC codes.
* The file also defines an array of DTC definitions and a timestamp indicating the generation time.
*
* @note This file is auto-generated by a script on 2025-05-04 12:01:55.
*
* @author Marcel Peterkau
* @date 04.05.2025
*/
#ifndef DTC_DEFS_H
#define DTC_DEFS_H
@@ -43,7 +57,12 @@ typedef struct {
#define DTC_FAKE_DTC_INFO 14
#define DTC_FAKE_DTC_WARN 15
#define DTC_FAKE_DTC_CRIT 16
#define DTC_LAST_DTC 17
#define DTC_OBD2_KLINE_TIMEOUT 17
#define DTC_OBD2_CAN_TIMEOUT 18
#define DTC_OBD2_CAN_NO_RESPONSE 19
#define DTC_OBD2_KLINE_NO_RESPONSE 20
#define DTC_OBD2_KLINE_BAD_FRAME 21
#define DTC_LAST_DTC 22
const DTC_t dtc_definitions[] = {
{ DTC_NO_DTC , DTC_NONE }, // No Error
@@ -63,9 +82,14 @@ const DTC_t dtc_definitions[] = {
{ DTC_FAKE_DTC_INFO , DTC_INFO }, // Ein Dummy-DTC der Schwere "Info" für Debugging-Zwecke
{ DTC_FAKE_DTC_WARN , DTC_WARN }, // Ein Dummy-DTC der Schwere "Warnung" für Debugging-Zwecke
{ DTC_FAKE_DTC_CRIT , DTC_CRITICAL }, // Ein Dummy-DTC der Schwere "Kritisch" für Debugging-Zwecke
{ DTC_OBD2_KLINE_TIMEOUT , DTC_CRITICAL }, // Die Anfrage über OBD2-KLine konnte nicht gesendet werden. Prüfen Sie den K-Line-Treiber (z.B. L9637D) und die Verkabelung.
{ DTC_OBD2_CAN_TIMEOUT , DTC_CRITICAL }, // Die Anfrage an das Steuergerät über OBD2-CAN konnte nicht gesendet werden. Prüfen Sie die Verbindung zum CAN-Modul und die OBD2-Konfiguration.
{ DTC_OBD2_CAN_NO_RESPONSE , DTC_WARN }, // Es wurde innerhalb der erwarteten Zeit keine Antwort vom Steuergerät über OBD2-CAN empfangen. Prüfen Sie, ob das Fahrzeug OBD2 unterstützt und die Verbindung korrekt ist.
{ DTC_OBD2_KLINE_NO_RESPONSE , DTC_WARN }, // Es wurde innerhalb der erwarteten Zeit keine Antwort über OBD2-KLine empfangen. Prüfen Sie die Verbindung zum Steuergerät und die Protokollkompatibilität.
{ DTC_OBD2_KLINE_BAD_FRAME , DTC_WARN }, // Das empfangene Frame war unvollständig oder entsprach nicht dem erwarteten OBD2-Format. Möglicherweise inkompatibles Steuergerät.
{ DTC_LAST_DTC , DTC_NONE } // Last Error
};
const uint32_t dtc_generation_timestamp = 1701652249;
#endif // DTC_DEFS_H
#endif // DTC_DEFS_H
// CODEGENERATOR_CHECKSUM: 15e9152fb712bc6ed7c3353a05b1b54dc697f3e489a6e1ff42b7e57f0fa094d4

View File

@@ -1,40 +0,0 @@
// Auto-generated by script on {{ timestamp }}
#ifndef DTC_DEFS_H
#define DTC_DEFS_H
#include <stdint.h>
typedef uint32_t DTCNum_t;
typedef enum
{
DTC_INACTIVE,
DTC_ACTIVE,
DTC_PREVIOUS
} DTCActive_t;
typedef enum
{
DTC_NONE,
DTC_INFO,
DTC_WARN,
DTC_CRITICAL
} DTCSeverity_t;
typedef struct {
DTCNum_t code;
DTCSeverity_t severity;
} DTC_t;
{% for dtc in dtc_macros -%}
{{ dtc }}
{% endfor %}
const DTC_t dtc_definitions[] = {
{% for struct in dtc_structs -%}
{{ struct }}
{% endfor -%}
};
const uint32_t dtc_generation_timestamp = {{ timestamp_unix }};
#endif // DTC_DEFS_H

View File

@@ -1,57 +1,49 @@
/**
* @file globals.h
*
* @brief Header file for global variables and enums in the ChainLube application.
*
* This file contains declarations for global variables and enums used in the ChainLube application.
* It includes enums for system status and EEPROM-related requests, as well as a struct for global variables.
* The file also defines a struct for constants and initializes it with firmware and required flash version information.
*
* @author Marcel Peterkau
* @date 09.01.2024
*/
#ifndef _GLOBALS_H_
#define _GLOBALS_H_
#include <Arduino.h>
typedef enum eSystem_Status
{
sysStat_Startup,
sysStat_Normal,
sysStat_Rain,
sysStat_Purge,
sysStat_Error,
sysStat_Shutdown
} tSystem_Status;
typedef enum eEERequest
{
EE_IDLE,
EE_CFG_SAVE,
EE_CFG_LOAD,
EE_CFG_FORMAT,
EE_PDS_SAVE,
EE_PDS_LOAD,
EE_PDS_FORMAT,
EE_FORMAT_ALL,
EE_ALL_SAVE
} tEERequest;
#include "config.h"
#include "common.h"
typedef struct Globals_s
{
tSystem_Status systemStatus = sysStat_Startup;
tSystem_Status resumeStatus = sysStat_Startup;
char systemStatustxt[16] = "";
uint16_t purgePulses = 0;
eEERequest requestEEAction = EE_IDLE;
char DeviceName[33];
char FlashVersion[10];
uint16_t eePersistanceAdress;
uint8_t TankPercentage;
bool hasDTC;
bool measurementActive;
uint32_t measuredPulses;
tSystem_Status systemStatus = sysStat_Startup; /**< Current system status */
tSystem_Status resumeStatus = sysStat_Startup; /**< Status to resume after rain mode */
char systemStatustxt[16] = ""; /**< Text representation of system status */
uint16_t purgePulses = 0; /**< Number of purge pulses */
EERequest_t requestEEAction = EE_IDLE;; /**< EEPROM-related request */
char DeviceName[33]; /**< Device name */
char FlashVersion[10]; /**< Flash version */
uint16_t eePersistanceAdress; /**< EEPROM persistence address */
uint8_t TankPercentage; /**< Tank percentage */
bool hasDTC; /**< Flag indicating the presence of Diagnostic Trouble Codes (DTC) */
bool measurementActive; /**< Flag indicating active measurement */
uint32_t measuredPulses; /**< Number of measured pulses */
bool toggle_wifi;
} Globals_t;
extern Globals_t globals;
extern Globals_t globals; /**< Global variable struct */
typedef struct Constants_s
{
uint8_t FW_Version_major;
uint8_t FW_Version_minor;
uint8_t Required_Flash_Version_major;
uint8_t Required_Flash_Version_minor;
char GitHash[11];
uint8_t FW_Version_major; /**< Firmware version major number */
uint8_t FW_Version_minor; /**< Firmware version minor number */
uint8_t Required_Flash_Version_major; /**< Required flash version major number */
uint8_t Required_Flash_Version_minor; /**< Required flash version minor number */
char GitHash[11]; /**< Git hash string */
} Constants_t;
const Constants_t constants PROGMEM = {
@@ -60,6 +52,9 @@ const Constants_t constants PROGMEM = {
GIT_REV // Git-Hash-String
};
/**
* @brief Initializes global variables.
*/
void initGlobals();
#endif
#endif // _GLOBALS_H_

View File

@@ -1,3 +1,17 @@
/**
* @file gps.h
*
* @brief Header file for GPS-related functions in the ChainLube application.
*
* This file contains declarations for functions related to GPS (Global Positioning System) functionality
* within the ChainLube application. It includes the initialization of the GPS module and processing of GPS
* data to calculate wheel speed. Additionally, it references other necessary header files for configuration,
* common definitions, diagnostics, and debugging.
*
* @author Marcel Peterkau
* @date 09.01.2024
*/
#ifndef _GPS_H_
#define _GPS_H_
@@ -7,7 +21,16 @@
#include "dtc.h"
#include "debugger.h"
/**
* @brief Initializes the GPS module.
*/
void Init_GPS();
/**
* @brief Processes GPS data to calculate wheel speed.
*
* @return Calculated wheel speed in millimeters per second.
*/
uint32_t Process_GPS_WheelSpeed();
#endif
#endif // _GPS_H_

View File

@@ -1,3 +1,16 @@
/**
* @file led_colors.h
*
* @brief Header file defining color values for LEDs in the ChainLube application.
*
* This file contains color definitions in hexadecimal format for various states and events of LEDs
* used in the ChainLube application. It provides a convenient way to reference specific colors for
* different visual indications in the system.
*
* @author Marcel Peterkau
* @date 09.01.2024
*/
#ifndef _LED_COLORS_H_
#define _LED_COLORS_H_
@@ -19,17 +32,14 @@
#define COLOR_AMBER 0xFF6400
#define COLOR_WARM_WHITE 0xFDF5E6
#define LED_DEFAULT_COLOR COLOR_WARM_WHITE
#define LED_STARTUP_NORMAL COLOR_WARM_WHITE
#define LED_STARTUP_TANKWARN COLOR_AMBER
#define LED_NORMAL_COLOR COLOR_GREEN
#define LED_RAIN_COLOR COLOR_BLUE
#define LED_NORMAL_COLOR COLOR_GREEN
#define LED_RAIN_COLOR COLOR_BLUE
#define LED_WIFI_BLINK COLOR_YELLOW
#define LED_PURGE_COLOR COLOR_MAGENTA
#define LED_ERROR_BLINK COLOR_RED
#define LED_SHUTDOWN_BLINK COLOR_CYAN
#endif /* _LED_COLORS_H_ */

View File

@@ -1,3 +1,15 @@
/**
* @file lubeapp.h
*
* @brief Header file for the ChainLube application functions.
*
* This file contains function declarations related to the main functionality of the ChainLube
* application. It includes functions for running the application and generating lubrication pulses.
*
* @author Marcel Peterkau
* @date 09.01.2024
*/
#ifndef _LUBEAPP_H_
#define _LUBEAPP_H_
@@ -12,4 +24,4 @@
void RunLubeApp(uint32_t add_milimeters);
void LubePulse();
#endif
#endif /* _LUBEAPP_H_ */

View File

@@ -0,0 +1,10 @@
#ifndef _OBD2_CAN_H_
#define _OBD2_CAN_H_
#include <Arduino.h>
// === Funktionen ===
void Init_OBD2_CAN();
uint32_t Process_OBD2_CAN_Speed();
#endif

View File

@@ -0,0 +1,10 @@
#ifndef _OBD2_KLINE_H_
#define _OBD2_KLINE_H_
#include <Arduino.h>
// === Funktionen ===
void Init_OBD2_KLine(Stream &serial); // Übergib z.B. SoftwareSerial oder Serial1
uint32_t Process_OBD2_KLine_Speed(); // liefert mm seit letztem Aufruf
#endif

View File

@@ -1,3 +1,15 @@
/**
* @file sanitycheck.h
*
* @brief Header file for sanity checks and configuration validation in the ChainLube application.
*
* This file contains checks and validations to ensure that the configuration and features of the
* ChainLube application are compatible with the selected PCB revision and defined parameters.
*
* @author Marcel Peterkau
* @date 09.01.2024
*/
#ifndef _SANITYCHECK_H_
#define _SANITYCHECK_H_
@@ -34,4 +46,4 @@
#error "You must define an WIFI_AP_PASSWORD for Standalone AP-Mode"
#endif
#endif //_SANITYCHECK_H_
#endif // _SANITYCHECK_H_

View File

@@ -0,0 +1,26 @@
/**
* @file struct2json.h
*
* @brief Header file for converting structs to JSON objects.
*
* @note This file is auto-generated by a script on 2024-01-30 20:29:34.
*
* @author Marcel Peterkau
* @date 30.01.2024
*/
#ifndef _STRUCT2JSON_H_
#define _STRUCT2JSON_H_
#include <Arduino.h>
#include <ArduinoJson.h>
#include "config.h"
void generateJsonObject_LubeConfig(JsonObject data);
void generateJsonObject_PersistenceData(JsonObject data);
#endif /* _STRUCT2JSON_H_ */
// CODEGENERATOR_CHECKSUM: 59f35aadffd0bbef253210ea2fbaaf9a515553a2e3cc9bf4cfa2819b63c969ce

View File

@@ -1,3 +1,16 @@
/**
* @file webui.h
*
* @brief Header file for the web-based user interface (WebUI) in the ChainLube application.
*
* This file contains declarations for functions related to the initialization and processing of the
* web-based user interface (WebUI). It includes the necessary libraries and dependencies for handling
* web server functionality, asynchronous JSON operations, and live debugging through WebSockets.
*
* @author Marcel Peterkau
* @date 09.01.2024
*/
#ifndef _WEBUI_H_
#define _WEBUI_H_
@@ -16,10 +29,21 @@
#include "dtc.h"
#include "common.h"
#include "debugger.h"
#include "struct2json.h"
typedef enum
{
info,
success,
warning,
error
} NotificationType_t;
void initWebUI();
void Webserver_Process();
void Webserver_Shutdown();
void Websocket_PushLiveDebug(String Message);
void Websocket_PushNotification(String Message, NotificationType_t type);
#endif
#endif // _WEBUI_H_

View File

@@ -11,79 +11,88 @@
[platformio]
extra_configs =
wifi_credentials.ini
default_envs = pcb_rev_1-3, pcb_rev_1-2
default_envs = pcb_rev_1-3_serial, pcb_rev_1-3_ota, pcb_rev_1-2_serial, pcb_rev_1-2_ota
[env]
platform = espressif8266
board = d1_mini
framework = arduino
upload_speed = 921600
upload_protocol = espota
upload_port = 10.0.1.14
upload_flags =
--port=8266
--auth=${wifi_cred.admin_password}
upload_speed = 921600
build_flags =
!python git_rev_macro.py
!python codegen/git_rev_macro.py
-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
-DATOMIC_FS_UPDATE
-DCAN_DEBUG_MESSAGE
;-DFEATURE_ENABLE_WIFI_CLIENT
;-DFEATURE_ENABLE_TIMER
-DFEATURE_ENABLE_OLED
board_build.filesystem = littlefs
extra_scripts =
post:prepare_littlefs.py
pre:build_dtcs.py
pre:prepare_fwfiles.py
post:codegen/prepare_littlefs.py
pre:codegen/run_pre.py
monitor_filters = esp8266_exception_decoder
monitor_speed = 115200
lib_ldf_mode = deep
lib_deps =
olikraus/U8g2 @ ^2.28.8
adafruit/Adafruit NeoPixel @ ^1.11.0
sstaub/Ticker @ ^4.2.0
robtillaart/I2C_EEPROM @ ^1.5.2
me-no-dev/ESP Async WebServer @ ^1.2.3
bblanchon/ArduinoJson @ ^6.19.4
[env:pcb_rev_1-3]
;build_type = debug
custom_pcb_revision = 3
build_flags =
${env.build_flags}
;-DFEATURE_ENABLE_WIFI_CLIENT
;-DFEATURE_ENABLE_TIMER
-DFEATURE_ENABLE_OLED
-DCAN_DEBUG_MESSAGE
-DPCB_REV=${this.custom_pcb_revision}
board_build.ldscript = eagle.flash.4m1m.ld
lib_deps =
${env.lib_deps}
olikraus/U8g2 @ ^2.35.9
adafruit/Adafruit NeoPixel @ ^1.12.0
sstaub/Ticker @ ^4.4.0
robtillaart/I2C_EEPROM @ ^1.8.2
esphome/ESPAsyncWebServer-esphome @ 3.1.0
bblanchon/ArduinoJson @ ^7.0.1
coryjfowler/mcp_can @ ^1.5.0
mikalhart/TinyGPSPlus @ ^1.0.3
[env:pcb_rev_1-2]
;build_type = debug
custom_pcb_revision = 2
[env:pcb_rev_1-3_serial]
extends = env
custom_pcb_revision = 3
upload_protocol = esptool
build_flags =
${env.build_flags}
;-DFEATURE_ENABLE_WIFI_CLIENT
;-DFEATURE_ENABLE_TIMER
-DFEATURE_ENABLE_OLED
-DFEATURE_ENABLE_WEBSOCKETS
-DPCB_REV=${this.custom_pcb_revision}
board_build.ldscript = eagle.flash.4m1m.ld
lib_deps =
${env.lib_deps}
[env:pcb_rev_1-3_ota]
extends = env
custom_pcb_revision = 3
upload_protocol = espota
upload_port = 10.0.1.14
upload_flags =
--port=8266
--auth=${wifi_cred.admin_password}
build_flags =
${env.build_flags}
-DPCB_REV=${this.custom_pcb_revision}
board_build.ldscript = eagle.flash.4m1m.ld
[env:pcb_rev_1-2_serial]
extends = env
custom_pcb_revision = 2
upload_protocol = esptool
build_flags =
${env.build_flags}
-DPCB_REV=${this.custom_pcb_revision}
board_build.ldscript = eagle.flash.4m1m.ld
[env:pcb_rev_1-2_ota]
extends = env
custom_pcb_revision = 2
upload_protocol = espota
upload_port = 10.0.1.14
upload_flags =
--port=8266
--auth=${wifi_cred.admin_password}
build_flags =
${env.build_flags}
-DPCB_REV=${this.custom_pcb_revision}
board_build.ldscript = eagle.flash.4m1m.ld

View File

@@ -1,3 +0,0 @@
Import("env")
env.Replace(PROGNAME="firmware_pcb_1.%s.fw" % env.GetProjectOption("custom_pcb_revision"))

View File

@@ -1,3 +1,17 @@
/**
* @file can.cpp
*
* @brief Implementation file for CAN-related functions in the ChainLube application.
*
* This file contains the implementation of functions related to CAN (Controller Area Network)
* communication within the ChainLube application. It includes the initialization of the CAN module,
* setup of masks and filters, and processing of CAN messages. Additionally, a debug message function
* is included if CAN debugging is enabled.
*
* @author Your Name
* @date Date
*/
#include "can.h"
MCP_CAN CAN0(GPIO_CS_CAN);
@@ -6,9 +20,14 @@ MCP_CAN CAN0(GPIO_CS_CAN);
void sendCANDebugMessage();
#endif
/**
* @brief Initializes the CAN module, sets masks, and filters based on the configured CAN source.
*
* This function initializes the CAN module, sets masks and filters based on the configured CAN source
* in the application settings, and sets the CAN module in normal mode for communication.
*/
void Init_CAN()
{
if (CAN0.begin(MCP_STDEXT, CAN_500KBPS, MCP_16MHZ) != CAN_OK)
MaintainDTC(DTC_CAN_TRANSCEIVER_FAILED, true);
@@ -30,17 +49,15 @@ void Init_CAN()
CAN0.setMode(MCP_NORMAL);
}
void CAN_Process()
{
static uint32_t previousMillis = 0;
if (millis() - previousMillis >= 100)
{
sendCANDebugMessage();
previousMillis = millis();
}
}
/**
* @brief Processes CAN messages to determine the wheel speed based on the configured CAN source.
*
* This function reads incoming CAN messages and extracts the rear wheel speed information.
* The wheel speed is then converted to millimeters per second based on the configured CAN source.
* The function also monitors the CAN signal for potential issues and triggers diagnostic trouble codes (DTCs).
*
* @return The calculated distance traveled in millimeters since the last call.
*/
uint32_t Process_CAN_WheelSpeed()
{
#define FACTOR_RWP_KMH_890ADV 18 // Divider to convert Raw Data to km/h
@@ -83,10 +100,27 @@ uint32_t Process_CAN_WheelSpeed()
MaintainDTC(DTC_NO_CAN_SIGNAL, (millis() > lastRecTimestamp + 10000 ? true : false));
}
#ifdef CAN_DEBUG_MESSAGE
static uint32_t previousMillis = 0;
if (millis() - previousMillis >= 1000)
{
sendCANDebugMessage();
previousMillis = millis();
}
#endif
return milimeters_to_add;
}
#ifdef CAN_DEBUG_MESSAGE
/**
* @brief Sends periodic CAN debug messages for monitoring and diagnostics.
*
* This function sends periodic CAN debug messages containing various system information for monitoring and diagnostics.
* The information includes system status, timestamps, tank percentage, DTC flags, and other relevant data.
* The debug messages are sent with a configurable multiplexer to broadcast different types of information in each cycle.
*/
void sendCANDebugMessage()
{
#define MAX_DEBUG_MULTIPLEXER 6
@@ -143,7 +177,7 @@ void sendCANDebugMessage()
}
else if (DebugSendFailTimeout == MAX_DEBUG_RETRIES)
{
Debug_pushMessage("disable CAN-DbgMsg due to timeout");
Debug_pushMessage("disable CAN-DbgMsg due to timeout\n");
DebugSendFailTimeout++;
}
}

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

@@ -0,0 +1,35 @@
#include "common.h"
// String representation of SpeedSource enum
const char *SpeedSourceString[] = {
#ifdef FEATURE_ENABLE_TIMER
"Timer",
#endif
"Impuls",
"GPS",
"CAN-Bus",
"OBD2 (K-Line)",
"OBD2 (CAN)",
};
const size_t SpeedSourceString_Elements = sizeof(SpeedSourceString) / sizeof(SpeedSourceString[0]);
// String representation of GPSBaudRate enum
const char *GPSBaudRateString[] = {
"4800",
"9600",
"19200",
"38400",
"57600",
"115200",
};
const size_t GPSBaudRateString_Elements = sizeof(GPSBaudRateString) / sizeof(GPSBaudRateString[0]);
// String representation of CANSource enum
const char *CANSourceString[] = {
"KTM 890 Adventure R (2021)",
"KTM 1290 Superduke R (2023)",
};
const size_t CANSourceString_Elements = sizeof(CANSourceString) / sizeof(CANSourceString[0]);

View File

@@ -1,24 +1,54 @@
/**
* @file config.cpp
* @brief Implementation of EEPROM and configuration-related functions.
*
* This file contains functions for managing EEPROM storage and handling configuration data.
* It includes the definitions of configuration structures, EEPROM access, and utility functions.
*/
#include "config.h"
#include "debugger.h"
#include "globals.h"
// Instance of I2C_eeprom for EEPROM access
I2C_eeprom ee(0x50, EEPROM_SIZE_BYTES);
// Configuration and persistence data structures
LubeConfig_t LubeConfig;
persistenceData_t PersistenceData;
const uint16_t eeVersion = 2; // inc
// EEPROM version identifier
const uint16_t eeVersion = EEPROM_STRUCTURE_REVISION;
// Flag indicating whether EEPROM is available
boolean eeAvailable = false;
// Offsets within EEPROM for LubeConfig and PersistenceData
const uint16_t startofLubeConfig = 16;
const uint16_t startofPersistence = 16 + sizeof(LubeConfig) + (sizeof(LubeConfig) % 16);
// Function prototype to check EEPROM availability
boolean checkEEPROMavailable();
/**
* @brief Initializes EEPROM and checks its availability.
*
* This function initializes the EEPROM using the I2C_eeprom instance and checks if it's available.
*/
void InitEEPROM()
{
LubeConfig = LubeConfig_defaults;
PersistenceData = {0};
ee.begin();
checkEEPROMavailable();
}
/**
* @brief Processes EEPROM actions based on the request from the global state.
*
* This function processes EEPROM actions based on the request from the global state.
* It performs actions such as saving, loading, and formatting EEPROM data for both configuration and persistence.
*/
void EEPROM_Process()
{
switch (globals.requestEEAction)
@@ -37,7 +67,7 @@ void EEPROM_Process()
FormatConfig_EEPROM();
globals.requestEEAction = EE_IDLE;
GetConfig_EEPROM();
Debug_pushMessage("Formated EEPROM CFG\n");
Debug_pushMessage("Formatted EEPROM CFG\n");
break;
case EE_PDS_SAVE:
StorePersistence_EEPROM();
@@ -53,7 +83,7 @@ void EEPROM_Process()
FormatPersistence_EEPROM();
globals.requestEEAction = EE_IDLE;
GetPersistence_EEPROM();
Debug_pushMessage("Formated EEPROM PDS\n");
Debug_pushMessage("Formatted EEPROM PDS\n");
break;
case EE_FORMAT_ALL:
FormatConfig_EEPROM();
@@ -61,7 +91,7 @@ void EEPROM_Process()
GetConfig_EEPROM();
GetPersistence_EEPROM();
globals.requestEEAction = EE_IDLE;
Debug_pushMessage("Formated EEPROM ALL\n");
Debug_pushMessage("Formatted EEPROM ALL\n");
break;
case EE_ALL_SAVE:
StorePersistence_EEPROM();
@@ -75,22 +105,36 @@ void EEPROM_Process()
}
}
/**
* @brief Stores the configuration data in EEPROM.
*
* This function calculates the checksum for the configuration data, updates it, and stores it in EEPROM.
* It also performs a sanity check on the configuration and raises a diagnostic trouble code (DTC) if needed.
*/
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));
uint32_t ConfigSanityCheckResult = ConfigSanityCheck(false);
if (ConfigSanityCheckResult > 0)
{
MaintainDTC(DTC_EEPROM_CFG_SANITY, true, ConfigSanityCheckResult);
}
}
/**
* @brief Retrieves the configuration data from EEPROM.
*
* This function reads the configuration data from EEPROM, performs a checksum validation,
* and conducts a sanity check on the configuration. It raises a diagnostic trouble code (DTC) if needed.
*/
void GetConfig_EEPROM()
{
if (!checkEEPROMavailable())
@@ -101,19 +145,22 @@ void GetConfig_EEPROM()
uint32_t checksum = LubeConfig.checksum;
LubeConfig.checksum = 0;
if (Checksum_EEPROM((uint8_t *)&LubeConfig, sizeof(LubeConfig)) != checksum)
{
MaintainDTC(DTC_EEPROM_CFG_BAD, true);
}
MaintainDTC(DTC_EEPROM_CFG_BAD, (Checksum_EEPROM((uint8_t *)&LubeConfig, sizeof(LubeConfig)) != checksum));
LubeConfig.checksum = checksum;
uint32_t ConfigSanityCheckResult = ConfigSanityCheck(false);
if (ConfigSanityCheckResult > 0)
{
MaintainDTC(DTC_EEPROM_CFG_SANITY, true, ConfigSanityCheckResult);
}
MaintainDTC(DTC_EEPROM_CFG_SANITY, (ConfigSanityCheckResult > 0), ConfigSanityCheckResult);
}
/**
* @brief Stores the persistence data in EEPROM.
*
* This function increments the write cycle counter, performs a checksum calculation on the persistence data,
* and stores it in EEPROM. It also handles EEPROM page movement when needed.
*/
void StorePersistence_EEPROM()
{
if (PersistenceData.writeCycleCounter >= 0xFFF0)
@@ -130,6 +177,13 @@ void StorePersistence_EEPROM()
ee.updateBlock(globals.eePersistanceAdress, (uint8_t *)&PersistenceData, sizeof(PersistenceData));
}
/**
* @brief Retrieves the persistence data from EEPROM.
*
* This function reads the EEPROM to get the start address of the persistence data.
* If the start address is out of range, it resets and stores defaults. Otherwise,
* it reads from EEPROM and checks if the data is correct.
*/
void GetPersistence_EEPROM()
{
if (!checkEEPROMavailable())
@@ -151,14 +205,17 @@ void GetPersistence_EEPROM()
uint32_t checksum = PersistenceData.checksum;
PersistenceData.checksum = 0;
if (Checksum_EEPROM((uint8_t *)&PersistenceData, sizeof(PersistenceData)) != checksum)
{
MaintainDTC(DTC_EEPROM_PDS_BAD, true);
}
MaintainDTC(DTC_EEPROM_PDS_BAD, (Checksum_EEPROM((uint8_t *)&PersistenceData, sizeof(PersistenceData)) != checksum));
PersistenceData.checksum = checksum;
}
}
/**
* @brief Formats the configuration partition in EEPROM.
*
* This function resets the configuration data to defaults and stores it in EEPROM.
*/
void FormatConfig_EEPROM()
{
Debug_pushMessage("Formatting Config-Partition\n");
@@ -167,6 +224,11 @@ void FormatConfig_EEPROM()
StoreConfig_EEPROM();
}
/**
* @brief Formats the persistence partition in EEPROM.
*
* This function resets the persistence data to defaults and stores it in EEPROM.
*/
void FormatPersistence_EEPROM()
{
Debug_pushMessage("Formatting Persistance-Partition\n");
@@ -174,16 +236,22 @@ void FormatPersistence_EEPROM()
// memset(&PersistenceData, 0, sizeof(PersistenceData));
StorePersistence_EEPROM();
}
/**
* @brief Moves the persistence page in EEPROM.
*
* This function adjusts the persistence page address and resets the write cycle counter.
*
* @param reset If true, the function resets the persistence page address to the start of the partition.
*/
void MovePersistencePage_EEPROM(boolean reset)
{
if (!checkEEPROMavailable())
return;
globals.eePersistanceAdress = +sizeof(PersistenceData);
globals.eePersistanceAdress += sizeof(PersistenceData);
PersistenceData.writeCycleCounter = 0;
// check if we reached the End of the EEPROM and Startover at the beginning
// Check if we reached the end of the EEPROM and start over at the beginning
if ((globals.eePersistanceAdress + sizeof(PersistenceData)) > ee.getDeviceSize() || reset)
{
globals.eePersistanceAdress = startofPersistence;
@@ -192,25 +260,45 @@ void MovePersistencePage_EEPROM(boolean reset)
ee.updateBlock(0, (uint8_t *)&globals.eePersistanceAdress, sizeof(globals.eePersistanceAdress));
}
/**
* @brief Calculate CRC-32 checksum for a block of data.
*
* This function implements the CRC-32 algorithm.
*
* @param data Pointer to the data block.
* @param len Length of the data block in bytes.
* @return CRC-32 checksum.
*/
uint32_t Checksum_EEPROM(uint8_t const *data, size_t len)
{
if (data == NULL)
return 0;
uint32_t crc, mask;
crc = 0xFFFFFFFF;
uint32_t crc = 0xFFFFFFFF;
uint32_t mask;
while (len--)
{
crc ^= *data++;
for (uint8_t k = 0; k < 8; k++)
{
mask = -(crc & 1);
crc = (crc >> 1) ^ (0xEDB88320 & mask);
}
}
return ~crc;
}
/**
* @brief Dump a portion of EEPROM contents for debugging.
*
* This function prints the contents of a specified portion of EEPROM in a formatted way.
*
* @param memoryAddress Starting address in EEPROM.
* @param length Number of bytes to dump.
*/
void dumpEEPROM(uint16_t memoryAddress, uint16_t length)
{
#define BLOCK_TO_LENGTH 16
@@ -220,42 +308,79 @@ void dumpEEPROM(uint16_t memoryAddress, uint16_t length)
char ascii_buf[BLOCK_TO_LENGTH + 1];
sprintf(ascii_buf, "%*s", BLOCK_TO_LENGTH, "ASCII");
// Print column headers
Debug_pushMessage(PSTR("\nAddress "));
for (int x = 0; x < BLOCK_TO_LENGTH; x++)
Debug_pushMessage("%3d", x);
// Align address and length to BLOCK_TO_LENGTH boundaries
memoryAddress = memoryAddress / BLOCK_TO_LENGTH * BLOCK_TO_LENGTH;
length = (length + BLOCK_TO_LENGTH - 1) / BLOCK_TO_LENGTH * BLOCK_TO_LENGTH;
// Iterate through the specified portion of EEPROM
for (unsigned int i = 0; i < length; i++)
{
int blockpoint = memoryAddress % BLOCK_TO_LENGTH;
// Print ASCII representation header for each block
if (blockpoint == 0)
{
ascii_buf[BLOCK_TO_LENGTH] = 0;
Debug_pushMessage(" %s", ascii_buf);
Debug_pushMessage("\n0x%05X:", memoryAddress);
}
// Read and print each byte
ascii_buf[blockpoint] = ee.readByte(memoryAddress);
Debug_pushMessage(" %02X", ascii_buf[blockpoint]);
// Replace non-printable characters with dots in ASCII representation
if (ascii_buf[blockpoint] < 0x20 || ascii_buf[blockpoint] > 0x7E)
ascii_buf[blockpoint] = '.';
memoryAddress++;
}
// Print a new line at the end of the dump
Debug_pushMessage("\n");
}
/**
* @brief Check if EEPROM is available and connected.
*
* This function checks if the EEPROM is available and connected. If not, it triggers
* a diagnostic trouble code (DTC) indicating the absence of EEPROM.
*
* @return true if EEPROM is available, false otherwise.
*/
boolean checkEEPROMavailable()
{
// Check if EEPROM is connected
if (!ee.isConnected())
{
// Trigger DTC for no EEPROM found
MaintainDTC(DTC_NO_EEPROM_FOUND, true);
return false;
}
// Clear DTC for no EEPROM found since it's available now
MaintainDTC(DTC_NO_EEPROM_FOUND, false);
// EEPROM is available
return true;
}
/**
* @brief Perform sanity check on configuration settings.
*
* This function checks the validity of various configuration settings and returns a bitmask
* indicating which settings need to be reset. If autocorrect is enabled, it resets the settings
* to their default values.
*
* @param autocorrect If true, automatically correct invalid settings by resetting to defaults.
* @return A bitmask indicating which settings need to be reset.
*/
uint32_t ConfigSanityCheck(bool autocorrect)
{
uint32_t setting_reset_bits = 0;
@@ -332,7 +457,7 @@ uint32_t ConfigSanityCheck(bool autocorrect)
LubeConfig.DistancePerRevolution_mm = LubeConfig_defaults.DistancePerRevolution_mm;
}
}
if (!(LubeConfig.BleedingPulses > 0) || !(LubeConfig.BleedingPulses < 1001))
{
SET_BIT(setting_reset_bits, 10);
@@ -360,5 +485,78 @@ uint32_t ConfigSanityCheck(bool autocorrect)
if (autocorrect)
LubeConfig.CANSource = LubeConfig_defaults.CANSource;
}
if (!validateWiFiString(LubeConfig.wifi_ap_ssid, sizeof(LubeConfig.wifi_ap_ssid)))
{
SET_BIT(setting_reset_bits, 14);
if (autocorrect)
strncpy(LubeConfig.wifi_ap_ssid, LubeConfig_defaults.wifi_ap_ssid, sizeof(LubeConfig.wifi_ap_ssid));
}
if (!validateWiFiString(LubeConfig.wifi_ap_password, sizeof(LubeConfig.wifi_ap_password)))
{
SET_BIT(setting_reset_bits, 15);
if (autocorrect)
strncpy(LubeConfig.wifi_ap_password, LubeConfig_defaults.wifi_ap_password, sizeof(LubeConfig.wifi_ap_password));
}
if (!validateWiFiString(LubeConfig.wifi_client_ssid, sizeof(LubeConfig.wifi_client_ssid)))
{
SET_BIT(setting_reset_bits, 16);
if (autocorrect)
strncpy(LubeConfig.wifi_client_ssid, LubeConfig_defaults.wifi_client_ssid, sizeof(LubeConfig.wifi_client_ssid));
}
if (!validateWiFiString(LubeConfig.wifi_client_password, sizeof(LubeConfig.wifi_client_password)))
{
SET_BIT(setting_reset_bits, 17);
if (autocorrect)
strncpy(LubeConfig.wifi_client_password, LubeConfig_defaults.wifi_client_password, sizeof(LubeConfig.wifi_client_password));
}
// Return the bitmask indicating which settings need to be reset
return setting_reset_bits;
}
}
/**
* @brief Validates whether a given string contains only characters allowed in WiFi SSIDs and passwords.
*
* This function checks each character in the provided string to ensure
* that it contains only characters allowed in WiFi SSIDs and passwords.
* It considers characters from 'A' to 'Z', 'a' to 'z', '0' to '9', as well as
* the following special characters: ! " # $ % & ' ( ) * + , - . / : ; < = > ? @ [ \ ] ^ _ ` { | } ~
*
* @param string Pointer to the string to be validated.
* @param size Size of the string including the null-terminator.
* @return true if the string contains only allowed characters or is NULL,
* false otherwise.
*/
bool validateWiFiString(char *string, size_t size)
{
if (string == NULL)
return false;
for (size_t i = 0; i < size; i++)
{
char c = string[i];
if (c == '\0')
{
// Reached the end of the string, all characters were valid WiFi characters.
return true;
}
if (!((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') ||
(c >= '0' && c <= '9') || c == '!' || c == '"' || c == '#' ||
c == '$' || c == '%' || c == '&' || c == '\'' || c == '(' ||
c == ')' || c == '*' || c == '+' || c == ',' || c == '-' ||
c == '.' || c == '/' || c == ':' || c == ';' || c == '<' ||
c == '=' || c == '>' || c == '?' || c == '@' || c == '[' ||
c == '\\' || c == ']' || c == '^' || c == '_' || c == '`' ||
c == '{' || c == '|' || c == '}' || c == '~'))
{
// Found a character that is not a valid WiFi character.
return false;
}
}
// If the loop completes without finding a null terminator, the string is invalid.
return false;
}

View File

@@ -1,52 +1,80 @@
/**
* @file debugger.cpp
* @brief Implementation of debugging functions for monitoring and diagnostics.
*
* This file contains the implementation of various debugging functions to monitor
* and diagnose the system. It includes functions to print system information, WiFi
* details, EEPROM status, dump configuration settings, dump persistence data, show
* Diagnostic Trouble Codes (DTCs), and more.
*
* @author Marcel Peterkau
* @date 09.04.2024
*/
#include "debugger.h"
DebugStatus_t DebuggerStatus[dbg_cntElements];
String IpAddress2String(const IPAddress &ipAddress);
void processCmdDebug(String command);
void Debug_formatCFG();
void Debug_formatPersistence();
void Debug_printSystemInfo();
void Debug_printWifiInfo();
void Debug_CheckEEPOM();
void Debug_CheckEEPOM(bool autocorrect);
void Debug_dumpConfig();
void Debug_dumpPersistance();
void Debug_ShowDTCs();
void Debug_dumpGlobals();
void Debug_printHelp();
void Debug_Purge();
const char *uint32_to_binary_string(uint32_t num);
/**
* @brief Initializes the debugger by setting the initial status for different debug ports.
* Serial debug output is turned off.
*/
void initDebugger()
{
// Set the initial status of debug ports
DebuggerStatus[dbg_Serial] = disabled;
DebuggerStatus[dbg_Webui] = disabled;
// Disable serial debug output
Serial.setDebugOutput(false);
}
/**
* @brief Processes incoming debug commands from the Serial interface.
* It reads characters from Serial and interprets them as commands.
* The recognized commands are processed accordingly.
*/
void Debug_Process()
{
// Enumeration for tracking the state of input processing
typedef enum InputProcessed_e
{
IDLE,
CMD_COMPLETE,
CMD_ABORT,
CMD_OVERFLOW
IDLE, ///< No command processing is in progress
CMD_COMPLETE, ///< Received a complete command
CMD_ABORT, ///< Received an abort command (Esc)
CMD_OVERFLOW ///< Input buffer overflow occurred
} InputProcessed_t;
static unsigned int inputCnt = 0;
static char inputBuffer[32];
InputProcessed_t InputProcessed = IDLE;
static unsigned int inputCnt = 0; ///< Counter for characters in the input buffer
static char inputBuffer[32]; ///< Buffer to store the received characters
InputProcessed_t InputProcessed = IDLE; ///< State variable for input processing
// Check if there are characters available in the Serial input buffer
if (Serial.available())
{
char inputChar = Serial.read();
// Process the received character based on its value
switch (inputChar)
{
case '\n':
inputBuffer[inputCnt] = 0; // terminate the String
inputCnt = 0;
InputProcessed = CMD_COMPLETE;
Serial.write(inputChar);
break;
case 0x1B: // Esc
@@ -55,15 +83,17 @@ void Debug_Process()
InputProcessed = CMD_ABORT;
break;
case 0x21 ... 0x7E: // its a real letter or sign and not some control-chars
case 0x21 ... 0x7E: // it's a real letter or sign and not some control-chars
inputBuffer[inputCnt] = inputChar;
inputCnt++;
Serial.write(inputChar);
break;
default:
break;
}
// Check for input buffer overflow
if (inputCnt > sizeof(inputBuffer))
{
inputCnt = 0;
@@ -72,6 +102,7 @@ void Debug_Process()
}
}
// Process the command based on the detected state of input processing
switch (InputProcessed)
{
case CMD_ABORT:
@@ -83,40 +114,65 @@ void Debug_Process()
break;
case CMD_OVERFLOW:
Debug_pushMessage("input Buffer overflow\n");
Debug_pushMessage("Input buffer overflow\n");
break;
default:
break;
}
if (InputProcessed != IDLE)
Serial.print(">");
InputProcessed = IDLE;
}
/**
* @brief Sets the status of a specific debug port (Serial or WebUI).
* Updates the status in the DebuggerStatus array and provides debug messages.
*
* @param port The debug port to set the status for (dbg_Serial or dbg_Webui).
* @param status The status to set (enabled or disabled).
*/
void SetDebugportStatus(DebugPorts_t port, DebugStatus_t status)
{
// Display a debug message based on the provided status
if (status == disabled)
Debug_pushMessage("disable DebugPort %s\n", sDebugPorts[port]);
Debug_pushMessage("Disable DebugPort %s\n", sDebugPorts[port]);
// Update the status in the DebuggerStatus array
DebuggerStatus[port] = status;
// Display a debug message based on the updated status
if (status == enabled)
Debug_pushMessage("enabled DebugPort %s\n", sDebugPorts[port]);
Debug_pushMessage("Enabled DebugPort %s\n", sDebugPorts[port]);
}
/**
* @brief Pushes a formatted debug message to the enabled debug ports (Serial or WebUI).
*
* @param format The format string for the debug message.
* @param ... Additional arguments for formatting the message.
*/
void Debug_pushMessage(const char *format, ...)
{
// Check if either the Serial or WebUI debug port is enabled
if ((DebuggerStatus[dbg_Serial] == enabled) || (DebuggerStatus[dbg_Webui] == enabled))
{
char buff[64];
va_list arg;
char buff[128]; // Buffer to hold the formatted message
va_list arg; // Variable argument list for vsnprintf
va_start(arg, format);
// Format the message and store it in the buffer
vsnprintf(buff, sizeof(buff), format, arg);
va_end(arg);
// Send the message to the Serial debug port if enabled
if (DebuggerStatus[dbg_Serial] == enabled)
{
Serial.print(buff);
}
// Push the message to the WebUI debug port if enabled
if (DebuggerStatus[dbg_Webui] == enabled)
{
Websocket_PushLiveDebug(String(buff));
@@ -124,12 +180,22 @@ void Debug_pushMessage(const char *format, ...)
}
}
/**
* @brief Pushes a formatted CAN debug message to the enabled debug ports (Serial or WebUI).
*
* @param id CAN message ID.
* @param dlc Data Length Code of the CAN message.
* @param data Pointer to the data array of the CAN message.
*/
void pushCANDebug(uint32_t id, uint8_t dlc, uint8_t *data)
{
// Check if either the Serial or WebUI debug port is enabled
if ((DebuggerStatus[dbg_Serial] == enabled) || (DebuggerStatus[dbg_Webui] == enabled))
{
char buff[100];
char *p = buff;
char buff[100]; // Buffer to hold the formatted message
char *p = buff; // Pointer to navigate the buffer
// Format the CAN message information into the buffer
p += snprintf(p, sizeof(buff), "CAN: 0x%08X | %d | ", id, dlc);
for (int i = 0; i < dlc; i++)
{
@@ -138,10 +204,13 @@ void pushCANDebug(uint32_t id, uint8_t dlc, uint8_t *data)
*(p++) = '\n';
*p = '\0';
// Send the formatted CAN message to the Serial debug port if enabled
if (DebuggerStatus[dbg_Serial] == enabled)
{
Serial.print(buff);
}
// Push the formatted CAN message to the WebUI debug port if enabled
if (DebuggerStatus[dbg_Webui] == enabled)
{
Websocket_PushLiveDebug(String(buff));
@@ -149,8 +218,14 @@ void pushCANDebug(uint32_t id, uint8_t dlc, uint8_t *data)
}
}
/**
* @brief Processes a debug command and performs corresponding actions.
*
* @param command The debug command to be processed.
*/
void processCmdDebug(String command)
{
// Check the received command and execute corresponding actions
if (command == "help")
Debug_printHelp();
else if (command == "sysinfo")
@@ -162,7 +237,9 @@ void processCmdDebug(String command)
else if (command == "formatPDS")
Debug_formatPersistence();
else if (command == "checkEE")
Debug_CheckEEPOM();
Debug_CheckEEPOM(false);
else if (command == "checkEEfix")
Debug_CheckEEPOM(true);
else if (command == "dumpEE1k")
dumpEEPROM(0, 1024);
else if (command == "dumpEE")
@@ -189,22 +266,45 @@ void processCmdDebug(String command)
MaintainDTC(DTC_FAKE_DTC_WARN, true, millis());
else if (command == "dtc_info")
MaintainDTC(DTC_FAKE_DTC_INFO, true, millis());
else if (command == "notify_error")
Websocket_PushNotification("Debug Error Notification", error);
else if (command == "notify_warning")
Websocket_PushNotification("Debug Warning Notification", warning);
else if (command == "notify_success")
Websocket_PushNotification("Debug Success Notification", success);
else if (command == "notify_info")
Websocket_PushNotification("Debug Info Notification", info);
else if (command == "purge")
Debug_Purge();
else if (command == "toggle_wifi")
globals.toggle_wifi = true;
else
Debug_pushMessage("unknown Command\n");
}
/**
* @brief Formats the Config-EEPROM and resets it to default values.
* Prints a debug message after formatting.
*/
void Debug_formatCFG()
{
Debug_pushMessage("Formatting Config-EEPROM and reseting to default\n");
Debug_pushMessage("Formatting Config-EEPROM and resetting to default\n");
FormatConfig_EEPROM();
}
/**
* @brief Formats the Persistence-EEPROM and resets it to default values.
* Prints a debug message after formatting.
*/
void Debug_formatPersistence()
{
Debug_pushMessage("Formatting Persistence-EEPROM and reseting to default\n");
Debug_pushMessage("Formatting Persistence-EEPROM and resetting to default\n");
FormatPersistence_EEPROM();
}
/**
* @brief Prints system information and status to the debug output.
*/
void Debug_printSystemInfo()
{
Debug_pushMessage("Souko's ChainOiler Mk1\n");
@@ -224,10 +324,13 @@ void Debug_printSystemInfo()
: ideMode == FM_DOUT ? "DOUT"
: "UNKNOWN"));
Debug_pushMessage("OTA-Pass: %s\n", QUOTE(ADMIN_PASSWORD));
Debug_pushMessage("Git-Revison: %s\n", constants.GitHash);
Debug_pushMessage("Git-Revision: %s\n", constants.GitHash);
Debug_pushMessage("Sw-Version: %d.%02d\n", constants.FW_Version_major, constants.FW_Version_minor);
}
/**
* @brief Dumps the current configuration parameters to the debug output.
*/
void Debug_dumpConfig()
{
Debug_pushMessage("DistancePerLube_Default: %d\n", LubeConfig.DistancePerLube_Default);
@@ -237,7 +340,7 @@ void Debug_dumpConfig()
Debug_pushMessage("TankRemindAtPercentage: %d\n", LubeConfig.TankRemindAtPercentage);
Debug_pushMessage("PulsePerRevolution: %d\n", LubeConfig.PulsePerRevolution);
Debug_pushMessage("TireWidth_mm: %d\n", LubeConfig.TireWidth_mm);
Debug_pushMessage("TireWidthHeight_Ratio: %d\n", LubeConfig.TireWidth_mm);
Debug_pushMessage("TireWidthHeight_Ratio: %d\n", LubeConfig.TireWidthHeight_Ratio);
Debug_pushMessage("RimDiameter_Inch: %d\n", LubeConfig.RimDiameter_Inch);
Debug_pushMessage("DistancePerRevolution_mm: %d\n", LubeConfig.DistancePerRevolution_mm);
Debug_pushMessage("BleedingPulses: %d\n", LubeConfig.BleedingPulses);
@@ -247,6 +350,9 @@ void Debug_dumpConfig()
Debug_pushMessage("checksum: 0x%08X\n", LubeConfig.checksum);
}
/**
* @brief Dumps the global variables and their values to the debug output.
*/
void Debug_dumpGlobals()
{
Debug_pushMessage("systemStatus: %d\n", globals.systemStatus);
@@ -261,6 +367,9 @@ void Debug_dumpGlobals()
Debug_pushMessage("hasDTC: %d\n", globals.hasDTC);
}
/**
* @brief Dumps the persistence data variables and their values to the debug output.
*/
void Debug_dumpPersistance()
{
Debug_pushMessage("writeCycleCounter: %d\n", PersistenceData.writeCycleCounter);
@@ -270,12 +379,21 @@ void Debug_dumpPersistance()
Debug_pushMessage("PSD Adress: 0x%04X\n", globals.eePersistanceAdress);
}
/**
* @brief Prints information related to WiFi to the debug output.
*/
void Debug_printWifiInfo()
{
Debug_pushMessage("IP Adress: %s\n", WiFi.localIP().toString().c_str());
}
void Debug_CheckEEPOM()
/**
* @brief Checks the EEPROM data integrity by calculating and comparing checksums.
* Prints the result to the debug output.
*/
void Debug_CheckEEPOM(bool autocorrect)
{
// Check PersistenceData EEPROM checksum
uint32_t checksum = PersistenceData.checksum;
PersistenceData.checksum = 0;
@@ -290,6 +408,7 @@ void Debug_CheckEEPOM()
PersistenceData.checksum = checksum;
// Check LubeConfig EEPROM checksum
checksum = LubeConfig.checksum;
LubeConfig.checksum = 0;
@@ -302,26 +421,45 @@ void Debug_CheckEEPOM()
Debug_pushMessage("LubeConfig EEPROM Checksum BAD\n");
}
LubeConfig.checksum = checksum;
uint32_t sanitycheck = ConfigSanityCheck(autocorrect);
if (sanitycheck == 0)
{
Debug_pushMessage("LubeConfig Sanity Check OK\n");
}
else
{
Debug_pushMessage("LubeConfig Sanity Check BAD: %s\n", uint32_to_binary_string(sanitycheck));
}
}
/**
* @brief Displays Diagnostic Trouble Codes (DTCs) along with their timestamps,
* status, and severity in a formatted manner.
*/
void Debug_ShowDTCs()
{
char buff_timestamp[16]; // Format: DD-hh:mm:ss:xxx
char buff_active[9];
// Header for the DTC display
Debug_pushMessage("\n timestamp | DTC-Nr. | status | severity\n");
// Iterate through DTCStorage and display each entry
for (uint32_t i = 0; i < MAX_DTC_STORAGE; i++)
{
if (DTCStorage[i].Number < DTC_LAST_DTC)
{
// Format timestamp
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
DTCStorage[i].timestamp % 1000); // Milliseconds
// Determine DTC status
if (DTCStorage[i].active == DTC_ACTIVE)
strcpy(buff_active, "active");
else if (DTCStorage[i].active == DTC_PREVIOUS)
@@ -329,19 +467,69 @@ void Debug_ShowDTCs()
else
strcpy(buff_active, "none");
// Display DTC information
Debug_pushMessage("%s %7d %8s %8d\n", buff_timestamp, DTCStorage[i].Number, buff_active);
}
}
}
/**
* @brief Displays the help commands for debugging through Serial or WebUI.
* Each command is printed individually in a formatted manner.
*/
void Debug_printHelp()
{
char buff[64];
for (unsigned int i = sizeof(helpCmd) / 63; i < sizeof(helpCmd) / 63; i++)
// Iterate through helpCmd and display each command
for (unsigned int i = 0; i < sizeof(helpCmd) / 63; i++)
{
// Copy a portion of helpCmd to buff for display
memcpy_P(buff, (helpCmd + (i * 63)), 63);
buff[63] = 0;
// Display the help command
Debug_pushMessage(buff);
}
}
/**
* @brief Start purging for 10 pulses.
*/
void Debug_Purge()
{
globals.purgePulses = 10;
globals.resumeStatus = globals.systemStatus;
globals.systemStatus = sysStat_Purge;
Debug_pushMessage("Purging 10 pulses\n");
}
/**
* @brief Convert a uint32_t value to a binary string with nibbles separated by a space.
*
* This function takes a uint32_t value and converts it to a binary string
* representation. The binary string is stored in a static buffer and returned
* as a const char pointer. Each nibble (4 bits) in the binary representation
* is separated by a space. The buffer is overwritten on subsequent calls to
* this function.
*
* @param num The uint32_t value to convert.
* @return A pointer to a const char string containing the binary representation
* of the input number with nibbles separated by a space.
*/
const char *uint32_to_binary_string(uint32_t num)
{
static char binary_str[65]; // 32 bits + 31 spaces + null terminator
int i, j;
for (i = 31, j = 0; i >= 0; i--, j++)
{
binary_str[j] = ((num >> i) & 1) ? '1' : '0';
if (i % 4 == 0 && i != 0)
{
binary_str[++j] = ' '; // Insert space after every nibble
}
}
binary_str[j] = '\0'; // Null terminator
return binary_str;
}

View File

@@ -1,14 +1,37 @@
/**
* @file dtc.cpp
* @brief Implementation of functions related to Diagnostic Trouble Codes (DTCs).
*
* This file contains the implementation of functions that manage the status
* and registration of Diagnostic Trouble Codes in the system.
*
* @author Marcel Peterkau
* @date 09.01.2024
*/
#include "dtc.h"
#include "debugger.h"
DTCEntry_t DTCStorage[MAX_DTC_STORAGE];
// Function implementations...
/**
* @brief Maintains the status of Diagnostic Trouble Codes (DTCs) in the DTCStorage array.
* Updates the status of existing DTCs or adds new ones based on their activity.
*
* @param DTC_no The number of the Diagnostic Trouble Code.
* @param active Indicates whether the DTC is active (true) or inactive (false).
* @param DebugValue Additional debugging information associated with the DTC.
*/
void MaintainDTC(DTCNum_t DTC_no, boolean active, uint32_t DebugValue)
{
// Iterate through the existing DTCs in the storage
for (int i = 0; i < MAX_DTC_STORAGE; i++)
{
// Check if the DTC with the specified number exists
if (DTCStorage[i].Number == DTC_no)
{
// If the DTC is active and was not active before, update its status
if (active && DTCStorage[i].active != DTC_ACTIVE)
{
Debug_pushMessage("DTC gone active: %d, DebugVal: %d\n", DTC_no, DebugValue);
@@ -16,21 +39,23 @@ void MaintainDTC(DTCNum_t DTC_no, boolean active, uint32_t DebugValue)
DTCStorage[i].active = DTC_ACTIVE;
DTCStorage[i].debugVal = DebugValue;
}
// If the DTC is not active anymore, update its status to previous
if (!active && DTCStorage[i].active == DTC_ACTIVE)
{
Debug_pushMessage("DTC gone previous: %d\n", DTC_no);
DTCStorage[i].active = DTC_PREVIOUS;
}
return;
return; // DTC found and processed, exit the function
}
}
// DTC was not found with upper iteration, but is active
// so we need to look for free space to store DTC
// DTC was not found in the existing storage, but it is active,
// so look for free space to store the new DTC
if (active == true)
{
for (int i = 0; i < MAX_DTC_STORAGE; i++)
{
// Check for an empty slot in the storage
if (DTCStorage[i].Number == DTC_LAST_DTC)
{
Debug_pushMessage("new DTC registered: %d, DebugVal: %d\n", DTC_no, DebugValue);
@@ -38,12 +63,20 @@ void MaintainDTC(DTCNum_t DTC_no, boolean active, uint32_t DebugValue)
DTCStorage[i].timestamp = millis();
DTCStorage[i].active = DTC_ACTIVE;
DTCStorage[i].debugVal = DebugValue;
return;
return; // New DTC registered, exit the function
}
}
}
}
/**
* @brief Clears a specific Diagnostic Trouble Code (DTC) entry.
*
* This function clears the information related to a specific DTC entry,
* setting its status to inactive and timestamp to zero.
*
* @param DTC_no The Diagnostic Trouble Code number to be cleared.
*/
void ClearDTC(DTCNum_t DTC_no)
{
for (int i = 0; i < MAX_DTC_STORAGE; i++)
@@ -57,6 +90,12 @@ void ClearDTC(DTCNum_t DTC_no)
}
}
/**
* @brief Clears all Diagnostic Trouble Code (DTC) entries.
*
* This function clears all DTC entries, setting their status to inactive and
* timestamps to zero.
*/
void ClearAllDTC()
{
for (int i = 0; i < MAX_DTC_STORAGE; i++)
@@ -67,6 +106,15 @@ void ClearAllDTC()
}
}
/**
* @brief Gets the last recorded Diagnostic Trouble Code (DTC) number.
*
* This function retrieves the DTC number of the last recorded DTC based on the
* timestamp. Optionally, it can filter only active DTCs.
*
* @param only_active If true, considers only active DTCs; otherwise, considers all.
* @return The DTC number of the last recorded DTC or DTC_LAST_DTC if none found.
*/
DTCNum_t getlastDTC(boolean only_active)
{
int8_t pointer = -1;
@@ -87,6 +135,15 @@ DTCNum_t getlastDTC(boolean only_active)
return pointer >= 0 ? DTCStorage[pointer].Number : DTC_LAST_DTC;
}
/**
* @brief Gets the severity level for a specific Diagnostic Trouble Code (DTC).
*
* This function looks up the severity level associated with the provided DTC code
* from the predefined list of DTC definitions.
*
* @param targetCode The DTC code for which to retrieve the severity.
* @return The severity level of the specified DTC or DTC_NONE if not found.
*/
DTCSeverity_t getSeverityForDTC(DTCNum_t targetCode)
{
for (int i = 0; i < DTC_LAST_DTC; i++)
@@ -99,6 +156,16 @@ DTCSeverity_t getSeverityForDTC(DTCNum_t targetCode)
return DTC_NONE;
}
/**
* @brief Processes Diagnostic Trouble Codes (DTCs) and updates system status accordingly.
*
* This function checks for the presence of active DTCs and adjusts the system status
* based on the severity of the most critical DTC. If a critical DTC is detected,
* the system status is set to sysStat_Error, potentially triggering a system shutdown.
*
* @note The function also preserves the original system status when transitioning to an error state
* and restores it when all DTCs are cleared.
*/
void DTC_Process()
{
static tSystem_Status preserverSysStatusError;
@@ -120,10 +187,10 @@ void DTC_Process()
else
{
globals.hasDTC = false;
if (globals.systemStatus == sysStat_Error)
{
globals.systemStatus = preserverSysStatusError;
}
}
}
}

View File

@@ -1,18 +1,23 @@
# No. | DTC-Constant | Severity | Title | Description
#-----|------------------------------|---------------|-----------------------|----------------------------------------------------------------------------------------------------------------------------------------------------
1; DTC_TANK_EMPTY; DTC_CRITICAL; Ölvorrat leer; Ölvorrat ist komplett leer. Den Ölvorrat auffüllen und im Menu 'Wartung' zurück setzen
2; DTC_TANK_LOW; DTC_WARN; Ölvorrat niedrig; Ölvorrat ist unter der Warnschwelle. Den Ölvorrat demnächst auffüllen und im Menu 'Wartung' zurück setzen
3; DTC_NO_EEPROM_FOUND; DTC_CRITICAL; kein EEPROM erkannt; Es wurde kein EEPROM gefunden. Dies lässt einen Hardware-Defekt vermuten.
4; DTC_EEPROM_CFG_BAD; DTC_CRITICAL; EEPROM CFG Checksumme; Die Checksumme der Config-Partition des EEPROM ist ungültig. Setzen sie den EEPROM-Bereich 'CFG' im Menu 'Wartung' zurück
5; DTC_EEPROM_PDS_BAD; DTC_CRITICAL; EEPROM PDS Checksumme; Die Checksumme der Betriebsdaten-Partition des EEPROM ist ungültig. Setzen sie den EEPROM-Bereich 'PDS' im Menu 'Wartung' zurück
6; DTC_EEPROM_PDSADRESS_BAD; DTC_CRITICAL; EEPROM PDS Adresse; Die Adresse der Betriebsdaten-Partition im EEPROM ist ungültig. Setzen sie den EEPROM-Bereich 'PDS' im Menu 'Wartung' zurück
7; DTC_EEPROM_VERSION_BAD; DTC_CRITICAL; EEPROM Version falsch; Die Layout-Version des EEPROM stimmt nicht mit der Firmware-Version überein. Setzen sie den EEPROM-Bereich 'CFG' im Menu 'Wartung' zurück
8; DTC_FLASHFS_ERROR; DTC_CRITICAL; Flashspeicher Fehler; Der Flashspeicher konnte nicht initialisiert werden. Aktualisieren sie Flash & Firmware
9; DTC_FLASHFS_VERSION_ERROR; DTC_CRITICAL; Flashversion falsch; Die Version des Flashspeicher stimmt nicht mit der Firmware-Version überein. Aktualisieren sie den Flash mit der passenden Update-Datei
10; DTC_NO_GPS_SERIAL; DTC_CRITICAL; Keine GPS-Verbindung; Es wurde kein GPS-Signal über die serielle Schnittstelle empfangen, Prüfen sie die Verbindung und das GPS-Modul
11; DTC_CAN_TRANSCEIVER_FAILED; DTC_CRITICAL; CAN-Transceiver Error; Es konnte keine Verbindung zum CAN-Transceiver hergestellt werden. Prüfen Sie die Hardware auf Defekte
12; DTC_NO_CAN_SIGNAL; DTC_WARN; Keine CAN-Verbindung; Es konnte kein CAN-Signal empfangen werden. Prüfen sie die Verbindung und die Einstellungen
13; DTC_EEPROM_CFG_SANITY; DTC_WARN; Config-Validierung; Ein oder mehrer Einstellungswerte sind ausserhalb plausibler Werte. Prüfen Sie Ihre Einstellungen
14; DTC_FAKE_DTC_INFO; DTC_INFO; Dummy-DTC Info; Ein Dummy-DTC der Schwere "Info" für Debugging-Zwecke
15; DTC_FAKE_DTC_WARN; DTC_WARN; Dummy-DTC Warnung; Ein Dummy-DTC der Schwere "Warnung" für Debugging-Zwecke
16; DTC_FAKE_DTC_CRIT; DTC_CRITICAL; Dummy-DTC Kritisch; Ein Dummy-DTC der Schwere "Kritisch" für Debugging-Zwecke
# No. | DTC-Constant | Severity | Title | Description
#-----|------------------------------|---------------|----------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------
1; DTC_TANK_EMPTY; DTC_CRITICAL; Ölvorrat leer; Ölvorrat ist komplett leer. Den Ölvorrat auffüllen und im Menu 'Wartung' zurück setzen
2; DTC_TANK_LOW; DTC_WARN; Ölvorrat niedrig; Ölvorrat ist unter der Warnschwelle. Den Ölvorrat demnächst auffüllen und im Menu 'Wartung' zurück setzen
3; DTC_NO_EEPROM_FOUND; DTC_CRITICAL; kein EEPROM erkannt; Es wurde kein EEPROM gefunden. Dies lässt einen Hardware-Defekt vermuten.
4; DTC_EEPROM_CFG_BAD; DTC_CRITICAL; EEPROM CFG Checksumme; Die Checksumme der Config-Partition des EEPROM ist ungültig. Setzen sie den EEPROM-Bereich 'CFG' im Menu 'Wartung' zurück
5; DTC_EEPROM_PDS_BAD; DTC_CRITICAL; EEPROM PDS Checksumme; Die Checksumme der Betriebsdaten-Partition des EEPROM ist ungültig. Setzen sie den EEPROM-Bereich 'PDS' im Menu 'Wartung' zurück
6; DTC_EEPROM_PDSADRESS_BAD; DTC_CRITICAL; EEPROM PDS Adresse; Die Adresse der Betriebsdaten-Partition im EEPROM ist ungültig. Setzen sie den EEPROM-Bereich 'PDS' im Menu 'Wartung' zurück
7; DTC_EEPROM_VERSION_BAD; DTC_CRITICAL; EEPROM Version falsch; Die Layout-Version des EEPROM stimmt nicht mit der Firmware-Version überein. Setzen sie den EEPROM-Bereich 'CFG' im Menu 'Wartung' zurück
8; DTC_FLASHFS_ERROR; DTC_CRITICAL; Flashspeicher Fehler; Der Flashspeicher konnte nicht initialisiert werden. Aktualisieren sie Flash & Firmware
9; DTC_FLASHFS_VERSION_ERROR; DTC_CRITICAL; Flashversion falsch; Die Version des Flashspeicher stimmt nicht mit der Firmware-Version überein. Aktualisieren sie den Flash mit der passenden Update-Datei
10; DTC_NO_GPS_SERIAL; DTC_CRITICAL; Keine GPS-Verbindung; Es wurde kein GPS-Signal über die serielle Schnittstelle empfangen, Prüfen sie die Verbindung und das GPS-Modul
11; DTC_CAN_TRANSCEIVER_FAILED; DTC_CRITICAL; CAN-Transceiver Error; Es konnte keine Verbindung zum CAN-Transceiver hergestellt werden. Prüfen Sie die Hardware auf Defekte
12; DTC_NO_CAN_SIGNAL; DTC_WARN; Keine CAN-Verbindung; Es konnte kein CAN-Signal empfangen werden. Prüfen sie die Verbindung und die Einstellungen
13; DTC_EEPROM_CFG_SANITY; DTC_WARN; Config-Validierung; Ein oder mehrer Einstellungswerte sind ausserhalb plausibler Werte. Prüfen Sie Ihre Einstellungen
14; DTC_FAKE_DTC_INFO; DTC_INFO; Dummy-DTC Info; Ein Dummy-DTC der Schwere "Info" für Debugging-Zwecke
15; DTC_FAKE_DTC_WARN; DTC_WARN; Dummy-DTC Warnung; Ein Dummy-DTC der Schwere "Warnung" für Debugging-Zwecke
16; DTC_FAKE_DTC_CRIT; DTC_CRITICAL; Dummy-DTC Kritisch; Ein Dummy-DTC der Schwere "Kritisch" für Debugging-Zwecke
17; DTC_OBD2_KLINE_TIMEOUT; DTC_CRITICAL; OBD2-KLine Timeout; Die Anfrage über OBD2-KLine konnte nicht gesendet werden. Prüfen Sie den K-Line-Treiber (z.B. L9637D) und die Verkabelung.
18; DTC_OBD2_CAN_TIMEOUT; DTC_CRITICAL; OBD2-CAN Timeout; Die Anfrage an das Steuergerät über OBD2-CAN konnte nicht gesendet werden. Prüfen Sie die Verbindung zum CAN-Modul und die OBD2-Konfiguration.
19; DTC_OBD2_CAN_NO_RESPONSE; DTC_WARN; Keine OBD2-CAN Antwort; Es wurde innerhalb der erwarteten Zeit keine Antwort vom Steuergerät über OBD2-CAN empfangen. Prüfen Sie, ob das Fahrzeug OBD2 unterstützt und die Verbindung korrekt ist.
20; DTC_OBD2_KLINE_NO_RESPONSE; DTC_WARN; Keine OBD2-KLine Antwort; Es wurde innerhalb der erwarteten Zeit keine Antwort über OBD2-KLine empfangen. Prüfen Sie die Verbindung zum Steuergerät und die Protokollkompatibilität.
21; DTC_OBD2_KLINE_BAD_FRAME; DTC_WARN; OBD2-KLine Antwort ungültig; Das empfangene Frame war unvollständig oder entsprach nicht dem erwarteten OBD2-Format. Möglicherweise inkompatibles Steuergerät.

View File

@@ -1,7 +1,23 @@
/**
* @file globals.cpp
* @brief Implementation of global variables and initialization functions.
*
* This file defines and initializes the global variables used throughout the project.
* The global variables are encapsulated in the Globals_t structure. The initGlobals function
* is responsible for initializing these variables to their default values during system startup.
*/
#include "globals.h"
// Global instance of the Globals_t structure
Globals_t globals;
/**
* @brief Initializes global variables to default values during system startup.
*
* This function sets the initial values for various global variables, ensuring proper
* initialization of system-wide parameters.
*/
void initGlobals()
{
globals.purgePulses = 0;
@@ -10,4 +26,5 @@ void initGlobals()
globals.systemStatus = sysStat_Startup;
globals.measurementActive = false;
globals.measuredPulses = 0;
globals.toggle_wifi = false;
}

View File

@@ -1,7 +1,26 @@
/**
* @file gps.cpp
*
* @brief Implementation file for GPS-related functions in the ChainLube application.
*
* This file contains the implementation of functions related to GPS functionality within the ChainLube
* application. It includes the initialization of the GPS module, processing GPS data for wheel speed,
* and maintaining Diagnostic Trouble Codes (DTCs) based on GPS communication status.
*
* @author Marcel Peterkau
* @date 09.01.2024
*/
#include "gps.h"
TinyGPSPlus gps;
/**
* @brief Initializes the GPS module with the specified baud rate.
*
* This function initializes the GPS module with the baud rate configured in the application settings.
* It also prints a debug message indicating the initialization status.
*/
void Init_GPS()
{
uint32_t baudrate;
@@ -22,6 +41,15 @@ void Init_GPS()
Serial.begin(baudrate);
}
/**
* @brief Processes GPS data to calculate rear wheel speed and returns the distance traveled.
*
* This function processes GPS data received from the GPS module, calculates the rear wheel speed in
* kilometers per hour, and returns the distance traveled based on the speed and time elapsed since
* the last valid speed measurement.
*
* @return The distance traveled in millimeters since the last GPS speed measurement.
*/
uint32_t Process_GPS_WheelSpeed()
{
static uint32_t lastRecTimestamp;
@@ -49,7 +77,9 @@ uint32_t Process_GPS_WheelSpeed()
lastRecTimestamp = millis();
}
}
// Maintain DTC for no GPS data received within a certain time frame
MaintainDTC(DTC_NO_GPS_SERIAL, (millis() > lastRecTimestamp + 10000));
return 0;
}
}

View File

@@ -1,28 +1,56 @@
/**
* @file lubeapp.cpp
*
* @brief Implementation file for the ChainLube application logic.
*
* This file contains the implementation of the ChainLube application logic, including functions
* for running the main application, initiating lubrication pulses, and maintaining system status.
* Global variables related to lubrication pulses are also defined in this file.
*
* @author Marcel Peterkau
* @date 09.01.2024
*/
#include "lubeapp.h"
uint32_t lubePulseTimestamp = 0;
/**
* @brief Runs the main logic of the ChainLube application based on the current system status.
*
* This function is responsible for executing the main logic of the ChainLube application. It calculates
* the tank percentage, maintains Diagnostic Trouble Codes (DTCs) related to the tank level, updates travel
* distances, triggers lubrication pulses, and handles the behavior based on the current system status
* (Startup, Normal, Rain, Purge, Error, Shutdown). It also manages the pin state of the lube pump.
*
* @param add_milimeters The additional distance traveled in millimeters to be processed by the application.
*/
void RunLubeApp(uint32_t add_milimeters)
{
// Calculate and update tank percentage
globals.TankPercentage = PersistenceData.tankRemain_microL / (LubeConfig.tankCapacity_ml * 10);
// Maintain DTCs related to tank level
MaintainDTC(DTC_TANK_EMPTY, (PersistenceData.tankRemain_microL < LubeConfig.amountPerDose_microL));
MaintainDTC(DTC_TANK_LOW, (globals.TankPercentage < LubeConfig.TankRemindAtPercentage));
// Add traveled Distance in mm
// Add traveled distance in millimeters
PersistenceData.TravelDistance_highRes_mm += add_milimeters;
PersistenceData.odometer_mm += add_milimeters;
// Update odometer if necessary
if (PersistenceData.odometer_mm >= 1000000)
{
PersistenceData.odometer++;
PersistenceData.odometer_mm = 0;
}
// Handle different system statuses
switch (globals.systemStatus)
{
case sysStat_Startup:
strcpy_P(globals.systemStatustxt, PSTR("Startup"));
// Transition to Normal status after startup delay
if (millis() > STARTUP_DELAY)
{
globals.systemStatus = sysStat_Normal;
@@ -32,6 +60,7 @@ void RunLubeApp(uint32_t add_milimeters)
case sysStat_Normal:
strcpy_P(globals.systemStatustxt, PSTR("Normal"));
// Trigger lube pulse if traveled distance exceeds the configured limit
if (PersistenceData.TravelDistance_highRes_mm / 1000 > LubeConfig.DistancePerLube_Default)
{
LubePulse();
@@ -41,16 +70,20 @@ void RunLubeApp(uint32_t add_milimeters)
case sysStat_Rain:
strcpy_P(globals.systemStatustxt, PSTR("Rain"));
// Trigger lube pulse if traveled distance exceeds the configured limit in Rain mode
if (PersistenceData.TravelDistance_highRes_mm / 1000 > LubeConfig.DistancePerLube_Rain)
{
LubePulse();
PersistenceData.TravelDistance_highRes_mm = 0;
}
break;
case sysStat_Purge:
strcpy_P(globals.systemStatustxt, PSTR("Purge"));
// Execute lube pulses during the Purge status
if (globals.purgePulses > 0)
{
// Check if enough time has passed since the last lube pulse
if (lubePulseTimestamp + LUBE_PULSE_PAUSE_MS < millis())
{
LubePulse();
@@ -60,35 +93,49 @@ void RunLubeApp(uint32_t add_milimeters)
}
else
{
// Transition back to the previous status after completing purge pulses
globals.systemStatus = globals.resumeStatus;
}
break;
case sysStat_Error:
strcpy_P(globals.systemStatustxt, PSTR("Error"));
globals.purgePulses = 0;
break;
case sysStat_Shutdown:
strcpy_P(globals.systemStatustxt, PSTR("Shutdown"));
break;
default:
break;
}
// maintain Pin-State of Lube-Pump
// Maintain Pin-State of Lube-Pump
if (lubePulseTimestamp > millis())
digitalWrite(GPIO_PUMP, HIGH);
else
digitalWrite(GPIO_PUMP, LOW);
}
/**
* @brief Initiates a lubrication pulse if there is sufficient oil remaining in the tank.
*
* This function checks if there is enough oil remaining in the tank to perform a lubrication pulse.
* If there is sufficient oil, it updates the lubePulseTimestamp to trigger the pulse and decreases
* the tank oil level by the configured amount per dose (LubeConfig.amountPerDose_microL).
*/
void LubePulse()
{
if (PersistenceData.tankRemain_microL > 0) // Only Lube if theres Oil remaining!
// Only initiate a lubrication pulse if there is oil remaining in the tank
if (PersistenceData.tankRemain_microL > 0)
{
lubePulseTimestamp = millis() + LUBE_PULSE_LENGHT_MS;
if (PersistenceData.tankRemain_microL < LubeConfig.amountPerDose_microL) // Prevent underrun and shiftover
// Prevent underrun and shift over by adjusting the tank oil level
if (PersistenceData.tankRemain_microL < LubeConfig.amountPerDose_microL)
PersistenceData.tankRemain_microL = 0;
else
PersistenceData.tankRemain_microL = PersistenceData.tankRemain_microL - LubeConfig.amountPerDose_microL;
PersistenceData.tankRemain_microL -= LubeConfig.amountPerDose_microL;
}
}
}

View File

@@ -1,3 +1,18 @@
/**
* @file main.cpp
*
* @brief Main source file for the Souko's ChainLube Mk1 ESP8266 project.
*
* This file includes necessary libraries, defines configuration options, and declares global variables
* and function prototypes. It sets up essential components, initializes peripherals, and defines
* callbacks for interrupt service routines (ISRs) and timers. The main setup function configures the
* project, and the loop function handles the main execution loop, performing various tasks based on
* the configured options.
*
* @author Marcel Peterkau
* @date 09.01.2024
*/
#include <Arduino.h>
#include <Wire.h>
#ifdef FEATURE_ENABLE_OLED
@@ -22,6 +37,8 @@
#include "gps.h"
#include "dtc.h"
#include "led_colors.h"
#include "obd2_kline.h"
#include "obd2_can.h"
#ifdef FEATURE_ENABLE_WIFI_CLIENT
#include <ESP8266WiFiMulti.h>
@@ -33,6 +50,8 @@ const uint32_t connectTimeoutMs = 5000;
ESP8266WiFiMulti wifiMulti;
#endif
uint32_t (*wheelSpeedcapture)() = nullptr;
bool startSetupMode = false;
volatile uint32_t wheel_pulse = 0;
@@ -46,8 +65,8 @@ U8X8_SSD1306_128X64_NONAME_HW_I2C u8x8(-1);
void Display_Process();
#endif
void Button_Process();
void toggleWiFiAP(boolean shutdown = false);
void SystemShutdown();
void toggleWiFiAP(bool shutdown = false);
void SystemShutdown(bool restart = false);
uint32_t Process_Impulse_WheelSpeed();
void EEPROMCyclicPDS_callback();
@@ -57,28 +76,49 @@ Ticker WiFiMaintainConnectionTicker(wifiMaintainConnectionTicker_callback, 1000,
#endif
Ticker EEPROMCyclicPDSTicker(EEPROMCyclicPDS_callback, 60000, 0, MILLIS);
/**
* @brief Initializes the ESP8266 project, configuring various components and setting up required services.
*
* This setup function is responsible for initializing the ESP8266 project, including setting the CPU frequency,
* configuring WiFi settings, initializing DTC storage, handling WiFi client functionality (if enabled),
* initializing the Serial communication, setting up an OLED display (if enabled), initializing EEPROM,
* loading configuration and persistence data from EEPROM, initializing LEDs, setting up the chosen speed source
* (CAN, GPS, Impulse), configuring GPIO pins, setting up Over-The-Air (OTA) updates, initializing the web user interface,
* initializing global variables, starting cyclic EEPROM updates for Persistence Data Structure (PDS), and printing
* initialization status messages to Serial.
*/
void setup()
{
// Set CPU frequency to 80MHz
system_update_cpu_freq(SYS_CPU_80MHZ);
// Generate a unique device name based on ESP chip ID
snprintf(globals.DeviceName, 32, HOST_NAME, ESP.getChipId());
// Disable WiFi persistent storage
WiFi.persistent(false);
ClearAllDTC(); // Init DTC-Storage
// Initialize and clear Diagnostic Trouble Code (DTC) storage
ClearAllDTC();
#ifdef FEATURE_ENABLE_WIFI_CLIENT
// Configure WiFi settings for client mode if enabled
WiFi.mode(WIFI_STA);
WiFi.setHostname(globals.DeviceName);
wifiMulti.addAP(QUOTE(WIFI_SSID_CLIENT), QUOTE(WIFI_PASSWORD_CLIENT));
WiFiMaintainConnectionTicker.start();
#else
// Disable WiFi if WiFi client feature is not enabled
WiFi.mode(WIFI_OFF);
#endif
// Initialize Serial communication
Serial.begin(115200);
Serial.print("\n\nSouko's ChainLube Mk1\n");
Serial.print(globals.DeviceName);
#ifdef FEATURE_ENABLE_OLED
// Initialize OLED display if enabled
u8x8.begin();
u8x8.setFont(u8x8_font_chroma48medium8_r);
u8x8.clearDisplay();
@@ -87,45 +127,65 @@ void setup()
Serial.print("\nDisplay-Init done");
#endif
// Initialize EEPROM, load configuration, and persistence data from EEPROM
InitEEPROM();
GetConfig_EEPROM();
GetPersistence_EEPROM();
Serial.print("\nEE-Init done");
// Initialize LEDs
leds.begin();
Serial.print("\nLED-Init done");
// Initialize based on the chosen speed source (CAN, GPS, Impulse)
switch (LubeConfig.SpeedSource)
{
case SOURCE_CAN:
Init_CAN();
wheelSpeedcapture = &Process_CAN_WheelSpeed;
Serial.print("\nCAN-Init done");
break;
case SOURCE_GPS:
Init_GPS();
wheelSpeedcapture = &Process_GPS_WheelSpeed;
Serial.print("\nGPS-Init done");
break;
case SOURCE_IMPULSE:
pinMode(GPIO_TRIGGER, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(GPIO_TRIGGER), trigger_ISR, FALLING);
wheelSpeedcapture = &Process_Impulse_WheelSpeed;
Serial.print("\nPulse-Input Init done");
break;
case SOURCE_OBD2_KLINE:
Init_OBD2_KLine(Serial);
wheelSpeedcapture = &Process_OBD2_KLine_Speed;
Serial.print("\nOBD2-KLine-Init done");
break;
case SOURCE_OBD2_CAN:
Init_OBD2_CAN();
wheelSpeedcapture = &Process_OBD2_CAN_Speed;
Serial.print("\nOBD2-CAN-Init done");
break;
default:
break;
}
Serial.print("\nSource-Init done");
// Configure GPIO pins for button and pump control
pinMode(GPIO_BUTTON, INPUT_PULLUP);
pinMode(GPIO_PUMP, OUTPUT);
// Set up OTA updates
ArduinoOTA.setPort(8266);
ArduinoOTA.setHostname(globals.DeviceName);
ArduinoOTA.setPassword(QUOTE(ADMIN_PASSWORD));
#ifdef FEATURE_ENABLE_OLED
// Set up OTA callbacks for OLED display if enabled
ArduinoOTA.onStart([]()
{
u8x8.clearDisplay();
u8x8.drawString(0, 0, "OTA-Update");
u8x8.drawString(0, 6, "OTA-Update");
u8x8.refreshDisplay(); });
ArduinoOTA.onProgress([](unsigned int progress, unsigned int total)
@@ -135,59 +195,60 @@ void setup()
{
u8x8.clearDisplay();
refreshed = true;
u8x8.drawString(0, 0, "OTA Upload");
u8x8.drawString(0, 6, "OTA Upload");
}
uint32_t percent = progress / (total / 100);
u8x8.setCursor(0, 1);
u8x8.setCursor(0, 7);
u8x8.printf("%d %%", percent);
u8x8.refreshDisplay(); });
ArduinoOTA.onEnd([]()
{
u8x8.clearDisplay();
u8x8.drawString(0, 0, "OTA-Restart");
u8x8.drawString(0, 6, "OTA-Restart");
u8x8.refreshDisplay(); });
#endif
// Begin OTA updates
ArduinoOTA.begin();
Serial.print("\nOTA-Init done");
// Initialize the web user interface
initWebUI();
Serial.print("\nWebUI-Init done");
// Initialize global variables
initGlobals();
Serial.print("\nglobals-Init done");
// Start cyclic EEPROM updates for Persistence Data Structure (PDS)
EEPROMCyclicPDSTicker.start();
Serial.print("\nSetup Done\n");
}
/**
* @brief Main execution loop for the ESP8266 project, performing various tasks based on configuration.
*
* This loop function handles different tasks based on the configured source of speed data (impulse, CAN, time, GPS).
* It calculates wheel distance, runs the lubrication application, updates the OLED display (if enabled),
* processes CAN messages, handles button input, manages LED behavior, performs EEPROM-related tasks, handles
* webserver operations, processes Diagnostic Trouble Codes (DTC), and manages debugging. Additionally, it
* integrates functionalities such as Over-The-Air (OTA) updates, cyclic EEPROM updates for Persistence Data
* Structure (PDS), WiFi connection maintenance, and system shutdown handling.
*/
void loop()
{
uint32_t wheelDistance = 0;
// Run lubrication application with the calculated wheel distance
if (wheelSpeedcapture != nullptr)
RunLubeApp(wheelSpeedcapture());
switch (LubeConfig.SpeedSource)
{
case SOURCE_IMPULSE:
wheelDistance = Process_Impulse_WheelSpeed();
break;
case SOURCE_CAN:
wheelDistance = Process_CAN_WheelSpeed();
break;
#ifdef FEATURE_ENABLE_TIMER
case SOURCE_TIME:
break;
#endif
case SOURCE_GPS:
wheelDistance = Process_GPS_WheelSpeed();
break;
}
RunLubeApp(wheelDistance);
#ifdef FEATURE_ENABLE_OLED
// Update OLED display if enabled
Display_Process();
#endif
if (LubeConfig.SpeedSource != SOURCE_IMPULSE)
{
CAN_Process();
}
// Process button input, manage LED behavior, perform EEPROM tasks, handle webserver operations,
// process Diagnostic Trouble Codes (DTC), and manage debugging
Button_Process();
LED_Process();
EEPROM_Process();
@@ -195,61 +256,104 @@ void loop()
DTC_Process();
Debug_Process();
if (globals.toggle_wifi == true){
globals.toggle_wifi = false;
toggleWiFiAP();
}
// Handle OTA updates and update cyclic EEPROM tasks for Persistence Data Structure (PDS)
ArduinoOTA.handle();
EEPROMCyclicPDSTicker.update();
#ifdef FEATURE_ENABLE_WIFI_CLIENT
// Update WiFi connection maintenance ticker if WiFi client feature is enabled
WiFiMaintainConnectionTicker.update();
#endif
// Perform system shutdown if the status is set to shutdown
if (globals.systemStatus == sysStat_Shutdown)
SystemShutdown();
SystemShutdown(false);
// Yield to allow other tasks to run
yield();
}
String IpAddress2String(const IPAddress &ipAddress)
{
return String(ipAddress[0]) + String(".") +
String(ipAddress[1]) + String(".") +
String(ipAddress[2]) + String(".") +
String(ipAddress[3]);
}
#ifdef FEATURE_ENABLE_WIFI_CLIENT
/**
* @brief Callback function for maintaining WiFi connection and handling connection failures.
*
* This callback function is used by a ticker to periodically check the WiFi connection status.
* If the device is not connected to WiFi, it counts connection failures. If the number of failures
* exceeds a defined threshold, the function triggers the initiation of an Access Point (AP) mode
* using the `toggleWiFiAP` function.
*/
void wifiMaintainConnectionTicker_callback()
{
// Static variables to track WiFi connection failure count and maximum allowed failures
static uint32_t WiFiFailCount = 0;
const uint32_t WiFiFailMax = 20;
// Check if the device is connected to WiFi
if (wifiMulti.run(connectTimeoutMs) == WL_CONNECTED)
{
return;
return; // Exit if connected
}
else
{
// Increment WiFi connection failure count
if (WiFiFailCount < WiFiFailMax)
{
WiFiFailCount++;
}
else
{
Debug_pushMessage("WiFi not connected! - Start AP");
// Trigger AP mode if the maximum failures are reached
Debug_pushMessage("WiFi not connected! - Start AP\n");
toggleWiFiAP();
}
}
}
#endif
/**
* @brief Callback function for cyclically storing Persistence Data Structure (PDS) to EEPROM.
*
* This callback function is invoked periodically to store the Persistence Data Structure (PDS)
* to the EEPROM. It ensures that essential data is saved persistently, allowing the system to
* recover its state after power cycles or resets.
*/
void EEPROMCyclicPDS_callback()
{
StorePersistence_EEPROM();
}
/**
* @brief Interrupt Service Routine (ISR) triggered by wheel speed sensor pulses.
*
* This ISR is called whenever a pulse is detected from the wheel speed sensor. It increments
* the `wheel_pulse` variable, which is used to track the number of pulses received.
*/
void trigger_ISR()
{
wheel_pulse++;
}
/**
* @brief Manages LED behavior based on the current system status and user overrides.
*
* This function handles LED behavior, including startup animations, confirmation animations for
* normal and rain modes, indication for purge, error, shutdown, and normal operation. It supports
* user overrides to set a specific LED color. The LED status is determined by the current system
* status, and specific LED patterns are displayed accordingly.
*
* @param override Flag indicating whether to override the LED behavior (0: No override, 1: Override, 2: Resume previous state).
* @param SetColor The color to set when overriding the LED behavior.
*/
void LED_Process(uint8_t override, uint32_t SetColor)
{
// Enumeration to represent LED status
typedef enum
{
LED_Startup,
@@ -263,17 +367,20 @@ void LED_Process(uint8_t override, uint32_t SetColor)
LED_Override
} tLED_Status;
// Static variables to track LED status, system status, override color, and previous LED status
static tSystem_Status oldSysStatus = sysStat_Startup;
static tLED_Status LED_Status = LED_Startup;
static uint32_t LED_override_color = 0;
static tLED_Status LED_ResumeOverrideStatus = LED_Startup;
// Variables for managing LED animation timing
uint8_t color = 0;
uint32_t timer = 0;
uint32_t animtimer = 0;
static uint32_t timestamp = 0;
timer = millis();
// Handle LED overrides
if (override == 1)
{
if (LED_Status != LED_Override)
@@ -294,6 +401,7 @@ void LED_Process(uint8_t override, uint32_t SetColor)
}
}
// Update LED status when system status changes
if (oldSysStatus != globals.systemStatus)
{
switch (globals.systemStatus)
@@ -330,6 +438,7 @@ void LED_Process(uint8_t override, uint32_t SetColor)
oldSysStatus = globals.systemStatus;
}
// Handle different LED statuses
switch (LED_Status)
{
case LED_Startup:
@@ -433,28 +542,47 @@ void LED_Process(uint8_t override, uint32_t SetColor)
}
leds.show();
}
#ifdef FEATURE_ENABLE_OLED
/**
* @brief Manages the display content based on the current system status and updates the OLED display.
*
* This function handles the content to be displayed on the OLED screen, taking into account the
* current system status. It clears the display and prints relevant information such as system mode,
* remaining lubrication distance, tank level, WiFi status, speed source, and IP address. Additionally,
* it refreshes the OLED display with the updated content.
*/
void Display_Process()
{
// Static variable to track the previous system status
static tSystem_Status oldSysStatus = sysStat_Startup;
// Check if the system status has changed since the last update
if (oldSysStatus != globals.systemStatus)
{
// Clear the display and print the system title when the status changes
u8x8.clearDisplay();
u8x8.drawString(0, 0, "KTM ChainLube V1");
oldSysStatus = globals.systemStatus;
}
// Set the cursor position for displaying information on the OLED screen
u8x8.setCursor(0, 1);
// Calculate remaining lubrication distance based on system mode
uint32_t DistRemain = globals.systemStatus == sysStat_Normal ? LubeConfig.DistancePerLube_Default : LubeConfig.DistancePerLube_Rain;
DistRemain = DistRemain - (PersistenceData.TravelDistance_highRes_mm / 1000);
// Display relevant information on the OLED screen based on system status
u8x8.printf(PSTR("Mode: %10s\n"), globals.systemStatustxt);
if (globals.systemStatus == sysStat_Error)
{
// Display the last Diagnostic Trouble Code (DTC) in case of an error
u8x8.printf(PSTR("last DTC: %6d\n"), getlastDTC(false));
}
else
{
// Display information such as next lubrication distance, tank level, WiFi status, speed source, and IP address
u8x8.printf(PSTR("next Lube: %4dm\n"), DistRemain);
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"
@@ -463,18 +591,29 @@ void Display_Process()
u8x8.printf(PSTR("Source: %8s\n"), SpeedSourceString[LubeConfig.SpeedSource]);
u8x8.printf("%s\n", WiFi.localIP().toString().c_str());
}
// Refresh the OLED display with the updated content
u8x8.refreshDisplay();
}
#endif
/**
* @brief Processes the button input and performs corresponding actions based on button state and timing.
*
* This function handles the button input, detecting button presses and executing actions based on
* predefined time delays. Actions include toggling WiFi, starting purge, toggling operating modes,
* and displaying feedback through LEDs. The function utilizes an enumeration to track button actions
* and manages the timing for different actions.
*/
void Button_Process()
{
// Time delays for different button actions
#define BUTTON_ACTION_DELAY_TOGGLEMODE 500
#define BUTTON_ACTION_DELAY_PURGE 3500
#define BUTTON_ACTION_DELAY_WIFI 6500
#define BUTTON_ACTION_DELAY_NOTHING 9500
// Enumeration to represent button actions
typedef enum buttonAction_e
{
BTN_INACTIVE,
@@ -484,15 +623,18 @@ void Button_Process()
BTN_STARTPURGE
} buttonAction_t;
// Static variables to track button state and timing
static uint32_t buttonTimestamp = 0;
static buttonAction_t buttonAction = BTN_INACTIVE;
// Check if button is pressed (LOW)
if (digitalRead(GPIO_BUTTON) == LOW)
{
// Update button timestamp on the first button press
if (buttonTimestamp == 0)
buttonTimestamp = millis();
// Check and execute actions based on predefined time delays
if (buttonTimestamp + BUTTON_ACTION_DELAY_NOTHING < millis())
{
LED_Process(1, COLOR_WARM_WHITE);
@@ -515,8 +657,9 @@ void Button_Process()
buttonAction = BTN_TOGGLEMODE;
}
}
else
else // Button is released
{
// Execute corresponding actions based on the detected button action
if (buttonAction != BTN_INACTIVE)
{
switch (buttonAction)
@@ -544,6 +687,7 @@ void Button_Process()
globals.systemStatus = sysStat_Normal;
globals.resumeStatus = sysStat_Normal;
break;
default:
break;
}
@@ -555,28 +699,49 @@ void Button_Process()
Debug_pushMessage("Nothing or invalid\n");
break;
}
// Display feedback through LEDs
LED_Process(2);
}
// Reset button state and timestamp
buttonAction = BTN_INACTIVE;
buttonTimestamp = 0;
}
}
void toggleWiFiAP(boolean shutdown)
/**
* @brief Toggles the WiFi functionality based on the current status.
*
* This function manages the WiFi state, either turning it off or starting it as an Access Point (AP),
* depending on the current mode. If the WiFi is turned off, it can be started in AP mode with the
* device name and password configured. Additionally, it may stop certain operations related to WiFi
* maintenance or display debug messages based on the defined features.
*
* @param shutdown Flag indicating whether the system is in a shutdown state.
*/
void toggleWiFiAP(bool shutdown)
{
// Check if WiFi is currently active
if (WiFi.getMode() != WIFI_OFF)
{
// Turn off WiFi
WiFi.mode(WIFI_OFF);
Debug_pushMessage("WiFi turned off\n");
// Stop WiFi maintenance connection ticker if enabled
#ifdef FEATURE_ENABLE_WIFI_CLIENT
WiFiMaintainConnectionTicker.stop();
#endif
}
else
{
// Start WiFi in Access Point (AP) mode
WiFi.mode(WIFI_AP);
WiFi.softAPConfig(IPAddress(WIFI_AP_IP_GW), IPAddress(WIFI_AP_IP_GW), IPAddress(255, 255, 255, 0));
WiFi.softAP(globals.DeviceName, QUOTE(WIFI_AP_PASSWORD));
// Stop WiFi maintenance connection ticker if enabled and display debug messages
#ifdef FEATURE_ENABLE_WIFI_CLIENT
WiFiMaintainConnectionTicker.stop();
Debug_pushMessage("WiFi AP started, stopped Maintain-Timer\n");
@@ -586,23 +751,52 @@ void toggleWiFiAP(boolean shutdown)
}
}
void SystemShutdown()
/**
* @brief Performs necessary tasks before shutting down and optionally restarts the ESP.
*
* This function initiates a system shutdown, performing tasks such as storing configuration
* and persistence data to EEPROM before shutting down. If a restart is requested, the ESP
* will be restarted; otherwise, the system will enter an indefinite loop.
*
* @param restart Flag indicating whether to restart the ESP after shutdown (default: false).
*/
void SystemShutdown(bool restart)
{
static uint32_t shutdown_delay = 0;
// Initialize shutdown delay on the first call
if (shutdown_delay == 0)
{
shutdown_delay = millis() + SHUTDOWN_DELAY_MS;
Serial.printf("Shutdown requested - Restarting in %d seconds\n", SHUTDOWN_DELAY_MS / 1000);
}
// Check if the shutdown delay has elapsed
if (shutdown_delay < millis())
{
StoreConfig_EEPROM();
Webserver_Shutdown();
// Store persistence data to EEPROM
StorePersistence_EEPROM();
ESP.restart();
// Perform restart if requested, otherwise enter an indefinite loop
if (restart)
ESP.restart();
else
while (1)
;
}
}
/**
* @brief Processes the impulses from the wheel speed sensor and converts them into traveled distance.
*
* This function takes the pulse count from the wheel speed sensor and converts it into distance
* traveled in millimeters. The conversion is based on the configured parameters such as the number
* of pulses per revolution and the distance traveled per revolution.
*
* @return The calculated distance traveled in millimeters.
*/
uint32_t Process_Impulse_WheelSpeed()
{
uint32_t add_milimeters = 0;

84
Software/src/obd2_can.cpp Normal file
View File

@@ -0,0 +1,84 @@
#include "obd2_can.h"
#include <mcp_can.h>
#include <SPI.h>
#include "common.h"
#include "globals.h"
#include "dtc.h"
#include "debugger.h"
// === Setup: MCP2515 CS-Pin definieren ===
#define OBD2_CAN_CS_PIN 10
#define OBD2_OBD_REQUEST_ID 0x7DF
#define OBD2_OBD_RESPONSE_ID 0x7E8
MCP_CAN OBD_CAN(OBD2_CAN_CS_PIN);
static uint32_t lastQueryTime = 0;
static uint32_t lastRecvTime = 0;
static uint32_t lastSpeedMMperSec = 0;
#define OBD2_QUERY_INTERVAL 500 // alle 500ms
void Init_OBD2_CAN()
{
if (OBD_CAN.begin(MCP_STD, CAN_500KBPS, MCP_16MHZ) != CAN_OK)
{
Serial.println("OBD2 CAN Init FAILED!");
return;
}
OBD_CAN.setMode(MCP_NORMAL);
delay(100);
Serial.println("OBD2 CAN Init OK");
}
uint32_t Process_OBD2_CAN_Speed()
{
if (millis() - lastQueryTime < OBD2_QUERY_INTERVAL)
return 0;
lastQueryTime = millis();
// Anfrage: 01 0D → Geschwindigkeit
byte obdRequest[8] = {0x02, 0x01, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00};
byte sendStat = OBD_CAN.sendMsgBuf(OBD2_OBD_REQUEST_ID, 0, 8, obdRequest);
if (sendStat != CAN_OK)
{
MaintainDTC(DTC_OBD2_CAN_TIMEOUT, true);
Debug_pushMessage("OBD2_CAN: send failed (%d)\n", sendStat);
return 0;
}
unsigned long rxId;
byte len = 0;
byte rxBuf[8];
uint32_t timeout = millis() + 100;
while (millis() < timeout)
{
if (OBD_CAN.checkReceive() == CAN_MSGAVAIL)
{
OBD_CAN.readMsgBuf(&rxId, &len, rxBuf);
if ((rxId & 0xFFF8) == OBD2_OBD_RESPONSE_ID && rxBuf[1] == 0x0D)
{
MaintainDTC(DTC_OBD2_CAN_NO_RESPONSE, false); // alles ok
uint8_t speed_kmh = rxBuf[3];
uint32_t speed_mm_per_sec = (uint32_t)speed_kmh * 1000000 / 3600;
uint32_t dt = millis() - lastRecvTime;
lastRecvTime = millis();
lastSpeedMMperSec = speed_mm_per_sec;
Debug_pushMessage("OBD2_CAN: %d km/h (%lu mm/s)\n", speed_kmh, speed_mm_per_sec);
return (speed_mm_per_sec * dt) / 1000;
}
}
}
// Keine Antwort erhalten
MaintainDTC(DTC_OBD2_CAN_NO_RESPONSE, true);
Debug_pushMessage("OBD2_CAN: no response within timeout\n");
return 0;
}

View File

@@ -0,0 +1,74 @@
#include "obd2_kline.h"
// === Konstante für Anfrageintervalle ===
#define OBD2_QUERY_INTERVAL 500 // alle 500 ms neue Anfrage
// === Private Variablen ===
static Stream *klineSerial = nullptr;
static uint32_t lastQueryTime = 0;
static uint32_t lastRecvTime = 0;
static uint32_t lastSpeedMMperSec = 0;
// === Slow Init nach ISO9141-2 ===
void OBD2_KLine_SlowInit()
{
pinMode(1, OUTPUT); // TXD-Pin (z.B. D1)
digitalWrite(1, HIGH);
delay(3000);
digitalWrite(1, LOW);
delay(200); // 200ms
digitalWrite(1, HIGH);
delay(400); // 400ms
digitalWrite(1, LOW);
delay(400); // 400ms
digitalWrite(1, HIGH);
delay(200); // 200ms
// zurück auf Serialbetrieb
pinMode(1, INPUT);
delay(300);
}
// === Initialisierung ===
void Init_OBD2_KLine(Stream &serial)
{
klineSerial = &serial;
OBD2_KLine_SlowInit();
delay(100);
// Sende 01 0D (Vehicle Speed)
byte speedRequest[] = {0x68, 0x6A, 0xF1, 0x01, 0x0D}; // OBD2 PID-Request
klineSerial->write(speedRequest, sizeof(speedRequest));
}
// === Geschwindigkeit abfragen ===
uint32_t Process_OBD2_KLine_Speed()
{
if (!klineSerial || (millis() - lastQueryTime < OBD2_QUERY_INTERVAL)) return 0;
byte req[] = {0x68, 0x6A, 0xF1, 0x01, 0x0D};
klineSerial->write(req, sizeof(req));
lastQueryTime = millis();
uint8_t buf[16];
size_t len = klineSerial->readBytes(buf, sizeof(buf));
for (size_t i = 0; i < len - 2; ++i)
{
if (buf[i] == 0x48 && buf[i + 1] == 0x6B && buf[i + 2] == 0x10)
{
if (buf[i + 3] == 0x41 && buf[i + 4] == 0x0D)
{
uint8_t speed_kmh = buf[i + 5];
uint32_t speed_mm_per_sec = (uint32_t)speed_kmh * 1000000 / 3600;
uint32_t dt = millis() - lastRecvTime;
lastRecvTime = millis();
lastSpeedMMperSec = speed_mm_per_sec;
return (speed_mm_per_sec * dt) / 1000;
}
}
}
return 0;
}

View File

@@ -0,0 +1,55 @@
/**
* @file struct2json.cpp
*
* @brief Implementation file for converting structs to JSON objects.
*
* @note This file is auto-generated by a script on 2024-01-30 20:29:34.
*
* @author Marcel Peterkau
* @date 30.01.2024
*/
#include "struct2json.h"
void generateJsonObject_LubeConfig(JsonObject data)
{
data["EEPROM_Version"] = LubeConfig.EEPROM_Version;
data["DistancePerLube_Default"] = LubeConfig.DistancePerLube_Default;
data["DistancePerLube_Rain"] = LubeConfig.DistancePerLube_Rain;
data["tankCapacity_ml"] = LubeConfig.tankCapacity_ml;
data["amountPerDose_microL"] = LubeConfig.amountPerDose_microL;
data["TankRemindAtPercentage"] = LubeConfig.TankRemindAtPercentage;
data["PulsePerRevolution"] = LubeConfig.PulsePerRevolution;
data["TireWidth_mm"] = LubeConfig.TireWidth_mm;
data["TireWidthHeight_Ratio"] = LubeConfig.TireWidthHeight_Ratio;
data["RimDiameter_Inch"] = LubeConfig.RimDiameter_Inch;
data["DistancePerRevolution_mm"] = LubeConfig.DistancePerRevolution_mm;
data["BleedingPulses"] = LubeConfig.BleedingPulses;
data["SpeedSource"] = LubeConfig.SpeedSource;
data["GPSBaudRate"] = LubeConfig.GPSBaudRate;
data["CANSource"] = LubeConfig.CANSource;
data["LED_Mode_Flash"] = LubeConfig.LED_Mode_Flash;
data["LED_Max_Brightness"] = LubeConfig.LED_Max_Brightness;
data["LED_Min_Brightness"] = LubeConfig.LED_Min_Brightness;
data["wifi_ap_ssid"] = LubeConfig.wifi_ap_ssid;
data["wifi_ap_password"] = LubeConfig.wifi_ap_password;
data["wifi_client_ssid"] = LubeConfig.wifi_client_ssid;
data["wifi_client_password"] = LubeConfig.wifi_client_password;
data["wifi_autoconnect"] = LubeConfig.wifi_autoconnect;
data["checksum"] = LubeConfig.checksum;
}
void generateJsonObject_PersistenceData(JsonObject data)
{
data["writeCycleCounter"] = PersistenceData.writeCycleCounter;
data["tankRemain_microL"] = PersistenceData.tankRemain_microL;
data["TravelDistance_highRes_mm"] = PersistenceData.TravelDistance_highRes_mm;
data["odometer_mm"] = PersistenceData.odometer_mm;
data["odometer"] = PersistenceData.odometer;
data["checksum"] = PersistenceData.checksum;
}
// CODEGENERATOR_CHECKSUM: 59f35aadffd0bbef253210ea2fbaaf9a515553a2e3cc9bf4cfa2819b63c969ce

File diff suppressed because it is too large Load Diff