Init repository für Z21PG nach Ph. Gahtow

Dieser Commit ist enthalten in:
Tom 2025-05-03 21:43:53 +02:00
Commit 993ba44359
525 geänderte Dateien mit 396078 neuen und 0 gelöschten Zeilen

5
.gitignore vendored Normale Datei
Datei anzeigen

@ -0,0 +1,5 @@
**/logs
ZIP
CAD/Z21PG/Z21PG-backups
CAD/Z21PG/fp-info-cache
Documents

Datei-Diff unterdrückt, da er zu groß ist Diff laden

Datei anzeigen

@ -0,0 +1,120 @@
(footprint "CUI_UJ2-MIBH2-4-SMT" (version 20221018) (generator pcbnew)
(layer "F.Cu")
(attr smd)
(fp_text reference "REF**" (at -1.67551 -4.08623) (layer "F.SilkS")
(effects (font (size 1.000299 1.000299) (thickness 0.15)))
(tstamp 3db68bab-ab54-4ac1-aaad-9613e3b9e1ad)
)
(fp_text value "CUI_UJ2-MIBH2-4-SMT" (at 7.219025 6.668735) (layer "F.Fab")
(effects (font (size 1.000559 1.000559) (thickness 0.15)))
(tstamp 1d4946fd-bc2f-4221-afa5-69478ed4a0fc)
)
(fp_line (start -4.6 -2.45) (end -2.975 -2.45)
(stroke (width 0.127) (type solid)) (layer "F.SilkS") (tstamp f19cfd37-dc1f-4117-8dbf-b144cdc9db93))
(fp_line (start -4.6 5.05) (end -4.6 -2.45)
(stroke (width 0.127) (type solid)) (layer "F.SilkS") (tstamp 1e419897-ded7-431b-a106-cdddab88dd41))
(fp_line (start -2.975 5.05) (end -4.6 5.05)
(stroke (width 0.127) (type solid)) (layer "F.SilkS") (tstamp f18f9cfe-2c70-4926-9de1-8e666f4b5fc0))
(fp_line (start -0.1 -2.45) (end 0.4 -2.45)
(stroke (width 0.127) (type solid)) (layer "F.SilkS") (tstamp a7e1bac2-43d0-41f1-935f-cfd338c327bb))
(fp_line (start 0.4 -2.45) (end 0.4 -1.7)
(stroke (width 0.127) (type solid)) (layer "F.SilkS") (tstamp ef9fbb8b-134b-4b7f-95f0-b40792b387a9))
(fp_line (start 0.4 4.3) (end 0.4 5.05)
(stroke (width 0.127) (type solid)) (layer "F.SilkS") (tstamp 2d1bf4ac-799a-40dd-91dc-8e01afb02f37))
(fp_line (start 0.4 5.05) (end -0.1 5.05)
(stroke (width 0.127) (type solid)) (layer "F.SilkS") (tstamp 3158e6d4-5dfa-428c-a76c-f41a8b85c25a))
(fp_circle (center 1.8 0) (end 1.95 0)
(stroke (width 0.127) (type solid)) (fill none) (layer "F.SilkS") (tstamp 3990c68f-7f0b-4972-8528-bdc3f8fa1454))
(fp_line (start 0.4755 -1.2505) (end 0.55 -1.2505)
(stroke (width 0.01) (type solid)) (layer "Edge.Cuts") (tstamp 13cc0fc7-3864-4a43-85ec-3e5c25437390))
(fp_line (start 0.4755 3.1995) (end 0.55 3.1995)
(stroke (width 0.01) (type solid)) (layer "Edge.Cuts") (tstamp a5de9256-fdf8-429e-9066-fbb503a5bc8a))
(fp_line (start 0.55 -1.25) (end 0.625 -1.25)
(stroke (width 0.01) (type solid)) (layer "Edge.Cuts") (tstamp 32bd03c9-7fb0-4945-8143-0a8a296ef12a))
(fp_line (start 0.55 -0.6) (end 0.475 -0.6)
(stroke (width 0.01) (type solid)) (layer "Edge.Cuts") (tstamp 55c0538c-7f37-4c41-8b4c-e3d64f4a3560))
(fp_line (start 0.55 3.2) (end 0.625 3.2)
(stroke (width 0.01) (type solid)) (layer "Edge.Cuts") (tstamp 37e3f6e7-d8c0-41a7-a721-d4707e3a0ee7))
(fp_line (start 0.55 3.85) (end 0.475 3.85)
(stroke (width 0.01) (type solid)) (layer "Edge.Cuts") (tstamp 706462ba-804b-4c7f-ba41-682c9a953728))
(fp_line (start 0.6245 -0.5995) (end 0.55 -0.5995)
(stroke (width 0.01) (type solid)) (layer "Edge.Cuts") (tstamp 10ec9946-5048-41ce-8522-2fc9cce3f4c1))
(fp_line (start 0.6245 3.8505) (end 0.55 3.8505)
(stroke (width 0.01) (type solid)) (layer "Edge.Cuts") (tstamp 6b70819a-bc49-49fb-94b9-10fc978ee426))
(fp_arc (start 0.15 -0.925) (mid 0.245337 -1.155163) (end 0.4755 -1.2505)
(stroke (width 0.01) (type solid)) (layer "Edge.Cuts") (tstamp 60900ef5-c73a-449f-b226-be2586f01072))
(fp_arc (start 0.15 3.525) (mid 0.245337 3.294837) (end 0.4755 3.1995)
(stroke (width 0.01) (type solid)) (layer "Edge.Cuts") (tstamp ac9f94af-5c08-4035-a289-b7b478872b2f))
(fp_arc (start 0.475 -0.6) (mid 0.24519 -0.69519) (end 0.15 -0.925)
(stroke (width 0.01) (type solid)) (layer "Edge.Cuts") (tstamp 4b2826a4-06e9-4e5a-ba76-20a781bf20d2))
(fp_arc (start 0.475 3.85) (mid 0.24519 3.75481) (end 0.15 3.525)
(stroke (width 0.01) (type solid)) (layer "Edge.Cuts") (tstamp 118bf556-2856-4c54-8802-4dd2ff2571d9))
(fp_arc (start 0.625 -1.25) (mid 0.85481 -1.15481) (end 0.95 -0.925)
(stroke (width 0.01) (type solid)) (layer "Edge.Cuts") (tstamp 02d2abcf-3430-463b-997f-6392676ba445))
(fp_arc (start 0.625 3.2) (mid 0.85481 3.29519) (end 0.95 3.525)
(stroke (width 0.01) (type solid)) (layer "Edge.Cuts") (tstamp f459220a-ff00-4965-95f8-29fb8cf8f701))
(fp_arc (start 0.95 -0.925) (mid 0.854663 -0.694837) (end 0.6245 -0.5995)
(stroke (width 0.01) (type solid)) (layer "Edge.Cuts") (tstamp 3f1970bb-8435-4485-b52c-60ea75cd4e23))
(fp_arc (start 0.95 3.525) (mid 0.854663 3.755163) (end 0.6245 3.8505)
(stroke (width 0.01) (type solid)) (layer "Edge.Cuts") (tstamp 61a424a0-3b09-40ce-a468-6618962fb7dd))
(fp_line (start -4.85 -2.7) (end -2.975 -2.7)
(stroke (width 0.05) (type solid)) (layer "F.CrtYd") (tstamp 7baa2e5b-a208-438f-8148-245d5f6194cb))
(fp_line (start -4.85 5.3) (end -4.85 -2.7)
(stroke (width 0.05) (type solid)) (layer "F.CrtYd") (tstamp c9a00c52-918b-4ba3-ae60-444f49a2c6d9))
(fp_line (start -2.975 -3.05) (end -0.1 -3.05)
(stroke (width 0.05) (type solid)) (layer "F.CrtYd") (tstamp ebae8a70-471f-426b-a465-48eeaa05dc10))
(fp_line (start -2.975 -2.7) (end -2.975 -3.05)
(stroke (width 0.05) (type solid)) (layer "F.CrtYd") (tstamp aee24f65-2582-42cd-9bfd-3947747815f0))
(fp_line (start -2.975 5.3) (end -4.85 5.3)
(stroke (width 0.05) (type solid)) (layer "F.CrtYd") (tstamp 335540d0-c2ab-474a-a9f1-220a3e67c654))
(fp_line (start -2.975 5.65) (end -2.975 5.3)
(stroke (width 0.05) (type solid)) (layer "F.CrtYd") (tstamp e585f68c-d225-475f-8dd9-2c8042310a61))
(fp_line (start -0.1 -3.05) (end -0.1 -2.7)
(stroke (width 0.05) (type solid)) (layer "F.CrtYd") (tstamp 82d71b2a-56ac-4d63-bb42-1fda68cbab34))
(fp_line (start -0.1 -2.7) (end 0.65 -2.7)
(stroke (width 0.05) (type solid)) (layer "F.CrtYd") (tstamp 11605796-b3c9-477a-9b5b-0222595970ff))
(fp_line (start -0.1 5.3) (end -0.1 5.65)
(stroke (width 0.05) (type solid)) (layer "F.CrtYd") (tstamp bea2b1ae-e11e-4976-8de2-eec2b47e6440))
(fp_line (start -0.1 5.65) (end -2.975 5.65)
(stroke (width 0.05) (type solid)) (layer "F.CrtYd") (tstamp 90150b90-411d-459c-b245-ed70ca759864))
(fp_line (start 0.65 -2.7) (end 0.65 -1.775)
(stroke (width 0.05) (type solid)) (layer "F.CrtYd") (tstamp ac27af15-4b8e-4780-9f05-a2f5ee4d8de1))
(fp_line (start 0.65 -1.775) (end 1.85 -1.775)
(stroke (width 0.05) (type solid)) (layer "F.CrtYd") (tstamp 4b66140b-f8ec-45ff-923d-93f1615fe79c))
(fp_line (start 0.65 4.375) (end 0.65 5.3)
(stroke (width 0.05) (type solid)) (layer "F.CrtYd") (tstamp 0737942c-3d15-4321-91dd-e99e87cca8ff))
(fp_line (start 0.65 5.3) (end -0.1 5.3)
(stroke (width 0.05) (type solid)) (layer "F.CrtYd") (tstamp fb3b2451-fa66-4cc3-954b-2564ca0e1d3e))
(fp_line (start 0.85 -0.075) (end 0.85 2.675)
(stroke (width 0.05) (type solid)) (layer "F.CrtYd") (tstamp b27a832e-ab38-40ef-9ee7-3dd7603b5e1e))
(fp_line (start 0.85 2.675) (end 1.85 2.675)
(stroke (width 0.05) (type solid)) (layer "F.CrtYd") (tstamp 0130f132-7fa1-4359-a5ef-64c5b448c24d))
(fp_line (start 1.85 -1.775) (end 1.85 -0.075)
(stroke (width 0.05) (type solid)) (layer "F.CrtYd") (tstamp b955d8d5-999b-4a1c-b69c-89f3c0557539))
(fp_line (start 1.85 -0.075) (end 0.85 -0.075)
(stroke (width 0.05) (type solid)) (layer "F.CrtYd") (tstamp b346d1d3-ed98-44b1-88ea-2ae55603baa7))
(fp_line (start 1.85 2.675) (end 1.85 4.375)
(stroke (width 0.05) (type solid)) (layer "F.CrtYd") (tstamp b468e67a-0676-417f-a4d0-bfa658c6934e))
(fp_line (start 1.85 4.375) (end 0.65 4.375)
(stroke (width 0.05) (type solid)) (layer "F.CrtYd") (tstamp 97832a6e-3ec6-437e-a2fd-2e8b94f6e8a1))
(fp_line (start -4.6 -2.45) (end 0.4 -2.45)
(stroke (width 0.127) (type solid)) (layer "F.Fab") (tstamp 82502ce9-6336-4e86-bb8f-e011cc5b9400))
(fp_line (start -4.6 5.05) (end -4.6 -2.45)
(stroke (width 0.127) (type solid)) (layer "F.Fab") (tstamp acd1d579-b04a-4ac7-8674-a4c3e46ee359))
(fp_line (start 0.4 -2.45) (end 0.4 5.05)
(stroke (width 0.127) (type solid)) (layer "F.Fab") (tstamp 7defc7ef-3074-430c-89ec-86dd5b82b35d))
(fp_line (start 0.4 5.05) (end -4.6 5.05)
(stroke (width 0.127) (type solid)) (layer "F.Fab") (tstamp 8ece92a4-bb3a-4c63-8602-402866eaebd1))
(fp_circle (center -0.15 0) (end -0.07 0)
(stroke (width 0.16) (type solid)) (fill none) (layer "F.Fab") (tstamp 641bcc65-594e-4e67-a01c-1697990a3b9a))
(pad "1" smd rect (at 0 0) (size 1.2 0.4) (layers "F.Cu" "F.Paste" "F.Mask") (tstamp 898b033c-aa54-406b-9448-6b25e2e4a6cc))
(pad "2" smd rect (at 0 0.65) (size 1.2 0.4) (layers "F.Cu" "F.Paste" "F.Mask") (tstamp ee03a1c7-9108-4bb4-8020-4406f20d2512))
(pad "3" smd rect (at 0 1.3) (size 1.2 0.4) (layers "F.Cu" "F.Paste" "F.Mask") (tstamp 18488c54-df7a-4fde-832b-ffce88c7ccfc))
(pad "4" smd rect (at 0 1.95) (size 1.2 0.4) (layers "F.Cu" "F.Paste" "F.Mask") (tstamp 78c937c4-9a3b-43e8-af1d-a6f154702044))
(pad "5" smd rect (at 0 2.6) (size 1.2 0.4) (layers "F.Cu" "F.Paste" "F.Mask") (tstamp 95b5488d-eabb-41a0-81e6-c50c4c6b8f5e))
(pad "SH1" thru_hole oval (at -1.55 -2.2) (size 2.4 1.2) (drill oval 1.4 0.6) (layers "*.Cu" "*.Mask") (tstamp 07ce6192-dc1d-4909-a819-ace931773b6b))
(pad "SH2" thru_hole oval (at 0.55 -0.925) (size 2.1 1.05) (drill 0.65) (layers "*.Cu" "*.Mask") (tstamp 6b9e5501-cead-486c-8b81-ac4001a92915))
(pad "SH3" smd rect (at -1.55 1.3) (size 0.9 3) (layers "F.Cu" "F.Paste" "F.Mask") (tstamp 7f6a95f8-eeac-4e84-a878-666fe047f077))
(pad "SH4" thru_hole oval (at -1.55 4.8) (size 2.4 1.2) (drill oval 1.4 0.6) (layers "*.Cu" "*.Mask") (tstamp 6db901a9-a25b-4169-b464-6d1c6eea318d))
(pad "SH5" thru_hole oval (at 0.55 3.525) (size 2.1 1.05) (drill 0.65) (layers "*.Cu" "*.Mask") (tstamp 2867db0e-5cd9-46c3-a439-1d3e41d8c23a))
)

94
CAD/Z21PG/Z21PG.kicad_pcb Normale Datei
Datei anzeigen

@ -0,0 +1,94 @@
(kicad_pcb
(version 20241229)
(generator "pcbnew")
(generator_version "9.0")
(general
(thickness 1.6)
(legacy_teardrops no)
)
(paper "A4")
(layers
(0 "F.Cu" signal)
(2 "B.Cu" signal)
(9 "F.Adhes" user "F.Adhesive")
(11 "B.Adhes" user "B.Adhesive")
(13 "F.Paste" user)
(15 "B.Paste" user)
(5 "F.SilkS" user "F.Silkscreen")
(7 "B.SilkS" user "B.Silkscreen")
(1 "F.Mask" user)
(3 "B.Mask" user)
(17 "Dwgs.User" user "User.Drawings")
(19 "Cmts.User" user "User.Comments")
(21 "Eco1.User" user "User.Eco1")
(23 "Eco2.User" user "User.Eco2")
(25 "Edge.Cuts" user)
(27 "Margin" user)
(31 "F.CrtYd" user "F.Courtyard")
(29 "B.CrtYd" user "B.Courtyard")
(35 "F.Fab" user)
(33 "B.Fab" user)
(39 "User.1" user)
(41 "User.2" user)
(43 "User.3" user)
(45 "User.4" user)
)
(setup
(pad_to_mask_clearance 0)
(allow_soldermask_bridges_in_footprints no)
(tenting front back)
(pcbplotparams
(layerselection 0x00000000_00000000_55555555_5755f5ff)
(plot_on_all_layers_selection 0x00000000_00000000_00000000_00000000)
(disableapertmacros no)
(usegerberextensions no)
(usegerberattributes yes)
(usegerberadvancedattributes yes)
(creategerberjobfile yes)
(dashed_line_dash_ratio 12.000000)
(dashed_line_gap_ratio 3.000000)
(svgprecision 4)
(plotframeref no)
(mode 1)
(useauxorigin no)
(hpglpennumber 1)
(hpglpenspeed 20)
(hpglpendiameter 15.000000)
(pdf_front_fp_property_popups yes)
(pdf_back_fp_property_popups yes)
(pdf_metadata yes)
(pdf_single_document no)
(dxfpolygonmode yes)
(dxfimperialunits yes)
(dxfusepcbnewfont yes)
(psnegative no)
(psa4output no)
(plot_black_and_white yes)
(plotinvisibletext no)
(sketchpadsonfab no)
(plotpadnumbers no)
(hidednponfab no)
(sketchdnponfab yes)
(crossoutdnponfab yes)
(subtractmaskfromsilk no)
(outputformat 1)
(mirror no)
(drillshape 1)
(scaleselection 1)
(outputdirectory "")
)
)
(net 0 "")
(gr_rect
(start 0 0)
(end 160 160)
(stroke
(width 0.1)
(type default)
)
(fill no)
(layer "Edge.Cuts")
(uuid "32e0d510-64dc-4a57-91ad-378888e283ca")
)
(embedded_fonts no)
)

129
CAD/Z21PG/Z21PG.kicad_prl Normale Datei
Datei anzeigen

@ -0,0 +1,129 @@
{
"board": {
"active_layer": 25,
"active_layer_preset": "",
"auto_track_width": true,
"hidden_netclasses": [],
"hidden_nets": [],
"high_contrast_mode": 0,
"net_color_mode": 1,
"opacity": {
"images": 0.6,
"pads": 1.0,
"shapes": 1.0,
"tracks": 1.0,
"vias": 1.0,
"zones": 0.6
},
"selection_filter": {
"dimensions": true,
"footprints": true,
"graphics": true,
"keepouts": true,
"lockedItems": false,
"otherItems": true,
"pads": true,
"text": true,
"tracks": true,
"vias": true,
"zones": true
},
"visible_items": [
"vias",
"footprint_text",
"footprint_anchors",
"ratsnest",
"grid",
"footprints_front",
"footprints_back",
"footprint_values",
"footprint_references",
"tracks",
"drc_errors",
"bitmaps",
"pads",
"zones",
"drc_warnings",
"locked_item_shadows",
"conflict_shadows",
"shapes"
],
"visible_layers": "ffffffff_ffffffff_ffffffff_ffffffff",
"zone_display_mode": 0
},
"git": {
"repo_type": "",
"repo_username": "",
"ssh_key": ""
},
"meta": {
"filename": "Z21PG.kicad_prl",
"version": 5
},
"net_inspector_panel": {
"col_hidden": [
false,
false,
false,
false,
false,
false,
false,
false,
false,
false
],
"col_order": [
0,
1,
2,
3,
4,
5,
6,
7,
8,
9
],
"col_widths": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
],
"custom_group_rules": [],
"expanded_rows": [],
"filter_by_net_name": true,
"filter_by_netclass": true,
"filter_text": "",
"group_by_constraint": false,
"group_by_netclass": false,
"show_unconnected_nets": false,
"show_zero_pad_nets": false,
"sort_ascending": true,
"sorting_column": 0
},
"open_jobsets": [],
"project": {
"files": []
},
"schematic": {
"selection_filter": {
"graphics": true,
"images": true,
"labels": true,
"lockedItems": false,
"otherItems": true,
"pins": true,
"symbols": true,
"text": true,
"wires": true
}
}
}

680
CAD/Z21PG/Z21PG.kicad_pro Normale Datei
Datei anzeigen

@ -0,0 +1,680 @@
{
"board": {
"3dviewports": [],
"design_settings": {
"defaults": {
"apply_defaults_to_fp_fields": false,
"apply_defaults_to_fp_shapes": false,
"apply_defaults_to_fp_text": false,
"board_outline_line_width": 0.1,
"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.05,
"dimension_precision": 4,
"dimension_units": 3,
"dimensions": {
"arrow_length": 1270000,
"extension_offset": 500000,
"keep_text_aligned": true,
"suppress_zeroes": true,
"text_position": 0,
"units_format": 0
},
"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.15,
"other_text_italic": false,
"other_text_size_h": 1.0,
"other_text_size_v": 1.0,
"other_text_thickness": 0.15,
"other_text_upright": false,
"pads": {
"drill": 0.8,
"height": 1.27,
"width": 2.54
},
"silk_line_width": 0.15,
"silk_text_italic": false,
"silk_text_size_h": 1.0,
"silk_text_size_v": 1.0,
"silk_text_thickness": 0.15,
"silk_text_upright": false,
"zones": {
"min_clearance": 0.5
}
},
"diff_pair_dimensions": [],
"drc_exclusions": [],
"meta": {
"version": 2
},
"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": "ignore",
"hole_clearance": "error",
"hole_to_hole": "warning",
"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": "warning",
"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_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",
"unresolved_variable": "error",
"via_dangling": "warning",
"zones_intersect": "error"
},
"rules": {
"max_error": 0.005,
"min_clearance": 0.0,
"min_connection": 0.0,
"min_copper_edge_clearance": 0.0,
"min_groove_width": 0.0,
"min_hole_clearance": 0.25,
"min_hole_to_hole": 0.25,
"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.0,
"min_via_annular_width": 0.1,
"min_via_diameter": 0.5,
"solder_mask_clearance": 0.0,
"solder_mask_min_width": 0.0,
"solder_mask_to_copper_clearance": 0.0,
"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": [],
"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": [],
"zones_allow_external_fillets": false
},
"ipc2581": {
"dist": "",
"distpn": "",
"internal_id": "",
"mfg": "",
"mpn": ""
},
"layer_pairs": [],
"layer_presets": [],
"viewports": []
},
"boards": [],
"cvpcb": {
"equivalence_files": []
},
"erc": {
"erc_exclusions": [],
"meta": {
"version": 0
},
"pin_map": [
[
0,
0,
0,
0,
0,
0,
1,
0,
0,
0,
0,
2
],
[
0,
2,
0,
1,
0,
0,
1,
0,
2,
2,
2,
2
],
[
0,
0,
0,
0,
0,
0,
1,
0,
1,
0,
1,
2
],
[
0,
1,
0,
0,
0,
0,
1,
1,
2,
1,
1,
2
],
[
0,
0,
0,
0,
0,
0,
1,
0,
0,
0,
0,
2
],
[
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
2
],
[
1,
1,
1,
1,
1,
0,
1,
1,
1,
1,
1,
2
],
[
0,
0,
0,
1,
0,
0,
1,
0,
0,
0,
0,
2
],
[
0,
2,
1,
2,
0,
0,
1,
0,
2,
2,
2,
2
],
[
0,
2,
0,
1,
0,
0,
1,
0,
2,
0,
0,
2
],
[
0,
2,
1,
1,
0,
0,
1,
0,
2,
0,
0,
2
],
[
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2
]
],
"rule_severities": {
"bus_definition_conflict": "error",
"bus_entry_needed": "error",
"bus_to_bus_conflict": "error",
"bus_to_net_conflict": "error",
"different_unit_footprint": "error",
"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",
"no_connect_dangling": "warning",
"pin_not_connected": "error",
"pin_not_driven": "error",
"pin_to_pin": "error",
"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"
}
},
"libraries": {
"pinned_footprint_libs": [
"arduino-library"
],
"pinned_symbol_libs": []
},
"meta": {
"filename": "Z21PG.kicad_pro",
"version": 3
},
"net_settings": {
"classes": [
{
"bus_width": 6,
"clearance": 0.2,
"diff_pair_gap": 0.25,
"diff_pair_via_gap": 0.25,
"diff_pair_width": 0.2,
"microvia_diameter": 0.3,
"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
},
{
"bus_width": 6,
"line_style": 0,
"name": "+12V",
"pcb_color": "rgba(0, 0, 0, 0.000)",
"priority": 2,
"schematic_color": "rgba(0, 0, 0, 0.000)",
"wire_width": 6
},
{
"bus_width": 6,
"name": "+15V",
"pcb_color": "rgba(0, 0, 0, 0.000)",
"priority": 0,
"schematic_color": "rgba(0, 0, 0, 0.000)",
"wire_width": 6
},
{
"bus_width": 6,
"line_style": 0,
"name": "+5V",
"pcb_color": "rgba(0, 0, 0, 0.000)",
"priority": 4,
"schematic_color": "rgba(0, 0, 0, 0.000)",
"wire_width": 6
},
{
"bus_width": 6,
"line_style": 0,
"name": "GND",
"pcb_color": "rgba(0, 0, 0, 0.000)",
"priority": 3,
"schematic_color": "rgba(0, 0, 0, 0.000)",
"wire_width": 6
},
{
"bus_width": 6,
"line_style": 0,
"name": "VRAIL",
"pcb_color": "rgba(0, 0, 0, 0.000)",
"priority": 1,
"schematic_color": "rgba(0, 0, 0, 0.000)",
"wire_width": 6
}
],
"meta": {
"version": 4
},
"net_colors": null,
"netclass_assignments": null,
"netclass_patterns": []
},
"pcbnew": {
"last_paths": {
"gencad": "",
"idf": "",
"netlist": "",
"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": "Reference"
},
"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": [],
"intersheets_ref_own_page": false,
"intersheets_ref_prefix": "",
"intersheets_ref_short": false,
"intersheets_ref_show": false,
"intersheets_ref_suffix": "",
"junction_size_choice": 3,
"label_size_ratio": 0.375,
"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.15
},
"legacy_lib_dir": "",
"legacy_lib_list": [],
"meta": {
"version": 1
},
"net_format_name": "",
"page_layout_descr_file": "Power",
"plot_directory": "",
"space_save_all_events": true,
"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": [
[
"c3838cec-10b2-4837-a76d-63e69a3fd4b1",
"Root"
],
[
"82005746-8e65-4c3e-866b-d2b67e757930",
"CPU & Interfaces"
],
[
"014e53f9-b7c5-4848-90a8-6c0ebd9294b7",
"Booster"
],
[
"88e40e78-2740-4e08-95a4-8be753c93e14",
"Power"
],
[
"70f60b7e-f6bf-4e28-8107-ed9c65f4d49a",
"Documentation"
]
],
"text_variables": {}
}

101509
CAD/Z21PG/Z21PG.kicad_sch Normale Datei

Datei-Diff unterdrückt, da er zu groß ist Diff laden

23081
CAD/Z21PG/booster.kicad_sch Normale Datei

Datei-Diff unterdrückt, da er zu groß ist Diff laden

28806
CAD/Z21PG/cpu.kicad_sch Normale Datei

Datei-Diff unterdrückt, da er zu groß ist Diff laden

2430
CAD/Z21PG/docu.kicad_sch Normale Datei

Datei-Diff unterdrückt, da er zu groß ist Diff laden

4624
CAD/Z21PG/power.kicad_sch Normale Datei

Datei-Diff unterdrückt, da er zu groß ist Diff laden

3258
CAD/Z21PG/untitled.kicad_sch Normale Datei

Datei-Diff unterdrückt, da er zu groß ist Diff laden

Binäre Datei nicht angezeigt.

BIN
Datasheets/DS_FT230X.pdf Normale Datei

Binäre Datei nicht angezeigt.

BIN
Datasheets/G2R.pdf Normale Datei

Binäre Datei nicht angezeigt.

Binäre Datei nicht angezeigt.

Binäre Datei nicht angezeigt.

BIN
Datasheets/IXDF604PI.pdf Normale Datei

Binäre Datei nicht angezeigt.

Binäre Datei nicht angezeigt.

Binäre Datei nicht angezeigt.

BIN
Datasheets/W5500_ds_v110e.pdf Normale Datei

Binäre Datei nicht angezeigt.

Binäre Datei nicht angezeigt.

Nachher

Breite:  |  Höhe:  |  Größe: 54 KiB

Datei anzeigen

@ -0,0 +1,2 @@
<html><head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8"></head><body></body></html>

Datei anzeigen

@ -0,0 +1,96 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// Partially based on https://searchfox.org/mozilla-central/source/browser/extensions/webcompat/shims/google-analytics-and-tag-manager.js
(() => {
'use strict';
const noop = () => {};
const noopHandler = {
get: function (target, prop) {
return noop;
}
};
const gaPointer = window.GoogleAnalyticsObject = (window.GoogleAnalyticsObject === undefined) ? 'ga' : window.GoogleAnalyticsObject;
const datalayer = window.dataLayer;
const Tracker = new Proxy({}, {
get (target, prop) {
if (prop === 'get') {
return (fieldName) => {
if (fieldName === 'linkerParam') {
// This fixed string is an example value of this API.
// As the extension exposes itself with many featues we shouldn't be concerned by exposing ourselves here also.
// If we randomised this to some other fake value there wouldn't be much benefit and could risk being a tracking vector.
// https://developers.google.com/analytics/devguides/collection/analyticsjs/field-reference#linkerParam
return '_ga=1.231587807.1974034684.1435105198';
}
return 'something';
};
}
return noop;
}
});
let callQueue = null;
if (window[gaPointer] && Array.isArray(window[gaPointer].q)) {
callQueue = window[gaPointer].q;
}
// Execute callback if exists.
// Note: There are other ways of using the API that aren't handled here yet.
const ga = function () {
const params = Array.from(arguments);
if (params.length === 1 && typeof params[0] === 'function') {
try {
params[0](Tracker);
} catch (error) {}
return undefined;
}
// See https://developers.google.com/analytics/devguides/collection/analyticsjs/field-reference#hitCallback
params.forEach((param) => {
if (param instanceof Object && typeof param.hitCallback === 'function') {
try {
param.hitCallback();
} catch (error) {}
}
});
};
ga.answer = 42;
ga.loaded = true;
ga.create = function () { return new Proxy({}, noopHandler); };
ga.getByName = function () { return new Proxy({}, noopHandler); };
ga.getAll = function () { return [Tracker]; };
ga.remove = noop;
window[gaPointer] = ga;
// prevent page delay, see https://developers.google.com/optimize
if (datalayer && datalayer.hide && typeof datalayer.hide.end === 'function') {
try {
datalayer.hide.end();
} catch (error) {}
}
if (!(window.gaplugins && window.gaplugins.Linker)) {
window.gaplugins = window.gaplugins || {};
window.gaplugins.Linker = class {
autoLink () {}
decorate (url) {
return url;
}
passthrough () {}
};
}
if (callQueue) {
for (const args of callQueue) {
try {
ga(...args);
} catch (e) { }
}
}
})();

Datei anzeigen

@ -0,0 +1 @@
!function(){var e;if(e=window.navigator.userAgent,!/(Opera\/.+Opera Mobi.+Version\/((10|11)\.0|11\.1|11\.5|12\.(0|1)))|(Opera\/((10|11)\.0|11\.1|11\.5|12\.(0|1)).+Opera Mobi)|(Opera Mobi.+Opera(?:\/|\s+)((10|11)\.0|11\.1|11\.5|12\.(0|1)))|(SamsungBrowser\/((4|5)\.0|5\.4))|(IEMobile[ /](10|11)\.0)|(Android Eclair)|(Android Froyo)|(Android Gingerbread)|(Android Honeycomb)|(PlayBook.+RIM Tablet OS (7\.0|10\.0)\.\d+)|((Black[bB]erry|BB10).+Version\/(7\.0|10\.0)\.\d+)|(Trident\/6\.0)|(Trident\/5\.0)|(Trident\/4\.0)|(([MS]?IE) (5\.5|([6-9]|10)\.0))/.test(e)&&window.navigator.cookieEnabled){if(!document.getElementById("ch-plugin")){var n=document.createElement("div");n.id="ch-plugin",document.body.appendChild(n)}var i=document.getElementById("ch-plugin");i.classList.add("notranslate"),i.innerHTML+=' <div id="ch-plugin-entry"></div> <div id="ch-plugin-script" style="display:none;"> <iframe id="ch-plugin-script-iframe" title="Channel chat" style="position:relative!important;height:100%!important;width:100%!important;border:none!important;"></iframe> </div> ';var t=document.getElementById("ch-plugin-script-iframe"),r=!1,o=function(){var e=t.contentDocument||t.contentWindow.document;e.open(),e.write('<!DOCTYPE html><script async type="text/javascript" src="https://cdn.channel.io/plugin/ch-plugin-core.9b91566b.vendor.js" charset="UTF-8"><\/script>'),e.write('<script async type="text/javascript" src="https://cdn.channel.io/plugin/ch-plugin-core-20250402160847.js" charset="UTF-8"><\/script>'),e.write('<html lang="en"><head><meta charset="utf-8"></head><body><div id="main"></div></body></html>'),e.close(),r=!0};t.onload||o(),t.onload=function(){r||o()}}}();

1
Datasheets/WIZ850io-Dateien/embed.min.js vendored Normale Datei

Dateidiff unterdrückt, weil mindestens eine Zeile zu lang ist

Dateidiff unterdrückt, weil mindestens eine Zeile zu lang ist

Dateidiff unterdrückt, weil mindestens eine Zeile zu lang ist

Binäre Datei nicht angezeigt.

Nachher

Breite:  |  Höhe:  |  Größe: 41 KiB

Dateidiff unterdrückt, weil mindestens eine Zeile zu lang ist

Binäre Datei nicht angezeigt.

Nachher

Breite:  |  Höhe:  |  Größe: 373 KiB

Datei anzeigen

@ -0,0 +1,3 @@
<!DOCTYPE html>
<html lang="en"><head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8"><script async="" type="text/javascript" src="wiz850io_data/ch-plugin-core.9b91566b.vendor.js" charset="UTF-8"></script><script async="" type="text/javascript" src="wiz850io_data/ch-plugin-core-20250402160847.js" charset="UTF-8"></script><meta charset="utf-8"><script async="" crossorigin="anonymous" src="wiz850io_data/b05367f6be924bb49e15838987b99ce6.min.js"></script><style data-styled="active" data-styled-version="5.3.9"></style></head><body><div id="main"><div class="Layoutstyled__PCAppLayout-ch-front__sc-19rvneg-0 eNrntj"><div class="ToastContainerstyled__ToastContainer-ch-front__sc-1riea3h-0 hNxhGs"></div><nav class="NavigationBarstyled__NavigationBar-ch-front__sc-1kd54kd-0 cmFLfh"><a href="https://docs.wiznet.io/home" class="NavigationBarstyled__Link-ch-front__sc-1kd54kd-1 gycYyn"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24" foundation="[object Object]" class="Iconstyled__Icon-sc-1iqwu2g-0 iudiaz" data-testid="bezier-react-icon" margintop="0" marginright="0" marginbottom="0" marginleft="0"><path fill="currentColor" fill-rule="evenodd" d="M3 20a1 1 0 0 0 1 1h5a1 1 0 0 0 1-1v-5a2 2 0 1 1 4 0v5a1 1 0 0 0 1 1h5a1 1 0 0 0 1-1V9.978a2 2 0 0 0-.772-1.579l-7.614-5.922a1 1 0 0 0-1.228 0L3.772 8.4A2 2 0 0 0 3 9.98z" clip-rule="evenodd"></path></svg><span class="Textstyled__Text-sc-1u7b1ni-0 iFTgEj NavigationBarstyled__TabTitle-ch-front__sc-1kd54kd-3 poOUN" data-testid="bezier-react-text">Home</span></a><a href="https://docs.wiznet.io/user-chats" class="NavigationBarstyled__Link-ch-front__sc-1kd54kd-1 XRBqa"><div class="NavigationBarstyled__IconWrapper-ch-front__sc-1kd54kd-2 eCofAM"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24" foundation="[object Object]" class="Iconstyled__Icon-sc-1iqwu2g-0 iudiaz" data-testid="bezier-react-icon" margintop="0" marginright="0" marginbottom="0" marginleft="0"><path fill="currentColor" fill-rule="evenodd" d="m21.406 19.052-.641-1.924c-.06-.205-.034-.256.307-.948l.053-.109c.29-.635.506-1.305.654-1.988.299-1.37.287-2.798.01-4.157-.56-2.763-2.358-5.2-4.778-6.599-1.206-.7-2.575-1.159-3.965-1.27-1.38-.142-2.805-.024-4.136.417a10.13 10.13 0 0 0-6.051 5.449A9.6 9.6 0 0 0 2 11.994c.011 1.383.258 2.798.848 4.074 1.139 2.565 3.39 4.577 6.056 5.445 1.337.43 2.749.58 4.14.432a9.9 9.9 0 0 0 3.026-.819c.155-.066.335-.157.48-.231.138-.071.244-.125.265-.124a.5.5 0 0 1 .313-.007l.894.298 1.027.342q.155.05.313.105c.194.067.389.134.577.177.291.05.513.014.712-.042.432-.111.88-.557.992-.99.057-.2.094-.42.044-.71-.041-.186-.107-.378-.174-.57q-.056-.161-.107-.322m-2.546-2.834a2.5 2.5 0 0 0 .006 1.544l.553 1.656-.764-.254-.896-.3a2.5 2.5 0 0 0-1.544-.003 4.4 4.4 0 0 0-.67.299c-.099.052-.185.098-.294.14a8 8 0 0 1-.783.303c-.53.177-1.079.29-1.633.351a8.1 8.1 0 0 1-3.313-.344c-2.121-.69-3.944-2.315-4.848-4.36-.47-1.013-.66-2.132-.672-3.256a7.6 7.6 0 0 1 .684-3.255 8.13 8.13 0 0 1 4.841-4.36c1.062-.354 2.2-.445 3.316-.331 1.122.086 2.194.45 3.163 1.01 1.938 1.12 3.382 3.083 3.822 5.268a8.1 8.1 0 0 1-.007 3.336 7.8 7.8 0 0 1-.521 1.59c-.042.11-.089.199-.143.3-.081.15-.178.332-.297.666M6.206 11.993c0 .744.609 1.353 1.353 1.353.745 0 1.353-.609 1.353-1.353S8.304 10.64 7.56 10.64c-.744 0-1.353.608-1.353 1.352m4.48 0c0 .744.61 1.353 1.354 1.353s1.353-.609 1.353-1.353-.609-1.352-1.353-1.352-1.353.608-1.353 1.352m5.835 1.353a1.356 1.356 0 0 1-1.353-1.353c0-.744.608-1.352 1.353-1.352.744 0 1.353.608 1.353 1.352s-.61 1.353-1.353 1.353" clip-rule="evenodd"></path></svg></div><span class="Textstyled__Text-sc-1u7b1ni-0 iFTgEj NavigationBarstyled__TabTitle-ch-front__sc-1kd54kd-3 poOUN" data-testid="bezier-react-text">Messages</span></a><a href="https://docs.wiznet.io/setting" class="NavigationBarstyled__Link-ch-front__sc-1kd54kd-1 XRBqa"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24" foundation="[object Object]" class="Iconstyled__Icon-sc-1iqwu2g-0 iudiaz" data-testid="bezier-react-icon" margintop="0" marginright="0" marginbottom="0" marginleft="0"><path fill="currentColor" fill-rule="evenodd" d="M7 12a5 5 0 1 1 10 0 5 5 0 0 1-10 0m15 1.5v-3l-2.23-.372a8 8 0 0 0-.955-2.296l1.316-1.843-2.12-2.12-1.844 1.316a8 8 0 0 0-2.295-.955L13.5 2h-3l-.372 2.23a8 8 0 0 0-2.296.955L5.99 3.868 3.87 5.99l1.315 1.843a8 8 0 0 0-.954 2.296L2 10.5v3l2.23.372c.198.822.523 1.594.954 2.296l-1.316 1.843 2.121 2.121 1.843-1.317a8 8 0 0 0 2.296.955L10.5 22h3l.372-2.23a8 8 0 0 0 2.295-.955l1.843 1.317 2.121-2.12-1.316-1.844a8 8 0 0 0 .955-2.296z" clip-rule="evenodd"></path></svg><span class="Textstyled__Text-sc-1u7b1ni-0 iFTgEj NavigationBarstyled__TabTitle-ch-front__sc-1kd54kd-3 poOUN" data-testid="bezier-react-text">Settings</span></a></nav></div></div></body></html>

Dateidiff unterdrückt, weil mindestens eine Zeile zu lang ist

Dateidiff unterdrückt, weil mindestens eine Zeile zu lang ist

Binäre Datei nicht angezeigt.

Nachher

Breite:  |  Höhe:  |  Größe: 46 KiB

Binäre Datei nicht angezeigt.

Nachher

Breite:  |  Höhe:  |  Größe: 397 KiB

Dateidiff unterdrückt, weil mindestens eine Zeile zu lang ist

Nachher

Breite:  |  Höhe:  |  Größe: 29 KiB

135
Datasheets/WIZ850io.html Normale Datei

Dateidiff unterdrückt, weil mindestens eine Zeile zu lang ist

Binäre Datei nicht angezeigt.

Dateidiff unterdrückt, weil mindestens eine Zeile zu lang ist

BIN
Datasheets/ina180.pdf Normale Datei

Binäre Datei nicht angezeigt.

BIN
Datasheets/ina226.pdf Normale Datei

Binäre Datei nicht angezeigt.

BIN
Datasheets/sn74hc00.pdf Normale Datei

Binäre Datei nicht angezeigt.

BIN
Datasheets/tps281c30.pdf Normale Datei

Binäre Datei nicht angezeigt.

BIN
Datasheets/tsr1_datasheet.pdf Normale Datei

Binäre Datei nicht angezeigt.

BIN
Pictures/SOaIN.jpg Normale Datei

Binäre Datei nicht angezeigt.

Nachher

Breite:  |  Höhe:  |  Größe: 129 KiB

Binäre Datei nicht angezeigt.

Nachher

Breite:  |  Höhe:  |  Größe: 51 KiB

Binäre Datei nicht angezeigt.

Nachher

Breite:  |  Höhe:  |  Größe: 46 KiB

Binäre Datei nicht angezeigt.

Nachher

Breite:  |  Höhe:  |  Größe: 916 KiB

6
README.md Normale Datei
Datei anzeigen

@ -0,0 +1,6 @@
<h1>Digitale DCC Modellbahnzentrale nach [Z21PG](https://www.gathow.de/w/Zentrale_Z21PG)</h1>
Der Sourcecode und die Schaltung für die Digitalzentrale nach Ph. Gahtow ist für ein ATMega2560 Arduino-Boards und die Arduino IDE erstellt. Dieses Projekt beinhaltet eine Platine für den Aufbau der Zentrale ohne Arduino-Boards und in dem Sourcecode werden die vielen Abhängigkeiten, bzw. mögliche Anpassungen für andere Arduino- und ESP Boards entfernt, so dass der Code nur noch genau für diese Platine passend ist.
Have fun!

Datei anzeigen

@ -0,0 +1,18 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
"version": "0.2.0",
"configurations": [
{
"cwd": "${workspaceFolder}",
"executable": "./bin/executable.elf",
"name": "Debug with ST-Link",
"request": "launch",
"type": "cortex-debug",
"runToEntryPoint": "main",
"showDevDebugOutput": "none",
"servertype": "stlink"
}
]
}

Datei anzeigen

@ -0,0 +1,78 @@
/************************************************************************************
Z21 Ethernet DCC Command Station Interface config file
Copyright (c) 2015-2023 by Philipp Gahtow
***********************************************************************************/
/*-------------**********************************-----------------------------------
/ ************ CHANGE TO SET UP YOUR INDIVIDUAL CONFIGURATION ***************
/ => uncomment ("//" or #undef) the following lines, if you not USE the Interface!
/-------------**********************************-----------------------------------*/
//#define S88N //S88N Interface (max 62 * 8 Module)
//#define WIFI //WiFi Interface über Serial-Port für Arduino UNO/MEGA/DUE zum ESP 8266
//#define WLAN Serial2 // (DEFAULT = Serial2!) use not the standard WLAN Serial Interface. Select another serial:
//#define Z21VIRTUAL // WiFi over SoftSerial for UNO only! - LAN and LocoNet will be inaktiv!
#define LAN //LAN Ethernet Z21 LAN Kommunikation mit W5100 oder ENC28 Ethernet Shield. Bitte diese IP nur über die Webseite (http://192.168.0.111) ändern! (not for ESP8266 and ESP32)
//#define ENC28 //USE a ENC28J60 module - instead of w5100 Shield (MEGA only!)
//#define LANmacB2 0xEF //Byte2 (DEFAULT = 84:2B:BC:EF:FE:ED!) change optional LAN MAC Address. MAC starts with: „84:2B:BC:..Byte*2..:..Byte*1..:..Byte*0..“
//#define LANmacB1 0xFE //Byte1
//#define LANmacB0 0xED //Byte0
//#define LANTimeoutDHCP 10000 //(DEFAULT!) Timeout to wait for a DHCP respose (Fix default Time: 5 sec)
// #define DCCGLOBALDETECTOR //DCC Railcom Global Detector for MEGA on Serial Port 3 (RX only) - (not for ESP8266 and ESP32)
#define XPRESSNET //XpressNet Auto Master/Salve Interface (not for ESP8266 and ESP32)
//#define LOCONET //LocoNet Interface (Timer1, Timer5 on MEGA, with LocoNet2 Library on ESP32)
//#define LnSLOTSRV //LocoNet Master-Mode: provide a Slot Server for Loco to use FRED & DaisyII
//#define LnBufferUSB //LocoNet LocoBuffer-USB at 57600 bps (Achtung: kein Debug über Serial Monitor möglich!)
//#define BOOSTER_EXT //External Booster Interface (zB. ROCO, CD[E])
#define BOOSTER_INT //internal Booster Interface (zB. TLE5206)
#define BOOSTER_INT_MAINCURRENT //Standard Short Circuit Detection over current Sense resistor (VAmpIntPin) activate the current sensor for prog track and SHORT CIRCUIT Sense over MAINCURRENT
#define BOOSTER_INT_CURRENT_SHORT_DETECT
#define DETECT_SHORT_INT_WAIT 20 //(OPTIONAL) Time in ms after internal short circuit is detected and power will switch off
#define DETECT_SHORT_INT_VALUE 2000 //(OPTIONAL) value = (Amper * senseResist) / (Uref / 1024)
/* (DEFAULT OFF - OPTIONAL!) activate only one - Short2 detection PIN reading use: (only one can be active!)*/
//#define BOOSTER_INT_TLE5206 //internal Booster with TLE5206 or
//#define BOOSTER_EXT_CDE //external CDE Booster
//#define PROG_OUT_INVERT //(DEFAULT OFF!) invert the Output Signal for Service-Mode (Prog-Relay) - for L298n H-Bridge usage without Relay!
//#define ADD_ACK_COMP //(DEFAULT OFF!) Comperator to detect exact the ACK pulse over interrupt
//#define DALLASTEMPSENSE //Dallas 18B20 Temperatur Sensor for Arduino MEGA only!
//#define Z21DISPLAY FIND //SSD1306 OLED I2C Display and Address for config Data for Arduino MEGA and ESP only! -->MEGA: 20(SDA), 21(SCL) || -->ESP8266: D2(SDA), D1(SCL)
//If you not know the Display I2C Address (normal: 0x3C) leave the value "FIND" so the central will search for it when starting!
//#define Z21DISPLAY_SH1106 //(DEFAULT OFF!) use OLEDs based on SH110X drivers
//#define Z21DISPLAY_CONTRAST 150 //(OPTIONAL) higher contrast (0..255; default = 20)
//#define AMP_DECIMALS 1 //(OPTIONAL) OLED decimal digits of precision for Amper on the Rail (default: x.xxA = 2)
#define FS128 //default speed steps (Fahrstufen) => possible values are: FS14, FS28, FS128
#define Uref 1.1 // measured reference voltage ARef-pin, individual value for every Arduino
// #define EXTERNAL_UREF_1V1 //optional: AREF with external 1.1 Volt, to get better CV# read with Arduino UNO
// #define INA219 0x40 //INA219 I2C current Sensor and Address for Arduino MEGA and ESP only!
#define senseResist 0.33 //or 0.1 // actual resistor for measuring current on track
/***************************************************************/
/*------------------DEBUG-ONLY---------------------------------*/
/***************************************************************/
#define Debug Serial //(DEFAULT = Serial!) use not the Default Standard Debug Serial Interface. Select another serial:
#define DebugBaud 115200 //Activate Debug on "Serial" with speed setting (on ESP8266 with LocoNet only 16660 baud)
/*---------- select what to show (options): --------------*/
#define DEBUG //To see System-DATA on Serial
//#define DEBUG_WLAN_CONFIG //to see config data of Wifi ESP8266 (IP, Pw, ..)
//#define REPORT //To see Sensor Messages (LocoNet & S88)
#define REQEST //To see answer Request Messages (Lok , Switch, CV)
//#define LnDEB //To see RAW DATA of LocoNet Protokoll
//#define XnDEB //To see XpressNet Data
//#define Z21DEBUG //to see Z21 LAN control data
//#define Z21DATADEBUG //to see RAW DATA of Z21 LAN Protokoll
//#define Z21SYSTEMDATADEBUG //to see the system data mainpower and temp

Datei anzeigen

@ -0,0 +1,132 @@
//--------------------------------------------------------------
//handle Lok Data to request central for all Interfaces to request Status on Master
void AllLocoData(uint16_t adr, uint8_t *data) {
//uint8_t Steps[0], uint8_t Speed[1], uint8_t F0[2], uint8_t F1[3], uint8_t F2[4], uint8_t F3[5]
//We are LocoNet Slave user?
#if defined(LOCONET) && !defined(ESP32_MCU) //handle ESP32 with call back function!
#if !defined(LnSLOTSRV)
LNGetSetLocoSlot(adr,false);
LNupdate(); //LocoNet update
#if defined(REQEST)
Debug.print(F("Ln Slave "));
#endif
#endif
#endif
//We are XpressNet Slave user?
#if defined(XPRESSNET)
if (XpressNet.getOperationModeMaster() == false) {
XpressNet.getLocoInfo(adr);
#if defined(REQEST)
Debug.print(F("Xn Slave "));
#endif
}
#endif
#if defined(DCC)
dcc.getLocoData(adr, data);
#endif
#if defined(REQEST)
Debug.print(F("LOK Data "));
Debug.print(adr);
Debug.print("-");
Debug.print(data[1]); //speed
Debug.print("-F0-4:");
Debug.print(data[2] & 0x1F, BIN); //F0, F4, F3, F2, F1
Debug.print("-F5-12:");
Debug.print(data[3], BIN); //F5 - F12; Funktion F5 ist bit0 (LSB)
Debug.print("-F13-20:");
Debug.print(data[4], BIN); //F13-F20
Debug.print("-F21-28:");
Debug.print(data[5], BIN); //F21-F28
Debug.print("-F29-31:");
Debug.println(data[2] >> 5, BIN); //F31-F29
#endif
}
//--------------------------------------------------------------
//DCC handle back the request switch state
void notifyTrnt(uint16_t Adr, bool State, bool active)
{
#if defined(LAN) || defined(WIFI) || defined(ESP_WIFI)
z21.setTrntInfo(Adr, State);
#endif
#if defined(LOCONET)
LNsetTrnt(Adr, State, active);
#endif
#if defined(XPRESSNET)
XpressNet.SetTrntPos(Adr, State, active);
#endif
#if defined(REQEST)
Debug.print(F("DCC Trnt "));
Debug.print(Adr);
Debug.print("-");
Debug.print(State);
Debug.print("-");
Debug.println(active);
#endif
}
//--------------------------------------------------------------
//DCC return a CV value:
void notifyCVVerify(uint16_t CV, uint8_t value) {
//#if defined(LAN) || defined(WIFI) || defined(ESP_WIFI)
//z21.setCVReturn (CV, value);
//#endif
#if defined(XPRESSNET)
XpressNet.setCVReadValue(CV, value);
#endif
#if defined(LOCONET)
LNsetCVReturn(CV, value, 0); //CV Read Okay
#endif
#if defined(REQEST)
Debug.print(F("Verify CV#"));
Debug.print(CV+1);
Debug.print(" - ");
Debug.print(value);
Debug.print(" b");
Debug.println(value, BIN);
#endif
}
//--------------------------------------------------------------
//DCC return no ACK:
void notifyCVNack(uint16_t CV) {
#if defined(LAN) || defined(WIFI) || defined(ESP_WIFI)
z21.setCVNack(); //send back to device and stop programming!
#endif
#if defined(XPRESSNET)
XpressNet.setCVNack();
#endif
#if defined(LOCONET)
LNsetCVReturn(CV, 0, 1); //CV Read Fails
#endif
#if defined(REQEST)
Debug.print("CV#");
Debug.print(CV+1);
Debug.println(F(" no ACK"));
#endif
}
//--------------------------------------------------------------
//Feedback the Current Sense value
#if defined(BOOSTER_INT_CURRENT_SHORT_DETECT)
uint16_t notifyCurrentSense() {
// uint16_t mA = ina219.getCurrent_mA();
uint16_t mA = getRailmA();
if (mA > 60000) //ignore this value!
return VAmpINT;
return mA;
}
#endif
//--------------------------------------------------------------

Datei anzeigen

@ -0,0 +1,206 @@
//--------------------------------------------------------------
/*
LocoNet Hardware Serial connector
only for ESP8266 and ESP32
Use a share
Copyright (c) by Philipp Gahtow, year 2022
*/
#if defined(LOCONET) && (defined(ESP8266_MCU) || defined(ESP32_MCU))
#include <LocoNet.h> //include LocoNet OP Codes
#include <SoftwareSerial.h>
SoftwareSerial LocoNetTX; //Software Serial for TX Signal
#define LocoNetRX Serial //Hardware Serial for RX Signal
#define LnBufferMaxData 21 //length of LocoNet data packet
#define LnBufferSize 5 //size of the RX and TX buffer
#define LnMsgTimeout 1000 //timeout to revert a msg in µs
typedef struct //Msg Buffer
{
uint8_t read = 0; //zähler lesen
uint8_t write = 0; //zähler schreiben
uint8_t data[LnBufferSize][LnBufferMaxData]; //zu sendende Daten
} LnBuffer;
uint8_t writeRXpos = 0;
LnBuffer LnRX;
LnBuffer LnTX;
unsigned long previousData = 0; // will store last time data war received
//--------------------------------------------------------------
void LocoNetHw_init() {
//ESP8266 and ESP32:
LocoNetRX.end(); //stop running configuration
LocoNetRX.begin(16660); //set speed to Hw Serial
//UCRXI = Invert RX
//UCTXI = Invert TX
//UCBN = DataBits Count (2bin) 0:5bit, 1:6bit, 2:7bit, 3:8bit
//UCSBN = StopBits Count (2bit) 0:disable, 1:1bit, 2:1.5bit, 3:2bit
//U0C0 = BIT(UCRXI) | BIT(UCBN) | BIT(UCBN+1) | BIT(UCSBN);
// Inverse RX, 11 = 8bit Data, 01 = 1bit Stop
LocoNetTX.begin(16660, SWSERIAL_8N1, LNTxPin, LNTxPin, true); //Set Up SoftwareSerial asyncron
LocoNetTX.enableTx(true); //enable TX Mode!
//clear the RX and TX Buffer:
for (uint8_t i; i < LnBufferSize; i++) {
for (uint8_t m; m < LnBufferMaxData; m++) {
LnRX.data[i][m] = 0xFF;
LnTX.data[i][m] = 0xFF;
}
}
LnRX.read = 0;
LnRX.write = 0;
LnTX.read = 0;
LnRX.write = 0;
}
//--------------------------------------------------------------
bool LocoNet_available() {
return LnRX.read != LnRX.write;
}
//--------------------------------------------------------------
uint8_t LocoNet_readLength() {
if (LocoNet_available()) {
uint8_t len = LnRX.data[LnRX.read][0] >> 5; //1. Byte = length
if (len == B100)
return 2;
else if (len == B101)
return 4;
else if (len == B110)
return 6;
else return LnRX.data[LnRX.read][1] & 0x7F; //Länge in 2. Byte codiert.
}
return 0;
}
//--------------------------------------------------------------
void LocoNet_readData(uint8_t *data) {
if (LocoNet_available()) {
uint8_t len = LocoNet_readLength();
for (uint8_t s = 0; s < len; s++) {
data[s] = LnRX.data[LnRX.read][s];
}
LnRX.data[LnRX.read][0] = 0xFF; //clear
LnRX.read++;
if (LnRX.read == LnBufferSize)
LnRX.read = 0;
}
}
//--------------------------------------------------------------
void LocoNet_sendData(uint8_t *data) {
uint8_t len = data[0] >> 5; //read 1. Byte
//calculate the length:
if (len == B100)
len = 2;
else if (len == B101)
len = 4;
else if (len == B110)
len = 6;
else len = (data[1] & 0x7F); //2. Byte in der Nachricht ein 7-Bit-Zählwert ist (BYTE COUNT)
uint8_t XOR = 0xFF;
//copy Data to TX Buffer:
for(uint8_t s = 0; s < (len-1); s++) { //without XOR
LnTX.data[LnTX.write][s] = data[s];
XOR ^= data[s];
}
LnTX.data[LnTX.write][len-1] = XOR; //last byte
data[len-1] = XOR; //add XOR to requested data
LnTX.write++;
if (LnTX.write == LnBufferSize)
LnTX.write = 0;
}
//--------------------------------------------------------------
void LocoNet_updateRX() {
if (LocoNetRX.available()) {
previousData = micros(); //save in time
uint8_t d = LocoNetRX.read();
LnRX.data[LnRX.write][writeRXpos] = d; //save data
uint8_t len = LnRX.data[LnRX.write][0] >> 5; //read 1. Byte
//calculate the length:
if (len == B100)
len = 2;
else if (len == B101)
len = 4;
else if (len == B110)
len = 6;
else if (writeRXpos >= 1) {
len = (LnRX.data[LnRX.write][1] & 0x7F); //2. Byte in der Nachricht ein 7-Bit-Zählwert ist (BYTE COUNT)
if (len >= LnBufferMaxData) { //ERROR LENGTH
LnRX.data[LnRX.write][0] = 0xFF; //reset
writeRXpos = 0;
}
}
writeRXpos++;
if ((writeRXpos == len) && (len > 1)) { //accept only data with min. length of 2
writeRXpos = 0;
uint8_t cksum = 0; //Prüfsumme
for (uint8_t i = 0; i < len; i++) {
cksum ^= LnRX.data[LnRX.write][i];
}
if (cksum == 0xFF) {
LnRX.write++;
if (LnRX.write == LnBufferSize)
LnRX.write = 0;
}
#if defined(LnDEB)
else Debug.println(F("LN XOR Fail!"));
#endif
}
}
else {
if ((writeRXpos != 0) && (micros() - previousData >= LnMsgTimeout)) { //Timeout!
LnRX.data[LnRX.write][0] = 0xFF; //reset
writeRXpos = 0;
}
}
}
//--------------------------------------------------------------
void LocoNetRXTXupdate() {
//check if we have received data?
LocoNet_updateRX();
//check if we have to send data?
if (LnTX.read != LnTX.write) {
uint8_t writepos = 0;
uint8_t len = LnTX.data[LnTX.read][writepos] >> 5;
if (len == B100)
len = 2;
else if (len == B101)
len = 4;
else if (len == B110)
len = 6;
else len = (LnTX.data[LnTX.read][writepos + 1] & 0x7F); // 2. Byte = length!
do {
LocoNetTX.write(LnTX.data[LnTX.read][writepos]);
LocoNet_updateRX();
if (writeRXpos == writepos && LnRX.data[LnRX.write][writeRXpos] != LnTX.data[LnTX.read][writepos]) {
return; //stop here!!!!!!!!!!!!!!!!!!
//we will not go further!!!!!!!!!
}
writepos++;
} while (writepos < len);
//next data:
LnTX.read++;
if (LnTX.read == LnBufferSize)
LnTX.read = 0;
}
}
#endif

Datei-Diff unterdrückt, da er zu groß ist Diff laden

Datei anzeigen

@ -0,0 +1,58 @@
//--------------------------------------------------------------
/*
* Setup up PIN-Configuration for different MCU
*
* Support for:
* - Arduino MEGA
*/
//--------------------------------------------------------------
//Setting PIN CONFIG:
//--------------------------------------------------------------
//Power:
#define Z21ResetPin 47 //RESET-Button-Pin bei Neustart betätigen um Standard IP zu setzten!
#define Z21ButtonPin Z21ResetPin //Pin where the POWER-Button is conected
//DCC and Booster
#define DCCLed 3 //LED to show DCC active
#define DCCPin 6 //Pin for DCC sginal out
#define additionalOutPin 11 //Pin for true DCC Output without Shutdown adn RailCom
#define RailcomLED 13
#define RailcomPort 15
#define ShortLed 45 //LED to show Short
#define ShortExtPin 5 //Pin to detect Short Circuit of Booster (detect LOW)
#define GoExtPin A4 //Pin for GO/STOP Signal of Booster
#define ProgRelaisPin A5 //Pin for using Kehrschleifen-Modul
#define ACKSensePin 2 //Pin for ACK Comperator input
//Booster INT config:
#define GoIntPin 39 //Pin for inverted DCC Signal
#define ShortIntPin 41 //Pin for second Booster like TLE5206 (detect HIGH)
#define VAmpIntPin A9 //Input for Current sensor (CV read)
//#define VAmSensePin A8 //ACS712 5A Sensor (for testing only)
#define VoltIntPin A10 //Rail Voltage: Rail:100k - Sense - 4,7k - GND
#define TempPin A11 //Temp.Sense_resistor (15k) with 46k Pull-Up or DALLAS
//XpressNet
#define XNetTxRxPin 9 //XpressNet Control-Port for Send/Receive at MAX485
//LocoNet
#define LNTxPin 7 //Sending Pin for LocoNet
//--------------------------------------------------------------
//Dallas Temperatur Sensor (MEGA only):
#if defined(DALLASTEMPSENSE) && defined(MEGA_MCU)
#define ONE_WIRE_BUS TempPin
#else
#undef DALLASTEMPSENSE
#endif
#if defined(S88N)
//Eingänge:
#define S88DataPin A0 //S88 Data IN
//Ausgänge:
#define S88ClkPin A1 //S88 Clock
#define S88PSPin A2 //S88 PS/LOAD
#define S88ResetPin A3 //S88 Reset
#endif
//--------------------------------------------------------------
//LAN-Interface:
#define LANSSPIN 10 //Chip Select Pin of most Ethernet Shields
#define SDSSPIN 4 //Chip Select Pin SD-Card Reader on Ethernet Shield

Datei anzeigen

@ -0,0 +1,531 @@
//--------------------------------------------------------------
/*
additional OLED Display 128x64 for Z21PG
- show system info
- show power status
- display IP Address
- show system information
- default Display Driver SSD1306 0.96"
- add second Display Driver SH1106 for 1.3"
- add logos for different power mode
- animate the CV progress
Copyright (c) by Philipp Gahtow, year 2022
*/
#if defined(Z21DISPLAY)
//--------------------------------------------------------------
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
#ifndef Z21DISPLAY_CONTRAST
#define Z21DISPLAY_CONTRAST 20 //reduce the contrast for a longer lifetime (0..255)
#endif
#ifndef AMP_DECIMALS
#define AMP_DECIMALS 2 // OLED decimal digits of precision for Amper on the Rail (x.xxA)
#endif
#define DISPLAY_POWER_LOGO 300 // x * 255 = ms time after config data will be removed in csNormal!
//--------------------------------------------------------------
static const unsigned char Z21Bitmap [] PROGMEM = {
// Z21 Logo, 80x37px
0x07, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x07, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x07, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x07, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x0f, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x01, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x01, 0xfe, 0x0f, 0xff, 0xff, 0x01, 0xff, 0xe0,
0x00, 0x00, 0x03, 0xfc, 0x0f, 0xff, 0xff, 0xc1, 0xff, 0xe0,
0x00, 0x00, 0x07, 0xfc, 0x1f, 0xff, 0xff, 0xe1, 0xff, 0xe0,
0x00, 0x00, 0x0f, 0xf8, 0x1f, 0xff, 0xff, 0xe1, 0xff, 0xe0,
0x00, 0x00, 0x1f, 0xf0, 0x1f, 0xff, 0xff, 0xf1, 0xff, 0xe0,
0x00, 0x00, 0x1f, 0xe0, 0x00, 0x00, 0x1f, 0xf0, 0x0f, 0xe0,
0x00, 0x00, 0x3f, 0xc0, 0x00, 0x00, 0x07, 0xf0, 0x0f, 0xe0,
0x00, 0x00, 0x7f, 0xc0, 0x00, 0x00, 0x07, 0xf0, 0x0f, 0xe0,
0x00, 0x00, 0xff, 0x80, 0x00, 0x00, 0x07, 0xf0, 0x0f, 0xe0,
0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x07, 0xf0, 0x0f, 0xe0,
0x00, 0x01, 0xfe, 0x00, 0x00, 0x00, 0x07, 0xf0, 0x0f, 0xe0,
0x00, 0x03, 0xfc, 0x00, 0x00, 0x00, 0x0f, 0xf0, 0x0f, 0xe0,
0x00, 0x07, 0xfc, 0x00, 0x00, 0x7f, 0xff, 0xf0, 0x0f, 0xe0,
0x00, 0x0f, 0xf8, 0x00, 0x03, 0xff, 0xff, 0xf0, 0x0f, 0xe0,
0x00, 0x0f, 0xf0, 0x00, 0x0f, 0xff, 0xff, 0xe0, 0x0f, 0xe0,
0x00, 0x1f, 0xe0, 0x00, 0x1f, 0xff, 0xff, 0xe0, 0x0f, 0xe0,
0x00, 0x3f, 0xc0, 0x00, 0x1f, 0xff, 0xff, 0xc0, 0x0f, 0xe0,
0x00, 0x7f, 0xc0, 0x00, 0x3f, 0xff, 0xff, 0x00, 0x0f, 0xe0,
0x00, 0xff, 0x80, 0x00, 0x3f, 0xf0, 0x00, 0x00, 0x0f, 0xe0,
0x00, 0xff, 0x00, 0x00, 0x3f, 0xc0, 0x00, 0x00, 0x0f, 0xe0,
0x01, 0xfe, 0x00, 0x00, 0x3f, 0x80, 0x00, 0x00, 0x0f, 0xe0,
0x03, 0xfc, 0x00, 0x00, 0x3f, 0x80, 0x00, 0x00, 0x0f, 0xe0,
0x07, 0xfc, 0x00, 0x00, 0x3f, 0x80, 0x00, 0x00, 0x0f, 0xe0,
0x07, 0xf8, 0x00, 0x00, 0x3f, 0x80, 0x00, 0x00, 0x0f, 0xe0,
0x07, 0xf0, 0x00, 0x00, 0x3f, 0x80, 0x00, 0x00, 0x0f, 0xe0,
0x07, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0xcf, 0xe0,
0x07, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0xcf, 0xe0,
0x07, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0xcf, 0xe0,
0x07, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0xcf, 0xe0,
0x07, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0xcf, 0xe0
};
//--------------------------------------------------------------
static const unsigned char Power_PROG [] PROGMEM =
//imageWidth 25, imageHeight 36
{ 0x00, 0x22, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xf0, 0x00,
0x3f, 0x80, 0xfe, 0x00, 0x3f, 0x80, 0xff, 0x00, 0x3f, 0x80, 0xff, 0x00, 0x7f, 0xff, 0xff, 0x00,
0x70, 0x00, 0x07, 0x00, 0x60, 0xe6, 0x63, 0x00, 0x61, 0x96, 0x63, 0x00, 0x61, 0x86, 0x63, 0x00,
0x61, 0x82, 0x43, 0x00, 0x61, 0x83, 0xc3, 0x00, 0x61, 0x83, 0xc3, 0x00, 0x61, 0x91, 0x83, 0x00,
0x60, 0xe1, 0x83, 0x00, 0x70, 0x00, 0x07, 0x00, 0x7f, 0xff, 0xff, 0x00, 0x7f, 0xff, 0xff, 0x00,
0x7f, 0xff, 0xff, 0x00, 0x7f, 0xff, 0xff, 0x00, 0x7c, 0xff, 0xcf, 0x00, 0x78, 0x7f, 0x87, 0x00,
0x78, 0x7f, 0x87, 0x00, 0x3c, 0xff, 0xcf, 0x00, 0x3f, 0xff, 0xfe, 0x00, 0x1f, 0xff, 0xfc, 0x00,
0x0f, 0xff, 0xf8, 0x00, 0x07, 0xff, 0xf8, 0x00, 0x0f, 0xff, 0xf8, 0x00, 0x1c, 0x00, 0x3c, 0x00,
0x1c, 0x00, 0x0e, 0x00, 0x38, 0x00, 0x06, 0x00, 0x70, 0x00, 0x07, 0x00, 0xe0, 0x00, 0x03, 0x80
};
//--------------------------------------------------------------
static const unsigned char Power_ON[] PROGMEM = {
// Power On Logo: 37x40px
0x00, 0x01, 0xfe, 0x00, 0x07, 0x00, 0x0f, 0xff, 0xc0, 0x07, 0x00, 0x3e, 0x01, 0xf0, 0x07, 0x00, 0xf0, 0x00, 0x38, 0x07,
0x07, 0x80, 0x08, 0x07, 0x07, 0x0e, 0x00, 0x1c, 0x03, 0x87, 0x0c, 0x00, 0x1c, 0x01, 0x87, 0x1c, 0xe0, 0x3c, 0x39, 0xc7,
0x18, 0xe0, 0x78, 0x38, 0xc7, 0x31, 0xc0, 0xf8, 0x1c, 0x67, 0x33, 0x80, 0xd8, 0x0e, 0x67, 0x73, 0x01, 0xd8, 0x06, 0x77,
0x63, 0x03, 0xb8, 0x06, 0x37, 0x67, 0x07, 0x3f, 0xc7, 0x37, 0x66, 0x06, 0x3f, 0xc3, 0x37, 0x66, 0x0e, 0x01, 0xc3, 0x37,
0x66, 0x1f, 0xe3, 0x83, 0x37, 0x66, 0x1f, 0xe7, 0x03, 0x37, 0x66, 0x00, 0xee, 0x03, 0x37, 0x67, 0x00, 0xcc, 0x07, 0x37,
0x63, 0x00, 0xdc, 0x06, 0x37, 0x73, 0x01, 0xf8, 0x06, 0x77, 0x33, 0x81, 0xf0, 0x0e, 0x67, 0x31, 0xc1, 0xe0, 0x1c, 0x67,
0x38, 0xe1, 0xe0, 0x38, 0xc7, 0xfc, 0xe3, 0xc0, 0x39, 0xff, 0x2c, 0x03, 0x80, 0x01, 0xc7, 0x2e, 0x03, 0x00, 0x03, 0xc7,
0x27, 0x00, 0x00, 0x07, 0x47, 0x20, 0xf0, 0x00, 0x38, 0x47, 0x20, 0xbe, 0x01, 0xf0, 0x47, 0x20, 0x8f, 0xff, 0xd0, 0x47,
0x20, 0x83, 0xfe, 0x10, 0x47, 0x20, 0x82, 0x04, 0x10, 0x47, 0x20, 0x82, 0x04, 0x10, 0x47, 0x20, 0x82, 0x04, 0x10, 0x47,
0x20, 0x82, 0x04, 0x10, 0x47, 0xff, 0xff, 0xff, 0xff, 0xff, 0x20, 0x82, 0x04, 0x10, 0x47, 0x3f, 0x83, 0xfc, 0x1f, 0xc7
};
//--------------------------------------------------------------
static const unsigned char Power_OFF[] PROGMEM = {
//Power OFF Logo: 37x40px
0x00, 0x01, 0xfe, 0x00, 0x07, 0x00, 0x0f, 0xff, 0xc0, 0x07, 0x00, 0x3e, 0x01, 0xf0, 0x07, 0x00, 0x70, 0x00, 0x38, 0x07,
0x00, 0xc0, 0x00, 0x0c, 0x07, 0x01, 0x80, 0x00, 0x06, 0x07, 0x03, 0x00, 0x00, 0x03, 0x07, 0x06, 0x00, 0x30, 0x01, 0x87,
0x0c, 0x00, 0x30, 0x00, 0xc7, 0x0c, 0x00, 0x30, 0x00, 0xc7, 0x18, 0x00, 0x30, 0x00, 0x67, 0x18, 0x06, 0x31, 0x80, 0x67,
0x18, 0x06, 0x31, 0x80, 0x67, 0x30, 0x0c, 0x30, 0xc0, 0x37, 0x30, 0x18, 0x30, 0xc0, 0x37, 0x30, 0x18, 0x30, 0x60, 0x37,
0x30, 0x18, 0x30, 0x60, 0x37, 0x30, 0x18, 0x00, 0x60, 0x37, 0x30, 0x18, 0x00, 0x60, 0x37, 0x30, 0x18, 0x00, 0xc0, 0x37,
0x38, 0x0c, 0x00, 0xc0, 0x67, 0x18, 0x06, 0x01, 0x80, 0x67, 0x18, 0x07, 0x87, 0x80, 0x67, 0x3c, 0x03, 0xfe, 0x00, 0xc7,
0x2c, 0x00, 0x78, 0x00, 0xc7, 0xff, 0x00, 0x00, 0x03, 0xff, 0x23, 0x80, 0x00, 0x03, 0x47, 0x21, 0x80, 0x00, 0x06, 0x47,
0x20, 0xe0, 0x00, 0x1c, 0x47, 0x20, 0xf0, 0x00, 0x38, 0x47, 0x20, 0x3e, 0x01, 0xf0, 0x47, 0x20, 0x8f, 0xff, 0xd0, 0x47,
0x20, 0x83, 0xfe, 0x10, 0x47, 0x20, 0x82, 0x04, 0x10, 0x47, 0x24, 0x82, 0x04, 0x12, 0x47, 0x20, 0x82, 0x04, 0x10, 0x47,
0x20, 0x82, 0x04, 0x10, 0x47, 0xff, 0xff, 0xff, 0xff, 0xff, 0x20, 0x82, 0x04, 0x10, 0x47, 0x3f, 0x83, 0xfc, 0x1f, 0xc7
};
//--------------------------------------------------------------
static const unsigned char Power_EmSTOP[] PROGMEM = {
//Power Em Stop Logo: 38x39px
0x00, 0x7f, 0xff, 0xf8, 0x03, 0x00, 0xff, 0xff, 0xfc, 0x03, 0x01, 0xff, 0xff, 0xfe, 0x03, 0x01, 0xc0, 0x00, 0x0e, 0x03,
0x03, 0xc0, 0x00, 0x0f, 0x03, 0x07, 0x80, 0x00, 0x07, 0x83, 0x07, 0x00, 0x00, 0x03, 0x83, 0x0f, 0x00, 0x00, 0x03, 0xc3,
0x0e, 0x00, 0x00, 0x01, 0xe3, 0x1c, 0x00, 0x00, 0x00, 0xe3, 0x3c, 0x00, 0x00, 0x00, 0xf3, 0x38, 0x00, 0x00, 0x00, 0x73,
0x78, 0xef, 0x9f, 0x1f, 0x7b, 0xf1, 0x02, 0x31, 0x91, 0x3f, 0xe1, 0x02, 0x20, 0x91, 0x1f, 0xe1, 0xc2, 0x20, 0x91, 0x1f,
0xe0, 0x22, 0x20, 0x9f, 0x1f, 0xe0, 0x22, 0x20, 0x90, 0x1f, 0xf0, 0x22, 0x31, 0x90, 0x3f, 0x79, 0xc2, 0x1f, 0x10, 0x3b,
0x38, 0x00, 0x00, 0x00, 0x73, 0x3c, 0x00, 0x00, 0x00, 0xf3, 0x3e, 0x00, 0x00, 0x01, 0xe3, 0x2e, 0x00, 0x00, 0x01, 0xe3,
0xff, 0x00, 0x00, 0x03, 0xff, 0x27, 0x80, 0x00, 0x03, 0xc3, 0x27, 0x80, 0x00, 0x07, 0xc3, 0x23, 0xc0, 0x00, 0x0f, 0x43,
0x21, 0xc0, 0x00, 0x1e, 0x43, 0x21, 0xff, 0xff, 0xfe, 0x43, 0x20, 0xff, 0xff, 0xfc, 0x43, 0x20, 0xff, 0xff, 0xf8, 0x43,
0x20, 0x82, 0x04, 0x10, 0x43, 0x24, 0x82, 0x04, 0x12, 0x43, 0x20, 0x82, 0x04, 0x10, 0x43, 0x20, 0x82, 0x04, 0x10, 0x43,
0xff, 0xff, 0xff, 0xff, 0xff, 0x20, 0x82, 0x04, 0x10, 0x43, 0x3f, 0x83, 0xfc, 0x1f, 0xc3
};
//--------------------------------------------------------------
#if defined(Z21DISPLAY_SH1106)
//-------------CONFIG SH110X DISPLAY DRIVER-----------------------------------------
#include <Adafruit_SH110X.h>
Adafruit_SH1106G display = Adafruit_SH1106G(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
#define DISPLAY_BG SH110X_BLACK //color for background
#define DISPLAY_TEXT SH110X_WHITE //Text color
#else
//-------------CONFIG SSD1306 DISPLAY DRIVER-----------------------------------------
#include <Adafruit_SSD1306.h>
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
#define DISPLAY_BG BLACK //color for background
#define DISPLAY_TEXT SSD1306_WHITE //Text color
#endif
//--------------------------------------------------------------
#define DisplayLineHight 9 //Pixel to get the next line
boolean DisplayReady = false; //Boot-Up progress has finish
uint8_t DisplayCounter = 0xFF; //for animation
//--------------------------------------------------------------
//remove old writing with a block box
void DisplayClearPart(uint8_t x, uint8_t y, uint8_t width) {
//x,y,width,hight
display.fillRect(x, y, width-x, DisplayLineHight, DISPLAY_BG);
display.setCursor(x,y);
}
//--------------------------------------------------------------
/*
#if defined(DISPLAY_TRANSMISSION)
//display LAN/WLAN transmission:
void DisplayDataTransmission(bool activ = true) {
if (Railpower == csShortCircuit) //no space for System Info!
return;
uint8_t color = DISPLAY_BG;
if (activ == true)
color = DISPLAY_TEXT;
display.fillTriangle(100, 1, 98, 3, 102, 3, color); // Send Data
display.drawLine(100,3,100,10,color);
display.fillTriangle(105, 10, 103, 8, 107, 8, color); // Receive Data
display.drawLine(105,1,105,8, color);
display.display(); //show...
}
#endif
*/
//--------------------------------------------------------------
//update Z21 System Info
#if defined(BOOSTER_INT_MAINCURRENT)
void DisplayUpdateRailData(uint16_t inAm, float volt, float temp) {
if (Railpower == csShortCircuit) //no space for System Info!
return;
//display WLAN signal on ESP:
#if defined(ESP_WIFI)
int WLAN_Signal = WiFi.RSSI();
#endif
#if defined(ESP_WIFI) || defined(WIFI)
display.fillRect(114, 0, 14, 13,DISPLAY_BG); //clear old WLAN Signal
if (WLAN_Signal > 30) { //not connected!
display.drawLine(121,4,127,12,DISPLAY_TEXT); // \ //
display.drawLine(127,4,121,12,DISPLAY_TEXT); // / //
}
else {
if (WLAN_Signal > -30)
display.drawLine(127,2,127,12,DISPLAY_TEXT); //Ausgezeichnet
if (WLAN_Signal > -65)
display.drawLine(125,4,125,12,DISPLAY_TEXT); //Sehr gut
if (WLAN_Signal > -71)
display.drawLine(123,6,123,12,DISPLAY_TEXT); //Akzeptabel
if (WLAN_Signal > -78)
display.drawLine(121,8,121,12,DISPLAY_TEXT); //Schlecht
if (WLAN_Signal > -85)
display.drawLine(119,10,119,12,DISPLAY_TEXT); //Sehr schlecht
//mark position of empty bar:
for (uint8_t i = 0; i < 6; i++) {
display.drawPixel(119 + (i * 2),12, DISPLAY_TEXT);
}
}
//WLAN Antenne:
display.drawLine(117,0,117,12,DISPLAY_TEXT); // | //
display.drawLine(114,0,120,0,DISPLAY_TEXT); // - //
display.drawLine(114,1,117,5,DISPLAY_TEXT); // \ //
display.drawLine(117,5,120,1,DISPLAY_TEXT); // / //
display.drawLine(117,5,120,1,DISPLAY_TEXT); // / //
DisplayClearPart(88, 0, 110);
#if defined(WIFI)
display.print(ESPsoftAPStationNum); //AP connected clients
#else
display.print(WiFi.softAPgetStationNum()); //AP connected clients
#endif
display.drawLine(95,0,95,7,DISPLAY_TEXT); // | //
display.setCursor(98,0);
display.print("8"); //max 8 number of clients
#endif
if (Railpower == csServiceMode) //stop here for full screen logo:
return;
//display System Info:
DisplayClearPart(40, DisplayLineHight, 80);
display.print(String(float(inAm)/1000, AMP_DECIMALS)); // A.aa Amper
display.print(F("A"));
//ESP8266 has only one ADC, so there is only the sense Value!
if (temp != 0.0) {
DisplayClearPart(90, 18, SCREEN_WIDTH); // 18 = DisplayLineHight * 2
display.print(temp,1); //one decimal place only!
display.print((char)247);
display.print(F("C"));
}
if (volt != 0) {
DisplayClearPart(0, DisplayLineHight, 40);
display.print(volt / 1000,1); //one decimal place only!
display.print(F("V"));
}
// drawing commands to make them visible on screen!
display.display();
}
#endif
//--------------------------------------------------------------
//draw a long rail on display
void drawLongRail(void) {
display.drawLine(0, 47, 44, 47,DISPLAY_TEXT); //Schiene links
display.drawLine(79, 47, SCREEN_WIDTH, 47,DISPLAY_TEXT); //Schiene rechts
display.drawLine(0, 59, SCREEN_WIDTH, 59,DISPLAY_TEXT); //Schiene unten
display.drawRect(-4, 45, 7, 17, DISPLAY_TEXT); //Schwelle
display.drawRect(8, 45, 7, 17, DISPLAY_TEXT); //Schwelle
display.drawRect(20, 45, 7, 17, DISPLAY_TEXT); //Schwelle
display.drawRect(32, 45, 7, 17, DISPLAY_TEXT); //Schwelle
//Logo
display.drawRect(81, 45, 7, 17, DISPLAY_TEXT); //Schwelle
display.drawRect(93, 45, 7, 17, DISPLAY_TEXT); //Schwelle
display.drawRect(105, 45, 7, 17, DISPLAY_TEXT); //Schwelle
display.drawRect(117, 45, 7, 17, DISPLAY_TEXT); //Schwelle
}
//--------------------------------------------------------------
//Update the config data on display
void DisplayConfigData() {
//remove all old data:
display.fillRect(0,18, SCREEN_WIDTH, 46, DISPLAY_BG); //remove the config data
byte y = DisplayLineHight; //Start after S88 Module output!
#if defined(S88N)
y += DisplayLineHight;
DisplayUpdateS88N();
#endif
#if defined(LAN)
y += DisplayLineHight;
DisplayClearPart(0, y, SCREEN_WIDTH);
display.print(F("Eth: "));
display.print(LAN_ip);
#endif
#if defined(WIFI)
if (ESPSwVer != 0.0) { //we already receive data?
y += DisplayLineHight;
DisplayClearPart(0, y, SCREEN_WIDTH);
display.print(F("WLAN: "));
if (WLANlocalIP[0] != 0)
display.print(WLANlocalIP); //0xE4 = Client IP
else display.print(F("[none]"));
y += DisplayLineHight;
DisplayClearPart(0, y, SCREEN_WIDTH);
display.print(WLANssid); //0xE5 = Client SSID Name
y += DisplayLineHight;
DisplayClearPart(0, y, SCREEN_WIDTH);
display.print(F("ESP Sw v"));
display.print(ESPSwVer); //0xE8 = ESP Sw Version
}
#endif
#if defined(ESP_WIFI)
y += DisplayLineHight;
DisplayClearPart(0, y, SCREEN_WIDTH);
display.print(F("ID:")); //AP SSID
display.print(ssidAP); //AP Name
y += DisplayLineHight;
DisplayClearPart(0, y, SCREEN_WIDTH);
display.print(F("Pw:"));
display.print(passAP);
y += DisplayLineHight;
DisplayClearPart(0, y, SCREEN_WIDTH);
display.print(F("IP:"));
display.print(WiFi.softAPIP());
y += DisplayLineHight;
DisplayClearPart(0, y, SCREEN_WIDTH);
display.print(F("WLAN: "));
display.print(WiFi.localIP().toString());
y += DisplayLineHight;
DisplayClearPart(0, y, SCREEN_WIDTH);
display.print(ssid.c_str());
#endif
// drawing commands to make them visible on screen!
display.display();
}
//--------------------------------------------------------------
//update power status
void DisplayUpdateRailPower(bool clear) {
//Railpower: ON, OFF, PROG, SHORT
if (DisplayCounter == 0xFF)
DisplayClearPart(40, 0, 70);
if (clear == true)
display.clearDisplay();
switch (Railpower) {
case csNormal: {
if (DisplayCounter == 0) //nothing more to do!
return;
else DisplayCounter--;
if (DisplayCounter == 1) { //last timer tick
display.fillRect(0,18, SCREEN_WIDTH, 46, DISPLAY_BG); //remove the config data
drawLongRail();
display.drawBitmap(42,22, Power_ON, 37, 40, DISPLAY_TEXT); //EmSTOP Logo
display.display();
return;
}
if (DisplayCounter == 254) {
display.print(F("-ON-")); //first time show power status
DisplayConfigData();
}
else return;
break;
}
case csTrackVoltageOff: {
display.print(F("-OFF-"));
display.fillRect(0,18, SCREEN_WIDTH, 46, DISPLAY_BG); //remove the config data
drawLongRail();
display.drawBitmap(42,22, Power_OFF, 37, 40, DISPLAY_TEXT); //Power OFF Logo
break;
}
case csServiceMode: {
display.fillRect(0,18, SCREEN_WIDTH, 46, DISPLAY_BG); //remove the config data
display.drawBitmap(51,22, Power_PROG, 25, 36, DISPLAY_TEXT); //Service Mode CV Logo
break;
}
case csShortCircuit: {
//draw blinking attention mark!
uint8_t color = DISPLAY_BG; //flash color
if (DisplayCounter == 0xFF) { //start-up
DisplayCounter = 0xF0; //clear the counter
display.clearDisplay();
color = DISPLAY_TEXT; //change color
}
else {
DisplayCounter = 0xFF; //reset
display.fillRect(0 ,0, SCREEN_WIDTH, SCREEN_HEIGHT, DISPLAY_TEXT); //make screen white
}
for(int8_t i=22; i < 26; i+=1) {
display.drawTriangle(
64 , 32-i,
64-i, 32+i,
64+i, 32+i, color);
}
display.fillTriangle(62 ,20, 64, 20, 58, 35, color); // (/)
display.drawLine(58, 35, 67, 31, color); // (-)
display.drawLine(58, 36, 67, 32, color); // (-)
display.fillTriangle(65 ,32, 67, 32, 62, 44, color); // (/)
display.fillTriangle(61 ,44, 65, 44, 63, 49, color); // (\/)
display.display();
return;
}
case csEmergencyStop: {
display.fillRect(0,18, SCREEN_WIDTH, 46, DISPLAY_BG); //remove the config data
drawLongRail();
display.drawBitmap(42,23, Power_EmSTOP, 38, 39, DISPLAY_TEXT); //EmSTOP Logo
break;
}
default: display.print(F("-!?!-")); break; //unknown!
}
display.setCursor(0,0); // Start at top-left corner
display.print(F("Z21PG"));
display.display();
if (Railpower != csNormal) { //only show config in normal mode
DisplayCounter = 0xFF; //reset
}
}
//--------------------------------------------------------------
//update S88N Module
#if defined(S88N)
void DisplayUpdateS88N() {
if (DisplayReady) {
display.setTextSize(1);
DisplayClearPart(0, 18, 89); //DisplayLineHight * 2
display.print(F("S88: "));
display.print(S88Module);
// drawing commands to make them visible on screen!
display.display();
}
}
#endif //S88 Module
//--------------------------------------------------------------
void DisplayBoot(byte percent) {
//draw a bar:
display.drawRoundRect(14, 47, 100, 6, 2, DISPLAY_TEXT); //outside (x0, y0, w, h, radius, color)
display.fillRect(14, 49, percent, 2, DISPLAY_TEXT); //inside
// drawing commands to make them visible on screen!
display.display();
}
//--------------------------------------------------------------
//report OTA Update on Display!
#if (defined(ESP8266_MCU) || defined(ESP32_MCU)) && defined(ESP_OTA)
void DisplayOTAStart() {
// Clear the buffer
display.clearDisplay();
display.setTextSize(2);
display.setCursor(0,0); // Start at top-left corner
display.print(F("Update..."));
// drawing commands to make them visible on screen!
display.display();
}
//--------------------------------------------------------------
void DisplayOTAProgress(uint8_t state) {
display.setTextSize(1);
DisplayClearPart(16, 36, SCREEN_WIDTH);
display.printf("Progress: %u%%", state);
// drawing commands to make them visible on screen!
DisplayBoot(state);
}
//--------------------------------------------------------------
void DisplayOTAFinish() {
display.clearDisplay();
display.drawBitmap(22, 8, Z21Bitmap, 80, 37, DISPLAY_TEXT); //Z21 Logo
display.display();
}
#endif //OTA Messages
//--------------------------------------------------------------
//Init the Display
void DisplaySetup(void) {
byte error, address = Z21DISPLAY;
//suchen der I2C Address des Display am Bus:
if (address == 0 || address > 127) {
#if defined(DEBUG)
Debug.print(F("Display..."));
#endif
Wire.begin();
do {
address++;
// The i2c_scanner uses the return value of
// the Write.endTransmisstion to see if
// a device did acknowledge to the address.
Wire.beginTransmission(address);
error = Wire.endTransmission();
}
while (error != 0 && address <= 127);
if (error != 0)
address = Z21DISPLAY; //kein I2C device!
#if defined(DEBUG)
if (error == 0) {
Debug.print(F("0x"));
if (address < 16)
Debug.print("0");
Debug.println(address,HEX);
}
else Debug.println(F("nicht gefunden!"));
#endif
}
#if defined(Z21DISPLAY_SH1106)
display.begin(address, true); // Address 0x3C default
#if defined(Z21DISPLAY_CONTRAST)
display.setContrast(Z21DISPLAY_CONTRAST); //gewünschter Kontrast-Wert 0-255
#endif
#else
// SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
display.begin(SSD1306_SWITCHCAPVCC, address); //<-- See datasheet for Address; 0x3D for 128x32, 0x3C for 128x64
#if defined(Z21DISPLAY_CONTRAST)
display.ssd1306_command(SSD1306_SETCONTRAST);
display.ssd1306_command(Z21DISPLAY_CONTRAST); //gewünschter Kontrast-Wert 0-255
#endif
#endif
// Clear the buffer
display.clearDisplay();
display.setTextColor(DISPLAY_TEXT); // Draw white text
display.setCursor(0,0); // Start at top-left corner with Sw Version
display.print(F("v"));
display.print(String(Z21mobileSwVer).substring(0,1));
display.print(".");
display.print(String(Z21mobileSwVer).substring(1));
display.setCursor(0,56);
display.print(comp_date); //Build Data
display.drawBitmap(22, 8, Z21Bitmap, 80, 37, DISPLAY_TEXT); //Z21 Logo
DisplayBoot(0); //Boot up bar...
}
#endif

Datei anzeigen

@ -0,0 +1,411 @@
//--------------------------------------------------------------------------------------------
//POWER set configuration:
void globalPower (byte state) {
if (Railpower != state) {
if (Railpower == csServiceMode && state == csShortCircuit) {
#if defined(LAN) || defined(WIFI) || defined(ESP_WIFI)
z21.setCVNackSC(); //response SHORT while Service Mode!
#endif
#if defined(XPRESSNET)
XpressNet.setCVNackSC();
#endif
}
#if defined(Z21DISPLAY)
DisplayCounter = 0xFF;
if ((Railpower == csShortCircuit) || (state == csShortCircuit)) {
Railpower = state;
DisplayUpdateRailPower(true);
}
else {
Railpower = state;
DisplayUpdateRailPower(false);
}
#else
Railpower = state;
#endif
#if defined(DEBUG)
Debug.print(F("Power State: "));
Debug.println(state);
#endif
switch (state) {
case csNormal:
#if defined(DCC)
dcc.setpower(ON);
#if defined(ProgRelaisPin)
#if defined(PROG_OUT_INVERT)
digitalWrite(ProgRelaisPin, HIGH); //ProgTrack
#else
digitalWrite(ProgRelaisPin, LOW); //ProgTrack
#endif
#endif
#if defined(INA219)
ina219.setPGain(PG_320); //Default setting range (320mV full range, ~16 A max. current, ~4mA resolution with 20 mOhm shunt)
#endif
#endif
#if defined(BOOSTER_EXT)
if (digitalRead(ShortExtPin) == LOW)
digitalWrite(GoExtPin, BOOSTER_EXT_ON);
#endif
#if (defined(BOOSTER_INT) && !defined(BOOSTER_INT_NDCC))
digitalWrite(GoIntPin, BOOSTER_INT_ON);
#endif
break;
case csTrackVoltageOff:
#if defined(DCC)
dcc.setpower(OFF);
#if defined(ProgRelaisPin)
#if defined(PROG_OUT_INVERT)
digitalWrite(ProgRelaisPin, HIGH); //ProgTrack
#else
digitalWrite(ProgRelaisPin, LOW); //ProgTrack
#endif
#endif
#endif
#if defined(BOOSTER_EXT)
digitalWrite(GoExtPin, BOOSTER_EXT_OFF);
#endif
#if (defined(BOOSTER_INT) && !defined(BOOSTER_INT_NDCC))
digitalWrite(GoIntPin, BOOSTER_INT_OFF);
#endif
break;
case csServiceMode:
#if defined(DCC)
dcc.setpower(SERVICE); //already on!
#if defined(ProgRelaisPin)
#if defined(PROG_OUT_INVERT)
digitalWrite(ProgRelaisPin, LOW); //ProgTrack
#else
digitalWrite(ProgRelaisPin, HIGH); //ProgTrack
#endif
#endif
#if defined(INA219)
ina219.setPGain(PG_80); //setting range (160mV full range
#endif
#endif
#if defined(BOOSTER_EXT)
#if defined(BOOSTER_INT)
digitalWrite(GoExtPin, BOOSTER_EXT_OFF);
#else
if (digitalRead(ShortExtPin) == LOW)
digitalWrite(GoExtPin, BOOSTER_EXT_ON);
#endif
#endif
#if (defined(BOOSTER_INT) && !defined(BOOSTER_INT_NDCC))
digitalWrite(GoIntPin, BOOSTER_INT_ON);
#endif
break;
case csShortCircuit:
#if defined(DCC)
dcc.setpower(SHORT); //shut down via GO/STOP just for the Roco Booster
#if defined(ProgRelaisPin)
#if defined(PROG_OUT_INVERT)
digitalWrite(ProgRelaisPin, HIGH); //ProgTrack
#else
digitalWrite(ProgRelaisPin, LOW); //ProgTrack
#endif
#endif
#endif
#if defined(BOOSTER_EXT)
digitalWrite(GoExtPin, BOOSTER_EXT_OFF);
#endif
#if (defined(BOOSTER_INT) && !defined(BOOSTER_INT_NDCC))
digitalWrite(GoIntPin, BOOSTER_INT_OFF);
#endif
break;
case csEmergencyStop:
#if defined(DCC)
dcc.eStop();
#endif
break;
}
if (Railpower == csShortCircuit)
digitalWrite(ShortLed, HIGH); //Short LED show State "short"
if (Railpower == csNormal)
digitalWrite(ShortLed, LOW); //Short LED show State "normal"
#if defined(LAN) || defined(WIFI) || defined(ESP_WIFI)
z21.setPower(Railpower);
#endif
#if defined(XPRESSNET)
XpressNet.setPower(Railpower); //send to XpressNet
#endif
#if defined(LOCONET)
LNsetpower(); //send to LocoNet
#endif
}
}
//--------------------------------------------------------------------------------------------
//from DCCPacketScheduler -> notify power state when change into Programming Mode
void notifyRailpower(uint8_t state) {
if (Railpower != state) {
#if defined(Z21DEBUG)
Debug.print(F("dcc "));
#endif
globalPower(state);
}
}
//--------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------
#if defined(DCC)
//--------------------------------------------------------------------------------------------
uint16_t getRailmA() {
#if defined (INA219) // current via INA219
uint16_t mA = ina219.getCurrent_mA();
if (mA > 65000) //ignore this value!
return VAmpINT;
return mA;
#elif defined(ESP32_MCU)
return (analogRead(VAmpIntPin)) / senseResist * 1000 * (3.3/4096); //adjusted to Uref more accurate
#elif defined(ESP8266_MCU) //Wemos D1 mini has a voltage divider!
uint16_t mA = analogRead(VAmpIntPin);
if (mA > 3) //remove to low values!
return mA / senseResist * 1000 * (3.3/1024); //adjusted to Uref more accurate
return 0;
#elif defined(AREF_1V1)
return analogRead(VAmpIntPin) / senseResist * 1000 * (Uref/1024); //adjusted to Uref more accurate
#else
return analogRead(VAmpIntPin) * 10; //old!
#endif
}
//--------------------------------------------------------------------------------------------
uint16_t getRailVolt() {
#if defined (INA219)
return (float) ((ina219.getBusVoltage_V() + (ina219.getShuntVoltage_mV()/1000)) * 1000); //rail voltage, correctded (shunt voltage)
#elif defined(ESP32_MCU)
return ((float) analogRead(VoltIntPin) * 1000 * (100/4.7) * (3.3/496)); //adjusted to Uref more accurate
#elif defined(MEGA_MCU)
//#if defined(AREF_1V1)
//return ((float) analogRead(VoltIntPin) * 1000 * (100/4.7) * (Uref/1024)); //adjusted to Uref more accurate
//#else
//return ((float)(analogRead(VoltIntPin)-121) / 0.008); //old!
// #endif
return ((float)15.00);
#else //other MCU:
return ((float)15.00);
#endif
}
//--------------------------------------------------------------------------------------------
void ShortDetection() {
//Short Circuit?
//Check BOOSTER extern
#if defined(BOOSTER_EXT)
if ((digitalRead(ShortExtPin) == HIGH) && (digitalRead(GoExtPin) == BOOSTER_EXT_ON) && (Railpower != csShortCircuit)) {
ShortTime++;
if(ShortTime == DetectShortCircuit) {
globalPower(csShortCircuit);
#if defined(DEBUG)
Debug.println(F("TRACK_SHORT_CIRCUIT EXT"));
#endif
}
}
else ShortTime = 0;
#endif
//Check BOOSTER2 (z.B. TLE5206)
#if defined(BOOSTER_INT)
//---------------Short2 for CDE external Booster----------------------------------
#if defined(BOOSTER_EXT_CDE)
if ((digitalRead(ShortIntPin) == LOW) && (Railpower != csShortCircuit)) {
globalPower(csShortCircuit);
#if defined(DEBUG)
Debug.println(F("TRACK_SHORT_CIRCUIT CDE"));
#endif
}
//---------------Short2 TLE detection----------------------------------
#elif defined(BOOSTER_INT_TLE5206)
#if defined(BOOSTER_INT_NDCC)
if ((digitalRead(ShortIntPin) == LOW) && (Railpower != csShortCircuit)) {
#else
//---------------Old: without RailCom support----------------------------------
if ((digitalRead(ShortIntPin) == LOW) && (digitalRead(GoIntPin) == BOOSTER_INT_ON) && (Railpower != csShortCircuit)) {
#endif
globalPower(csShortCircuit);
#if defined(DEBUG)
Debug.println(F("TRACK_SHORT_CIRCUIT_INT"));
#endif
}
#endif
#if defined(BOOSTER_INT_CURRENT_SHORT_DETECT)
//Check if RailCom is on the rail?
if (dcc.getRailComStatus() == false) {
/*
#if defined (INA219) // current via INA219
float mA = ina219.getCurrent_mA() - 5; //reduce 5mA current power of H-Bridge
if (mA >= 0)
VAmpINT = mA;
if (ina219.getOverflow()) {
#if defined(DEBUG)
Debug.println(F("INA Overflow!"));
#endif
}
*/
VAmpINT = getRailmA();
if ((VAmpINT >= DETECT_SHORT_INT_VALUE) && (Railpower != csShortCircuit)) {
#if defined(DEBUG)
Debug.print(digitalRead(DCCPin));
Debug.print(digitalRead(GoIntPin));
Debug.print("-");
Debug.print(millis() - ShortTimeINT);
Debug.print(" mA: ");
Debug.print(VAmpINT);
#endif
ShortTimeINTcounter = 6; //ignore low values!
if (((millis() - ShortTimeINT) > DETECT_SHORT_INT_WAIT) || (VAmpINT >= DETECT_SHORT_INT_VALUE + (DETECT_SHORT_INT_VALUE / 2) ) ) {
globalPower(csShortCircuit);
#if defined(DEBUG)
Debug.print(VAmpINT);
Debug.print("-t");
Debug.print(millis() - ShortTimeINT);
Debug.println(F(" TRACK_SHORT_INT"));
#endif
}
}
else {
if (ShortTimeINTcounter > 0) {
ShortTimeINTcounter--;
/*
#if defined(DEBUG)
Debug.print(dcc.getRailComStatus());
Debug.print(digitalRead(DCCPin));
Debug.print(digitalRead(GoIntPin));
Debug.print("-");
Debug.print(VAmpINT);
Debug.print(" mA ");
Debug.println(ShortTimeINTcounter);
#endif
*/
}
else ShortTimeINT = millis();
}
}
#endif
#endif
}
#endif
//--------------------------------------------------------------------------------------------
void updateLedButton() {
//read out last LED status:
bool lastLedState = false; //OFF
#if defined(POWER_LED_INVERT)
if (digitalRead(DCCLed) == LOW)
#else
if (digitalRead(DCCLed) == HIGH)
#endif
lastLedState = true; //ON
//Button to control Railpower state
pinMode(Z21ButtonPin, INPUT_PULLUP);
if ((digitalRead(Z21ButtonPin) == LOW) && (Z21ButtonLastState == false)) { //Button DOWN
#if !(defined(ADD_ACK_COMP) && defined(ESP8266_MCU))
Z21ButtonLastState = true;
LEDcount = millis();
#endif
}
else {
if ((digitalRead(Z21ButtonPin) == HIGH) && (Z21ButtonLastState == true)) { //Button UP
Z21ButtonLastState = false;
#if defined(DEBUG)
Debug.print(F("Button "));
#endif
if (Railpower == csNormal) {
if(millis() - LEDcount > 750) { //push long?
if (FIXSTORAGE.read(52) == 0x00) //Power-Button (short): 0=Gleisspannung aus, 1=Nothalt
globalPower(csEmergencyStop);
else globalPower(csTrackVoltageOff);
}
else {
if (FIXSTORAGE.read(52) == 0x00) //Power-Button (short): 0=Gleisspannung aus, 1=Nothalt
globalPower(csTrackVoltageOff);
else globalPower(csEmergencyStop);
}
}
else globalPower(csNormal);
LEDcount = millis();
}
}
//reset to the last State:
if (lastLedState) {
pinMode(DCCLed, OUTPUT);
#if defined(POWER_LED_INVERT)
digitalWrite(DCCLed, LOW);
#else
digitalWrite(DCCLed, HIGH);
#endif
}
//Update LED
if (Railpower == csNormal) {
pinMode(DCCLed, OUTPUT);
#if defined(POWER_LED_INVERT)
digitalWrite(DCCLed, LOW);
#else
digitalWrite(DCCLed, HIGH);
#endif
#if defined(Z21DISPLAY)
if(millis() % DISPLAY_POWER_LOGO == 0 )
DisplayUpdateRailPower(false); //Update OLED Display
#endif
}
else { //Flash:
unsigned long currentMillis = millis();
if (currentMillis > LEDcount) {
pinMode(DCCLed, OUTPUT);
if (Railpower == csTrackVoltageOff) {
if (lastLedState)
LEDcount = currentMillis + 1100; //long OFF
else LEDcount = currentMillis + 300; //short ON
}
else if (Railpower == csEmergencyStop) {
if (lastLedState)
LEDcount = currentMillis + 80; //short OFF
else LEDcount = currentMillis + 700; //long ON
}
else if (Railpower == csShortCircuit) {
LEDcount = currentMillis + 200; //short flash
#if defined(Z21DISPLAY)
DisplayUpdateRailPower(false); //Update OLED Display
#endif
}
else { //csServiceMode:
LEDcount = currentMillis + 100; //fast short flash
#if defined(Z21DISPLAY)
if(currentMillis % 5 == 0 ) {
DisplayUpdateRailPower(false); //Update OLED Display
}
#endif
}
if (lastLedState)
pinMode(DCCLed, INPUT); //OFF
else {
#if defined(POWER_LED_INVERT)
digitalWrite(DCCLed, LOW); //ON
#else
digitalWrite(DCCLed, HIGH); //OFF
#endif
}
}
}
}

Datei anzeigen

@ -0,0 +1,323 @@
//--------------------------------------------------------------------------------------------
#if defined(HTTPCONF) || defined(ESP_HTTPCONF)
//--------------------------------------------------------------------------------------------
#if defined(LAN)
void Webconfig() {
EthernetClient client = server.available();
if (client) {
String receivedText = String(50);
// an http request ends with a blank line
boolean currentLineIsBlank = true;
while (client.connected()) {
if (client.available()) {
char c = client.read();
if (receivedText.length() < 50) {
receivedText += c;
}
// if you've gotten to the end of the line (received a newline
// character) and the line is blank, the http request has ended,
// so you can send a reply
if (c == '\n' && currentLineIsBlank) {
// send a standard http response header
client.println(F("HTTP/1.1 200 OK"));
client.println(F("Content-Type: text/html"));
client.println(F("Connection: close")); // the connection will be closed after completion of the response
//client.println(F("Refresh: 5")); // refresh the page automatically every 5 sec
client.println(); //don't forget this!!!
//Website:
client.println(F("<!DOCTYPE html><html><head>"));
client.println(F("<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"/>"));
client.println(F("<title>Z21</title></head><body><h1>Z21</h1>"));
//----------------------------------------------------------------------------------------------------
int firstPos = receivedText.indexOf("?");
if (firstPos > -1) {
byte lastPos = receivedText.indexOf(" ", firstPos);
String theText = receivedText.substring(firstPos+3, lastPos); // 10 is the length of "?A="
byte S88Pos = receivedText.indexOf("S=");
#if defined(S88N)
S88Module = receivedText.substring(S88Pos+2, receivedText.indexOf("HTTP")-1).toInt();
#endif
byte Sip = theText.indexOf("A="); //Start IP, nur wenn DHCP aktiv ist Ausdruck vorhanden!
if (Sip == 0xFF) { //DHCP off
LAN_DHCP = false;
Sip = 0;
}
else {
LAN_DHCP = true;
Sip += 2;
}
byte Aip = theText.indexOf("&B=", Sip);
byte Bip = theText.indexOf("&C=", Aip);
byte Cip = theText.indexOf("&D=", Bip);
byte Dip = theText.substring(Cip+3, S88Pos).toInt();
Cip = theText.substring(Bip+3, Cip).toInt();
Bip = theText.substring(Aip+3, Bip).toInt();
Aip = theText.substring(Sip, Aip).toInt();
LAN_ip[0] = Aip;
LAN_ip[1] = Bip;
LAN_ip[2] = Cip;
LAN_ip[3] = Dip;
#if defined(DEBUG)
#if defined(S88N)
Debug.print("S88: ");
Debug.println(S88Module);
#endif
if (LAN_DHCP)
Debug.print("DHCP ");
Debug.print("IP: ");
Debug.println(LAN_ip);
#if !defined(SOFT_RESET)
Debug.println(F("-> Restart to accept!"));
#endif
#endif
#if !defined(SOFT_RESET)
client.print(F("<dialog open><p>Reset Z21 to accept!</p></dialog>"));
#endif
FIXSTORAGE.FIXMODE(EELANDHCP, LAN_DHCP);
FIXSTORAGE.FIXMODE(EELANip, Aip);
FIXSTORAGE.FIXMODE(EELANip+1, Bip);
FIXSTORAGE.FIXMODE(EELANip+2, Cip);
FIXSTORAGE.FIXMODE(EELANip+3, Dip);
#if defined(ESP_WIFI)
FIXSTORAGE.commit();
#endif
#if defined(S88N)
if (FIXSTORAGE.read(EES88Moduls) != S88Module) {
FIXSTORAGE.FIXMODE(EES88Moduls, S88Module);
#if defined(ESP_WIFI)
FIXSTORAGE.commit();
#endif
#if defined(DEBUG)
Debug.print("neu S88: ");
Debug.println(S88Module);
#endif
SetupS88();
#if defined(WIFI)
WLANSetup();
#endif
}
else {
#endif
#if defined(SOFT_RESET)
soft_restart(); //Reboot MCU!
#endif
#if defined(S88N)
}
#endif
}
//----------------------------------------------------------------------------------------------------
client.print(F("<form method=get>"));
client.print(F("DHCP <input type=checkbox name=P"));
if (LAN_DHCP)
client.print(" checked");
client.print(F("><br>"));
client.print(F("IP: <input type=number min=0 max=254 name=A value="));
client.println(LAN_ip[0]);
client.print(F("><input type=number min=0 max=254 name=B value="));
client.println(LAN_ip[1]);
client.print(F("><input type=number min=0 max=254 name=C value="));
client.println(LAN_ip[2]);
client.print(F("><input type=number min=0 max=254 name=D value="));
client.println(LAN_ip[3]);
client.print(F("><br><br>8x S88 Module: <input type=number min=0 max="));
#if defined(S88N)
client.print(S88MAXMODULE);
#else
client.print("0");
#endif
client.print(F(" name=S value="));
#if defined(S88N)
client.print(S88Module);
#else
client.print("-");
#endif
client.print(F("><br><br><input type=submit></form></body></html>"));
break;
}
if (c == '\n')
currentLineIsBlank = true; // you're starting a new line
else if (c != '\r')
currentLineIsBlank = false; // you've gotten a character on the current line
}
}
client.stop(); // close the connection:
}
}
#endif
//--------------------------------------------------------------------------------------------
#if defined(ESP8266_MCU) || defined(ESP32_MCU)
void Webconfig() {
WiFiClient client = ESPWebserver.available();
if (!client)
return;
String HTTP_req; // stores the HTTP request
if (client) { // got client?
boolean currentLineIsBlank = true;
while (client.connected()) {
if (client.available()) { // client data available to read
char c = client.read(); // read 1 byte (character) from client
HTTP_req += c; // save the HTTP request 1 char at a time
// last line of client request is blank and ends with \n
// respond to client only after last line received
if (c == '\n' && currentLineIsBlank) {
// send a standard http response header
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println("Connection: keep-alive");
client.println(); //don't forget this!!!
// AJAX request for switch state
if (HTTP_req.indexOf("/ajax_switch") > -1) {
#if defined(DEBUG)
Debug.println("Reset WLAN conf!");
#endif
// read switch state and send appropriate paragraph text
ssid = HTTP_req.substring(HTTP_req.indexOf("&s=")+3,HTTP_req.indexOf("&p="));
pass = HTTP_req.substring(HTTP_req.indexOf("&p=")+3,HTTP_req.indexOf("&As="));
ssidAP = HTTP_req.substring(HTTP_req.indexOf("&As=")+4,HTTP_req.indexOf("&Ap="));
passAP = HTTP_req.substring(HTTP_req.indexOf("&Ap=")+4,HTTP_req.indexOf("&Ak="));
kanalAP = HTTP_req.substring(HTTP_req.indexOf("&Ak=")+4,HTTP_req.indexOf("&S8=")).toInt();
#if defined(S88N)
S88Module = HTTP_req.substring(HTTP_req.indexOf("&S8=")+4,HTTP_req.indexOf("&nocache")).toInt();
#endif
if ((kanalAP < 1) || (kanalAP > 13)) {
kanalAP = SkanalAP;
client.print("Ka. error! ");
}
if (passAP.length() < 8) {
passAP = SpassAP;
client.print("Code length error (min. 8)! ");
}
// write eeprom
EEPROMwrite (ssid, EEssidLength, EEssidBegin);
EEPROMwrite (pass, EEpassLength, EEpassBegin);
EEPROMwrite (ssidAP, EEssidAPLength, EEssidAPBegin);
EEPROMwrite (passAP, EEpassAPLength, EEpassAPBegin);
FIXSTORAGE.FIXMODE(EEkanalAP, kanalAP);
FIXSTORAGE.commit();
ESPSetup();
Udp.begin(z21Port);
client.println("saved"); //OK!
}
else { // HTTP request for web page
// send web page - contains JavaScript with AJAX calls
client.println("<!DOCTYPE html>");
client.println("<html><head><title>Z21</title>");
client.println("<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"/>");
client.println("<script>");
client.println("function SetState() {");
client.println("document.getElementById(\"state\").innerHTML = \"wait\";");
client.println("nocache = \"&s=\" + document.getElementById(\"ssid\").value;");
client.println("nocache += \"&p=\" + document.getElementById(\"pass\").value;");
client.println("nocache += \"&As=\" + document.getElementById(\"ssidAP\").value;");
client.println("nocache += \"&Ap=\" + document.getElementById(\"passAP\").value;");
client.println("nocache += \"&Ak=\" + document.getElementById(\"kanalAP\").value;");
client.println("nocache += \"&S8=\" + document.getElementById(\"S88\").value;");
client.println("nocache += \"&nocache=\" + Math.random() * 1000000;");
client.println("var request = new XMLHttpRequest();");
client.println("request.onreadystatechange = function() {");
client.println("if (this.readyState == 4){");
// client.println("if (this.status == 200){");
// client.println("if (this.responseText != null) {");
client.println("document.getElementById(\"state\").innerHTML = this.responseText;");
client.println("top.window.location.reload(true);");
client.println("}}");
client.println("request.open(\"GET\", \"ajax_switch\" + nocache, true);");
client.println("request.send(null);");
//client.println("setTimeout('SetState()', 1000);");
client.println("}");
client.println("</script>");
client.println("</head>");
client.println("<body><h1>Z21 Einstellungen</h1><hr>");
client.print("<h2>WiFi Access-Point</h2>");
client.print("<dl><dd>IP: ");
client.print(WiFi.softAPIP());
client.print("</dd><dd>Connected Clients: ");
client.print(WiFi.softAPgetStationNum());
client.print(" of 8</dd><dd>SSID: <input type=\"text\" id=\"ssidAP\" value=\"");
client.print(ssidAP);
client.print("\"></dd><dd>code: <input type=\"text\" id=\"passAP\" value=\"");
client.print(passAP);
client.print("\"></dd><dd>Ka.: <input type=\"number\" min=\"1\" max=\"13\" id=\"kanalAP\" value=\"");
client.print(kanalAP);
client.println("\"></dd></dl>");
client.print("<h2>WiFi Client</h2>");
client.print("<dl><dd>IP: ");
if (WiFi.status() == WL_CONNECTED) {
client.print(WiFi.localIP());
client.print(" (");
client.print(WiFi.RSSI());
client.print("dBm)");
}
else client.print("none");
client.print("</dd><dd>SSID: <input type=text id=\"ssid\" value=\"");
client.print(ssid);
client.print("\"></dd><dd>code: <input type=text id=\"pass\" value=\"");
client.print(pass);
client.println("\"></dd></dl>");
client.println("<h2>S88 Module</h2>");
client.print("<dl><dd>8x Anzahl: <input type=number min=\"0\" max=\"62\" id=\"S88\" value=\"");
#if defined(S88N)
client.print(S88Module);
client.print("\"");
#else
client.print("0\" disabled");
#endif
client.println("></dd></dl><br>");
client.println("<input type=submit onclick=\"SetState()\">");
client.println("<p id=\"state\"></p>");
client.print("<hr><p>Z21_ESP_Central_Station_v");
client.print(Z21mobileSwVer);
client.print(bitRead(FIXSTORAGE.read(EEPROMRCN213), 2)); //RCN-213
#if defined (BOOSTER_INT_NDCC)
if (FIXSTORAGE.read(EEPROMRailCom) == 0x01)
client.print(".RAILCOM");
#endif
client.println("<br>Build: ");
client.println(comp_date);
client.println("<br>Copyright (c) 2022 Philipp Gahtow<br>digitalmoba@arcor.de");
client.println("</p></body>");
client.print("</html>");
}
// display received HTTP request on serial port
//Serial.print(HTTP_req);
HTTP_req = ""; // finished with request, empty string
break;
}
// every line of text received from the client ends with \r\n
if (c == '\n') {
// last character on line of received text
// starting new line with next character read
currentLineIsBlank = true;
}
else if (c != '\r') {
// a text character was received from client
currentLineIsBlank = false;
}
} // end if (client.available())
} // end while (client.connected())
delay(1); // give the web browser time to receive the data
client.stop(); // close the connection
} // end if (client)
}
#endif
//--------------------------------------------------------------------------------------------
#endif //HTTPconf

Datei anzeigen

@ -0,0 +1,338 @@
//--------------------------------------------------------------
/*
XpressNetMaster Interface for Arduino
Funktionsumfang:
- Fahren per LokMaus2 und MultiMaus
- Schalten von DCC Weichen mit der MultiMaus
- CV Programmieren CV Direct only
Copyright (c) by Philipp Gahtow, year 2022
*/
#if defined(XPRESSNET)
//**************************************************************
//byte XNetUserOps = 0x00;
//byte XNetReturnLoco = 0x00;
//--------------------------------------------------------------
//Change Power Status
void notifyXNetPower(uint8_t State) {
if (Railpower != State) {
#if defined(XnDEB)
Debug.print("XNet ");
#if !defined(DEBUG)
Debug.print("Power: ");
Debug.println(State, HEX);
#endif
#endif
globalPower(State);
}
}
//--------------------------------------------------------------
void notifyXNetgiveLocoInfo(uint8_t UserOps, uint16_t Address) {
//XNetReturnLoco |= 0x01;
//XNetUserOps = UserOps;
#if defined(DCC)
//dcc.getLocoStateFull(Address, false); //request for XpressNet only!
uint8_t ldata[6];
AllLocoData(Address, ldata); //uint8_t Steps[0], uint8_t Speed[1], uint8_t F0[2], uint8_t F1[3], uint8_t F2[4], uint8_t F3[5]
if (ldata[0] == 0x03) //128 Steps?
ldata[0]++; //set Steps to 0x04
XpressNet.SetLocoInfo(UserOps, ldata[0], ldata[1], ldata[2] & 0x1F, ldata[3]); //UserOps,Steps,Speed,F0,F1
#endif
}
//--------------------------------------------------------------
void notifyXNetgiveLocoFunc(uint8_t UserOps, uint16_t Address) {
//XNetReturnLoco |= 0x02;
//XNetUserOps = UserOps;
#if defined(DCC)
//dcc.getLocoStateFull(Address, false); //request for XpressNet only!
XpressNet.SetFktStatus(UserOps, dcc.getFunktion13to20(Address), dcc.getFunktion21to28(Address)); //Fkt4, Fkt5
#endif
}
//--------------------------------------------------------------
void notifyXNetgiveLocoMM(uint8_t UserOps, uint16_t Address) {
uint8_t ldata[6];
AllLocoData(Address, ldata); //uint8_t Steps[0], uint8_t Speed[1], uint8_t F0[2], uint8_t F1[3], uint8_t F2[4], uint8_t F3[5]
if (ldata[0] == 0x03) //128 Steps?
ldata[0]++; //set Steps to 0x04
XpressNet.SetLocoInfoMM(UserOps, ldata[0], ldata[1], ldata[2] & 0x1F, ldata[3], ldata[4], ldata[5]); //Steps,Speed,F0,F1,F2,F3
}
//--------------------------------------------------------------
void notifyXNetLocoDrive14(uint16_t Address, uint8_t Speed) {
#if defined(LOCONET)
sendLNSPD(Address, map(Speed, -14, 14, -128, 128));
#endif
#if defined(XnDEB)
Debug.print("XNet A:");
Debug.print(Address);
Debug.print(", S14:");
Debug.println(Speed, BIN);
#endif
#if defined(DCC)
if (Speed == 0)
dcc.setSpeed14(Address, (dcc.getLocoDir(Address) << 7) | (Speed & B01111111));
else dcc.setSpeed14(Address, Speed);
//dcc.getLocoStateFull(Address); //request for other devices
#endif
#if defined(LAN) || defined(WIFI) || defined(ESP_WIFI)
z21.setLocoStateExt (Address);
#endif
}
//--------------------------------------------------------------
void notifyXNetLocoDrive28(uint16_t Address, uint8_t Speed) {
#if defined(LOCONET)
sendLNSPD(Address, map(Speed, -28, 28, -128, 128));
#endif
#if defined(XnDEB)
Debug.print("XNet A:");
Debug.print(Address);
Debug.print(", S28:");
Debug.println(Speed, BIN);
#endif
#if defined(DCC)
if (Speed == 0)
dcc.setSpeed28(Address, (dcc.getLocoDir(Address) << 7) | (Speed & B01111111));
else dcc.setSpeed28(Address, Speed);
//dcc.getLocoStateFull(Address); //request for other devices
#endif
#if defined(LAN) || defined(WIFI) || defined(ESP_WIFI)
z21.setLocoStateExt (Address);
#endif
}
//--------------------------------------------------------------
void notifyXNetLocoDrive128(uint16_t Address, uint8_t Speed) {
#if defined(LOCONET)
sendLNSPD(Address, Speed);
#endif
#if defined(XnDEB)
Debug.print("XNet A:");
Debug.print(Address);
Debug.print(", S128:");
Debug.println(Speed, BIN);
#endif
#if defined(DCC)
//if ((Speed & 0x7F) == 0)
// dcc.setSpeed128(Address, (dcc.getLocoDir(Address) << 7) | (Speed & B01111111));
//else
dcc.setSpeed128(Address, Speed);
//dcc.getLocoStateFull(Address); //request for other devices
#endif
#if defined(LAN) || defined(WIFI) || defined(ESP_WIFI)
z21.setLocoStateExt (Address);
#endif
}
//--------------------------------------------------------------
void notifyXNetLocoFunc1(uint16_t Address, uint8_t Func1) {
#if defined(XnDEB)
Debug.print("XNet A:");
Debug.print(Address);
Debug.print(", F1:");
Debug.println(Func1, BIN);
#endif
#if defined(DCC)
dcc.setFunctions0to4(Address, Func1); //- F0 F4 F3 F2 F1
//dcc.getLocoStateFull(Address); //request for other devices
#endif
#if defined(LAN) || defined(WIFI) || defined(ESP_WIFI)
z21.setLocoStateExt (Address);
#endif
#if defined(LOCONET)
byte DIRF = Func1 | (!dcc.getLocoDir(Address) << 5); //invertierte Fahrtrichtung!
//Beim einschalten einer Funktion wird die Fahrtrichtung geändert - deshalb hier invertiert!
sendLNDIRF(Address, DIRF);
#endif
}
//--------------------------------------------------------------
void notifyXNetLocoFunc2(uint16_t Address, uint8_t Func2) {
#if defined(XnDEB)
Debug.print("XNet A:");
Debug.print(Address);
Debug.print(", F2:");
Debug.println(Func2, BIN);
#endif
#if defined(DCC)
dcc.setFunctions5to8(Address, Func2); //- F8 F7 F6 F5
//dcc.getLocoStateFull(Address); //request for other devices
#endif
#if defined(LAN) || defined(WIFI) || defined(ESP_WIFI)
z21.setLocoStateExt (Address);
#endif
#if defined(LOCONET)
sendLNSND(Address, Func2);
#endif
}
//--------------------------------------------------------------
void notifyXNetLocoFunc3(uint16_t Address, uint8_t Func3) {
#if defined(XnDEB)
Debug.print("XNet A:");
Debug.print(Address);
Debug.print(", F3:");
Debug.println(Func3, BIN);
#endif
#if defined(DCC)
dcc.setFunctions9to12(Address, Func3); //- F12 F11 F10 F9
//dcc.getLocoStateFull(Address); //request for other devices
#endif
#if defined(LAN) || defined(WIFI) || defined(ESP_WIFI)
z21.setLocoStateExt (Address);
#endif
#if defined(LOCONET)
sendLNF3(Address, Func3);
#endif
}
//--------------------------------------------------------------
void notifyXNetLocoFuncX(uint16_t Address, uint8_t group, uint8_t Func) {
#if defined(XnDEB)
Debug.print("XNet A:");
Debug.print(Address);
Debug.print(", F");
Debug.print(group);
Debug.print(":");
Debug.println(Func, BIN);
#endif
if (group == 0x04) {
#if defined(DCC)
dcc.setFunctions13to20(Address, Func); //F20 F19 F18 F17 F16 F15 F14 F13
#endif
#if defined(LOCONET)
sendLNF4(Address, Func);
#endif
}
else if (group == 0x05) {
#if defined(DCC)
dcc.setFunctions21to28(Address, Func); //F28 F27 F26 F25 F24 F23 F22 F21
#endif
#if defined(LOCONET)
sendLNF5(Address, Func);
#endif
}
else if (group == 0x06) {
#if defined(DCC)
dcc.setFunctions29to36(Address, Func);
#endif
}
#if defined(LAN) || defined(WIFI) || defined(ESP_WIFI)
z21.setLocoStateExt (Address);
#endif
}
//--------------------------------------------------------------
void notifyXNetTrntInfo(uint8_t UserOps, uint16_t Address, uint8_t data) {
uint16_t adr = ((Address * 4) + ((data & 0x01) * 2));
byte pos = data << 4;
bitWrite(pos, 7, 1); //command completed!
if (dcc.getBasicAccessoryInfo(adr) == false)
bitWrite(pos, 0, 1);
else bitWrite(pos, 1, 1);
if (dcc.getBasicAccessoryInfo(adr+1) == false)
bitWrite(pos, 2, 1);
else bitWrite(pos, 3, 1);
XpressNet.SetTrntStatus(UserOps, Address, pos);
#if defined(XnDEB)
Debug.print("XNet: ");
Debug.print(adr);
Debug.print(", P:");
Debug.println(pos, BIN);
#endif
}
//--------------------------------------------------------------
void notifyXNetTrnt(uint16_t Address, uint8_t data) {
#if defined(XnDEB)
Debug.print("XNet TA:");
Debug.print(Address);
Debug.print(", P:");
Debug.println(data, BIN);
#endif
#if defined(DCC)
dcc.setBasicAccessoryPos(Address,data & 0x01, bitRead(data,3)); //Adr, left/right, activ
#endif
}
//--------------------------------------------------------------
void notifyXNetDirectCV(uint16_t CV, uint8_t data) {
#if defined(XnDEB)
Debug.print(F("XNet CV#:"));
Debug.print(CV+1);
Debug.print(" - ");
Debug.println(data);
#endif
#if defined(DCC)
dcc.opsProgDirectCV(CV,data); //return value from DCC via 'notifyCVVerify'
#endif
}
//--------------------------------------------------------------
void notifyXNetDirectReadCV(uint16_t cvAdr) {
#if defined(DCC)
dcc.opsReadDirectCV(cvAdr); //read cv
#endif
#if defined(XnDEB)
Debug.print(F("XNet CV#:"));
Debug.println(cvAdr+1);
#endif
}
//--------------------------------------------------------------
void notifyXNetPOMwriteByte (uint16_t Adr, uint16_t CV, uint8_t data) {
#if defined(XnDEB)
Debug.print(F("XNet POM:"));
Debug.print(Adr);
Debug.print(" CV#");
Debug.print(CV+1);
Debug.print("-");
Debug.println(data);
#endif
#if defined(DCC)
dcc.opsProgramCV(Adr, CV, data); //set decoder byte
#endif
}
//--------------------------------------------------------------
void notifyXNetPOMwriteBit (uint16_t Adr, uint16_t CV, uint8_t data) {
#if defined(XnDEB)
Debug.print(F("XNet POM Bit:"));
Debug.print(Adr);
Debug.print("- CV: ");
Debug.print(CV+1);
Debug.print(" - ");
Debug.println(data, BIN);
#endif
#if defined(DCC)
dcc.opsPOMwriteBit(Adr, CV, data); //set decoder bit
#endif
}
#endif

Datei anzeigen

@ -0,0 +1,104 @@
//--------------------------------------------------------------
//Reset the EEPROM to default:
void EEPROM_Load_Defaults() {
#if defined(ESP32_MCU)
portMUX_TYPE myMutex = portMUX_INITIALIZER_UNLOCKED;
portENTER_CRITICAL(&myMutex);
#endif
#if defined(DEBUG)
Debug.println(F("Set all EEPROM to default!"));
#endif
//DCCInterfaceMaster:
FIXSTORAGE.FIXMODE(EEPROMRailCom, 1); //RailCom ON
FIXSTORAGE.FIXMODE(EEPROMRSTsRepeat, 25); //Reset Pakete (start)
FIXSTORAGE.FIXMODE(EEPROMRSTcRepeat, 6); //Reset Pakete (fortsetzen)
#if defined(ESP8266_MCU)
FIXSTORAGE.FIXMODE(EEPROMProgRepeat, 18); //Programmier Pakete, more to better detect ACK!
#else
FIXSTORAGE.FIXMODE(EEPROMProgRepeat, 7); //Programmier Pakete
#endif
FIXSTORAGE.FIXMODE(EES88Moduls, 62); //S88 max Module
//IP Werkseinstellung:
FIXSTORAGE.FIXMODE(EELANDHCP, 0); //kein DHCP
FIXSTORAGE.FIXMODE(EELANip, 192);
FIXSTORAGE.FIXMODE(EELANip+1, 168);
FIXSTORAGE.FIXMODE(EELANip+2, 0);
FIXSTORAGE.FIXMODE(EELANip+3, 111);
//Default VCC Rail and Prog to 20V:
FIXSTORAGE.FIXMODE(72, 32);
FIXSTORAGE.FIXMODE(73, 78);
FIXSTORAGE.FIXMODE(74, 32);
FIXSTORAGE.FIXMODE(75, 78);
//Default Prog option:
FIXSTORAGE.FIXMODE(52, 0); //Power Button behaviour
FIXSTORAGE.FIXMODE(53, 3);
//Z21 Library:
FIXSTORAGE.FIXMODE(1, 0xE8); //Z21 Serial LSB
FIXSTORAGE.FIXMODE(0, 0x01); //Z21 Serial MSB
#if defined(ESP_WIFI)
FIXSTORAGE.commit();
#endif
#if defined(ESP32_MCU)
portEXIT_CRITICAL(&myMutex);
#endif
}
//--------------------------------------------------------------
//Check the firmware status need update?:
void EEPROM_Setup() {
#if defined(DEBUG)
Debug.print(F("Check EEPROM..."));
#endif
byte SwVerMSB = FIXSTORAGE.read(EEPROMSwVerMSB);
byte SwVerLSB = FIXSTORAGE.read(EEPROMSwVerLSB);
//Check if we already run on this MCU?
if ((SwVerMSB == 0xFF) && (SwVerLSB == 0xFF)) {
//First Startup, set everything to default!
EEPROM_Load_Defaults();
}
//Check if there need to handel an update?
if ( (SwVerMSB != highByte(Z21mobileSwVer)) || (SwVerLSB != lowByte(Z21mobileSwVer)) ) {
//Update to new Firmware
#if defined(DEBUG)
Debug.println(F("Firmware Update!"));
#endif
/*
#if defined(ESP32)
portMUX_TYPE myMutex = portMUX_INITIALIZER_UNLOCKED;
portENTER_CRITICAL(&myMutex);
#endif
*/
FIXSTORAGE.FIXMODE(EEPROMSwVerMSB, highByte(Z21mobileSwVer));
FIXSTORAGE.FIXMODE(EEPROMSwVerLSB, lowByte(Z21mobileSwVer));
#if defined(ESP_WIFI)
FIXSTORAGE.commit();
#endif
/*
#if defined(ESP32)
portEXIT_CRITICAL(&myMutex);
#endif
*/
}
else {
#if defined(DEBUG)
Debug.println(F("OK"));
#endif
}
#if defined(ESP32)
yield();
#endif
}
//--------------------------------------------------------------

Datei anzeigen

@ -0,0 +1,459 @@
//--------------------------------------------------------------------------------------------
#define FIND 0x00 //Display Mode - search for Address!
//**************************************************************
//Setup up PIN-Configuration for different MCU (UNO/MEGA/Sanduino)
#include "MCU_config.h"
//--------------------------------------------------------------------------------------------
//Load everything that is used:
//**************************************************************
//Report Upload Sketch Time:
#if defined(DebugBaud) || defined(Z21DISPLAY) || defined(HTTPCONF) || defined(ESP_WIFI)
const char* comp_date = __DATE__ " " __TIME__; //sketch was compiled
#endif
//**************************************************************
//LocoNet LocoBuffer-USB -> deaktiviere alle DEBUG Funktionen!
#if (defined(LnBufferUSB) && defined(LOCONET)) || (defined(UNO_MCU) && defined(XPRESSNET))
#undef DebugBaud
#undef Debug
#undef DEBUG
#undef DEBUG_WLAN_CONFIG
#undef REPORT
#undef REQEST
#undef LnDEB
#undef XnDEB
#undef Z21DEBUG
#undef Z21DATADEBUG
#undef Z21SYSTEMDATADEBUG
#else
#undef LnBufferUSB //deaktiviere!
#endif
//**************************************************************
//Firmware store in EEPROM:
#define EEPROMSwVerMSB 0
#define EEPROMSwVerLSB 1
/**************************************************************
Serial Debug Output:*/
#ifdef DebugBaud
#ifndef Debug
#define Debug Serial //Interface for Debugging
#endif
#endif
/**************************************************************
XpressNet Library:*/
#ifdef XPRESSNET
#include <XpressNetMaster.h>
#endif
/**************************************************************
LocoNet Library:*/
#ifdef LOCONET
#if defined(ESP32_MCU) //use LocoNet2 Library
#include "LNSerial.h"
LocoNetBus bus;
#include <LocoNetESP32.h>
LocoNetESP32 locoNetPhy(&bus, LNRxPin, LNTxPin, 0);
LocoNetDispatcher parser(&bus);
#elif defined(ESP8266_MCU)
#include "LNHwSerial.h"
#else
#include <LocoNet.h>
#endif
#endif
/**************************************************************
BOOSTER EXT:*/
#ifdef BOOSTER_EXT
#define BOOSTER_EXT_ON HIGH
#define BOOSTER_EXT_OFF LOW
#endif
/**************************************************************
BOOSTER INT:*/
#ifdef BOOSTER_INT
//#define BOOSTER_INT_ON LOW //only for old Mode without RAILCOM support over NDCC!
//#define BOOSTER_INT_OFF HIGH //only for old Mode without RAILCOM support over NDCC!
#define BOOSTER_INT_NDCC //for new RAILCOM Booster3R - GoIntPin activate inverted booster signal
#endif
/**************************************************************
DCC Master to create a DCC Signal:*/
#include <DCCPacketScheduler.h> //DCC Interface Library
//**************************************************************
void AllLocoData(uint16_t adr, uint8_t data[]); //so function can be found!
//Power functions:
static void globalPower (byte state);
static uint16_t getRailmA();
static uint16_t getRailVolt();
//--------------------------------------------------------------
// certain global XPressnet status indicators
#define csNormal 0x00 // Normal Operation Resumed ist eingeschaltet
#define csEmergencyStop 0x01 // Der Nothalt ist eingeschaltet
#define csTrackVoltageOff 0x02 // Die Gleisspannung ist abgeschaltet
#define csShortCircuit 0x04 // Kurzschluss
#define csServiceMode 0x08 // Der Programmiermodus ist aktiv - Service Mode
byte Railpower = csTrackVoltageOff; //State of RailPower at Startup
bool Z21ButtonLastState = false; //store last value of the Push Button for GO/STOP
/**************************************************************
ESP OTA Upload:*/
#if defined(ESP_OTA)
#include <ArduinoOTA.h>
#include "ESP_OTA.h"
#endif
//**************************************************************
#if defined(Z21VIRTUAL)
#include <SoftwareSerial.h>
SoftwareSerial SoftSerial(TXvWiFi, RXvWiFi); // init Soft Serial
#undef LAN //LAN nicht zulassen - Doppelbelegung der Signalleitungen!
#undef HTTPCONF
#undef LOCONET
#endif
//**************************************************************
#if defined(LAN) //W5100 LAN Interface Library
#define HTTPCONF //activate Website to configure DHCP, IP Adress and Number of S88 Bus Module
#if !defined(MEGA_MCU)
#undef ENC28
#endif
#if defined(ENC28) //MEGA MCU only!
#include <UIPEthernet.h>
#else
#include <SPI.h> // needed for Arduino versions later than 0018
#include <Ethernet.h>
#include <EthernetUdp.h> // UDP library
#endif
#else
//need class for variable type "IPAddress" (WLANlocalIP) what is showing WLAN IP on Display!
#if defined(WIFI) && defined(Z21DISPLAY)
#include <IPAddress.h>
#endif
#endif
#if defined(ESP_WIFI) //ESP8266 or ESP32
#if defined(ESP8266_MCU)
#include <ESP8266WiFi.h>
//#include <ESP8266WebServer.h>
#if defined ESP_OTA
#include <ESP8266mDNS.h> //OTA update
#endif
#elif defined(ESP32_MCU)
#include <WiFi.h>
#include <WiFiAP.h> //optional?
#if defined(ESP_OTA)
#include <ESPmDNS.h> //ESP32 only, OTA update
#endif
#endif
#include <WiFiClient.h>
#include <WiFiUdp.h>
#endif
//**************************************************************
//Configure the analog 1.1V refenence voltage:
#ifndef AREF_1V1
#if defined(EXTERNAL_UREF_1V1)
#define AREF_1V1 EXTERNAL //externe 1.1 Volt
#elif defined(MEGA_MCU)
#define AREF_1V1 INTERNAL1V1 //Arduino MEGA internal 1,1 Volt
#elif defined(UNO_MCU)
#define AREF_1V1 INTERNAL //Arduino UNO (equal to 1.1 volts on the ATmega168 or ATmega328P)
#elif defined(ESP32_MCU) | defined(ESP8266_MCU) //ESP Modul
#define AREF_1V1 //always 1,1 Volt
#endif
//other Arduino's 5,0 Volt internal refence!
#endif
//**************************************************************
//Z21 LAN Protokoll:
#if defined(LAN) || defined (WIFI) || defined(ESP_WIFI)
#include <z21.h>
z21Class z21;
#else
//make LocoNet work when no WLAN and LAN is used!
#if defined(LOCONET)
#include <z21header.h>
#endif
#endif
//**************************************************************
#if defined(DUE_MCU)
#include <DueFlashStorage.h>
DueFlashStorage Flash;
#define FIXSTORAGE Flash
#define FIXMODE write
#elif defined(ESP32_MCU) //use NVS on ESP32!
#include <z21nvs.h>
z21nvsClass NVSEEPROMZ21;
#define FIXSTORAGE NVSEEPROMZ21
#define FIXMODE write
#else
#include <EEPROM.h> //EEPROM - to store number of S88 Module and LAN IP
#define FIXSTORAGE EEPROM
#if defined(ESP8266_MCU) || defined(ESP32_MCU)
#define FIXMODE write
#else
#define FIXMODE update
#endif
#endif
#if defined(ESP8266_MCU) || defined(ESP32_MCU)
//--> EEPROM Konfiguration ESP:
#define EESize 767 //Größe des EEPROM
#define EEStringMaxSize 40 //Länge String im EEPROM
//Client:
#define EEssidLength 200 //Länge der SSID
#define EEssidBegin 201 //Start Wert
#define EEpassLength 232 //Länge des Passwort
#define EEpassBegin 233 //Start Wert
//AP:
#define EEssidAPLength 264 //Länge der SSID AP
#define EEssidAPBegin 265 //Start Wert
#define EEpassAPLength 298 //Länge des Passwort AP
#define EEpassAPBegin 300 //Start Wert
#define EEkanalAP 299 //Kanal AP
#endif
//--> Allgemeine EEPROM Konfiguration:
//S88:
#define EES88Moduls 38 //Adresse EEPROM Anzahl der Module für S88
//LAN:
#define EELANDHCP 39 //aktiviert DHCP auf dem LAN Interface
#define EELANip 40 //Startddress im EEPROM für die IP
//---------------------------------------------------------------
#if defined(LAN) //W5100 LAN Udp Setup:
EthernetUDP Udp; //UDP for communication with APP/Computer (Port 21105)
#if defined(Z21MT)
EthernetUDP UdpMT; //UDP to Z21 Maintenance Tool (Port 21106)
#include "Z21Maintenance.h"
#endif
//---------------------------------------------------------------
boolean LAN_DHCP = false; //LAN DHCP Modus aus
// The IP address will be dependent on your local network:
IPAddress LAN_ip(192, 168, 0, 111); //Werkseinstellung ist: 192.168.0.111
/*LAN MAC configuration: */
#ifndef LANmacB2
#define LANmacB2 0xEF
#endif
#ifndef LANmacB1
#define LANmacB1 0xFE
#endif
#ifndef LANmacB0
#define LANmacB0 0xED
#endif
static byte mac[] = { 0x84, 0x2B, 0xBC, LANmacB2, LANmacB1, LANmacB0 };
/*LAN DHCP configuration: */
#ifndef LANTimeoutDHCP
#define LANTimeoutDHCP 5000 //Timeout to wait for a DHCP respose
#endif
#if defined(HTTPCONF) //W5100 LAN config Website:
EthernetServer server(80); // (port 80 is default for HTTP):
#endif
#endif //LAN end
//---------------------------------------------------------------
#if defined(ESP_WIFI)
#ifndef ESP_HTTPCONF
#define ESP_HTTPCONF
#endif
#ifndef SssidAP
#if defined(ESP32_MCU)
#define SssidAP "Z21_ESP32_Central" // Default Z21 AP (SSID)
#else
#define SssidAP "Z21_ESP_Central" // Default Z21 AP (SSID)
#endif
#endif
#ifndef SpassAP
#define SpassAP "12345678" // Default Z21 network password
#endif
#ifndef SkanalAP
#define SkanalAP 3 // Default Kanal des AP
#endif
//AP default Z21 IP
IPAddress AP_ip(192, 168, 0, 111); //Werkseinstellung ist: 192.168.0.111
IPAddress AP_sb(255, 255, 255, 0); //Werkseinstellung Subnet
WiFiUDP Udp;
#if defined(ESP_HTTPCONF) //Setting Website
WiFiServer ESPWebserver(80); //default port 80 for HTTP
#endif
#endif
//--------------------------------------------------------------
//Z21 Protokoll Typ Spezifikationen
#if defined(LAN) || defined (WIFI) || defined(ESP_WIFI)
#include "Z21type.h" //Z21 Data Information
#endif
//--------------------------------------------------------------
//S88 Singel Bus:
#if defined(S88N)
#include "S88.h"
#endif
//--------------------------------------------------------------
//Dallas Temperatur Sensor:
#if defined(DALLASTEMPSENSE) //&& defined(MEGA_MCU)
#include <OneWire.h>
#include <DallasTemperature.h>
// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
OneWire oneWire(ONE_WIRE_BUS);
// Pass our oneWire reference to Dallas Temperature.
DallasTemperature sensors(&oneWire);
// arrays to hold device address
DeviceAddress insideThermometer;
#define DALLAS_RESOLUTION 9 //Temperatur resolution
#endif
//--------------------------------------------------------------
//INA219 current sensor
#if defined (INA219)
#include <Wire.h>
#include <INA219_WE.h>
INA219_WE ina219 = INA219_WE(INA219); //default Address 0x40
#endif
//--------------------------------------------------------------
//DCC Interface Master Short Detection:
//EXTERNAL BOOSTER:
#define DetectShortCircuit 0x1FF //to detect short circuit (0xFF)
unsigned int ShortTime = 0; //Time Count for Short Detect
unsigned long LEDcount = 0; //Timer for Status LED
//INTERNAL BOOSTER:
#if defined(BOOSTER_INT_MAINCURRENT)
#define BOOSTER_INT_CURRENT_SHORT_DETECT //wenn nicht aktiviert dann hier einschalten!
unsigned long ShortTimeINT = 0; //Time Count for internal short detect
byte ShortTimeINTcounter = 0; //Count the low detection
#if defined(ESP8266_MCU)
//slow down readings on ESP8266 to let WIFI work! Slow down to min. ATTENTION WIFI may stop!
#define VAmpReadTimeNormal 10 //interval of reading normal (ms)
#else //other MCU:
#define VAmpINTMesureCount 10 //Anzahl des Messungen
byte CountVAmpINT = 0; //Zahl des Messung
#endif
uint16_t CalcVAmpINT = 0; //zwischen Messung
uint16_t VAmpINT = 0; //current power on the track
#ifndef DETECT_SHORT_INT_WAIT
#define DETECT_SHORT_INT_WAIT 20 //time in ms to wait before power off
#endif
#ifndef DETECT_SHORT_INT_VALUE //normal operation
#if defined(INA219)
#define DETECT_SHORT_INT_VALUE 3200 //mA for Short Power
#elif defined(ESP8266_MCU)
#define DETECT_SHORT_INT_VALUE 205 //because of WeMos internal voltage devider! á (2A * 0.33 Ohm) / (3,3/1024) = 204.8
#else
#if defined(AREF_1V1)
#define DETECT_SHORT_INT_VALUE 1000 //analogRead value for "mA" that is too much (AREF = 1.1V) á (3,3A * 0.33 Ohm) / (1,1/1024) = 1014
#else
#define DETECT_SHORT_INT_VALUE 250 //analogRead value for "mA" that is too much (AREF = 5.0V)
#endif
#endif
#endif
#endif
//setting for DCC ACK sense Value
#if defined(INA219)
#define DCC_ACK_SENSE_VALUE 60 //WeMos D1 Mini with INA219 connected!
#elif defined(ESP8266) //ESP8266 or WeMos D1 mini
#define DCC_ACK_SENSE_VALUE 4 //WeMos has a voltage divider for 3.1 Volt -> we not want to modify the board!
#else
#define DCC_ACK_SENSE_VALUE 30 //value difference
#endif
//--------------------------------------------------------------
DCCPacketScheduler dcc;
#define DCC //activate DCC Interface (always)
//--------------------------------------------------------------
#if defined(DCCGLOBALDETECTOR) && defined(DCC)
#include "Z21_RailCom.h"
#endif
//--------------------------------------------------------------
#if defined(XPRESSNET)
XpressNetMasterClass XpressNet;
#endif
//--------------------------------------------------------------
//LocoNet-Bus:
#if defined (LOCONET)
#include "LNInterface.h"
#endif
//--------------------------------------------------------------
//XpressNet-Bus:
#if defined(XPRESSNET)
#include "XBusInterface.h"
#endif
//--------------------------------------------------------------
//Z21 Ethernet communication:
#if defined(LAN) || defined(WIFI) || defined(ESP_WIFI)
#include "Z21_LAN.h"
#endif
//--------------------------------------------------------------
//OLED Display
#if defined(Z21DISPLAY)
#include "OLEDdisplay.h"
#endif
//--------------------------------------------------------------
//Power function:
#include "POWER.h" //load Z21 Power functions
//--------------------------------------------------------------
//Webpage
#if defined(HTTPCONF) || defined(ESP_HTTPCONF)
#include "Webpage.h"
#endif
//--------------------------------------------------------------------------------------------
//Z21 Software Reset:
#if defined(SOFT_RESET)
#include <avr/wdt.h>
#define soft_restart() \
do \
{ \
wdt_enable(WDTO_15MS); \
for(;;) \
{ \
} \
} while(0)
#endif
//--------------------------------------------------------------------------------------------
#if defined(DEBUG) && !defined(DUE_MCU) && !defined(ESP8266) && !defined(ESP32)
//ONLY for Atmega, not for Arduino DUE or ESP chip (ARM)!
int freeRam ()
{
extern int __heap_start, *__brkval;
int v;
return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
}
#endif
//--------------------------------------------------------------------------------------------
//ONLY for ESP
#if defined(DEBUG) && (defined(ESP8266) || defined(ESP32))
int freeRam ()
{
return ESP.getFreeHeap();
}
#endif
//--------------------------------------------------------------

Datei anzeigen

@ -0,0 +1,782 @@
#include <DCCHardware.h>
#include <DCCPacket.h>
#include <DCCPacketQueue.h>
#include <DCCPacketScheduler.h>
#include <DDCHardware_config.h>
/**************************************************************
* Z21 Ethernet DCC Command Station
* Copyright (c) 2015-2023 by Philipp Gahtow
***************************************************************
*
* This is a simple dcc command station that receive commands via Ethernet, XpressNet or LocoNet.
* It base on the Z21 ethernet protocol of ROCO
Unterstützte Funktionen/Protokolle:
* NMRA DCC output (POM and Railcom Cutout with Detector)
* support functions F0 - F68 and binary instructions
* Z21 Ethernet over LAN and/or WLAN
* - support W5100 or ENC28 LAN Shield
* - support WLAN with ESP8266 over Serial
* S88N feedback, with DCC
* XpressNet with AUTO switch MASTER-SLAVE-MODE
* LocoNet T/B with optional Slotserver
* LocoNet LocoBuffer
* RailCom Detector
* separate Programming Rail
* Display for System Status
* multi Hardware Support:
* - support for ATmega 328p/644/1280/1284/2560 (NANO, UNO, MEGA, Sanguino)
* - support for ARM (DUE) (only: DCC, LAN, WLAN, S88)
* - support ESP8266 and ESP32
* --> a use of all functions/interfaces is only awayable on Arduino MEGA!!!
***************************************************************
- DCC Master Interface with Timer 2 by modifired CmdrArduino library by Philipp Gahtow
- Z21 LAN Protokoll mit W5100/ENC28 Ethernet Shield with z21.h library
- LAN HTTP Website on Port 80 to configure ethernet IP and S88 bus length
- ESP8266 WiFi Z21 LAN Untersützung with z21.h library and HTTP Webite
- fast S88N feedback (with Timer when LocoNet is disable)
- LocoNet at MEGA with Timer 5, normal Timer1 with Loconet.h library and Slotserver for FRED
- XpressNet (RS485) via LOOP-Function with XpressNetMaster.h library
- Relais for seperate program track
- Global Railcom Detector for MEGA on Serial3
- continus DCC for S88N and LocoNet-B
- support external LocoNet Booster over LocoNet-B Line
- use as LocoNet LocoBuffer over USB with JMRI and Rocrail (Arduino MEGA only)
***************************************************************
Softwareversion: */
#define Z21mobileSwVer 498
/*
---------------------------------------------------------------
changes:
15.04.2015 Abschaltung S88 Interface per Define (S88N)
16.04.2015 Aktualisierung Z21 LAN Protokoll V1.05 & Firmware-Version 1.26
17.04.2015 LN OPC_INPUT_REP msg von Belegmeldern über LAN_LOCONET_DETECTOR
20.04.2015 kurze/Lange DCC Adressen (1..99 kurz, ab 100 lang)
22.04.2015 Add in DCC Lib Function support F13 - F28
Add Power Button with Reset (press at startup)
23.04.2015 Add LocoNet set Railpower (OPC_GPOFF, OPC_GPON, OPC_IDLE)
Add LocoNet Slot Write (OPC_WR_SL_DATA)
New Broadcast Msg (8 Bit) Z21 Protokoll V1.05 (Include LocoNet)
Add LocoNet OPC_RQ_SL_DATA, OPC_UHLI_FUN, OPC_SW_REQ, OPC_SW_REP, OPC_SW_ACK, OPC_SW_STATE
28.04.2015 Add DCC CV Write and Decoder Reset Packet before CV-Programming
04.07.2015 Add Support Sanguino (ATmega644p and ATmega1284p) =>MCU_config.h
10.07.2015 Change Timer for DCC Interface and S88 to support LocoNet for all MCU
Add second Booster support (intenal/external)
21.07.2015 S88 max Module define hinzu und S88 HTTP Ausgabe angepasst
30.07.2015 Versionsnummer für Debug definiert
02.08.2015 DCC Accessory Befehl korrigiert
PowerButton Input geändert von Pin 51 nach Pin 47
03.08.2015 DCC Decoder Funktion korrigiert
17.09.2015 S88 Timer Auswahl (MEGA = Timer3)
18.09.2015 ESP8266 WiFi Support; Z21 LAN über externe Library
23.09.2015 Überarbeitung LAN_LOCONET_DETECTOR
Neues Kommando OPC_MULTI_SENSE
DCC Dekoder ohne Timer4!
Optionale Lok-Event-Informationen im LocoNet (reduzierung der Sendedaten)
03.10.2015 S88 verbessert -> Fehler in der S88 Modulanzahl korrigiert (Überlauf der Zählervariale)
LocoNet TX/RX Packetverarbeitung verbessert
04.10.2015 ROCO EXT Booster Short mit Transistor (invertiert!)
Optimierung S88 Timer (Rechenoperationen und Seicherbedarf)
10.10.2015 Anzeigen Reset Zentrale mittels binkenden LEDs
13.10.2015 Rückmelder über LocoNet
Senden von DCC Weichenschaltmeldungen auch über LocoNet
LAN Webseite angepasst für Smartphone Display
14.10.2015 Einstellung der Anzahl von S88 Modulen über WiFi
Verbesserung der Kommunikation mit dem ESP
04.11.2015 LocoNet Master- oder Slave-Mode auswählbar
19.12.2015 Support kombinierte UDP Paket für WLAN und LAN
26.12.2015 Add Track-Power-Off after Service Mode
20.02.2016 Speicherreduzierung wenn kein WLAN und LAN genutzt wird
LocoNet Client Modus Kommunikation mit IB verbessert
Extra Serial Debug Option für XpressNet
27.02.2016 Änderung Dekodierung DCC14 und DCC28
Invertierung Fahrtrichtung DCC Decoder DIRF
LocoNet Slave-Mode ignoriere Steuerbefehle, wenn Slot = 0
02.06.2016 Baud für Debug und WiFi einstellbar
Software Serial für WiFi wählbar (zB. für Arduino UNO)
-> WiFi Modul Firmware ab v2.5
17.07.2016 Fix Network UDP Antwortport - Sende Pakete an Quellport zurück
25.07.2016 add busy message for XpressNet (MultiMaus update screen now)
Aug.2016 add Railcom Support and update DCCInterfaceMaster and Booster Hardware,
support POM read over I2C with external MCU (GLOBALDETECTOR)
26.08.2016 add DHCP for Ethernet Shield
21.11.2016 DCC: fix Railcom - still Problem with Startup: Analog-Power on the rails - Hardware change needed!
26.11.2016 LocoNet: add Uhlenbrock Intellibox-II F13 to F28 support
27.11.2016 LocoNet: fix Speed DIR in OPC_SL_RD_DATA in data byte to 0x80 = B10000000 and OPC_LOCO_DIRF remove invert
27.12.2016 Z21 add CV lesen am Programmiergleis
01.02.2017 add negative DCC output option and seperate this feature from RAILCOM
15.03.2017 fix narrowing conversation inside LNInterface.h
28.03.2017 external Booster active in ServiceMode when no internal Booster
24.04.2017 fix data lost on loconet - s88 timer3 block packets - deactivated
28.04.2017 add MultiMaus support for F13 to F20 without fast flashing
10.05.2017 add XpressNet information for loco speed and function and switch position change
11.05.2017 add internal Booster Short Detection over Current Sense Resistor
25.05.2017 add RailCom Global Reader for Arduino MEGA on Serial3 (POM CV read only)
19.06.2017 fix problems with Arduino UNO compiling
09.07.2017 fix problems when using without XpressNet
23.07.2017 add support for Arduino DUE
26.08.2017 add default speed step setting
09.01.2018 add POM Bit write
21.01.2018 optimize LocoNet Slot system - reduce RAM use
18.08.2018 add support for Arduino DUE XpressNet
02.11.2018 adjust Z21 WiFi data communication and rise up baud rate
22.11.2018 add support for Arduino ESP8266 (WiFi, DCC extern and intern without seperate prog track)
09.06.2019 add extra DCC-Output for S88 and LocoNet without Power-OFF and RailCom
12.04.2020 adjust problems with the Serial communication to ESP8266 WiFi
22.06.2020 remove DUE XpressNet statememts
28.07.2020 change Input Pins VoltInPin and TempPin set only to INPUT Mode.
29.07.2020 add ENC28J60 module - instead of w5100 Shield for MEGA only.
30.07.2020 central startup Railpower sync for all interfaces
04.08.2020 fix size of data type "RailcomCVAdr"
24.10.2020 fix error inside LocoNetInterface with Master-Mode
29.10.2020 reduce timeout for LAN DHCP challange
30.10.2020 add Z21 Interface config file with template
04.12.2020 fix LocoNet Client Mode, don't answer on Master commands!
remove Ethernet LAN DHCP timeout when using UIP Library
05.01.2021 fix WiFi RX problem with long UDP Packet and zero Packets (LAN_LOCONET_DETECTOR)
fix wrong Adr in LocoNet Slot data response, when doing a DISPATCH Adr > 127
06.01.2021 add new AREF with 1.1 Volt
07.07.2021 fix EEPROM Problem with ESP32 and ESP8266 when doing a commit
08.01.2021 use ESP DNS library only for ESP32 and set a seperate one for ESP8266
02.03.2021 fix Ethernet S88 Module change if DHCP is on
03.03.2021 fix big UDP ethernet receive when package is empty
17.03.2021 fix error with inactiv Debug on HTTP reading S88Module at Debug.print
change EEPROM storage for ESP
add firmware to EEPROM and full EEPROM reset when no firmware is found or when POWER pressed on start
Serialnumber in Z21-APP show now the firmware version
06.04.2021 fix report LocoNet sensor messages to Z21-APP for display
18.05.2021 add LocoNet2 library to support LocoNet on ESP32
20.05.2021 fix some mistakes in LocoNet packet working
v4.92:--------------------------------------------------------------------------------
02.06.2021 fix wrong function notifyPower into notifyRailpower
fix DCCLed calculation when flashing
06.06.2021 fix wrong adr in LocoNet OPC_SW_REQ
10.06.2021 fix power button doesn't change back to csNormal
16.06.2021 add LocoNet drive direction invert for IntelliBox slave usage (#define LnInvDir)
18.06.2021 fix LocoNet Function 9-28 by Uhlenbrock (0xD4 0x20)
v4.93:--------------------------------------------------------------------------------
21.06.2021 add LAN Interface DHCP change over HTTPCONF
07.07.2021 fix ESP32 DCC Output and Pin config
30.09.2021 fix ethernet to not check port all the time
fix enc28 ethernet shield bug for boardcast message send out
05.11.2021 add to handel Lok information request central and ask the master (DCC/LocoNet/XpressNet)
add new debug flag "REQUEST" for global lok, switch and cv requests
07.11.2021 fix usage without WLAN and LAN problem with Z21 header #defines in LNInterface.h
v4.94:--------------------------------------------------------------------------------
14.11.2021 fix LocoNet from LAN
15.11.2021 fix LocoNet reporting to z21 interface
16.11.2021 fix ethernet update the source port on each request
17.11.2021 add LocoNet Buffer USB connection
add ACK Sense detection with LM357
v4.95:--------------------------------------------------------------------------------
18.11.2021 add prio delay to LocoNet send
21.11.2021 fix missing feedback data from XpressNet to LocoNet
30.11.2021 add middle Booster Sense value
14.12.2021 get Booster Sense not when RailCom cutout is on
27.12.2021 add option for OLED Display that shows the configuration data
28.12.2021 fix software number with additional dot
30.12.2021 remove blocking when receiving WLAN data
add sketch build time for Debug output and Display
06.01.2022 slow down sense reading only for ESP8266 to let WLAN work with ADC too
add invert option for DCC/Power LED and Service Mode (Prog Relay) output
08.10.2022 fix Short Detection and ACK for WeMos D1 mini with voltage devider
v4.96:--------------------------------------------------------------------------------
13.01.2022 fix config request for WLAN-Interface that report 'OKOKOKOKOK' to DISPLAY -> add some wait
fix slow S88 by removing the wait timing #define S88CLOCKTIME when using option: no timer (S88noT)
02.02.2022 add XpressNet support for ESP8266 and ESP32
03.02.2022 fix error "endless loop", when getting loco data as Xpressnet Client
04.02.2022 for ESP MCU switch WLAN client off if connection fail (AP only) - strange errors!
10.02.2022 I2C Display SSD1306 Adresse kann automatisch ermittelt werden: "#define Z21DISPLAY FIND"
change Slot-Server to 50x loco when using UNO without LAN and WiFi Module
22.02.2022 add I2C Display driver SH110X
23.02.2022 correct the output mA of sense reading for ESP8266 and ESP32, fix Uref for this MCU to 3.3V
v4.97:--------------------------------------------------------------------------------
11.04.2022 fix ESP OTA csTrackVoltageOff was not defined
if LocoNet is not active S88 use Timer3 on MEGA by default, to have a better S88 timing
12.04.2022 deactivate unsupported interface on ESP8266 by default
13.04.2022 fix problems in CV reading inside DCCInterfaceMaster and display progress on display
adjust internal short detection
14.04.2022 create display icon for service- ands short circuit mode
15.04.2022 add display icon for all power mode, auto remove config data after 50 sec. when running
16.04.2022 show WLAN Signal connection on display if using ESP8266
show send and receive data from LAN/WLAN on display
21.04.2022 fix Display output for AVR, add WLAN Signal from ESP interface
25.04.2022 fix ESP AP not working, when client wifi is set but not connected/found
clean up software structure and remove legacy DCCDecoder.h and #define DECODER
26.04.2022 add Z21 Firmware 1.42 with additional loco function 29..32767 and DDCext
27.04.2022 modify AVR serial communication protokoll with ESP WLAN interface
28.04.2022 fix Display updates and ESP WLAN interface
02.05.2022 remove display RX/TX data transmit
fix ESP serial wlan data decoding
add WLANMaus CV read and write
v4.98:--------------------------------------------------------------------------------
03.05.2022 change mA on display to A
07.05.2022 add XOR check for ESP LocoNet RX Interface
08.05.2022 OTA slow down XpressNet and LocoNet -> WiFi client had no connection, need to switch STA off!
11.05.2022 add at ESP the RSSI on website
18.05.2022 add setCVNackSC for XpressNet
fix LocoNet Slave Loco Data Request feedback to Z21 and XpressNet
05.07.2022 remove #define SwitchFormat, now use the APP with RCN-213 switch!
07.07.2022 add APP setting for short Adr and repeat >F13
21.07.2022 add INA219 current sensor
23.07.2022 change INA219 settings (10 Bit, gain 320)
25.07.2022 clear up source code remove unused defines
31.07.2023 add pin to detect prog ACK pulse
31.08.2023 fix problem compiling when Ethernet is not used and a Display is on that shows WLAN IPAddress
08.09.2023 add Z21DISPLAY_CONTRAST to have longer OLED Display lifetime
remove animation on display when programming
15.09.2023 add DCC ACK sense Value for different MCU
------------------------------------
*/
//--------------------------------------------------------------------------------------------
//Prepare Z21PG:
#include "CONFIG.h" //Load individual Z21 central configuration
#include "Z21Include.h" //load all Interfaces #include "main/Z21Include.h" //load all Interfaces
#include "DCCGlobal.h" //DCC all Interface function
#include "Z21EEPROM.h" //EEPROM/Flash constant store
//--------------------------------------------------------------
//--------------------------------------------------------------
//INIT all ports and interfaces:
void setup() {
//Reduce the reference Voltage to 1,1 Volt!
#if defined(AREF_1V1) && !defined(ESP32_MCU) && !defined(ESP8266_MCU)
analogReference(AREF_1V1); //EXTERNAL or INTERNAL1V1
#endif
pinMode(DCCLed, INPUT); //DCC Status LED "off" State
pinMode(ShortLed, OUTPUT); //Short Status LED
pinMode(RailcomLED, OUTPUT);
pinMode(RailcomPort, OUTPUT);
digitalWrite(ShortLed, HIGH); //Short LED showes working and Power up
#if defined(ProgRelaisPin)
pinMode(ProgRelaisPin, OUTPUT); //ProgTrack-Relais
#if defined(PROG_OUT_INVERT)
digitalWrite(ProgRelaisPin, HIGH); //ProgTrack
#else
digitalWrite(ProgRelaisPin, LOW); //ProgTrack
#endif
#endif
#if defined(BOOSTER_EXT) //Booster (ROCO) external:
pinMode(ShortExtPin, INPUT_PULLUP); //set short pin and Turn on internal Pull-Up Resistor
pinMode(GoExtPin, OUTPUT); //GO/STOP Signal
digitalWrite(GoExtPin, BOOSTER_EXT_OFF); //set STOP to Booster
#endif
#if defined(BOOSTER_INT) //Booster2 internal:
#if !defined(BOOSTER_INT_NDCC)
pinMode(GoIntPin, OUTPUT); //GO/STOP2 Signal
digitalWrite(GoIntPin, BOOSTER_INT_OFF); //set STOP to Booster2 invertet
#endif
#if defined(BOOSTER_INT_TLE5206) || defined(BOOSTER_EXT_CDE)
pinMode(ShortIntPin, INPUT_PULLUP); //set up short2 PIN and Turn on internal Pull-Up Resistor
#endif
#endif
pinMode(Z21ResetPin, INPUT_PULLUP); //Turn on internal Pull-Up Resistor
pinMode(Z21ButtonPin, INPUT_PULLUP); //Turn on internal Pull-Up Resistor
#if defined(DebugBaud)
Debug.begin(DebugBaud);
#if defined(ESP8266_MCU) || defined(ESP32_MCU)
Debug.println("/n"); //Zeilenumbruch einfügen
#endif
#endif
#if defined(Z21DISPLAY)
DisplaySetup(); //Display init
#endif
#if defined(MEGA_MCU)
//pinMode(VAmSensePin, INPUT_PULLUP); //AC 5A Sensor (for testing only)
#if defined(AREF_1V1)
pinMode(VoltIntPin, INPUT); //Rail Voltage: Rail:100k - Sense - 4,7k - GND
#if !defined(DALLASTEMPSENSE)
pinMode(TempPin, INPUT); //Temp.Resistor(15k)
#endif
#else
pinMode(VoltIntPin, INPUT_PULLUP); //Rail Voltage: Rail:100k - Sense - 4,7k - GND
#if !defined(DALLASTEMPSENSE)
pinMode(TempPin, INPUT_PULLUP); //Temp.Resistor(15k)
#endif
#endif
#endif
#if defined(SOFT_RESET) //Arduino UNO, MEGA, Sangduino ONLY!
MCUSR = 0;
wdt_disable();
#endif
#if defined(ESP_WIFI)
FIXSTORAGE.begin(EESize); //init EEPROM
#endif
#if defined(LOCONET) && (defined(ESP8266_MCU) || defined(ESP32_MCU))
//rewrite Debug Baud rate!
LocoNetHw_init();
#endif
#if defined(Z21DISPLAY)
DisplayBoot(5); //Boot up bar...
#endif
//Check Firmware in EEPROM:
EEPROM_Setup(); //init Z21 EEPROM defaults
#if defined(ESP_WIFI)
ESPSetup(); //ESP8266 and ESP32 WLAN Setup
#endif
#if defined(DebugBaud)
Debug.print(F("Z21PG v"));
Debug.print(String(Z21mobileSwVer).substring(0,1));
Debug.print(".");
Debug.print(String(Z21mobileSwVer).substring(1));
Debug.print("-");
Debug.print(bitRead(FIXSTORAGE.read(EEPROMRCN213), 2));
#if defined(UNO_MCU)
Debug.print(F(" UNO"));
#elif defined(MEGA_MCU)
Debug.print(F(" MEGA"));
#elif defined(SANGUINO_MCU)
Debug.print(F(" SANGUINO"));
#elif defined(DUE_MCU)
Debug.print(F(" DUE"));
#elif defined(ESP8266_MCU)
Debug.print(F(" ESP8266"));
#elif defined(ESP32_MCU)
Debug.print(F(" ESP32"));
#endif
#if defined(DCC)
Debug.print(".DCC");
#endif
#if defined (BOOSTER_INT_NDCC)
if (FIXSTORAGE.read(EEPROMRailCom) == 0x01)
Debug.print(".RAILCOM");
#endif
#if defined(ACKBOOSTER)
Debug.print(".ACK_BOOST");
#endif
#if defined(AREF_1V1)
Debug.print(".AREF_1V1");
#endif
#endif
#if defined(Z21DISPLAY)
DisplayBoot(10);
#endif
#if defined(XPRESSNET)
#if defined(ESP8266_MCU) || defined(ESP32_MCU)
#if defined(FS14)
XpressNet.setup(Loco14, XNetSerialPin, XNetTxRxPin); //Initialisierung XNet Serial und Send/Receive-PIN
#elif defined(FS28)
XpressNet.setup(Loco28, XNetSerialPin, XNetTxRxPin); //Initialisierung XNet Serial und Send/Receive-PIN
#else
XpressNet.setup(Loco128, XNetSerialPin, XNetTxRxPin); //Initialisierung XNet Serial und Send/Receive-PIN
#endif
#else //other AVR MCU:
#if defined(FS14)
XpressNet.setup(Loco14, XNetTxRxPin); //Initialisierung XNet Serial und Send/Receive-PIN
#elif defined(FS28)
XpressNet.setup(Loco28, XNetTxRxPin); //Initialisierung XNet Serial und Send/Receive-PIN
#else
XpressNet.setup(Loco128, XNetTxRxPin); //Initialisierung XNet Serial und Send/Receive-PIN
#endif
#endif
XpressNet.setPower(Railpower); //send Railpowerinformation to XpressNet
#endif
#if defined(ESP_WIFI)
delay(10);
#endif
#if defined(Z21DISPLAY)
DisplayBoot(20);
#endif
#if defined(INA219)
Wire.begin();
Wire.setClock(400000); //400kHz für die I2C Übertragungsrate
#endif
#if defined(INA219)
if(!ina219.init()){
#if defined(DebugBaud)
Debug.println(F("INA219 not found!"));
#endif
}
/* Set ADC Mode for Bus and ShuntVoltage
* Mode * * Res / Samples * * Conversion Time *
BIT_MODE_9 9 Bit Resolution 84 µs
BIT_MODE_10 10 Bit Resolution 148 µs
BIT_MODE_11 11 Bit Resolution 276 µs
BIT_MODE_12 12 Bit Resolution 532 µs (DEFAULT)
SAMPLE_MODE_2 Mean Value 2 samples 1.06 ms
SAMPLE_MODE_4 Mean Value 4 samples 2.13 ms
SAMPLE_MODE_8 Mean Value 8 samples 4.26 ms
SAMPLE_MODE_16 Mean Value 16 samples 8.51 ms
SAMPLE_MODE_32 Mean Value 32 samples 17.02 ms
SAMPLE_MODE_64 Mean Value 64 samples 34.05 ms
SAMPLE_MODE_128 Mean Value 128 samples 68.10 ms
*/
ina219.setADCMode(BIT_MODE_10); //more speed!
ina219.setMeasureMode(CONTINUOUS);
// ina219.setADCMode(SAMPLE_MODE_2);
ina219.setShuntSizeInOhms(senseResist); //setting shunt value
ina219.setPGain(PG_320); //Default setting range (320mV full range, ~16 A max. current, ~4mA resolution with 20 mOhm shunt)
#endif
//first read a value to mesure the power on the track
#if defined(BOOSTER_INT_CURRENT_SHORT_DETECT)
do {
VAmpINT = getRailmA();
delay(2);
}
while (VAmpINT > 65000); //read until INA219 is started up!
#if defined(DEBUG)
Debug.print(F(",mA:"));
Debug.print(VAmpINT);
#endif
#endif
#if defined(DCC)
//setup the DCC signal:
#if defined(BOOSTER_INT_NDCC)
#if defined(FS14)
dcc.setup(DCCPin, GoIntPin, DCC14, Railpower, DCC_ACK_SENSE_VALUE);
#elif defined(FS28)
dcc.setup(DCCPin, GoIntPin, DCC28, Railpower, DCC_ACK_SENSE_VALUE);
#else
dcc.setup(DCCPin, GoIntPin, DCC128, Railpower, DCC_ACK_SENSE_VALUE);
#endif
#endif
//for CV reading over RAILCOM activate i2c communication:
#if defined(DCCGLOBALDETECTOR)
#if defined(MEGA_MCU)
RailComSetup(); //init the Serial interface for receiving RailCom
#endif
#endif
//extra DCC Output for S88 or LocoNet
#if defined(additionalOutPin)
#if (!defined(LAN) && defined (UNO_MCU)) || defined(MEGA_MCU) || defined(DUE_MCU) || defined(ESP_WIFI)
dcc.enable_additional_DCC_output(additionalOutPin);
#if defined(DebugBaud)
Debug.print(F(".addOutput"));
#endif
#endif
#endif
#endif
#if defined(DebugBaud)
Debug.println(); //finish config line!
Debug.print(F("Build: "));
Debug.println(comp_date);
#endif
#if defined(Z21DISPLAY)
DisplayBoot(30);
#endif
#if defined(LAN)
//Want to RESET Ethernet to default IP?
if ((digitalRead(Z21ButtonPin) == LOW) || (not( (FIXSTORAGE.read(EELANip) == 10) /*Class A */ || (FIXSTORAGE.read(EELANip) == 172) /*Class B */ || (FIXSTORAGE.read(EELANip) == 192) /*Class C */ ))) {
EEPROM_Load_Defaults();
bool LEDstate = true;
while (digitalRead(Z21ButtonPin) == LOW) { //Wait until Button - "UP"
#if defined(DEBUG)
Debug.print(".");
#endif
delay(200); //Flash:
if (LEDstate) {
pinMode(DCCLed, OUTPUT);
#if defined(POWER_LED_INVERT)
digitalWrite(DCCLed, LOW);
#else
digitalWrite(DCCLed, HIGH);
#endif
digitalWrite(ShortLed, LEDstate); //ON
LEDstate = false;
}
else {
pinMode(DCCLed, INPUT);
digitalWrite(ShortLed, LEDstate);
LEDstate = true;
}
}
#if defined(DEBUG)
Debug.println(); //new line!
#endif
pinMode(DCCLed, INPUT); //DCC LED is in "off" State
digitalWrite(ShortLed, LOW); //Short LED is in "off" State
}
if (FIXSTORAGE.read(EELANDHCP) == 1)
LAN_DHCP = true;
LAN_ip[0] = FIXSTORAGE.read(EELANip);
LAN_ip[1] = FIXSTORAGE.read(EELANip+1);
LAN_ip[2] = FIXSTORAGE.read(EELANip+2);
LAN_ip[3] = FIXSTORAGE.read(EELANip+3);
#endif
#if defined(S88N)
SetupS88(); //S88 Setup
#endif
#if defined(Z21DISPLAY)
DisplayBoot(40);
#endif
#if defined(LOCONET)
LNsetup(); //LocoNet Interface init
LNsetpower(); //send Railpowerinformation to LocoNet
#endif
#if defined(LAN) || defined(WIFI) || defined(ESP_WIFI)
z21.setPower(Railpower); //send Railpowerinformation to Z21 Interface
#endif
#if defined(Z21DISPLAY)
DisplayBoot(50);
#endif
#if defined(ESP_WIFI)
#if defined(ESP_HTTPCONF)
#if defined(DEBUG)
Debug.print(F("Server Begin..."));
#endif
ESPWebserver.begin(); //Start the HTTP server
#if defined(DEBUG)
Debug.println("OK");
#endif
#endif
#if defined(DEBUG)
Debug.print(F("Start UDP listener..."));
#endif
Udp.begin(z21Port); //open Z21 port
#if defined(DEBUG)
Debug.println("OK");
#endif
#if defined(ESP32)
yield();
#endif
#if defined(ESP_OTA)
#if defined(DEBUG)
Debug.print(F("Init OTA..."));
#endif
ESP_OTA_Init();
#if defined(DEBUG)
Debug.println("OK");
#endif
#endif
#endif
#if defined(Z21DISPLAY)
DisplayBoot(60);
#endif
#if defined(LAN)
// start the Ethernet and UDP:
delay(120); //wait for Ethernet Shield to get up (need longer to boot!)
Ethernet.init(53); //SS-Pin Most Arduino shields
if (LAN_DHCP) {
#if defined(DEBUG)
Debug.print(F("IP over DHCP..."));
#endif
#if defined(ENC28)
if (Ethernet.begin(mac) == 0) { //ENC28 UIP Lib doesn't have timeout option!
#else
if (Ethernet.begin(mac,LANTimeoutDHCP,2000) == 0) { //Trying to get an IP address using DHCP
#endif
#if defined(DEBUG)
Debug.println(F("fail!"));
#endif
LAN_DHCP = false; //DHCP not found!
}
else {
//Save IP that receive from DHCP
LAN_ip = Ethernet.localIP();
if (LAN_DHCP) {
//Store IP in EEPROM:
FIXSTORAGE.FIXMODE(EELANip, LAN_ip[0]);
FIXSTORAGE.FIXMODE(EELANip+1, LAN_ip[1]);
FIXSTORAGE.FIXMODE(EELANip+2, LAN_ip[2]);
FIXSTORAGE.FIXMODE(EELANip+3, LAN_ip[3]);
#if defined(ESP_WIFI)
FIXSTORAGE.commit();
#endif
#if defined(DEBUG)
Debug.println("SAVE");
#endif
}
#if defined(DEBUG)
else Debug.println("OK");
#endif
}
}
if (!LAN_DHCP) { //kein DHCP:
// initialize the Ethernet device not using DHCP:
Ethernet.begin(mac,LAN_ip); //set IP and MAC
}
Udp.begin(z21Port); //UDP Z21 Port 21105
//#if defined(Z21MT)
//UdpMT.begin(34472); //UDP Maintenance Tool 21106
//#endif
#if defined(HTTPCONF)
server.begin(); //HTTP Server
#endif
#endif
#if defined(Z21DISPLAY)
DisplayBoot(70);
#endif
#if defined(DEBUG)
#if defined(LAN)
if (LAN_DHCP)
Debug.print(F("DHCP "));
Debug.print(F("Eth IP: "));
Debug.println(LAN_ip);
#endif
#if defined(S88N)
Debug.print(F("S88: "));
Debug.println(S88Module);
#endif
#if !defined(DUE_MCU) //not for the DUE!
Debug.print(F("RAM: "));
Debug.println(freeRam());
#endif
#endif
#if defined(Z21DISPLAY)
DisplayBoot(80);
#endif
#if defined(DALLASTEMPSENSE)
sensors.begin();
sensors.getAddress(insideThermometer, 0);
// set the resolution to 9 bit (Each Dallas/Maxim device is capable of several different resolutions)
sensors.setResolution(insideThermometer, DALLAS_RESOLUTION);
sensors.setWaitForConversion(false); //kein Warten auf die Umwandlung!
sensors.requestTemperatures(); //1. Abfrage der Temperatur
#endif
#if defined(Z21DISPLAY)
DisplayBoot(90);
#endif
#if defined(WIFI)
WLANSetup(); //Start ESP WLAN
#endif
#if defined(Z21DISPLAY)
DisplayBoot(100);
DisplayReady = true;
DisplayUpdateRailPower(true); //Aktualisierung!
#if defined(BOOSTER_INT_MAINCURRENT)
notifyz21getSystemInfo(0); //SysInfo an alle BC Clients senden!
#endif
#endif
//init ready:
globalPower(csNormal); //Start up the Railpower
Debug.println("Z21 Conf: ");
FIXSTORAGE.write(EEPROMRailCom,0x01);
Debug.print(F("RailCom: ")); //RailCom: 0=aus/off, 1=ein/on
Debug.print(FIXSTORAGE.read(EEPROMRailCom), HEX);
Debug.print(F(", PWR-B: ")); //Power-Button: 0=Gleisspannung aus, 1=Nothalt
Debug.print(FIXSTORAGE.read(52), HEX);
Debug.print(F(", Prog-R: ")); //Auslese-Modus: 0=Nichts, 1=Bit, 2=Byte, 3=Beides
Debug.print(FIXSTORAGE.read(EEPROMProgReadMode), HEX);
Debug.print(F(", RstP(s): "));
Debug.print(FIXSTORAGE.read(EEPROMRSTsRepeat));
Debug.print(F(", RstP(f): "));
Debug.print(FIXSTORAGE.read(EEPROMRSTcRepeat));
Debug.print(F(", ProgP: "));
Debug.print(FIXSTORAGE.read(EEPROMProgRepeat));
Debug.print(F(", MainV: "));
Debug.print(word(FIXSTORAGE.read(73),FIXSTORAGE.read(72)));
Debug.print(F(", ProgV: "));
Debug.println(word(FIXSTORAGE.read(75),FIXSTORAGE.read(74)));
digitalWrite(ShortLed, LOW); //Short LED goes off - we are ready to work!
digitalWrite(RailcomLED,HIGH);
}
//--------------------------------------------------------------
//--------------------------------------------------------------------------------------------
//run the state machine to update all interfaces
void loop() {
updateLedButton(); //DCC Status LED and Button
#if defined(DCC)
ShortDetection(); //handel short on rail to => power off
dcc.update(); //handel Rail Data
#if defined(DCCGLOBALDETECTOR) && defined(MEGA_MCU)
RailComRead(); //check RailCom Data
#endif
#endif
#if (defined(HTTPCONF) && defined(LAN)) || ((defined(ESP8266_MCU) || defined(ESP32_MCU)) && defined(ESP_HTTPCONF))
Webconfig(); //Webserver for Configuration
#endif
#if defined(S88N)
notifyS88Data(); //R-Bus geänderte Daten 1. Melden
#endif
#if defined(XPRESSNET)
XpressNet.update(); //XpressNet Update
#endif
#if defined(LOCONET)
LNupdate(); //LocoNet update
#endif
#if defined(DCC)
dcc.update(); //handel Rail Data second time!
#endif
#if defined(LAN) || defined(WIFI) || defined(ESP_WIFI)
Z21LANreceive(); //Z21 LAN Decoding
#endif
/*
#if defined(LAN) && defined(Z21MT)
Z21MTreceive();
#endif
*/
#if defined(LAN)
if (LAN_DHCP) {
Ethernet.maintain(); //renewal of DHCP leases
}
#endif
#if defined(ESP_OTA)
ArduinoOTA.handle();
#endif
}
//--------------------------------------------------------------------------------------------

Datei-Diff unterdrückt, da er zu groß ist Diff laden

Datei anzeigen

@ -0,0 +1,185 @@
//Z21 DCC RailCom Decoder
//Dekodierung globaler Railcomdaten am Serial3 (MEGA only!)
//
//Copyright (c) by Philipp Gahtow, year 2021
//--------------------------------------------------------------
#if defined(DCCGLOBALDETECTOR) && defined(DCC)
uint16_t RailcomCVAdr = 0; //init global RailCom detector for POM
//--------------------------------------------------------------
#if defined(MEGA_MCU)
/*
void notifyCVPOMRead(uint16_t Adr, uint8_t value) {
#if defined(LAN) || defined(WIFI) || defined(ESP_WIFI)
z21.setCVPOMBYTE(Adr, value);
#endif
}
*/
#define RCSerial Serial3 //Serial Port that we will listen to for RailCom Data
//--------------------------------------------------------------
byte RailComGetCV = false; //try to receive a CV value
byte RailComReadFirst = true;
byte RailComReadData = 0; //Save the first 2 bit data
byte RailComReadLastCV = 0xFF; //Save the last read CV value
byte RailComCVRead = false; //receive a CV value
byte RailComCVTime = 0; //cycle time
uint16_t RailComReadAdr = 0; //Adress read over RailCom
//--------------------------------------------------------------
//init the Serial interface for receiving RailCom
void RailComSetup(void) {
RCSerial.begin(250000); //Read Railcom Message at 250KBit
}
//--------------------------------------------------------------
//Decoding RailCom Received Data
byte RailComDecodeInData (void) {
switch (RCSerial.read()) {
case B10101100: return 0x00;
case B10110010: return 0x10;
case B01010110: return 0x20;
case B11000110: return 0x30;
case B10101010: return 0x01;
case B10110100: return 0x11;
case B01001110: return 0x21;
case B11001100: return 0x31;
case B10101001: return 0x02;
case B10111000: return 0x12;
case B01001101: return 0x22;
case B01111000: return 0x32;
case B10100101: return 0x03;
case B01110100: return 0x13;
case B01001011: return 0x23;
case B00010111: return 0x33;
case B10100011: return 0x04;
case B01110010: return 0x14;
case B01000111: return 0x24;
case B00011011: return 0x34;
case B10100110: return 0x05;
case B01101100: return 0x15;
case B01110001: return 0x25;
case B00011101: return 0x35;
case B10011100: return 0x06;
case B01101010: return 0x16;
case B11101000: return 0x26;
case B00011110: return 0x36;
case B10011010: return 0x07;
case B01101001: return 0x17;
case B11100100: return 0x27;
case B00101110: return 0x37;
case B10011001: return 0x08;
case B01100101: return 0x18;
case B11100010: return 0x28;
case B00110110: return 0x38;
case B10010101: return 0x09;
case B01100011: return 0x19;
case B11010001: return 0x29;
case B00111010: return 0x39;
case B10010011: return 0x0A;
case B01100110: return 0x1A;
case B11001001: return 0x2A;
case B00100111: return 0x3A;
case B10010110: return 0x0B;
case B01011100: return 0x1B;
case B11000101: return 0x2B;
case B00101011: return 0x3B;
case B10001110: return 0x0C;
case B01011010: return 0x1C;
case B11011000: return 0x2C;
case B00101101: return 0x3C;
case B10001101: return 0x0D;
case B01011001: return 0x1D;
case B11010100: return 0x2D;
case B00110101: return 0x3D;
case B10001011: return 0x0E;
case B01010101: return 0x1E;
case B11010010: return 0x2E;
case B00111001: return 0x3E;
case B10110001: return 0x0F;
case B01010011: return 0x1F;
case B11001010: return 0x2F;
case B00110011: return 0x3F;
case 0x0F: return 0xF0; //ACK
}
return 0xFF;
}
//--------------------------------------------------------------
//Check if we receive data?
void RailComRead(void) {
if (RailComGetCV) { //need to read data?
RailComCVTime++;
while (RCSerial.available()) { //is there serial data in buffer?
byte data = RailComDecodeInData(); //read Railcom Data and decode Railcom Data
if (data < 0x40) { //gültige Railcom Message empfangen
if (RailComReadFirst) {
RailComReadData = data; //Save first Byte of Data
if ((data >> 2) < 3) //app:pom, app:adr_low, app:adr_high -> read only 12 Bit!
RailComReadFirst = false;
}
else {
RailComReadFirst = true;
byte RailComID = RailComReadData >> 2; //Save ID
RailComReadData = (RailComReadData << 6) | data; //first 2 Bit and add next 6 Bit
if (RailComID == 0) { //app:pom
RailComCVTime = 25; //Reset Timer!
RailComReadLastCV = RailComReadData;
RailComCVRead = true;
}
else if (RailComID == 1) { //app:adr_high
RailComReadAdr = (RailComReadData << 8) | (RailComReadAdr & 0xFF);
}
else if (RailComID == 2) { //app:adr_low
RailComReadAdr = (RailComReadAdr & 0xFF00) | RailComReadData;
}
}
}
else RailComReadFirst = true;
}
if (RailComCVTime == 0) { //TIMEOUT?
RailComGetCV = false; //Stop reading! ERROR!
if (RailComCVRead == true) {
RailComCVRead = false;
#if defined(LAN) || defined(WIFI) || defined(ESP_WIFI)
z21.setCVPOMBYTE(RailcomCVAdr, RailComReadLastCV);
#endif
#if defined(RCDEB)
Debug.print(F(" result: A"));
Debug.print(RailComReadAdr);
Debug.print(" CV");
Debug.print(RailcomCVAdr+1);
Debug.print(" = ");
Debug.println(RailComReadLastCV);
#endif
}
else {
#if defined(LAN) || defined(WIFI) || defined(ESP_WIFI)
z21.setCVNack(); //Antwort: LAN_X_CV_NACK
#endif
#if defined(RCDEB)
Debug.println(" RC ERROR");
#endif
}
}
}
}
//--------------------------------------------------------------
//Start Reading Data!
void RailComStart(void) {
while(RCSerial.available()){RCSerial.read();} //remove all rubish data
RailComGetCV = true; //start reading RailCom Data
RailComReadLastCV = 0xFF; //Reset the last Value
RailComCVTime = 0; //Reset the cycle time
RailComReadAdr = 0;
RailComRead(); //Try to read data...
}
#endif //End MEGA Serial
//--------------------------------------------------------------
#endif

Datei anzeigen

@ -0,0 +1,34 @@
/*
* Z21type.h
* Created on: 16.04.2015
*
* Define param for Z21 client handle
*
* Copyright (c) by Philipp Gahtow, year 2021
*/
//**************************************************************
//Client Configuration:
//Speichergröße/Slot size:
#if defined(__AVR_ATmega1284P__)
#define LANmaxIP 15 //max IP-Adressen (max Clients)
#define WLANmaxIP 15 //Anzahl Clients über ESP
#elif defined(MEGA_MCU) //Arduino MEGA
#define LANmaxIP 15
#define WLANmaxIP 15 //Anzahl Clients über ESP
#elif defined (DUE_MCU)
#define LANmaxIP 20
#define WLANmaxIP 20 //Anzahl Clients über ESP
#elif defined (__AVR_ATmega644P__)
#define LANmaxIP 15
#define WLANmaxIP 15 //Anzahl Clients über ESP
#elif defined(ESP8266_MCU) || defined(ESP32_MCU)
#define LANmaxIP 20 //Clients auf ESP werden als LAN behandelt
#define WLANmaxIP 0 //no support for Ethernet Shield on ESP!
#else //Arduino UNO
#define LANmaxIP 5
#define WLANmaxIP 10 //Anzahl Clients über ESP
#endif
#define ActTimeIP 10 //Aktivhaltung einer IP für (sec./2)
#define IPinterval 4000 //Interval in milliseconds for checking IP aktiv state

Datei anzeigen

@ -0,0 +1,505 @@
/*
* DCC Waveform Generator
*
* modified by Philipp Gahtow
* Copyright digitalmoba@arcor.de, http://pgahtow.de
*
*/
#include "Arduino.h"
#if defined(__AVR__)
#include <avr/io.h>
#include <avr/interrupt.h>
#endif
#include "DCCHardware.h"
#include "DDCHardware_config.h"
//#define DCCDEBUG //Serial output of DCC DATA
/// An enumerated type for keeping track of the state machine used in the timer1 ISR
/** Given the structure of a DCC packet, the ISR can be in one of 5 states.
*dos_idle: there is nothing to put on the rails. In this case, the only legal thing
to do is to put a '1' on the rails. The ISR should almost never be in this state.
*dos_send_premable: A packet has been made available, and so we should broadcast the preamble with at least: 12 '1's in a row
*dos_send_longpreamble: Additional '1's for Service Mode packets
*dos_send_bstart: Each data uint8_t is preceded by a '0'
*dos_send_uint8_t: Sending the current data uint8_t
*dos_end_bit: After the final uint8_t is sent, send a '0'.
*/
typedef enum {
dos_idle,
dos_send_preamble,
dos_send_longpreamble,
dos_send_bstart,
dos_send_next_uint8_t,
dos_send_uint8_t,
dos_end_bit
} DCC_output_state_t;
volatile DCC_output_state_t DCC_state = dos_idle; //just to start out
/// The Pin where the DCC Waveform comes out.
bool POWER_STATUS = false; //set the railsignal on/off
uint8_t DCCPin = 6;
uint8_t DCCPin2 = 0xFF; // inverted DCC (for RailCom support)
bool RailCom = false; //provide a cut out of four bit in preamble
bool RailComHalfOneBit = false; //last bit before RC start is only a half one!
uint8_t DCCS88Pin = 0xFF; //provide all the time a DCC Signal (no RailCom), even when Railpower is off!
#if defined(__AVR__)
//data for DCC direct register setting
uint8_t d1bit; //_BV Bit for DCC
uint8_t d2bit; //_BV Bit for DCC2
uint8_t d3bit; //_BV Bit for S88
volatile uint8_t *d1reg, *d2reg, *d3reg; //PORT Register
#endif
#if defined(ESP32)
hw_timer_t * timer = NULL;
portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED;
#endif
volatile bool get_next_packet = true; //notify to update() that we need the next packet
volatile uint8_t sending_packet[6] = {0,0,0,0,0,0};
volatile uint8_t sending_packet_size = 0;
/// The currently queued packet to be put on the rails. Default is a reset packet.
volatile uint8_t current_packet[6] = {0,0,0,0,0,0};
/// is in Service Mode:
volatile uint8_t current_packet_service = 0; //actual packet is a service mode packet
// 0 = Normal Packet
// 255 = Service Mode
// < 255 = Service Mode Repeat counter
volatile uint8_t ProgRepeat = 10; //number of Service Mode Packet repeat
/// How many data uint8_ts in the queued packet?
volatile uint8_t current_packet_size = 0;
/// How many uint8_ts remain to be put on the rails?
volatile uint8_t sending_uint8_t_counter = 0;
/// How many bits remain in the current data uint8_t/preamble before changing states?
volatile uint8_t current_bit_counter = PREAMBLE_LENGTH; //init to 16 1's for the preamble
/// Timer1 TOP values for one and zero
/** S 9.1 A specifies that '1's are represented by a square wave with a half-period of 58us (valid range: 55-61us)
and '0's with a half-period of >100us (valid range: 95-9900us)
Because '0's are stretched to provide DC power to non-DCC locos, we need two zero counters,
one for the top half, and one for the bottom half.
Here is how to calculate the timer1 counter values (from ATMega168 datasheet, 15.9.2):
f_{OC1A} = \frac{f_{clk_I/O}}{2*N*(1+OCR1A)})
where N = prescalar, and OCR1A is the TOP we need to calculate.
We know the desired half period for each case, 58us and >100us.
So:
for ones:
58us = (8*(1+OCR1A)) / (16MHz)
58us * 16MHz = 8*(1+OCR1A)
58us * 2MHz = 1+OCR1A
OCR1A = 115
for zeros:
100us * 2MHz = 1+OCR1A
OCR1A = 199
This, we also know that the valid range for stretched-zero operation is something like this:
9900us = (8*(1+OCR1A)) / (16MHz)
9900us * 2MHz = 1+OCR1A
OCR1A = 19799
*/
#if defined(DCC_USE_TIMER2)
uint8_t last_timer = one_count; //last time set to timer
#elif defined(ESP8266) || defined(ESP32)
uint16_t last_timer = one_count; //last time set to timer
#endif
volatile uint8_t oldstate = LOW; //state of the output
volatile uint8_t RailComActiv = false;
/// This is the Interrupt Service Routine (ISR) for Timer compare match.
ISR(DCC_TMR_SIGNAL)
{
digitalWrite(13,LOW);
//in CTC mode, timer TCINT1 automatically resets to 0 when it matches OCR1A. Depending on the next bit to output,
//we may have to alter the value in OCR1A, maybe.
//to switch between "one" waveform and "zero" waveform, we assign a value to OCR1A.
//remember, anything we set for OCR1A takes effect IMMEDIATELY, so we are working within the cycle we are setting.
//first, check to see if we're in the second half of a uint8_t; only act on the first half of a uint8_t
/*
//On Arduino UNO, etc, OC1A is digital pin 9, or Port B/Pin 1
//On Arduino MEGA, etc, OC1A is digital pin 11, or Port B/Pin 5
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_AT90CAN128__) || defined(__AVR_AT90CAN64__) || defined(__AVR_AT90CAN32__)
if(PINB & (1<<PINB6)) //if the pin is low, we need to use a different zero counter to enable streched-zero DC operation
#else
if(PINB & (1<<PINB1)) //if the pin is low, we need to use a different zero counter to enable streched-zero DC operation
#endif
*/
if (RailComHalfOneBit) {
//deactivate:
RailComHalfOneBit = false;
DCC_TMR_OUTP_ONE_HALF(); //Produce another halve "one" Bit
DCC_OUTPUT1_RC(); //LOW
return; //make the next halve one bit => one bit
} else {
oldstate = !oldstate; //change State
}
if (POWER_STATUS) { //Railpower ON?
if (RailComActiv) { //Railcom CutOut:
//Sendepause beträgt mindestens 448µs oder 4 logische 1 Bits (=464µs).
digitalWrite(15,HIGH);
DCC_OUTPUT1_RC(); //LOW
DCC_OUTPUT2_RC(); //LOW
}
else {
// digitalWrite(15,LOW);
//normal Working = no RailCom Cutout:
if (oldstate == LOW) {
DCC_OUTPUT1_LOW(); //LOW
DCC_OUTPUT2_LOW(); //HIGH
}
else {
DCC_OUTPUT1_HIGH(); //HIGH
DCC_OUTPUT2_HIGH(); //LOW
}
}
digitalWrite(15,LOW);
}
//True DCC Output for S88/LocoNet without RailCom cutout!
if (DCCS88Pin != 0xFF) {
if (oldstate == LOW) {
#if defined(__AVR__)
*d3reg &= ~d3bit; //LOW
#else
digitalWrite(DCCS88Pin, LOW);
#endif
}
else {
#if defined(__AVR__)
*d3reg |= d3bit; //HIGH
#else
digitalWrite(DCCS88Pin, HIGH);
#endif
}
}
//only repeat the last output:
if (oldstate == LOW)
{
//if the pin is low and outputting a zero, we need to be using zero_low_count
#if defined(DCC_USE_TIMER1)
if (DCC_TMR_OUTP_CAPT_REG == zero_high_count)
{
DCC_TMR_OUTP_ZERO_LOW();
}
#elif defined(DCC_USE_TIMER2)
if (last_timer == zero_high_count)
{
DCC_TMR_OUTP_ZERO_LOW();
}
else {
DCC_TMR_OUTP_ONE_COUNT();
}
#endif
//ca. 16µs vor dem Ende des 4. Einsbit wieder ein!
if ((DCC_state == dos_send_preamble) && current_bit_counter == (PREAMBLE_LENGTH - RAILCOM_CUTOUT_LENGTH)) {
RailComActiv = false; //stop railcom cutout with the next circle
}
}
//the pin is high. New cycle is begining. Here's where the real work goes.
//time to switch things up, maybe. send the current bit in the current packet.
//if this is the last bit to send, queue up another packet (might be the idle packet).
else {
//check the state we are in?
//change structure to if/else because ESP32/ESP-IDF, compiler bug in switch/case #1330 - IRAM crash (Cache disabled but cached memory region accessed)
/// Idle: Check if a new packet is ready. If it is, fall through to dos_send_preamble. Otherwise just stick a '1' out there.
if (DCC_state == dos_idle || DCC_state == dos_send_preamble) {
if (DCC_state == dos_idle) {
DCC_state = dos_send_preamble; //and fall through to dos_send_preamble
//29µs (+/-3µs) nach dem Aussenden des Endebits einer DCC-Nachricht schaltet die Zentrale ab!
if (RailCom) { //in Service Mode kein RailCom
RailComActiv = true; //start railcom cutout within the next circle
RailComHalfOneBit = true; //next Bit has only halve length
}
}
/// Preamble: In the process of producing 16 '1's, counter by current_bit_counter; when complete, move to dos_send_bstart or long preamble
if (RailComHalfOneBit) {
DCC_TMR_OUTP_ONE_HALF();
} else {
DCC_TMR_OUTP_ONE_COUNT();
}
#if defined(DCCDEBUG)
Serial.print("P");
#endif
if(!--current_bit_counter) {
if (current_packet_service > 0) { //long Preamble in Service Mode
current_bit_counter = ADD_LONG_PREAMBLE_LENGTH; //additional '1's
DCC_state = dos_send_longpreamble;
} else DCC_state = dos_send_bstart;
}
//break;
}
/// long Preamble: producess additional '1's for Service Mode data
else if (DCC_state == dos_send_longpreamble) {
DCC_TMR_OUTP_ONE_COUNT();
#if defined(DCCDEBUG)
Serial.print("L");
#endif
if (!--current_bit_counter) {
DCC_state = dos_send_bstart;
}
//break;
}
/// About to send a data uint8_t, but have to peceed the data with a '0'. Send that '0', then move to dos_send_uint8_t
else if (DCC_state == dos_send_bstart) {
DCC_TMR_OUTP_ZERO_HIGH();
#if defined(DCCDEBUG)
Serial.print(" 0 ");
#endif
//check if we have received a next packet to send?
if (get_next_packet) { //ERROR! - We didn't get the next packet until now!
if (current_packet_service > 0) {
//load a default reset packet!
sending_packet[0] = 0;
sending_packet[1] = 0;
sending_packet[2] = 0;
sending_packet_size = 3; //feed to the starting ISR.
} else {
//load a default idle packet!
sending_packet[0] = 0xFF;
sending_packet[1] = 0;
sending_packet[2] = 0xFF;
sending_packet_size = 3; //feed to the starting ISR.
}
}
//store the current_packet to let time for getting the next one while sending this.
else {
if ((current_packet_service == 0xFF) || (current_packet_service == 0)) {
sending_packet[0] = current_packet[0];
sending_packet[1] = current_packet[1];
sending_packet[2] = current_packet[2];
sending_packet[3] = current_packet[3];
sending_packet[4] = current_packet[4];
sending_packet[5] = current_packet[5];
sending_packet_size = current_packet_size;
//need this packet a ACK response?
if ((sending_packet[0] >> 4) == B0111) //CV read/write packet with ACK response!
current_packet_service = 0xFF - ProgRepeat; //repeat packet timer intern and active ACK read!
}
else current_packet_service++; //count of internal Service Mode Packet repeat
}
if ((current_packet_service == 0) || (current_packet_service == 0xFF))
get_next_packet = true; //request the next packet
DCC_state = dos_send_uint8_t;
current_bit_counter = 8; //reset the counter for bit sending
sending_uint8_t_counter = sending_packet_size; //reset the counter to the packet_size
//break;
}
/// About to send next data uint8_t, but have to peceed the data with a '0'. Send that '0', then move to dos_send_uint8_t
else if (DCC_state == dos_send_next_uint8_t) {
DCC_TMR_OUTP_ZERO_HIGH();
DCC_state = dos_send_uint8_t; //continue sending...
current_bit_counter = 8; //reset the counter for bit sending
//break;
}
/// Sending a data uint8_t; current bit is tracked with current_bit_counter, and current uint8_t with sending_uint8_t_counter
else if (DCC_state == dos_send_uint8_t) {
if(((sending_packet[sending_packet_size-sending_uint8_t_counter])>>(current_bit_counter-1)) & 1) //is current bit a '1'?
{
DCC_TMR_OUTP_ONE_COUNT();
#if defined(DCCDEBUG)
Serial.print("1");
#endif
}
else //or is it a '0'
{
DCC_TMR_OUTP_ZERO_HIGH();
#if defined(DCCDEBUG)
Serial.print("0");
#endif
}
if(!--current_bit_counter) //out of bits! time to either send a new uint8_t, or end the packet
{
if(!--sending_uint8_t_counter) //if not more uint8_ts, move to dos_end_bit
{
DCC_state = dos_end_bit;
}
else //there are more uint8_ts…so, go back to dos_send_bstart
{
DCC_state = dos_send_next_uint8_t;
}
}
//break;
}
/// Done with the packet. Send out a final '1', then head back to dos_idle to check for a new packet.
else if (DCC_state == dos_end_bit) {
DCC_TMR_OUTP_ONE_COUNT();
DCC_state = dos_idle;
current_bit_counter = PREAMBLE_LENGTH; //in preparation for a premable...
#if defined(DCCDEBUG)
Serial.println(" 1");
#endif
//break;
}
//} //END SWITCH CASE
} //END the pin is high.
digitalWrite(13,HIGH);
}
void DCC_stop_output_signal()
{
POWER_STATUS = false;
digitalWrite(DCCPin, LOW); //DCC output pin inaktiv
if (DCCPin2 != 0xFF) {
digitalWrite(DCCPin2, LOW); //DCC output pin inaktiv
}
}
void DCC_run_output_signal()
{
POWER_STATUS = true;
}
/// Setup phase: configure and enable timer1 CTC interrupt, set OC1A and OC1B to toggle on CTC
void setup_DCC_waveform_generator() {
/*
//Set the OC1A and OC1B pins (Timer1 output pins A and B) to output mode
//On Arduino UNO, etc, OC1A is Port B/Pin 1 and OC1B Port B/Pin 2
//On Arduino MEGA, etc, OC1A is or Port B/Pin 5 and OC1B Port B/Pin 6
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_AT90CAN128__) || defined(__AVR_AT90CAN64__) || defined(__AVR_AT90CAN32__)
DDRB |= (1<<DDB5) | (1<<DDB6);
#else
DDRB |= (1<<DDB1) | (1<<DDB2);
#endif
// Configure timer1 in CTC mode, for waveform generation, set to toggle OC1A, OC1B, at /8 prescalar, interupt at CTC
TCCR1A = (0<<COM1A1) | (1<<COM1A0) | (0<<COM1B1) | (1<<COM1B0) | (0<<WGM11) | (0<<WGM10);
TCCR1B = (0<<ICNC1) | (0<<ICES1) | (0<<WGM13) | (1<<WGM12) | (0<<CS12) | (1<<CS11) | (0<<CS10);
//finally, force a toggle on OC1B so that pin OC1B will always complement pin OC1A
TCCR1C |= (1<<FOC1B);
*/
pinMode(DCCPin, OUTPUT); //Set output mode for DCC Pin
/******************************************/
#if defined(__AVR__)
d1bit = digitalPinToBitMask(DCCPin);
d1reg = portOutputRegister(digitalPinToPort(DCCPin)); //PORTB, PORTC, ....
DCC_OUTPUT1_OFF(); //LOW
pinMode(DCCPin2, OUTPUT); //Set output mode for DCC Pin2
d2bit = digitalPinToBitMask(DCCPin2);
d2reg = portOutputRegister(digitalPinToPort(DCCPin2));
DCC_OUTPUT2_OFF(); //LOW
if (DCCS88Pin != 0xFF) {
pinMode(DCCS88Pin, OUTPUT); //Set output mode for DCC S88 Pin
d3bit = digitalPinToBitMask(DCCS88Pin);
d3reg = portOutputRegister(digitalPinToPort(DCCS88Pin));
*d3reg &= ~d3bit; //LOW
}
DCC_INIT_COMPARATOR = 0; // set entire TCCR1A register to 0
DCC_TMR_CONTROL_REG = 0; // same for TCCR1B
// start by outputting a '1'
DCC_TMR_OUTP_ONE_COUNT(); //Whenever we set OCR1A, we must also set OCR1B, or else pin OC1B will get out of sync with OC1A!
DCC_TMR_COUNT_REG = 0; //get the timer rolling (not really necessary? defaults to 0. Just in case.)
DCC_TMR_CONTROL_SET(); //Timer Prescaler and mode set
/******************************************/
/******************************************/
#else //other
digitalWrite(DCCPin, DCC_OUTPUT1_OFF_legacy);
pinMode(DCCPin2, OUTPUT); //Set output mode for DCC Pin2
digitalWrite(DCCPin2, DCC_OUTPUT2_OFF_legacy);
if (DCCS88Pin != 0xFF) {
pinMode(DCCS88Pin, OUTPUT); //Set output mode for DCC S88 Pin
digitalWrite(DCCS88Pin, LOW);
}
/******************************************/
#if defined(ESP32) //ESP32 Modul
/* Use 1st timer of 4 */
/* 1 tick take 1/(80MHZ/80) = 1us so we set divider 80 and count up */
timer = timerBegin(DCC_ESP_TIMER_ID, DCC_ESP_TIMER_PRESCALE, DCC_ESP_TIMER_FLAG);
/* Set alarm to call onTimer function every second 1 tick is 1us => 1 second is 1000000us */
/* Repeat the alarm (third parameter) */
timerAttachInterrupt(timer, &onTimerISR, true);
DCC_TMR_OUTP_ONE_COUNT(); //start output "1"
/******************************************/
#elif defined (ESP8266) //ESP8266
noInterrupts();
timer1_isr_init();
timer1_enable(DCC_ESP_TIMER_DIV, DCC_ESP_TIMER_SET, DCC_ESP_TIMER_LOOP);
DCC_TMR_OUTP_ONE_COUNT(); //start output "1"
interrupts();
/******************************************/
#else //Arduino DUE
// Tell the Power Management Controller to disable
// the write protection of the (Timer/Counter) registers:
pmc_set_writeprotect(false);
// Enable clock for the timer
pmc_enable_periph_clk((uint32_t)DCC_ARM_MATCH_INT);
// Set up the Timer in waveform mode which creates a PWM
// in UP mode with automatic trigger on RC Compare
// and sets it up with the determined internal clock as clock input.
TC_Configure(DCC_ARM_TC_TIMER, DCC_ARM_TC_CHANNEL, TC_CMR_WAVE | TC_CMR_WAVSEL_UP_RC | TC_CMR_TCCLKS_TIMER_CLOCK2);
// Set up timing...
DCC_TMR_OUTP_ONE_COUNT();
// Enable the RC Compare Interrupt...
DCC_ARM_TC_TIMER->TC_CHANNEL[DCC_ARM_TC_CHANNEL].TC_IER=TC_IER_CPCS;
// ... and disable all others.
DCC_ARM_TC_TIMER->TC_CHANNEL[DCC_ARM_TC_CHANNEL].TC_IDR=~TC_IER_CPCS;
#endif
/******************************************/
#endif
/******************************************/
//Enable the Interrupt (all MCUs):
#if defined(__AVR__)
//enable match interrupt
DCC_TMR_MATCH_INT();
#elif defined(ESP8266) //ESP8266
timer1_attachInterrupt(onTimerISR);
#elif defined(ESP32) //ESP32
timerAlarmEnable(timer);
#else //Arduino DUE
NVIC_EnableIRQ(DCC_ARM_MATCH_INT);
#endif
}

Datei anzeigen

@ -0,0 +1,19 @@
#ifndef __DCCHARDWARE_H__
#define __DCCHARDWARE_H__
#ifdef __cplusplus
extern "C"
{
#endif
void setup_DCC_waveform_generator(void);
void DCC_waveform_generation_hasshin(void);
void DCC_stop_output_signal(void);
void DCC_run_output_signal(void);
#ifdef __cplusplus
}
#endif
#endif //__DCCHARDWARE_H__

Datei anzeigen

@ -0,0 +1,88 @@
#include "DCCPacket.h"
DCCPacket::DCCPacket(uint16_t new_address, uint8_t max_short_address) //: address(new_address), kind(idle_packet_kind), size_repeat(0x40)
{
address = new_address; //if address param is empty it's set per default to 0xFF!
data[0] = 0x00; //default idle packet with address 0xFF and data 0x00
data[1] = 0x00;
data[2] = 0x00;
size_repeat = 0x40;
kind = idle_packet_kind;
maxkAdr = max_short_address;
}
uint8_t DCCPacket::getBitstream(uint8_t rawbytes[]) //returns size of array.
{
int total_size = 1; //minimum size
if (kind & MULTIFUNCTION_PACKET_KIND_MASK) {
if (kind == idle_packet_kind) //idle packets work a bit differently:
// since the "address" field is 0xFF, the logic below will produce C0 FF 00 3F instead of FF 00 FF
{
rawbytes[0] = 0xFF; //Leerlauf oder auch Idle Paket (255)
}
else if ((address > maxkAdr) && (kind != ops_mode_programming_kind)) //This is a 14-bit address (128 - 10239)
{
rawbytes[0] = (uint8_t)((address >> 8) | 0xC0); //(192-231)
if (rawbytes[0] > 0xE7) //231=0xE7
rawbytes[0] = 0xE7;
rawbytes[1] = (uint8_t)(address & 0xFF);
++total_size;
} else //we have an 7-bit address
{
rawbytes[0] = (uint8_t)(address & 0x7F); // (1-127)
}
uint8_t i;
for (i = 0; i < getSize(); ++i, ++total_size) {
rawbytes[total_size] = data[i];
}
uint8_t XOR = 0;
for (i = 0; i < total_size; ++i) {
XOR ^= rawbytes[i];
}
rawbytes[total_size] = XOR;
return total_size + 1;
} else if (kind & ACCESSORY_PACKET_KIND_MASK) {
if ((kind == basic_accessory_packet_kind) || (kind == extended_accessory_packet_kind)) {
// Basic Accessory Packet looks like this:
// {preamble} 0 10AAAAAA 0 1AAACAAD 0 EEEEEEEE 1
// {preamble} 0 10AAAAAA 0 0AAA0AA1 0 DDDDDDDD 0 EEEEEEEE 1 (extACC)
// or this:
// {preamble} 0 10AAAAAA 0 1AAACDDD 0 (1110CCVV 0 VVVVVVVV 0 DDDDDDDD) 0 EEEEEEEE 1 (if programming)
rawbytes[0] = 0x80; //set up address byte 0
if (kind != extended_accessory_packet_kind) //do not set the bit for extACC
rawbytes[1] = 0x80; //set up address byte 1
rawbytes[0] |= address & 0x03F;
rawbytes[1] |= (~(address >> 2) & 0x70) | (data[0] & 0x0F);
//now, add any programming bytes (skipping first data byte, of course)
uint8_t i;
uint8_t total_size = 2;
for (i = 1; i < getSize(); ++i, ++total_size) {
rawbytes[total_size] = data[i];
}
//and, finally, the XOR
uint8_t XOR = 0;
for (i = 0; i < total_size; ++i) {
XOR ^= rawbytes[i];
}
rawbytes[total_size] = XOR;
return total_size + 1;
}
}
return 0; //ERROR! SHOULD NEVER REACH HERE! do something useful, like transform it into an idle packet or something! TODO
}
void DCCPacket::addData(uint8_t new_data[], uint8_t new_size) //insert freeform data.
{
for(int i = 0; i < new_size; ++i)
data[i] = new_data[i];
size_repeat = (size_repeat & 0x3F) | (new_size<<6);
}

Datei anzeigen

@ -0,0 +1,71 @@
#ifndef __DCCPACKET_H__
#define __DCCPACKET_H__
#include "Arduino.h"
typedef unsigned char uint8_t;
//Packet kinds
// enum packet_kind_t {
// idle_packet_kind,
// e_stop_packet_kind,
// speed_packet_kind,
// function_packet_kind,
// accessory_packet_kind,
// reset_packet_kind,
// ops_mode_programming_kind,
// other_packet_kind
// };
#define MULTIFUNCTION_PACKET_KIND_MASK 0x10
#define idle_packet_kind 0x10
#define e_stop_packet_kind 0x11
#define speed_packet_kind 0x12
#define function_packet_1_kind 0x13
#define function_packet_2_kind 0x14
#define function_packet_3_kind 0x15
#define function_packet_4_kind 0x19
#define function_packet_5_kind 0x1A
#define function_packet_b_kind 0x1B
#define accessory_packet_kind 0x16
#define reset_packet_kind 0x17
#define ops_mode_programming_kind 0x18 //always use short Address Mode!
#define pom_mode_programming_kind 0x1B
#define ACCESSORY_PACKET_KIND_MASK 0x40
#define basic_accessory_packet_kind 0x40
#define extended_accessory_packet_kind 0x41
#define other_packet_kind 0x00
#define MAX_DCC_SHORT_ADDRESS_DEFAULT 127 //Maximum of short DCC Address, from the next on use LONG ADDRESS (NMRA)!
class DCCPacket
{
private:
//A DCC packet is at most 6 uint8_ts: 2 of address, three of data, one of XOR
uint16_t address;
//uint8_t address_kind;
uint8_t data[3];
uint8_t size_repeat; //a bit field! 0b11000000 = 0xC0 = size; 0x00111111 = 0x3F = repeat
uint8_t kind;
uint8_t maxkAdr; //Maximum of short DCC Address, from the next on use LONG ADDRESS (NMRA)!
public:
DCCPacket(uint16_t decoder_address=0xFF, uint8_t max_short_address=MAX_DCC_SHORT_ADDRESS_DEFAULT);
uint8_t getBitstream(uint8_t rawuint8_ts[]); //returns size of array.
inline uint8_t getSize(void) { return (size_repeat >> 6); }
inline uint16_t getAddress(void) { return address; }
//inline uint8_t getAddressKind(void) { return address_kind; }
inline void setAddress(uint16_t new_address) { address = new_address; }
//inline void setAddress(uint16_t new_address, uint8_t new_address_kind) { address = new_address; address_kind = new_address_kind; }
void addData(uint8_t new_data[], uint8_t new_size); //insert freeform data.
inline void setKind(uint8_t new_kind) { kind = new_kind; /*if (kind == basic_accessory_packet_kind) address_kind = other_packet_kind; */}
inline uint8_t getKind(void) { return kind; }
inline void setRepeat(uint8_t new_repeat) { size_repeat = ((size_repeat&0xC0) | (new_repeat&0x3F)) ;}
inline uint8_t getRepeat(void) { return size_repeat & 0x3F; }//return repeat; }
};
#endif //__DCCPACKET_H__

Datei anzeigen

@ -0,0 +1,202 @@
#include "DCCPacketQueue.h"
DCCPacketQueue::DCCPacketQueue(void) : read_pos(0), write_pos(0), size(10), written(0)
{
return;
}
void DCCPacketQueue::setup(byte length)
{
size = length;
queue = (DCCPacket *)malloc(sizeof(DCCPacket) *size);
for(int i = 0; i<size; ++i)
{
queue[i] = DCCPacket();
}
}
bool DCCPacketQueue::insertPacket(DCCPacket *packet)
{
// Serial.print("Enqueueing a packet of kind: ");
// Serial.println(packet->getKind(), DEC);
//First: Overwrite any packet with the same address and kind; if no such packet THEN hitup the packet at write_pos
byte i = read_pos;
while(i != (read_pos+written)%(size) )//(size+1) ) //size+1 so we can check the last slot, too…
{
if( (queue[i].getAddress() == packet->getAddress()) && (queue[i].getKind() == packet->getKind()) && (packet->getKind() != basic_accessory_packet_kind) && (packet->getKind() != ops_mode_programming_kind))
{
//ATTENTION: accessory packet does have a 2. Adr inside the packet - just add them all, also ops_mode_programming_kind!
// Serial.print("Overwriting existing packet at index ");
// Serial.println(i, DEC);
memcpy(&queue[i],packet,sizeof(DCCPacket));
//do not increment written or modify write_pos
return true;
}
i = (i+1)%size;
}
//else, tack it on to the end
if(!isFull())
{
//else, just write it at the end of the queue.
memcpy(&queue[write_pos],packet,sizeof(DCCPacket));
// Serial.print("Write packet to index ");
// Serial.println(write_pos, DEC);
write_pos = (write_pos + 1) % size;
++written;
return true;
}
// Serial.println("Queue is full!");
return false;
}
// void DCCPacketQueue::printQueue(void)
// {
// byte i, j;
// for(i = 0; i < size; ++i)
// {
// for(j = 0; j < (queue[i].size_repeat>>4); ++j)
// {
// Serial.print(queue[i].data[j],BIN);
// Serial.print(" ");
// }
// if(i == read_pos) Serial.println(" r");
// else if(i == write_pos) Serial.println(" w");
// else Serial.println("");
// }
// }
bool DCCPacketQueue::readPacket(DCCPacket *packet)
{
if(!isEmpty())
{
// Serial.print("Reading a packet from index: ");
// Serial.println(read_pos, DEC);
memcpy(packet,&queue[read_pos],sizeof(DCCPacket));
read_pos = (read_pos + 1) % size;
--written;
return true;
}
return false;
}
bool DCCPacketQueue::forget(uint16_t address /*, uint8_t address_kind*/)
{
bool found = false;
for(int i = 0; i < size; ++i)
{
if( (queue[i].getAddress() == address) /*&& (queue[i].getAddressKind() == address_kind)*/ )
{
found = true;
queue[i] = DCCPacket(); //revert to default value
}
}
--written;
return found;
}
void DCCPacketQueue::clear(uint8_t packet_kind)
{
// read_pos = 0;
// write_pos = 0;
// written = 0;
for(int i = 0; i<size; ++i)
{
if ((queue[i].getKind() == packet_kind) || (packet_kind == 0x00)) {
queue[i] = DCCPacket();
--written;
}
}
}
/*****************************/
DCCRepeatQueue::DCCRepeatQueue(void) : DCCPacketQueue()
{
}
bool DCCRepeatQueue::insertPacket(DCCPacket *packet)
{
if(packet->getRepeat())
{
return(DCCPacketQueue::insertPacket(packet));
}
return false;
}
bool DCCRepeatQueue::readPacket(DCCPacket *packet)
{
if(!isEmpty())
{
memcpy(packet,&queue[read_pos],sizeof(DCCPacket));
read_pos = (read_pos + 1) % size;
--written;
if(packet->getRepeat()) //the packet needs to be sent out at least one more time
{
//***************************************************************************
//Add repeat for special packets!!
// if (packet->getKind() != speed_packet_kind && packet->getKind() != function_packet_1_kind && packet->getKind() != function_packet_2_kind && packet->getKind() != function_packet_3_kind)
packet->setRepeat(packet->getRepeat()-1);
insertPacket(packet);
}
return true;
}
return false;
}
/**************/
DCCEmergencyQueue::DCCEmergencyQueue(void) : DCCPacketQueue()
{
}
/* Goes through each packet in the queue, repeats it getRepeat() times, and discards it */
bool DCCEmergencyQueue::readPacket(DCCPacket *packet)
{
if(!isEmpty()) //anything in the queue?
{
queue[read_pos].setRepeat(queue[read_pos].getRepeat()-1); //decrement the current packet's repeat count
if(queue[read_pos].getRepeat()) //if the topmost packet needs repeating
{
memcpy(packet,&queue[read_pos],sizeof(DCCPacket));
return true;
}
else //the topmost packet is ready to be discarded; use the DCCPacketQueue mechanism
{
return(DCCPacketQueue::readPacket(packet));
}
}
return false;
}
/**********DCCTemporalQueue*******************/
//for speed and function repeat (repeat never stops!)
DCCTemporalQueue::DCCTemporalQueue(void) : DCCPacketQueue()
{
}
bool DCCTemporalQueue::insertPacket(DCCPacket *packet)
{
return(DCCPacketQueue::insertPacket(packet));
}
bool DCCTemporalQueue::readPacket(DCCPacket *packet)
{
if (!isEmpty())
{
memcpy(packet, &queue[read_pos], sizeof(DCCPacket));
read_pos = (read_pos + 1) % size;
--written;
insertPacket(packet);
return true;
}
return false;
}

Datei anzeigen

@ -0,0 +1,86 @@
#ifndef __DCCPACKETQUEUE_H__
#define __DCCPACKETQUEUE_H__
#include "Arduino.h"
/**
* A FIFO queue for holding DCC packets, implemented as a circular buffer.
* Copyright 2010 D.E. Goodman-Wilson
* TODO
**/
#include "DCCPacket.h"
class DCCPacketQueue
{
public: //protected:
DCCPacket *queue;
byte read_pos;
byte write_pos;
byte size;
byte written; //how many cells have valid data? used for determining full status.
public:
DCCPacketQueue(void);
virtual void setup(byte);
~DCCPacketQueue(void)
{
free(queue);
}
virtual inline bool isFull(void)
{
return (written == size);
}
virtual inline bool isEmpty(void)
{
return (written == 0);
}
virtual inline bool notEmpty(void)
{
return (written > 0);
}
virtual inline bool notRepeat(unsigned int address)
{
return (address != queue[read_pos].getAddress());
}
//void printQueue(void);
virtual bool insertPacket(DCCPacket *packet); //makes a local copy, does not take over memory management!
virtual bool readPacket(DCCPacket *packet); //does not hand off memory management of packet. used immediately.
bool forget(uint16_t address/*, uint8_t address_kind*/);
void clear(uint8_t packet_kind = 0x00);
};
//A queue that, when a packet is read, puts that packet back in the queue if it requires repeating.
class DCCRepeatQueue: public DCCPacketQueue
{
public:
DCCRepeatQueue(void);
//void setup(byte length);
bool insertPacket(DCCPacket *packet);
bool readPacket(DCCPacket *packet);
};
//A queue that repeats the topmost packet as many times as is indicated by the packet before moving on
class DCCEmergencyQueue: public DCCPacketQueue
{
public:
DCCEmergencyQueue(void);
bool readPacket(DCCPacket *packet);
};
class DCCTemporalQueue : public DCCPacketQueue
{
public:
DCCTemporalQueue(void);
//void setup(byte length);
bool insertPacket(DCCPacket *packet);
bool readPacket(DCCPacket *packet);
};
#endif //__DCCPACKETQUEUE_H__

Datei anzeigen

@ -0,0 +1,375 @@
/*
* DCC Waveform Generator v6.4.0
*
* Author: Philipp Gahtow digitalmoba@arcor.de
* Don Goodman-Wilson dgoodman@artificial-science.org
*
* based on software by Wolfgang Kufer, http://opendcc.de
*
* modified by Philipp Gahtow
* Copyright 2023 digitalmoba@arcor.de, http://pgahtow.de
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Hardware requirements:
* * A DCC booster with Data and GND wired to pin configured in setup routine (PIN 6) - BASIC OUTPUT!
* * A locomotive/switch with a DCC decoder installed (NMRA).
*
* Attention: only can handel CV Direct Bit/Byte Mode
*
* change log:
* - add a store for active loco, so you can request the actual state
* - add a store for BasicAccessory states
* - add a repeat queue for Speed and Function packets
* - add Function support F13-F20 and F21-F28
* - add POM CV Programming
* - add BasicAccessory increment 4x (Intellibox - ROCO)
* - add request for state of Loco funktion F0 - F28
* - support DCC generation with Timer1 or Timer2
* - add notify of BasicAccessory even when power is off
* - change praeambel to 16 Bit for Railcom support
* - add Railcom hardware support and inverted DCC signal
* - add Rail Power management
* - add CV read
* - add track load information
* - optimize RailCom CutOut
* - fix RailCom de/aktivation
* - add variable packet repeat for programming and reset
* - fix Power notify for Service Mode
* - add support for Arduino DUE
* - fix DCC speed steps
* - add long Adress Mode for POM
* - fix getBasicAccessoryInfo for Adress zero
* - add request array for loco information
* - add support for Arduino ESP8266
* - add additional DCC output signal -without- "power off" and RailCom! (DCCHardware.c)
* - fix idle_packet_kind to send a correct idll packet 0xFF 0x00 0xFF (inside DCCPacket.cpp and DCCHardware.c)
* - fix accessory packet address problem that filters out packets (DCCPAcketQueue.cpp)
* - removed unused variable with the name "last_packet_address"
* - change, new loco with speed direction forward (0x80)
* - change loco slot direction bit now under speed
* - change start up power status to ON!
* - when loco request the first time (new loco), start also to send drive information directly
- activate by config #define InitLocoDirect
* - add truth table inside DCCHardware.c for easy adjust the output states!
* - add support for ESP32 and adjust ESP8266
* - add support for AREF with 1.1 Volt and adjust the CV# read parts.
* - add a DCC timer interrupt start/stop function because of problems crashing ESP32 and ESP8266 when EEPROM.commit runs
* - add EEPROM.commit statement for ESP32 and ESP8266
* - optimize CV# read with new detection time
* - add NVS to store EEPROM data on ESP32
* - add active label to notifyTrnt message
* - add CV to notifyCVNack return
* - fix reset start packet count
* - fix direct programming handle
* - add request for actual RailCom cutout status
* - fix ACK Value for ESP8266
* - fix DCC timing on ESP32
* - change ACK detection and add state machine for CV direct
* - add function bit control from F29...F32767
* - add function setExtAccessoryPos
* - add timing to ACK detection
* - fix saving problem with F13-F20
* - add interrupt to detect ACK over comperator
* - fix CV#1 to max 127 (DCC Adr. 1 - 127)
* - add external ACK Sense value to work better with different H-Bridge
*/
#ifndef __DCCCOMMANDSTATION_H__
#define __DCCCOMMANDSTATION_H__
#include "DCCPacket.h"
#include "DCCPacketQueue.h"
/*******************************************************************/
//#define PROG_DEBUG //Serial output of Prog Informaton
//PG: uncommentet due better reaction on ACK!!
//#define ACK_SENSE_MIN 3 //min ACK length in ms
//#define ACK_SENSE_MAX 14 //max ACK length in ms
//read value again if verify fails:
#define CV_BIT_MAX_TRY_READ 4 //times to try in Bit-Mode
#define CV_BYTE_MAX_TRY_READ 1 //times to try in Byte-Mode
/*******************************************************************/
//When loco request the first time (new loco), start also to send drive information directly
//#define InitLocoDirect
//Function F29-F68 control
#define EXTENDFUNCTION //activate functions over F28
/*******************************************************************/
//Protokoll can handel max 16384 switch (Weichenzustände max 16384):
#if defined(__SAM3X8E__)
// Arduino Due Board follows
#define AccessoryMax 4096 //max DCC 2048 Weichen / 8 = 255 byte
#define SlotMax 255 //Slots für Lokdaten
#define PERIODIC_REFRESH_QUEUE_SIZE 255
#elif defined(ESP8266) || defined(ESP32) //ESP8266 or WeMos D1 mini
// Arduino ESP8266 Board follows
#define AccessoryMax 4096 //max DCC 2048 Weichen / 8 = 255 byte
#define SlotMax 255 //Slots für Lokdaten
#define PERIODIC_REFRESH_QUEUE_SIZE 255
#elif defined(__AVR_ATmega1284P__)
//more then 8 KB RAM
#define AccessoryMax 2048 //max DCC 2048 Weichen / 8 = 255 byte
#define SlotMax 255 //Slots für Lokdaten
#define PERIODIC_REFRESH_QUEUE_SIZE 200
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
//8 KB RAM
#define AccessoryMax 2048 //max DCC 2048 Weichen / 8 = 255 byte
#define SlotMax 120 //Slots für Lokdaten
#define PERIODIC_REFRESH_QUEUE_SIZE 100
//#define GLOBALRAILCOMREADER //Activate Global RailCom Reading in CutOut over Serial3 - now in external Code???
#elif defined (__AVR_ATmega644P__)
//4 KB RAM
#define AccessoryMax 512 //normal 512 Weichen / 8 = 64 byte
#define SlotMax 36 //Slots für Lokdaten
#define PERIODIC_REFRESH_QUEUE_SIZE 70
#else
//less then 2,5 KB RAM
#define AccessoryMax 128 //64 Weichen / 8 = 8 byte
#define SlotMax 15 //Slots für Lokdaten
#define PERIODIC_REFRESH_QUEUE_SIZE 60
#endif
/*******************************************************************/
#define E_STOP_QUEUE_SIZE 15
#define REPEAT_QUEUE_SIZE 25
#define PROG_QUEUE_SIZE 5
//How often a packet is repeat:
#define ONCE_REFRESH_INTERVAL 4 //send estop, switch, pom each "second" packet
//Repaet for Packetkinds:
#define SPEED_REPEAT 3
#define FUNCTION_REPEAT 3
#define E_STOP_REPEAT 6
#define RESET_START_REPEAT 25 //(default, read fom EEPROM)
#define RESET_CONT_REPEAT 6 //(default, read fom EEPROM)
#if defined(ESP8266) //ESP8266 or WeMos D1 mini
#define OPS_MODE_PROGRAMMING_REPEAT 18 //(default, read fom EEPROM)
#else
#define OPS_MODE_PROGRAMMING_REPEAT 7 //(default, read fom EEPROM)
#endif
#define OTHER_REPEAT 9 //for example accessory paket
//State of Railpower:
#define OFF 0x02 //no power on the rails
#define ON 0x00 //signal on the rails
#define ESTOP 0x01 //no Loco drive but rails have power
#define SHORT 0x04
#define SERVICE 0x08 //system is in CV programming mode
//DCC Speed Steps
#define DCC14 0x01
#define DCC28 0x02
#define DCC128 0x03
//EEPROM Configuration Store:
#define EEPROMRailCom 50
#define EEPROMRCN213 57 //The way BasicAccessory Messages Addressing works (RCN-213)
#define EEPROMProgReadMode 53 //Auslese-Modus: 0=Nichts, 1=Bit, 2=Byte, 3=Beides
#define EEPROMRSTsRepeat 60 //RESET_START_REPEAT
#define EEPROMRSTcRepeat 61 //RESET_CONT_REPEAT
#define EEPROMProgRepeat 62 //PROGRAMMING_REPEAT
#define EEPROMDCCPROPERTY 71 //0x03 -> Ausgabeformat (0x00) DCC+MM, (0x02) nur DCC, (0x03) nur MM
//0x40 -> DCC Funktion ab F13 periodisch wiederholen
//0x80 -> kurze DCC Lokaddressen (0x00 = 1..99 / 0x80 = 1..127)
//PROG STATUS States 'ProgState':
#define ProgStart 0x00
#define ProgACKRead 0x01
#define ProgBitRead 0x02 //Bit read
#define ProgVerifyCV 0x04 //Byte read
#define ProgWriteByte 0x05 //Byte write
#define ProgSuccess 0x0F
#define ProgFail 0xF0
#define ProgEnde 0xFF
//PROG Mode Select
#define ProgModeBit 0x10
#define ProgModeBitVerify 0x11
#define ProgModeByte 0x20
#define ProgModeByteVerify 0x21
#define ProgModeWriteByte 0x30
typedef struct //Lokdaten (Lok Events)
{
uint16_t adr; // SS1, SS0, A13, A12| A11, A10, A9, A8| A7, A6, A5, A4| A3, A2, A1, A0
// A0-A13 = Adresse
// SS = Fahrstufen-speedsteps (0=error, 1=14, 2=28, 3=128)
uint8_t speed; //Dir, Speed 0..127 (0x00 - 0x7F) -> 0SSS SSSS + (0x80) -> D000 0000
uint8_t f0; //X X X F0 | F4 F3 F2 F1
uint8_t f1; //F12 F11 F10 F9 | F8 F7 F6 F5
uint8_t f2; //F20 F19 F18 F17| F16 F15 F14 F13
uint8_t f3; //F28 F27 F26 F25| F24 F23 F22 F21
} NetLok;
class DCCPacketScheduler
{
public:
DCCPacketScheduler(void);
//for configuration
//void setDefaultSpeedSteps(uint8_t new_speed_steps);
void setup(uint8_t pin, uint8_t pin2, uint8_t steps = DCC128, uint8_t power = ON, uint16_t AckSENSE = 30, int8_t ack_pin = -1); //for any post-constructor initialization - with RailCom
void enable_additional_DCC_output(uint8_t pin); //extra DCC signal for S88/LocoNet without Shutdown and Railcom
void disable_additional_DCC_output(void);
void loadEEPROMconfig(void); //Load Configuration from EEPROM
//more specific functions:
void setpower(uint8_t state, bool notify = false); //set Mode of output aktive/inactive - should notify other clients?
byte getpower(void); //return the Mode of output power
void setrailcom(bool rc = true); //to de-/activate RailCom output
bool getrailcom(void); //return the State of RailCom output
void eStop(void); //Broadcast Stop Packet For All Decoders
// bool eStop(uint16_t address); //just one specific loco -> use setSpeed with speed = 1
//for enqueueing packets
bool setSpeed(uint16_t address, uint8_t speed); //use default speed steps!
bool setSpeed14(uint16_t address, uint8_t speed); //new_speed: [-13,13]
bool setSpeed28(uint16_t address, uint8_t speed); //new_speed: [-28,28]
bool setSpeed128(uint16_t address, uint8_t speed); //new_speed: [-127,127]
//void getLocoStateFull(uint16_t adr); //aktuellen Zustand aller Funktionen und Speed der Lok
void getLocoData(uint16_t adr, uint8_t data[]); //aktuellen Zustand aller Funktionen und Speed der Lok
byte getLocoDir(uint16_t adr); //Gibt aktuelle Fahrtrichtung der angefragen Lok zurück
byte getLocoSpeed(uint16_t adr); //Gibt aktuelle Geschwindigkeit der angefragten Lok zurück
//the function methods are NOT stateful; you must specify all functions each time you call one
//keeping track of function state is the responsibility of the calling program.
void setLocoFunc(uint16_t address, uint8_t type, uint8_t fkt); //type => 0 = AUS; 1 = EIN; 2 = UM; 3 = error | fkt => 0...68
void setLocoFuncBinary(uint16_t address, uint8_t low, uint8_t high); //Binärzustandsadressen von 29 bis 32767
bool setFunctions0to4(uint16_t address, uint8_t functions); //- F0 F4 F3 F2 F1
bool setFunctions5to8(uint16_t address, uint8_t functions); //- F8 F7 F6 F5
bool setFunctions9to12(uint16_t address, uint8_t functions); //- F12 F11 F10 F9
bool setFunctions13to20(uint16_t address, uint8_t functions); //F20 F19 F18 F17 F16 F15 F14 F13
bool setFunctions21to28(uint16_t address, uint8_t functions); //F28 F27 F26 F25 F24 F23 F22 F21
bool setFunctions29to36(uint16_t address, uint8_t functions); //F29-F36
bool setFunctions37to44(uint16_t address, uint8_t functions); //F37-F44
bool setFunctions45to52(uint16_t address, uint8_t functions); //F45-52
bool setFunctions53to60(uint16_t address, uint8_t functions); //F53-60
bool setFunctions61to68(uint16_t address, uint8_t functions); //F61-68
byte getFunktion0to4(uint16_t address); //gibt Funktionszustand - F0 F4 F3 F2 F1 zurück
byte getFunktion5to8(uint16_t address); //gibt Funktionszustand - F8 F7 F6 F5 zurück
byte getFunktion9to12(uint16_t address); //gibt Funktionszustand - F12 F11 F10 F9 zurück
byte getFunktion13to20(uint16_t address); //gibt Funktionszustand F20 - F13 zurück
byte getFunktion21to28(uint16_t address); //gibt Funktionszustand F28 - F21 zurück
byte getFunktion29to31(uint16_t address); //gibt Funktionszustand F31 - F29 zurück
bool setBasicAccessoryPos(uint16_t address, bool state);
bool setBasicAccessoryPos(uint16_t address, bool state, bool activ);
bool getBasicAccessoryInfo(uint16_t address);
bool setExtAccessoryPos(uint16_t address, uint8_t state);
bool opsProgDirectCV(uint16_t CV, uint8_t CV_data); //Direct Mode - Write byte
bool opsVerifyDirectCV(uint16_t CV, uint8_t CV_data); //Direct Mode - Verify Byte
bool opsReadDirectCV(uint16_t CV); //Direct Mode - Read Bit
bool opsProgramCV(uint16_t address, uint16_t CV, uint8_t CV_data); //POM write byte
bool opsPOMwriteBit(uint16_t address, uint16_t CV, uint8_t Bit_data); //POM write bit
bool opsPOMreadCV(uint16_t address, uint16_t CV); //POM read
//to be called periodically within loop()
void update(void); //checks queues, puts whatever's pending on the rails via global current_packet. easy-peasy
bool getRailComStatus(void); //return the actual RailComStatus on the rails
#if defined(GLOBALRAILCOMREADER)
// public only for easy access by interrupt handlers
//static inline void handle_RX_interrupt(); //Serial RX Interrupt bearbeiten
#endif
private:
bool setFunctionsXXtoXX(uint16_t address, uint8_t functions, uint8_t significantFkt); //F13 to F64
#if defined(GLOBALRAILCOMREADER)
static DCCPacketScheduler *active_object; //aktuelle aktive Object for interrupt handler
void RailComReceive(void); //Read the incomming RailCom data
uint8_t RailComID; //1. Channel RailCom ID and 2 Bit data
uint8_t RailComData; //next 6 Bit Data
#endif
uint8_t TrntFormat = 0; // The Addressing of BasicAccessory Messages
uint8_t MaxShortAdr = 127; // The Addressing of Loco with short Adr to max....
uint8_t DCCdefaultSteps; //default Speed Steps
volatile byte railpower = 0xFF; // actual state of the power that goes to the rails
uint16_t LASTVAmpSense = 0; //Save the maximal level of mA on the Rail for ACK detection
byte BasicAccessory[AccessoryMax / 8]; //Speicher für Weichenzustände
NetLok LokDataUpdate[SlotMax]; //Speicher zu widerholdene Lok Daten
byte LokStsgetSlot(uint16_t adr); //gibt Slot für Adresse zurück / erzeugt neuen Slot (0..126)
void LokStsSetNew(byte Slot, uint16_t adr); //Neue Lok eintragen mit Adresse
byte slotFullNext; //if no free slot, override existing slots
int8_t ACKPIN; //Input Pin for Comperator to trigger the ACK Interrupt
uint16_t AckSenseValue; //Difference to detect a ACK replay
uint8_t ProgState; //Direct CV Zustand
uint8_t ProgMode; //Direct CV Modus
byte ProgReadMode; //lese-Modus für Direct CV
byte RSTsRepeat; //Repeat for Reset start Packet
byte RSTcRepeat; //Repeat for Reset contingue Packet
void opsWriteCV(uint16_t CV, uint8_t CV_data); //Direct CV write
void opsVerifyCV(uint16_t CV, uint8_t CV_data); //Direct CV prüfen
void opsReadCV(uint16_t CV, uint8_t bitToRead, bool bitState = 1); //Direct CV lesen
bool opsDecoderReset(uint8_t repeat = RESET_CONT_REPEAT); //Decoder Reset Packet For all Decoders
uint8_t packet_counter; //to not repeat only one queue
DCCEmergencyQueue e_stop_queue; //for accessory and estop only - repeat between periodic!
DCCRepeatQueue repeat_queue; //send direct then add to periodic repeat!
//NEW
DCCTemporalQueue periodic_refresh_queue; //special - never stop repeating the paket!
DCCEmergencyQueue ops_programmming_queue; //NEW ops programming - repeat directly!
};
//DCCPacketScheduler packet_scheduler;
#if defined (__cplusplus)
extern "C" {
#endif
extern void notifyLokAll(uint16_t Adr, uint8_t Steps, uint8_t Speed, uint8_t F0, uint8_t F1, uint8_t F2, uint8_t F3) __attribute__((weak));
extern void notifyTrnt(uint16_t Adr, bool State, bool active) __attribute__((weak));
extern void notifyExtTrnt(uint16_t Adr, uint8_t) __attribute__((weak));
extern void notifyCVVerify(uint16_t CV, uint8_t value) __attribute__((weak));
extern void notifyCVPOMRead(uint16_t CVAdr, uint8_t value) __attribute__((weak));
extern void notifyRailpower(uint8_t state) __attribute__((weak));
extern uint16_t notifyCurrentSense(void) __attribute__((weak)); //request the CurrentSense value
extern void notifyCVNack(uint16_t CV) __attribute__((weak)); //no ACK while programming
#if defined (__cplusplus)
}
#endif
#endif //__DCC_COMMANDSTATION_H__

Datei anzeigen

@ -0,0 +1,123 @@
/****************************************************************************
* Copyright (C) 2016-2022 Philipp Gahtow
*
* DCC Waveform Timer Configuration
*
* DCC Master Interface can generate DCC Signal
* either with Timer1 (16-bit) or with Timer2 (8-bit) by default!
* for ARM on Arduino DUE with TC3 = Timer4 (TC1 Channel 0)
* for ESP8266 with Timer1
* for ESP32 with Timer1
****************************************************************************/
#define PREAMBLE_LENGTH 16 //1's for the preamble (NMRA mind. 10x, normal: 12x plus RailCom cutout)
#define ADD_LONG_PREAMBLE_LENGTH 8 //additional length for Service Mode Packet
#define RAILCOM_CUTOUT_LENGTH 4 //length the preamble will be cut out when railcom data will transmit
//--------------------------------------------------------------------------------------
/*
NEM 670 Ausgabe 2013:
Dauer des Teil-Einsbits: t = 58 µs & zulässige Toleranzen +/- 3 µs am Gleis
Dauer des Teil-Nullbits: t 100 µs, normal: 116µs
*/
/******************************************/
#if defined(__AVR__)
//CONTROL What Timer we should use:
//#define DCC_USE_TIMER1 //USE 16-bit TIMER1
#undef DCC_USE_TIMER1 //USE 8-bit TIMER2
#endif
/******************************************/
//DCC truth table:
//OFF:
#if defined(__AVR__)
#define DCC_OUTPUT1_OFF() {*d1reg &= ~d1bit;} //LOW
#endif
#define DCC_OUTPUT1_OFF_legacy LOW
#if defined(__AVR__)
#define DCC_OUTPUT2_OFF() {*d2reg &= ~d2bit;} //LOW
#endif
#define DCC_OUTPUT2_OFF_legacy LOW
//RailCom:
#if defined(__AVR__)
#define DCC_OUTPUT1_RC() {*d1reg &= ~d1bit;} //LOW
#endif
#define DCC_OUTPUT1_RC_legacy LOW
#if defined(__AVR__)
#define DCC_OUTPUT2_RC() {*d2reg &= ~d2bit;} //LOW
#endif
#define DCC_OUTPUT2_RC_legacy LOW
//DCC LOW:
#if defined(__AVR__)
#define DCC_OUTPUT1_LOW() {*d1reg &= ~d1bit;} //LOW
#endif
#define DCC_OUTPUT1_LOW_legacy LOW
#if defined(__AVR__)
#define DCC_OUTPUT2_LOW() {*d2reg |= d2bit;} //HIGH
#endif
#define DCC_OUTPUT2_LOW_legacy HIGH
//DCC HIGH:
#if defined(__AVR__)
#define DCC_OUTPUT1_HIGH() {*d1reg |= d1bit;} //HIGH
#endif
#define DCC_OUTPUT1_HIGH_legacy HIGH
#if defined(__AVR__)
#define DCC_OUTPUT2_HIGH() {*d2reg &= ~d2bit;} //LOW
#endif
#define DCC_OUTPUT2_HIGH_legacy LOW
/******************************************/
//USE the Timer1 for the DCC Signal generation on AVR
#if defined(DCC_USE_TIMER1)
#undef DCC_USE_TIMER2
#define half_one_count 57 //29usec pulse
#define one_count 115 //58us = 115
#define zero_high_count 199 //100us = 199 !old: 116us = 228
#define zero_low_count 199 //100us
#define DCC_TMR_SIGNAL TIMER1_COMPA_vect
#define DCC_INIT_COMPARATOR TCCR1A
#define DCC_TMR_CONTROL_REG TCCR1B
//turn on CTC mode in WGM12 and set CS11 for 8 prescaler in TCCR1B
#define DCC_TMR_CONTROL_SET() {DCC_TMR_CONTROL_REG = 1 << WGM12 | 1 << CS11;}
#define DCC_TMR_COUNT_REG TCNT1
#define DCC_TMR_MATCH_INT() {TIMSK1 |= (1 << OCIE1A);} //Compare Match Interrupt Enable
#define DCC_TMR_OUTP_CAPT_REG OCR1A
#define DCC_TMR_OUTP_ONE_HALF() {OCR1A = OCR1B = half_one_count;}
#define DCC_TMR_OUTP_ONE_COUNT() {OCR1A = OCR1B = one_count;}
#define DCC_TMR_OUTP_ZERO_HIGH() {OCR1A = OCR1B = zero_high_count;}
#define DCC_TMR_OUTP_ZERO_LOW() {OCR1A = OCR1B = zero_low_count;}
/******************************************/
//USE the Timer2 for the DCC Signal generation on AVR
#else
#define DCC_USE_TIMER2
#define half_one_count 198 //29usec pulse
#define one_count 141 //58usec pulse length = 141 = 0x8D
#define zero_high_count 56 //100us = 56 !old: 116us = 0x1B (27) pulse length
#define zero_low_count 56 //100us
#define DCC_TMR_SIGNAL TIMER2_OVF_vect
#define DCC_INIT_COMPARATOR TCCR2A
#define DCC_TMR_CONTROL_REG TCCR2B
//Timer2 Settings: Timer Prescaler /8, mode 0
//Timmer clock = 16MHz/8 = 2MHz oder 0,5usec
#define DCC_TMR_CONTROL_SET() {DCC_TMR_CONTROL_REG = 0 << CS22 | 1 << CS21 | 0 << CS20;}
#define DCC_TMR_COUNT_REG TCNT2
#define DCC_TMR_MATCH_INT() {TIMSK2 = 1 << TOIE2;} //Overflow Interrupt Enable
//note that there is a latency so take the last time of Timer2 also:
#define DCC_TMR_OUTP_ONE_HALF() {DCC_TMR_COUNT_REG = DCC_TMR_COUNT_REG + half_one_count; last_timer = half_one_count;}
#define DCC_TMR_OUTP_ONE_COUNT() {DCC_TMR_COUNT_REG = DCC_TMR_COUNT_REG + one_count; last_timer = one_count;}
#define DCC_TMR_OUTP_ZERO_HIGH() {DCC_TMR_COUNT_REG = DCC_TMR_COUNT_REG + zero_high_count; last_timer = zero_high_count;}
#define DCC_TMR_OUTP_ZERO_LOW() {DCC_TMR_COUNT_REG = DCC_TMR_COUNT_REG + zero_low_count; last_timer = zero_low_count;}
/******************************************/
#endif

Datei anzeigen

@ -0,0 +1,33 @@
DCC Interface Master (C) Philipp Gahtow
base on CmdrArduino
This library create a DCC Signal with RailCom (optional). It can handle two DCC outputs, one with Power feature and
one permanent for driving LocoNet Railsync or S88N Raildata line.
More about the features: http://pgahtow.de/wiki/index.php?title=DCC#Arduino_DCC_Library
I build up the library to use it with the Arduino Z21pg central station: http://pgahtow.de/wiki/index.php?title=Zentrale
===========
modified by Philipp Gahtow 2015-2021 digitalmoba@arcor.de
* - add a store for active loco, so you can request the actual state
* - add a store for BasicAccessory states
* - add a repeat queue for Speed and Function packets
* - add Function support F13-F20 and F21-F28
* - add CV POM Messages
* - add BasicAccessory increment 4x (Intellibox - ROCO)
* - add request for state of Loco funktion F0 - F28
* - support DCC generation with Timer1 or Timer2
* - add notify of BasicAccessory even when power is off
* - change praeambel to 16 Bit for Railcom support
* - add Railcom hardware support
* - optimize Railcom signal timing
* - fix bug on ESP32 (https://github.com/crosstool-ng/crosstool-ng/issues/1330)
* - fix DCC ACK Detection
* - fix DCC Timing on ESP8266 and ESP32
* - fix bug with ACK Detection
===========
To install, see the general instructions for Arduino library installation here:
http://arduino.cc/en/Guide/Environment#libraries

Binäre Datei nicht angezeigt.

Nachher

Breite:  |  Höhe:  |  Größe: 8.6 KiB

Datei anzeigen

@ -0,0 +1,50 @@
/********************
* modified by Philipp Gahtow 2015 digitalmoba@arcor.de
*
* Creates a minimum DCC command station that flips a turnout open and closed.
* The DCC waveform is output on Pin define in Setup, and is suitable for connection to an LMD18200-based booster directly,
* or to a single-ended-to-differential driver, to connect with most other kinds of boosters.
********************/
#include <DCCPacketScheduler.h>
#define SwitchFormat IB //ROCO (+4) or IB (+0)
#define DCCPin 6
#define NDCCPin 0
DCCPacketScheduler dps;
byte prev_state = 1;
unsigned long timer = 0;
unsigned int address = 4; //this address is not, strictly speaking, the accessory decoder address, but the address as it appears to the user
void setup() {
Serial.begin(115200);
dps.setup(DCCPin,NDCCPin,DCC128,SwitchFormat); //with Railcom
dps.setpower(true);
//set up button on pin 4
pinMode(4, OUTPUT);
digitalWrite(4, HIGH); //activate built-in pull-up resistor
}
void loop() {
if(millis() - timer > 1000) //only do this one per seconds
{
Serial.print(address);
if(prev_state)
{
dps.setBasicAccessoryPos(address, 1, true);
Serial.println(" - on");
}
else
{
dps.setBasicAccessoryPos(address, 0, true);
Serial.println(" - off");
}
prev_state = prev_state?0:1;
timer = millis();
}
dps.update();
}

Datei anzeigen

@ -0,0 +1,61 @@
/********************
* modified by Philipp Gahtow 2015 digitalmoba@arcor.de
*
* Creates a minimum DCC command station that flips a turnout open and closed.
* The DCC waveform is output on Pin define in Setup, and is suitable for connection to an LMD18200-based booster directly,
* or to a single-ended-to-differential driver, to connect with most other kinds of boosters.
********************/
#include <DCCPacketScheduler.h>
#define SwitchFormat IB //ROCO (+4) or IB (+0)
#define DCCPin 6 //(Pin 6) for DCC sginal out
#define NDCCPin 0
DCCPacketScheduler dps;
byte prev_state = 1; //Intellibox red = 0 or green = 1
byte activ_state = 0;
unsigned long timer = 0;
unsigned int address = 4; //this address is not, strictly speaking, the accessory decoder address, but the address as it appears to the user
#define flip_time 1000 //flip time in ms
void setup() {
Serial.begin(115200);
dps.setup(DCCPin,NDCCPin,DCC128,ROCO); //with Railcom
dps.setpower(true); //switch power ON
}
void loop() {
if((millis() - timer) > flip_time) //only do this one per seconds
{ //switch active - Button goes down
Serial.print(address);
activ_state = true; //save state - is active now!
if(prev_state) //get switch state (red/green)?
{
dps.setBasicAccessoryPos(address, 1,activ_state); //turn
Serial.print(" - left");
}
else
{
dps.setBasicAccessoryPos(address, 0, activ_state); //staight
Serial.print(" - right");
}
timer = millis(); //save last time
}
if(((millis() - timer) > 200) && (activ_state == true)) //only do this after 200ms
{ //the button goes Up now
activ_state = false; //set state inactive
Serial.println(" - off");
if(prev_state)
dps.setBasicAccessoryPos(address, 1, activ_state);
else
dps.setBasicAccessoryPos(address, 0, activ_state);
prev_state = !prev_state; //change state now - we are ready
}
dps.update(); //do this all the time to update dcc!
}

Datei anzeigen

@ -0,0 +1,77 @@
/********************
* Creates a minimum DCC command station
********************/
//#include <DCCPacket.h>
//#include <DCCPacketQueue.h>
#include <DCCPacketScheduler.h>
#define DCCPin 6 //Pin for DCC sginal out
#define ShortPin 41 //Pin to detect Short Circuit
#define NDCCPin 39
const int DetectShortCircuit = 15; //ms to detect short circuit
DCCPacketScheduler dps;
char speed_byte, old_speed = 0;
byte count = 0;
byte prev_state = 1;
byte F0 = 1;
unsigned long previousMillis = 0; // will store last updated - rail ok
unsigned long lastMillis = 0;
void setup() {
Serial.begin(115200);
dps.setup(DCCPin,NDCCPin,true,ROCO); //with Railcom
pinMode(ShortPin, INPUT); //set short pin
digitalWrite(ShortPin, HIGH); //Pull-UP
Serial.print("Power: ");
Serial.println(dps.getpower());
delay(3000);
dps.setpower(0x00);
Serial.print("Power: ");
Serial.println(dps.getpower());
dps.setSpeed128(3,0);
}
void loop() {
unsigned long cMillis = millis();
if (cMillis - lastMillis >= 1000) {
lastMillis = cMillis;
if (count % 5 == 0) {
//toggle!
F0 ^= 1;
Serial.print("SET A29, F0: ");
Serial.println(F0,BIN);
dps.setLocoFunc(29,F0,0);
dps.setBasicAccessoryPos(1,F0, true); //Adr, Status(straight, turnout), activ
dps.setBasicAccessoryPos(4,F0, true);
}
//handle reading throttle
++count;
// Serial.print("SET A22, Speed: ");
// Serial.println(count);
// dps.setSpeed128(22,count);
if (count > 127)
count = 0;
}
//ShortDetection(); //handel short on rail => power off
dps.update();
}
void ShortDetection() {
unsigned long currentMillis = millis();
if (digitalRead(ShortPin) == HIGH) { //Short Circuit!
// if(currentMillis - previousMillis >= DetectShortCircuit) {
if (dps.getpower() == true) {
Serial.println("Short Circuit");
dps.setpower(false);
}
}
else previousMillis = currentMillis;
}

Datei anzeigen

@ -0,0 +1,105 @@
/********************
* Creates a minimum DCC command station
********************/
#include <DCCPacketScheduler.h>
#define DEBUG Serial
#define POWER //Switch the RailPower ON and OFF!
#if defined(__arm__) && defined(DEBUG)
#define DEBUG Serial //SerialUSB for SAM
#endif
#define DCCPin 6 //(Pin 6) for DCC sginal out
#define ShortPin 41 //(Pin 41) to detect Short Circuit
#define NDCCPin 39 //(Pin 39)
const int DetectShortCircuit = 15; //ms to detect short circuit
DCCPacketScheduler dps;
char speed_byte, old_speed = 0;
byte count = 0;
byte prev_state = 1;
byte F0 = 1;
unsigned long previousMillis = 0; // will store last updated - rail ok
unsigned long lastMillis = 0;
void setup() {
DEBUG.begin(115200);
dps.setup(DCCPin,NDCCPin,DCC128,ROCO); //with Railcom
dps.enable_additional_DCC_output(11);
dps.setCurrentLoadPin(A0);
dps.setRailcom(true);
pinMode(ShortPin, INPUT); //set short pin
digitalWrite(ShortPin, HIGH); //Pull-UP
DEBUG.print("Power: ");
DEBUG.println(dps.getPower());
delay(3000);
dps.setPower(0x00);
DEBUG.print("Power: ");
DEBUG.println(dps.getPower());
dps.setSpeed128(15,B10000000);
}
void loop() {
dps.update();
//delay(100);
unsigned long cMillis = millis();
if (cMillis - lastMillis >= 500) {
lastMillis = cMillis;
if (count % 5 == 0) {
if (count % 10 == 0) {
//toggle!
F0 ^= 1;
DEBUG.print("SET A15, F0: ");
DEBUG.println(F0,BIN);
dps.setLocoFunc(3,F0,0);
}
}
#if defined(POWER)
if (count % 25 == 0) {
if (dps.getPower() == 0) {
dps.setPower(2); //off
}
else dps.setPower(0); //on
DEBUG.print("Power: ");
DEBUG.println(dps.getPower());
}
#endif
++count;
/*
DEBUG.print("SET A6221, Speed: ");
DEBUG.println(count);
dps.setSpeed128(6221,count);
if (count > 127)
count = 0;
*/
}
//ShortDetection(); //handel short on rail => power off
}
void ShortDetection() {
unsigned long currentMillis = millis();
if (digitalRead(ShortPin) == HIGH) { //Short Circuit!
// if(currentMillis - previousMillis >= DetectShortCircuit) {
if (dps.getPower() == true) {
DEBUG.println("Short Circuit");
dps.setPower(false);
}
}
else previousMillis = currentMillis;
}

Datei anzeigen

@ -0,0 +1,112 @@
/********************
* Creates a minimum DCC command station
********************/
#include <DCCPacketScheduler.h>
#define DEBUG Serial
#define POWER //Switch the RailPower ON and OFF!
#if defined(__arm__) && defined(DEBUG)
#define DEBUG Serial //SerialUSB for SAM
#endif
#define DCCPin 2 //(Pin 6) for DCC sginal out
#define ShortPin 41 //(Pin 41) to detect Short Circuit
#define NDCCPin 33 //(Pin 39)
const int DetectShortCircuit = 15; //ms to detect short circuit
DCCPacketScheduler dps;
char speed_byte, old_speed = 0;
byte count = 0;
byte prev_state = 1;
byte F0 = 1;
unsigned long previousMillis = 0; // will store last updated - rail ok
unsigned long lastMillis = 0;
void setup() {
DEBUG.begin(115200);
pinMode(DCCPin, OUTPUT);
digitalWrite(DCCPin, HIGH);
DEBUG.println("INIT");
delay(3000);
DEBUG.println("Start");
dps.setup(DCCPin,NDCCPin,DCC128,ROCO); //with Railcom
delay(2000);
dps.enable_additional_DCC_output(11);
dps.setCurrentLoadPin(A0);
dps.setrailcom(true);
pinMode(ShortPin, INPUT); //set short pin
digitalWrite(ShortPin, HIGH); //Pull-UP
DEBUG.print("Power: ");
DEBUG.println(dps.getpower());
delay(3000);
//dps.setpower(0x00);
DEBUG.print("Power: ");
DEBUG.println(dps.getpower());
dps.setSpeed128(15,B10000000);
}
void loop() {
dps.update();
//delay(100);
unsigned long cMillis = millis();
if (cMillis - lastMillis >= 500) {
lastMillis = cMillis;
if (count % 5 == 0) {
if (count % 10 == 0) {
//toggle!
F0 ^= 1;
DEBUG.print("SET A15, F0: ");
DEBUG.println(F0,BIN);
dps.setLocoFunc(3,F0,0);
}
}
#if defined(POWER)
if (count % 25 == 0) {
if (dps.getpower() == 0) {
dps.setpower(2); //off
}
else dps.setpower(0); //on
DEBUG.print("Power: ");
DEBUG.println(dps.getpower());
}
#endif
++count;
/*
DEBUG.print("SET A6221, Speed: ");
DEBUG.println(count);
dps.setSpeed128(6221,count);
if (count > 127)
count = 0;
*/
}
//ShortDetection(); //handel short on rail => power off
}
void ShortDetection() {
unsigned long currentMillis = millis();
if (digitalRead(ShortPin) == HIGH) { //Short Circuit!
// if(currentMillis - previousMillis >= DetectShortCircuit) {
if (dps.getpower() == true) {
DEBUG.println("Short Circuit");
dps.setpower(false);
}
}
else previousMillis = currentMillis;
}

Datei anzeigen

@ -0,0 +1,254 @@
// 23. November 2009
// works well with LMD18200 Booster !!!!!
// http://www.oscale.net/?q=book/export/html/117
/*Copyright (C) 2009 Michael Blank
This program is free software; you can redistribute it and/or modify it under the terms of the
GNU General Public License as published by the Free Software Foundation;
either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
*/
#define DCC_PIN 4 // Arduino pin for DCC out
// this pin is connected to "DIRECTION" of LMD18200
#define DCC_PWM 5 // must be HIGH for signal out
// connected to "PWM in" of LMD18200
#define DCC_THERM 7 // thermal warning PIN
#define AN_SPEED 2 // analog reading for Speed Poti
#define AN_CURRENT 0 // analog input for current sense reading
//Timer frequency is 2MHz for ( /8 prescale from 16MHz )
#define TIMER_SHORT 0x8D // 58usec pulse length
#define TIMER_LONG 0x1B // 116usec pulse length
unsigned char last_timer=TIMER_SHORT; // store last timer value
unsigned char flag=0; // used for short or long pulse
unsigned char every_second_isr = 0; // pulse up or down
// definitions for state machine
#define PREAMBLE 0
#define SEPERATOR 1
#define SENDBYTE 2
unsigned char state= PREAMBLE;
unsigned char preamble_count = 16;
unsigned char outbyte = 0;
unsigned char cbit = 0x80;
// variables for throttle
int locoSpeed=0;
int dir;
int last_locoSpeed=0;
int last_dir;
int dirPin = 12;
int FPin[] = { 8,9,10,11};
int maxF =3;
int locoAdr=40; // this is the (fixed) address of the loco
// buffer for command
struct Message {
unsigned char data[7];
unsigned char len;
} ;
#define MAXMSG 2
// for the time being, use only two messages - the idle msg and the loco Speed msg
struct Message msg[MAXMSG] = {
{ { 0xFF, 0, 0xFF, 0, 0, 0, 0}, 3}, // idle msg
{ { locoAdr, 0x3F, 0, 0, 0, 0, 0}, 4} // locoMsg with 128 speed steps
}; // loco msg must be filled later with speed and XOR data byte
int msgIndex=0;
int byteIndex=0;
//Setup Timer2.
//Configures the 8-Bit Timer2 to generate an interrupt at the specified frequency.
//Returns the time load value which must be loaded into TCNT2 inside your ISR routine.
void SetupTimer2(){
//Timer2 Settings: Timer Prescaler /8, mode 0
//Timmer clock = 16MHz/8 = 2MHz oder 0,5usec
TCCR2A = 0;
TCCR2B = 0<<CS22 | 1<<CS21 | 0<<CS20;
//Timer2 Overflow Interrupt Enable
TIMSK2 = 1<<TOIE2;
//load the timer for its first cycle
TCNT2=TIMER_SHORT;
}
//Timer2 overflow interrupt vector handler
ISR(TIMER2_OVF_vect) {
//Capture the current timer value TCTN2. This is how much error we have
//due to interrupt latency and the work in this function
//Reload the timer and correct for latency.
// for more info, see http://www.uchobby.com/index.php/2007/11/24/arduino-interrupts/
unsigned char latency;
// for every second interupt just toggle signal
if (every_second_isr) {
digitalWrite(DCC_PIN,1);
every_second_isr = 0;
// set timer to last value
latency=TCNT2;
TCNT2=latency+last_timer;
} else { // != every second interrupt, advance bit or state
digitalWrite(DCC_PIN,0);
every_second_isr = 1;
switch(state) {
case PREAMBLE:
flag=1; // short pulse
preamble_count--;
if (preamble_count == 0) { // advance to next state
state = SEPERATOR;
// get next message
msgIndex++;
if (msgIndex >= MAXMSG) { msgIndex = 0; }
byteIndex = 0; //start msg with byte 0
}
break;
case SEPERATOR:
flag=0; // long pulse
// then advance to next state
state = SENDBYTE;
// goto next byte ...
cbit = 0x80; // send this bit next time first
outbyte = msg[msgIndex].data[byteIndex];
break;
case SENDBYTE:
if (outbyte & cbit) {
flag = 1; // send short pulse
} else {
flag = 0; // send long pulse
}
cbit = cbit >> 1;
if (cbit == 0) { // last bit sent, is there a next byte?
byteIndex++;
if (byteIndex >= msg[msgIndex].len) {
// this was already the XOR byte then advance to preamble
state = PREAMBLE;
preamble_count = 16;
} else {
// send separtor and advance to next byte
state = SEPERATOR ;
}
}
break;
}
if (flag) { // if data==1 then short pulse
latency=TCNT2;
TCNT2=latency+TIMER_SHORT;
last_timer=TIMER_SHORT;
} else { // long pulse
latency=TCNT2;
TCNT2=latency+TIMER_LONG;
last_timer=TIMER_LONG;
}
}
}
void setup(void) {
//Set the pins for DCC to "output".
pinMode(DCC_PIN,OUTPUT); // this is for the DCC Signal
pinMode(DCC_PWM,OUTPUT); // will be kept high, PWM pin
digitalWrite(DCC_PWM,1);
pinMode(DCC_THERM, INPUT);
digitalWrite(DCC_THERM,1); //enable pull up
pinMode(dirPin, INPUT);
digitalWrite(dirPin, 1); //enable pull-up resistor !!
for (int i=0 ; i<=maxF; i++){
pinMode(FPin[i], INPUT);
digitalWrite(FPin[i], 1); //enable pull-up resistor
}
read_locoSpeed_etc();
assemble_dcc_msg();
//Start the timer
SetupTimer2();
}
void loop(void) {
delay(200);
if (read_locoSpeed_etc()) {
// some reading changed
// make new dcc message
assemble_dcc_msg();
;
}
}
boolean read_locoSpeed_etc() {
boolean changed = false;
// read the analog input into a variable:
// limit range to 0..127
locoSpeed = (127L * analogRead(AN_SPEED))/1023;
if (locoSpeed != last_locoSpeed) {
changed = true;
last_locoSpeed = locoSpeed;
}
dir = digitalRead(dirPin);
if (dir != last_dir) {
changed = true;
last_dir = dir;
}
return changed;
}
void assemble_dcc_msg() {
int i;
unsigned char data, xdata;
if (locoSpeed == 1) { // this would result in emergency stop
locoSpeed = 0;
}
// direction info first
if (dir) { // forward
data = 0x80;
} else {
data = 0;
}
data |= locoSpeed;
// add XOR byte
xdata = (msg[1].data[0] ^ msg[1].data[1]) ^ data;
noInterrupts(); // make sure that only "matching" parts of the message are used in ISR
msg[1].data[2] = data;
msg[1].data[3] = xdata;
interrupts();
}

Datei anzeigen

@ -0,0 +1,210 @@
/*
* Creates a minimum DCC command station
*/
#include <EEPROM.h>
#include <p50x.h>
#include <DCCPacket.h>
#include <DCCPacketQueue.h>
#include <DCCPacketScheduler.h>
DCCPacketScheduler dcc;
p50xClass p50x;
// Pin 13 has an LED connected on most Arduino boards.
// give it a name:
int led = 13;
byte cts = 5; //CTS Pin des COM-Ports
long count = 0;
// the setup routine runs once when you press reset:
void setup() {
// initialize the digital pin as an output.
pinMode(led, OUTPUT);
pinMode(cts, OUTPUT);
digitalWrite(cts, LOW);
p50x.setup(57600); //Initialisierung P50x
dcc.setup(6); //DCC OUT PIN
}
// the loop routine runs over and over again forever:
void loop() {
p50x.receive();
dcc.update();
count++;
if (count > 10000) {
p50x.xLokStsUpdate(); //Update Informationen
count = 0;
}
}
void notifyRS232 (uint8_t State)
{
digitalWrite(led, State);
}
void notifyTrntRequest( uint16_t Address, uint8_t State, uint8_t Direction, uint8_t Lock )
{
dcc.setBasicAccessoryPos(Address, (Direction & 0x01));
/*
Serial.print("Switch Request: ");
Serial.print(Address, DEC);
Serial.print(':');
Serial.print(Direction ? "closed" : "thrown");
Serial.print(" - ");
Serial.print(State ? "ein" : "aus");
Serial.print(" - Locked: ");
Serial.println(Lock ? "On" : "Off");
*/
}
void notifyLokRequest( uint16_t Address, uint8_t Speed, uint8_t Direction, uint8_t F0)
{
int8_t spd = Speed;
bitWrite(spd, 7, Direction);
dcc.setSpeed(Address, spd, 128);
dcc.setFunctions0to4(Address,F0);
/*
Serial.print("XLok Request - Adr: ");
Serial.print(Address, DEC);
Serial.print(':');
Serial.print(Direction ? "vorwaerts" : "rueckwaerts");
Serial.print(" - Speed: ");
Serial.print(Speed, DEC);
Serial.print(" - lights=");
Serial.println(F0 ? "on" : "off");
*/
}
void notifyLokF1F4Request( uint16_t Address, uint8_t Function )
{
dcc.setFunctions0to4(Address, Function);
/*
Serial.print("Function Request - Adr: ");
Serial.print(Address, DEC);
Serial.print(", F4-F1: ");
Serial.println(Function, BIN);
*/
}
void notifyLokFuncRequest( uint16_t Address, uint8_t Function )
{
dcc.setFunctions0to4(Address,Function & 0x0F); //override F0 if active !!!
dcc.setFunctions5to8(Address,(Function & 0xF0) >> 4);
/*
Serial.print("Func Request - Adr: ");
Serial.print(Address, DEC);
Serial.print(", F8-F1: ");
Serial.println(Function, BIN);
*/
}
void notifyLokFunc2Request( uint16_t Address, uint8_t Function2 )
{
dcc.setFunctions9to12(Address,Function2);
/* Serial.print("Func Request - Adr: ");
Serial.print(Address, DEC);
Serial.print(", F16-F9: ");
Serial.println(Function2, BIN);
*/
}
void notifyLokFunc34Request( uint16_t Address, uint8_t Function3, uint8_t Function4 )
{
dcc.setFunctions13to20(Address,Function3);
dcc.setFunctions21to28(Address,Function4);
/*
Serial.print("Func Request - Adr: ");
Serial.print(Address, DEC);
Serial.print(", F24-F17: ");
Serial.print(Function3, BIN);
Serial.print(", F28-F25: ");
Serial.println(Function4, BIN);*/
}
void notifyPowerRequest (uint8_t Power) {
//Serial.println(Power ? "Power ON" : "Power OFF");
// if (Power == false)
// dcc.eStop();
dcc.setpower(Power);
}
//PoM Mode
void notifyXDCC_PDRRequest( uint16_t Address, uint16_t CVAddress ) {
/* Serial.print("XDCC_PDR PoM Request - Adr: ");
Serial.print(Address, DEC);
Serial.print(", CV: ");
Serial.println(CVAddress, DEC);*/
//p50x.ReturnPT(byte CV-Wert);
}
void notifyXDCC_PDRequest( uint16_t Address, uint16_t CVAddress, uint8_t Value ) {
dcc.opsProgramCV(Address, CVAddress, Value);
/*
Serial.print("XDCC_PDR PoM Request - Adr: ");
Serial.print(Address, DEC);
Serial.print(", CV: ");
Serial.print(CVAddress, DEC);
Serial.print(", Value: ");
Serial.println(Value, DEC);
*/
}
//Paged Mode
void notifyXPT_DCCRPRequest( uint16_t CVAddress ) { //lesen
/* Serial.print("Paged Mode Request - CVAdr: ");
Serial.println(CVAddress, DEC);*/
}
void notifyXPT_DCCWPRequest( uint16_t CVAddress, uint8_t Value ) { //schreiben
/* Serial.print("Paged Mode Request - CVAdr: ");
Serial.print(CVAddress, DEC);
Serial.print(", Value: ");
Serial.println(Value, DEC);*/
}
//Bit-Mode
void notifyXPT_DCCRBRequest( uint16_t CVAddress ) { //lesen
/* Serial.print("Bit-Mode Request - CVAdr: ");
Serial.println(CVAddress, DEC);*/
}
void notifyXPT_DCCWBRequest( uint16_t CVAddress, uint8_t Bit, uint8_t Value ) { //schreiben
/* Serial.print("Bit-Mode Request - CVAdr: ");
Serial.print(CVAddress, DEC);
Serial.print(", Value: ");
Serial.println(Value, DEC);*/
}
//Direct-Mode
void notifyXPT_DCCRDRequest( uint16_t CVAddress ) { //lesen
/* Serial.print("Direct-Mode Request - CVAdr: ");
Serial.println(CVAddress, DEC);*/
}
void notifyXPT_DCCWDRequest( uint16_t CVAddress, uint8_t Value ) { //schreiben
/* Serial.print("Direct-Mode Request - CVAdr: ");
Serial.print(CVAddress, DEC);
Serial.print(", Value: ");
Serial.println(Value, DEC);*/
}
//Programmierung Rückmelden
byte notifyXPT_TermRequest() {
return 0xF3; //no task is active
}

Binäre Datei nicht angezeigt.

Nachher

Breite:  |  Höhe:  |  Größe: 46 KiB

Binäre Datei nicht angezeigt.

Nachher

Breite:  |  Höhe:  |  Größe: 46 KiB

Binäre Datei nicht angezeigt.

Nachher

Breite:  |  Höhe:  |  Größe: 71 KiB

Binäre Datei nicht angezeigt.

Nachher

Breite:  |  Höhe:  |  Größe: 78 KiB

Binäre Datei nicht angezeigt.

Nachher

Breite:  |  Höhe:  |  Größe: 42 KiB

Datei anzeigen

@ -0,0 +1,57 @@
DCCPacketScheduler
DCCPacket KEYWORD1
DCCPacketQueue KEYWORD1
setDefaultSpeedSteps KEYWORD1
setup KEYWORD2
enable_additional_DCC_output KEYWORD2
disable_additional_DCC_output KEYWORD2
loadEEPROMconfig KEYWORD2
setpower KEYWORD2
getpower KEYWORD2
setCurrentLoadPin KEYWORD2
setrailcom KEYWORD2
getrailcom KEYWORD2
eStop KEYWORD2
setSpeed KEYWORD2
setSpeed14 KEYWORD2
setSpeed28 KEYWORD2
setSpeed128 KEYWORD2
getLocoDir KEYWORD2
getLocoSpeed KEYWORD2
getLocoStateFull KEYWORD2
setLocoFunc KEYWORD2
setLocoFuncBinary KEYWORD2
setFunctions0to4 KEYWORD2
setFunctions5to8 KEYWORD2
setFunctions9to12 KEYWORD2
setFunctions13to20 KEYWORD2
setFunctions21to28 KEYWORD2
setFunctions29to36 KEYWORD2
setFunctions37to44 KEYWORD2
setFunctions45to52 KEYWORD2
setFunctions53to60 KEYWORD2
setFunctions61to68 KEYWORD2
getFunktion0to4 KEYWORD2
getFunktion5to8 KEYWORD2
getFunktion9to12 KEYWORD2
getFunktion13to20 KEYWORD2
getFunktion21to28 KEYWORD2
getFunktion29to31 KEYWORD2
setBasicAccessoryPos KEYWORD2
getBasicAccessoryInfo KEYWORD2
setExtAccessoryPos KEYWORD2
opsProgDirectCV KEYWORD2
opsVerifyDirectCV KEYWORD2
opsReadDirectCV KEYWORD2
opsProgramCV KEYWORD2
opsPOMwriteBit KEYWORD2
opsPOMreadCV KEYWORD2
update KEYWORD2
notifyLokAll KEYWORD2
notifyTrnt KEYWORD2
notifyExtTrnt KEYWORD2
notifyCVVerify KEYWORD2
notifyCVPOMRead KEYWORD2
notifyRailpower KEYWORD2
notifyCurrentSense KEYWORD2
notifyCVNack KEYWORD2

Datei anzeigen

@ -0,0 +1,9 @@
name=DCCInterfaceMaster
version=6.4.0
author=Philipp Gahtow
maintainer=Philipp Gahtow <digitalmoba@arcor.de>
sentence=Enables NMRA DCC Communication
paragraph=This library allows you to generate a NMRA DCC signal, optional with Railcom and inverted DCC signal and CV-Direct read option.
category=Communication
url=http://pgahtow.de/wiki/index.php?title=DCC
architectures=avr,sam,esp32,esp8266

Binäre Datei nicht angezeigt.

Nachher

Breite:  |  Höhe:  |  Größe: 44 KiB

Datei anzeigen

@ -0,0 +1,10 @@
# Author: diplfranzhoepfinger
# reference: https://docs.espressif.com/projects/arduino-esp32/en/latest/esp-idf_component.html
# URL: https://github.com/milesburton/Arduino-Temperature-Control-Library
# DATE: 15.02.2023
idf_component_register(
SRCS "DallasTemperature.cpp"
INCLUDE_DIRS "."
PRIV_REQUIRES OneWire arduino
)

Datei anzeigen

@ -0,0 +1,809 @@
#include "DallasTemperature.h"
#if ARDUINO >= 100
#include "Arduino.h"
#else
extern "C" {
#include "WConstants.h"
}
#endif
// OneWire commands
#define STARTCONVO 0x44 // Tells device to take a temperature reading
#define COPYSCRATCH 0x48 // Copy scratchpad to EEPROM
#define READSCRATCH 0xBE // Read from scratchpad
#define WRITESCRATCH 0x4E // Write to scratchpad
#define RECALLSCRATCH 0xB8 // Recall from EEPROM to scratchpad
#define READPOWERSUPPLY 0xB4 // Determine if device needs parasite power
#define ALARMSEARCH 0xEC // Query bus for devices with an alarm condition
// Scratchpad locations
#define TEMP_LSB 0
#define TEMP_MSB 1
#define HIGH_ALARM_TEMP 2
#define LOW_ALARM_TEMP 3
#define CONFIGURATION 4
#define INTERNAL_BYTE 5
#define COUNT_REMAIN 6
#define COUNT_PER_C 7
#define SCRATCHPAD_CRC 8
// Device resolution
#define TEMP_9_BIT 0x1F
#define TEMP_10_BIT 0x3F
#define TEMP_11_BIT 0x5F
#define TEMP_12_BIT 0x7F
#define NO_ALARM_HANDLER ((AlarmHandler *)0)
// DSROM FIELDS
#define DSROM_FAMILY 0
#define DSROM_CRC 7
DallasTemperature::DallasTemperature() {
_wire = nullptr;
devices = 0;
ds18Count = 0;
parasite = false;
bitResolution = 9;
waitForConversion = true;
checkForConversion = true;
autoSaveScratchPad = true;
useExternalPullup = false;
#if REQUIRESALARMS
setAlarmHandler(NO_ALARM_HANDLER);
alarmSearchJunction = -1;
alarmSearchExhausted = 0;
#endif
}
DallasTemperature::DallasTemperature(OneWire* _oneWire) : DallasTemperature() {
setOneWire(_oneWire);
}
DallasTemperature::DallasTemperature(OneWire* _oneWire, uint8_t _pullupPin) : DallasTemperature(_oneWire) {
setPullupPin(_pullupPin);
}
void DallasTemperature::setOneWire(OneWire* _oneWire) {
_wire = _oneWire;
devices = 0;
ds18Count = 0;
parasite = false;
bitResolution = 9;
waitForConversion = true;
checkForConversion = true;
autoSaveScratchPad = true;
}
void DallasTemperature::setPullupPin(uint8_t _pullupPin) {
useExternalPullup = true;
pullupPin = _pullupPin;
pinMode(pullupPin, OUTPUT);
deactivateExternalPullup();
}
void DallasTemperature::begin(void) {
DeviceAddress deviceAddress;
for (uint8_t retry = 0; retry < MAX_INITIALIZATION_RETRIES; retry++) {
_wire->reset_search();
devices = 0;
ds18Count = 0;
delay(INITIALIZATION_DELAY_MS);
while (_wire->search(deviceAddress)) {
if (validAddress(deviceAddress)) {
devices++;
if (validFamily(deviceAddress)) {
ds18Count++;
if (!parasite && readPowerSupply(deviceAddress)) {
parasite = true;
}
uint8_t b = getResolution(deviceAddress);
if (b > bitResolution) {
bitResolution = b;
}
}
}
}
if (devices > 0) break;
}
}
void DallasTemperature::activateExternalPullup() {
if (useExternalPullup) digitalWrite(pullupPin, LOW);
}
void DallasTemperature::deactivateExternalPullup() {
if (useExternalPullup) digitalWrite(pullupPin, HIGH);
}
bool DallasTemperature::validFamily(const uint8_t* deviceAddress) {
switch (deviceAddress[0]) {
case DS18S20MODEL:
case DS18B20MODEL:
case DS1822MODEL:
case DS1825MODEL:
case DS28EA00MODEL:
return true;
default:
return false;
}
}
bool DallasTemperature::validAddress(const uint8_t* deviceAddress) {
return (_wire->crc8(const_cast<uint8_t*>(deviceAddress), 7) == deviceAddress[7]);
}
bool DallasTemperature::getAddress(uint8_t* deviceAddress, uint8_t index) {
if (index < devices) {
uint8_t depth = 0;
_wire->reset_search();
while (depth <= index && _wire->search(deviceAddress)) {
if (depth == index && validAddress(deviceAddress)) {
return true;
}
depth++;
}
}
return false;
}
uint8_t DallasTemperature::getDeviceCount(void) {
return devices;
}
uint8_t DallasTemperature::getDS18Count(void) {
return ds18Count;
}
bool DallasTemperature::isConnected(const uint8_t* deviceAddress) {
ScratchPad scratchPad;
return isConnected(deviceAddress, scratchPad);
}
bool DallasTemperature::isConnected(const uint8_t* deviceAddress, uint8_t* scratchPad) {
bool b = readScratchPad(deviceAddress, scratchPad);
return b && !isAllZeros(scratchPad) && (_wire->crc8(scratchPad, 8) == scratchPad[SCRATCHPAD_CRC]);
}
bool DallasTemperature::readPowerSupply(const uint8_t* deviceAddress) {
bool parasiteMode = false;
_wire->reset();
if (deviceAddress == nullptr) {
_wire->skip();
} else {
_wire->select(deviceAddress);
}
_wire->write(READPOWERSUPPLY);
if (_wire->read_bit() == 0) {
parasiteMode = true;
}
_wire->reset();
return parasiteMode;
}
bool DallasTemperature::isParasitePowerMode(void) {
return parasite;
}
bool DallasTemperature::isAllZeros(const uint8_t* const scratchPad, const size_t length) {
for (size_t i = 0; i < length; i++) {
if (scratchPad[i] != 0) return false;
}
return true;
}
bool DallasTemperature::readScratchPad(const uint8_t* deviceAddress, uint8_t* scratchPad) {
int b = _wire->reset();
if (b == 0) return false;
_wire->select(deviceAddress);
_wire->write(READSCRATCH);
for (uint8_t i = 0; i < 9; i++) {
scratchPad[i] = _wire->read();
}
b = _wire->reset();
return (b == 1);
}
void DallasTemperature::writeScratchPad(const uint8_t* deviceAddress, const uint8_t* scratchPad) {
_wire->reset();
_wire->select(deviceAddress);
_wire->write(WRITESCRATCH);
_wire->write(scratchPad[HIGH_ALARM_TEMP]); // high alarm temp
_wire->write(scratchPad[LOW_ALARM_TEMP]); // low alarm temp
// DS1820 and DS18S20 have no configuration register
if (deviceAddress[0] != DS18S20MODEL) {
_wire->write(scratchPad[CONFIGURATION]);
}
if (autoSaveScratchPad) {
saveScratchPad(deviceAddress);
} else {
_wire->reset();
}
}
bool DallasTemperature::saveScratchPad(const uint8_t* deviceAddress) {
if (_wire->reset() == 0) return false;
if (deviceAddress == nullptr)
_wire->skip();
else
_wire->select(deviceAddress);
_wire->write(COPYSCRATCH, parasite);
// Specification: NV Write Cycle Time is typically 2ms, max 10ms
// Waiting 20ms to allow for sensors that take longer in practice
if (!parasite) {
delay(20);
} else {
activateExternalPullup();
delay(20);
deactivateExternalPullup();
}
return (_wire->reset() == 1);
}
bool DallasTemperature::recallScratchPad(const uint8_t* deviceAddress) {
if (_wire->reset() == 0) return false;
if (deviceAddress == nullptr)
_wire->skip();
else
_wire->select(deviceAddress);
_wire->write(RECALLSCRATCH, parasite);
// Specification: Strong pullup only needed when writing to EEPROM
unsigned long start = millis();
while (_wire->read_bit() == 0) {
if (millis() - start > 20) return false;
yield();
}
return (_wire->reset() == 1);
}
int32_t DallasTemperature::getTemp(const uint8_t* deviceAddress, byte retryCount) {
ScratchPad scratchPad;
byte retries = 0;
while (retries++ <= retryCount) {
if (isConnected(deviceAddress, scratchPad)) {
return calculateTemperature(deviceAddress, scratchPad);
}
}
return DEVICE_DISCONNECTED_RAW;
}
float DallasTemperature::getTempC(const uint8_t* deviceAddress, byte retryCount) {
return rawToCelsius(getTemp(deviceAddress, retryCount));
}
float DallasTemperature::getTempF(const uint8_t* deviceAddress) {
return rawToFahrenheit(getTemp(deviceAddress));
}
float DallasTemperature::getTempCByIndex(uint8_t index) {
DeviceAddress deviceAddress;
if (!getAddress(deviceAddress, index)) {
return DEVICE_DISCONNECTED_C;
}
return getTempC((uint8_t*)deviceAddress);
}
float DallasTemperature::getTempFByIndex(uint8_t index) {
DeviceAddress deviceAddress;
if (!getAddress(deviceAddress, index)) {
return DEVICE_DISCONNECTED_F;
}
return getTempF((uint8_t*)deviceAddress);
}
void DallasTemperature::setResolution(uint8_t newResolution) {
bitResolution = constrain(newResolution, 9, 12);
DeviceAddress deviceAddress;
_wire->reset_search();
for (uint8_t i = 0; i < devices; i++) {
if (_wire->search(deviceAddress) && validAddress(deviceAddress)) {
setResolution(deviceAddress, bitResolution, true);
}
}
}
bool DallasTemperature::setResolution(const uint8_t* deviceAddress, uint8_t newResolution, bool skipGlobalBitResolutionCalculation) {
bool success = false;
if (deviceAddress[0] == DS18S20MODEL) {
success = true;
} else {
newResolution = constrain(newResolution, 9, 12);
uint8_t newValue = 0;
ScratchPad scratchPad;
if (isConnected(deviceAddress, scratchPad)) {
switch (newResolution) {
case 12: newValue = TEMP_12_BIT; break;
case 11: newValue = TEMP_11_BIT; break;
case 10: newValue = TEMP_10_BIT; break;
case 9:
default: newValue = TEMP_9_BIT; break;
}
if (scratchPad[CONFIGURATION] != newValue) {
scratchPad[CONFIGURATION] = newValue;
writeScratchPad(deviceAddress, scratchPad);
}
success = true;
}
}
if (!skipGlobalBitResolutionCalculation && success) {
bitResolution = newResolution;
if (devices > 1) {
DeviceAddress deviceAddr;
_wire->reset_search();
for (uint8_t i = 0; i < devices; i++) {
if (bitResolution == 12) break;
if (_wire->search(deviceAddr) && validAddress(deviceAddr)) {
uint8_t b = getResolution(deviceAddr);
if (b > bitResolution) bitResolution = b;
}
}
}
}
return success;
}
uint8_t DallasTemperature::getResolution() {
return bitResolution;
}
uint8_t DallasTemperature::getResolution(const uint8_t* deviceAddress) {
if (deviceAddress[0] == DS18S20MODEL) return 12;
ScratchPad scratchPad;
if (isConnected(deviceAddress, scratchPad)) {
if (deviceAddress[0] == DS1825MODEL && scratchPad[CONFIGURATION] & 0x80) {
return 12;
}
switch (scratchPad[CONFIGURATION]) {
case TEMP_12_BIT: return 12;
case TEMP_11_BIT: return 11;
case TEMP_10_BIT: return 10;
case TEMP_9_BIT: return 9;
}
}
return 0;
}
float DallasTemperature::toFahrenheit(float celsius) {
return (celsius * 1.8f) + 32.0f;
}
float DallasTemperature::toCelsius(float fahrenheit) {
return (fahrenheit - 32.0f) * 0.555555556f;
}
float DallasTemperature::rawToCelsius(int32_t raw) {
if (raw <= DEVICE_DISCONNECTED_RAW)
return DEVICE_DISCONNECTED_C;
return (float)raw * 0.0078125f; // 1/128
}
float DallasTemperature::rawToFahrenheit(int32_t raw) {
if (raw <= DEVICE_DISCONNECTED_RAW)
return DEVICE_DISCONNECTED_F;
return rawToCelsius(raw) * 1.8f + 32.0f;
}
int16_t DallasTemperature::celsiusToRaw(float celsius) {
return static_cast<int16_t>(celsius * 128.0f);
}
uint16_t DallasTemperature::millisToWaitForConversion(uint8_t bitResolution) {
switch (bitResolution) {
case 9: return 94;
case 10: return 188;
case 11: return 375;
default: return 750;
}
}
uint16_t DallasTemperature::millisToWaitForConversion() {
return millisToWaitForConversion(bitResolution);
}
void DallasTemperature::setWaitForConversion(bool flag) {
waitForConversion = flag;
}
bool DallasTemperature::getWaitForConversion() {
return waitForConversion;
}
void DallasTemperature::setCheckForConversion(bool flag) {
checkForConversion = flag;
}
bool DallasTemperature::getCheckForConversion() {
return checkForConversion;
}
bool DallasTemperature::isConversionComplete() {
uint8_t b = _wire->read_bit();
return (b == 1);
}
void DallasTemperature::setAutoSaveScratchPad(bool flag) {
autoSaveScratchPad = flag;
}
bool DallasTemperature::getAutoSaveScratchPad() {
return autoSaveScratchPad;
}
DallasTemperature::request_t DallasTemperature::requestTemperatures() {
request_t req = {};
req.result = true;
_wire->reset();
_wire->skip();
_wire->write(STARTCONVO, parasite);
req.timestamp = millis();
if (!waitForConversion) return req;
blockTillConversionComplete(bitResolution, req.timestamp);
return req;
}
DallasTemperature::request_t DallasTemperature::requestTemperaturesByAddress(const uint8_t* deviceAddress) {
request_t req = {};
uint8_t deviceBitResolution = getResolution(deviceAddress);
if (deviceBitResolution == 0) {
req.result = false;
return req;
}
_wire->reset();
_wire->select(deviceAddress);
_wire->write(STARTCONVO, parasite);
req.timestamp = millis();
req.result = true;
if (!waitForConversion) return req;
blockTillConversionComplete(deviceBitResolution, req.timestamp);
return req;
}
DallasTemperature::request_t DallasTemperature::requestTemperaturesByIndex(uint8_t index) {
DeviceAddress deviceAddress;
getAddress(deviceAddress, index);
return requestTemperaturesByAddress(deviceAddress);
}
void DallasTemperature::blockTillConversionComplete(uint8_t bitResolution) {
unsigned long start = millis();
blockTillConversionComplete(bitResolution, start);
}
void DallasTemperature::blockTillConversionComplete(uint8_t bitResolution, unsigned long start) {
if (checkForConversion && !parasite) {
while (!isConversionComplete() && ((unsigned long)(millis() - start) < (unsigned long)MAX_CONVERSION_TIMEOUT)) {
yield();
}
} else {
unsigned long delayInMillis = millisToWaitForConversion(bitResolution);
activateExternalPullup();
delay(delayInMillis);
deactivateExternalPullup();
}
}
void DallasTemperature::blockTillConversionComplete(uint8_t bitResolution, request_t req) {
if (req.result) {
blockTillConversionComplete(bitResolution, req.timestamp);
}
}
int32_t DallasTemperature::calculateTemperature(const uint8_t* deviceAddress, uint8_t* scratchPad) {
int32_t fpTemperature = 0;
// looking thru the spec sheets of all supported devices, bit 15 is always the signing bit
int32_t neg = 0x0;
if (scratchPad[TEMP_MSB] & 0x80)
neg = 0xFFF80000;
// detect MAX31850
if (deviceAddress[0] == DS1825MODEL && scratchPad[CONFIGURATION] & 0x80) {
if (scratchPad[TEMP_LSB] & 1) { // Fault Detected
if (scratchPad[HIGH_ALARM_TEMP] & 1) {
return DEVICE_FAULT_OPEN_RAW;
} else if (scratchPad[HIGH_ALARM_TEMP] >> 1 & 1) {
return DEVICE_FAULT_SHORTGND_RAW;
} else if (scratchPad[HIGH_ALARM_TEMP] >> 2 & 1) {
return DEVICE_FAULT_SHORTVDD_RAW;
} else {
return DEVICE_DISCONNECTED_RAW;
}
}
// We must mask out bit 1 (reserved) and 0 (fault) on TEMP_LSB
fpTemperature = (((int32_t)scratchPad[TEMP_MSB]) << 11)
| (((int32_t)scratchPad[TEMP_LSB] & 0xFC) << 3)
| neg;
} else {
fpTemperature = (((int16_t)scratchPad[TEMP_MSB]) << 11)
| (((int16_t)scratchPad[TEMP_LSB]) << 3)
| neg;
}
/*
DS1820 and DS18S20 have a 9-bit temperature register.
Resolutions greater than 9-bit can be calculated using the data from
the temperature, and COUNT REMAIN and COUNT PER °C registers in the
scratchpad. The resolution of the calculation depends on the model.
While the COUNT PER °C register is hard-wired to 16 (10h) in a
DS18S20, it changes with temperature in DS1820.
After reading the scratchpad, the TEMP_READ value is obtained by
truncating the 0.5°C bit (bit 0) from the temperature data. The
extended resolution temperature can then be calculated using the
following equation:
COUNT_PER_C - COUNT_REMAIN
TEMPERATURE = TEMP_READ - 0.25 + --------------------------
COUNT_PER_C
Hagai Shatz simplified this to integer arithmetic for a 12 bits
value for a DS18S20, and James Cameron added legacy DS1820 support.
See - http://myarduinotoy.blogspot.co.uk/2013/02/12bit-result-from-ds18s20.html
*/
if ((deviceAddress[DSROM_FAMILY] == DS18S20MODEL) && (scratchPad[COUNT_PER_C] != 0)) {
fpTemperature = (((fpTemperature & 0xfff0) << 3) - 32
+ (((scratchPad[COUNT_PER_C] - scratchPad[COUNT_REMAIN]) << 7)
/ scratchPad[COUNT_PER_C])) | neg;
}
return fpTemperature;
}
#if REQUIRESALARMS
void DallasTemperature::setAlarmHandler(const AlarmHandler* handler) {
_AlarmHandler = handler;
}
void DallasTemperature::setHighAlarmTemp(const uint8_t* deviceAddress, int8_t celsius) {
// make sure the alarm temperature is within the device's range
if (celsius > 125) celsius = 125;
else if (celsius < -55) celsius = -55;
ScratchPad scratchPad;
if (isConnected(deviceAddress, scratchPad)) {
scratchPad[HIGH_ALARM_TEMP] = (uint8_t)celsius;
writeScratchPad(deviceAddress, scratchPad);
}
}
void DallasTemperature::setLowAlarmTemp(const uint8_t* deviceAddress, int8_t celsius) {
// make sure the alarm temperature is within the device's range
if (celsius > 125) celsius = 125;
else if (celsius < -55) celsius = -55;
ScratchPad scratchPad;
if (isConnected(deviceAddress, scratchPad)) {
scratchPad[LOW_ALARM_TEMP] = (uint8_t)celsius;
writeScratchPad(deviceAddress, scratchPad);
}
}
int8_t DallasTemperature::getHighAlarmTemp(const uint8_t* deviceAddress) {
ScratchPad scratchPad;
if (isConnected(deviceAddress, scratchPad))
return (int8_t)scratchPad[HIGH_ALARM_TEMP];
return DEVICE_DISCONNECTED_C;
}
int8_t DallasTemperature::getLowAlarmTemp(const uint8_t* deviceAddress) {
ScratchPad scratchPad;
if (isConnected(deviceAddress, scratchPad))
return (int8_t)scratchPad[LOW_ALARM_TEMP];
return DEVICE_DISCONNECTED_C;
}
void DallasTemperature::resetAlarmSearch() {
alarmSearchJunction = -1;
alarmSearchExhausted = 0;
for (uint8_t i = 0; i < 7; i++) {
alarmSearchAddress[i] = 0;
}
}
bool DallasTemperature::alarmSearch(uint8_t* newAddr) {
uint8_t i;
int8_t lastJunction = -1;
uint8_t done = 1;
if (alarmSearchExhausted)
return false;
if (!_wire->reset())
return false;
_wire->write(ALARMSEARCH);
for (i = 0; i < 64; i++) {
uint8_t a = _wire->read_bit();
uint8_t nota = _wire->read_bit();
uint8_t ibyte = i / 8;
uint8_t ibit = 1 << (i & 7);
if (a && nota)
return false;
if (!a && !nota) {
if (i == alarmSearchJunction) {
a = 1;
alarmSearchJunction = lastJunction;
} else if (i < alarmSearchJunction) {
if (alarmSearchAddress[ibyte] & ibit) {
a = 1;
} else {
a = 0;
done = 0;
lastJunction = i;
}
} else {
a = 0;
alarmSearchJunction = i;
done = 0;
}
}
if (a)
alarmSearchAddress[ibyte] |= ibit;
else
alarmSearchAddress[ibyte] &= ~ibit;
_wire->write_bit(a);
}
if (done)
alarmSearchExhausted = 1;
for (i = 0; i < 8; i++)
newAddr[i] = alarmSearchAddress[i];
return true;
}
bool DallasTemperature::hasAlarm(const uint8_t* deviceAddress) {
ScratchPad scratchPad;
if (isConnected(deviceAddress, scratchPad)) {
int8_t temp = calculateTemperature(deviceAddress, scratchPad) >> 7;
return (temp <= (int8_t)scratchPad[LOW_ALARM_TEMP] ||
temp >= (int8_t)scratchPad[HIGH_ALARM_TEMP]);
}
return false;
}
bool DallasTemperature::hasAlarm(void) {
DeviceAddress deviceAddress;
resetAlarmSearch();
return alarmSearch(deviceAddress);
}
void DallasTemperature::processAlarms(void) {
if (!hasAlarmHandler())
return;
resetAlarmSearch();
DeviceAddress alarmAddr;
while (alarmSearch(alarmAddr)) {
if (validAddress(alarmAddr)) {
_AlarmHandler(alarmAddr);
}
}
}
bool DallasTemperature::hasAlarmHandler() {
return (_AlarmHandler != NO_ALARM_HANDLER);
}
#endif
#if REQUIRESNEW
void* DallasTemperature::operator new(unsigned int size) {
void* p = malloc(size);
memset(p, 0, size);
return p;
}
void DallasTemperature::operator delete(void* p) {
free(p);
}
#endif
bool DallasTemperature::verifyDeviceCount(void) {
uint8_t actualCount = 0;
float temp;
requestTemperatures();
do {
temp = getTempCByIndex(actualCount);
if (temp > DEVICE_DISCONNECTED_C) {
actualCount++;
}
} while (temp > DEVICE_DISCONNECTED_C && actualCount < 255);
if (actualCount > devices) {
devices = actualCount;
begin();
return true;
}
return false;
}
void DallasTemperature::setUserData(const uint8_t* deviceAddress, int16_t data) {
// return when stored value == new value
if (getUserData(deviceAddress) == data)
return;
ScratchPad scratchPad;
if (isConnected(deviceAddress, scratchPad)) {
scratchPad[HIGH_ALARM_TEMP] = data >> 8;
scratchPad[LOW_ALARM_TEMP] = data & 255;
writeScratchPad(deviceAddress, scratchPad);
}
}
void DallasTemperature::setUserDataByIndex(uint8_t deviceIndex, int16_t data) {
DeviceAddress deviceAddress;
if (getAddress(deviceAddress, deviceIndex)) {
setUserData((uint8_t*)deviceAddress, data);
}
}
int16_t DallasTemperature::getUserData(const uint8_t* deviceAddress) {
int16_t data = 0;
ScratchPad scratchPad;
if (isConnected(deviceAddress, scratchPad)) {
data = scratchPad[HIGH_ALARM_TEMP] << 8;
data += scratchPad[LOW_ALARM_TEMP];
}
return data;
}
int16_t DallasTemperature::getUserDataByIndex(uint8_t deviceIndex) {
DeviceAddress deviceAddress;
getAddress(deviceAddress, deviceIndex);
return getUserData((uint8_t*)deviceAddress);
}

Datei anzeigen

@ -0,0 +1,192 @@
#ifndef DallasTemperature_h
#define DallasTemperature_h
#define DALLASTEMPLIBVERSION "4.0.3"
// Configuration
#ifndef REQUIRESNEW
#define REQUIRESNEW false
#endif
#ifndef REQUIRESALARMS
#define REQUIRESALARMS true
#endif
// Includes
#include <inttypes.h>
#include <Arduino.h>
#ifdef __STM32F1__
#include <OneWireSTM.h>
#else
#include <OneWire.h>
#endif
// Constants for device models
#define DS18S20MODEL 0x10 // also DS1820
#define DS18B20MODEL 0x28 // also MAX31820
#define DS1822MODEL 0x22
#define DS1825MODEL 0x3B // also MAX31850
#define DS28EA00MODEL 0x42
// Error Codes
#define DEVICE_DISCONNECTED_C -127
#define DEVICE_DISCONNECTED_F -196.6
#define DEVICE_DISCONNECTED_RAW -7040
#define DEVICE_FAULT_OPEN_C -254
#define DEVICE_FAULT_OPEN_F -425.199982
#define DEVICE_FAULT_OPEN_RAW -32512
#define DEVICE_FAULT_SHORTGND_C -253
#define DEVICE_FAULT_SHORTGND_F -423.399994
#define DEVICE_FAULT_SHORTGND_RAW -32384
#define DEVICE_FAULT_SHORTVDD_C -252
#define DEVICE_FAULT_SHORTVDD_F -421.599976
#define DEVICE_FAULT_SHORTVDD_RAW -32256
// Configuration Constants
#define MAX_CONVERSION_TIMEOUT 750
#define MAX_INITIALIZATION_RETRIES 3
#define INITIALIZATION_DELAY_MS 50
typedef uint8_t DeviceAddress[8];
class DallasTemperature {
public:
struct request_t {
bool result;
unsigned long timestamp;
operator bool() { return result; }
};
// Constructors
DallasTemperature();
DallasTemperature(OneWire*);
DallasTemperature(OneWire*, uint8_t);
// Setup & Configuration
void setOneWire(OneWire*);
void setPullupPin(uint8_t);
void begin(void);
bool verifyDeviceCount(void);
// Device Information
uint8_t getDeviceCount(void);
uint8_t getDS18Count(void);
bool validAddress(const uint8_t*);
bool validFamily(const uint8_t* deviceAddress);
bool getAddress(uint8_t*, uint8_t);
bool isConnected(const uint8_t*);
bool isConnected(const uint8_t*, uint8_t*);
// Scratchpad Operations
bool readScratchPad(const uint8_t*, uint8_t*);
void writeScratchPad(const uint8_t*, const uint8_t*);
bool readPowerSupply(const uint8_t* deviceAddress = nullptr);
// Resolution Control
uint8_t getResolution();
void setResolution(uint8_t);
uint8_t getResolution(const uint8_t*);
bool setResolution(const uint8_t*, uint8_t, bool skipGlobalBitResolutionCalculation = false);
// Conversion Configuration
void setWaitForConversion(bool);
bool getWaitForConversion(void);
void setCheckForConversion(bool);
bool getCheckForConversion(void);
// Temperature Operations
request_t requestTemperatures(void);
request_t requestTemperaturesByAddress(const uint8_t*);
request_t requestTemperaturesByIndex(uint8_t);
int32_t getTemp(const uint8_t*, byte retryCount = 0);
float getTempC(const uint8_t*, byte retryCount = 0);
float getTempF(const uint8_t*);
float getTempCByIndex(uint8_t);
float getTempFByIndex(uint8_t);
// Conversion Status
bool isParasitePowerMode(void);
bool isConversionComplete(void);
static uint16_t millisToWaitForConversion(uint8_t);
uint16_t millisToWaitForConversion();
// EEPROM Operations
bool saveScratchPadByIndex(uint8_t);
bool saveScratchPad(const uint8_t* = nullptr);
bool recallScratchPadByIndex(uint8_t);
bool recallScratchPad(const uint8_t* = nullptr);
void setAutoSaveScratchPad(bool);
bool getAutoSaveScratchPad(void);
#if REQUIRESALARMS
typedef void AlarmHandler(const uint8_t*);
void setHighAlarmTemp(const uint8_t*, int8_t);
void setLowAlarmTemp(const uint8_t*, int8_t);
int8_t getHighAlarmTemp(const uint8_t*);
int8_t getLowAlarmTemp(const uint8_t*);
void resetAlarmSearch(void);
bool alarmSearch(uint8_t*);
bool hasAlarm(const uint8_t*);
bool hasAlarm(void);
void processAlarms(void);
void setAlarmHandler(const AlarmHandler*);
bool hasAlarmHandler();
#endif
// User Data Operations
void setUserData(const uint8_t*, int16_t);
void setUserDataByIndex(uint8_t, int16_t);
int16_t getUserData(const uint8_t*);
int16_t getUserDataByIndex(uint8_t);
// Temperature Conversion Utilities
static float toFahrenheit(float);
static float toCelsius(float);
static float rawToCelsius(int32_t);
static int16_t celsiusToRaw(float);
static float rawToFahrenheit(int32_t);
#if REQUIRESNEW
void* operator new(unsigned int);
void operator delete(void*);
#endif
// Conversion Completion Methods
void blockTillConversionComplete(uint8_t);
void blockTillConversionComplete(uint8_t, unsigned long);
void blockTillConversionComplete(uint8_t, request_t);
private:
typedef uint8_t ScratchPad[9];
// Internal State
bool parasite;
bool useExternalPullup;
uint8_t pullupPin;
uint8_t bitResolution;
bool waitForConversion;
bool checkForConversion;
bool autoSaveScratchPad;
uint8_t devices;
uint8_t ds18Count;
OneWire* _wire;
// Internal Methods
int32_t calculateTemperature(const uint8_t*, uint8_t*);
bool isAllZeros(const uint8_t* const scratchPad, const size_t length = 9);
void activateExternalPullup(void);
void deactivateExternalPullup(void);
#if REQUIRESALARMS
uint8_t alarmSearchAddress[8];
int8_t alarmSearchJunction;
uint8_t alarmSearchExhausted;
AlarmHandler* _AlarmHandler;
#endif
};
#endif // DallasTemperature_h

Datei anzeigen

@ -0,0 +1,10 @@
MIT License
Copyright (c) 2024 Miles Burton
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Datei anzeigen

@ -0,0 +1,123 @@
# 🌡️ Arduino Temperature Control Library
[![Arduino CI](https://github.com/milesburton/Arduino-Temperature-Control-Library/workflows/Arduino%20CI/badge.svg)](https://github.com/marketplace/actions/arduino_ci)
[![Arduino-lint](https://github.com/milesburton/Arduino-Temperature-Control-Library/actions/workflows/arduino-lint.yml/badge.svg)](https://github.com/RobTillaart/AS5600/actions/workflows/arduino-lint.yml)
[![JSON check](https://github.com/milesburton/Arduino-Temperature-Control-Library/actions/workflows/jsoncheck.yml/badge.svg)](https://github.com/RobTillaart/AS5600/actions/workflows/jsoncheck.yml)
[![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/milesburton/Arduino-Temperature-Control-Library/blob/master/LICENSE)
[![GitHub release](https://img.shields.io/github/release/milesburton/Arduino-Temperature-Control-Library.svg?maxAge=3600)](https://github.com/milesburton/Arduino-Temperature-Control-Library/releases)
A robust and feature-complete Arduino library for Maxim Temperature Integrated Circuits.
## 📌 Supported Devices
- DS18B20
- DS18S20 (⚠️ Known issues with this series)
- DS1822
- DS1820
- MAX31820
- MAX31850
## 🚀 Installation
### Using Arduino IDE Library Manager (Recommended)
1. Open Arduino IDE
2. Go to Tools > Manage Libraries...
3. Search for "DallasTemperature"
4. Click Install
5. Also install the required "OneWire" library by Paul Stoffregen using the same method
### Manual Installation
1. Download the latest release from [GitHub releases](https://github.com/milesburton/Arduino-Temperature-Control-Library/releases)
2. In Arduino IDE, go to Sketch > Include Library > Add .ZIP Library...
3. Select the downloaded ZIP file
4. Repeat steps 1-3 for the required "OneWire" library
## 📝 Basic Usage
1. **Hardware Setup**
- Connect a 4k7 kΩ pull-up resistor between the 1-Wire data line and 5V power. Note this applies to the Arduino platform, for ESP32 and 8266 you'll need to adjust the resistor value accordingly.
- For DS18B20: Ground pins 1 and 3 (the centre pin is the data line)
- For reliable readings, see pull-up requirements in the [DS18B20 datasheet](https://datasheets.maximintegrated.com/en/ds/DS18B20.pdf) (page 7)
2. **Code Example**
```cpp
#include <OneWire.h>
#include <DallasTemperature.h>
// Data wire is connected to GPIO 4
#define ONE_WIRE_BUS 4
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
void setup(void) {
Serial.begin(9600);
sensors.begin();
}
void loop(void) {
sensors.requestTemperatures();
delay(750);
float tempC = sensors.getTempCByIndex(0);
Serial.print("Temperature: ");
Serial.print(tempC);
Serial.println("°C");
delay(1000);
}
```
## 🛠️ Advanced Features
- Multiple sensors on the same bus
- Temperature conversion by address (`getTempC(address)` and `getTempF(address)`)
- Asynchronous mode (added in v3.7.0)
- Configurable resolution
### Configuration Options
You can slim down the code by defining the following at the top of DallasTemperature.h:
```cpp
#define REQUIRESNEW // Use if you want to minimise code size
#define REQUIRESALARMS // Use if you need alarm functionality
```
## 📚 Additional Documentation
Visit our [Wiki](https://www.milesburton.com/w/index.php/Dallas_Temperature_Control_Library) for detailed documentation.
## 🔧 Library Development
If you want to contribute to the library development:
### Using Dev Container
The project includes a development container configuration for VS Code that provides a consistent development environment.
1. **Prerequisites**
- Visual Studio Code
- Docker
- VS Code Remote - Containers extension
2. **Development Commands**
Within the dev container, use:
- `arduino-build` - Compile the library and examples
- `arduino-test` - Run the test suite
- `arduino-build-test` - Complete build and test process
> Note: Currently compiling against arduino:avr:uno environment
## ✨ Credits
- Original development by Miles Burton <mail@milesburton.com>
- Multiple sensor support by Tim Newsome <nuisance@casualhacker.net>
- Address-based temperature reading by Guil Barros [gfbarros@bappos.com]
- Async mode by Rob Tillaart [rob.tillaart@gmail.com]
## 📄 License
MIT License | Copyright (c) 2025 Miles Burton
Full license text available in [LICENSE](LICENSE) file.

Datei anzeigen

@ -0,0 +1,19 @@
board_manager:
additional_urls: []
daemon:
port: "50051"
directories:
data: $GITHUB_WORKSPACE/.arduino15
downloads: $GITHUB_WORKSPACE/.arduino15/staging
user: $GITHUB_WORKSPACE/libraries
library:
enable_unsafe_install: true
logging:
file: ""
format: text
level: info
metrics:
addr: :9090
enabled: true
sketch:
always_export_binaries: false

Datei anzeigen

@ -0,0 +1,66 @@
#!/bin/bash
# Set error handling
set -e
# Function to display usage
show_usage() {
echo "Usage: ./build.sh [option]"
echo "Options:"
echo " build - Only compile library and examples"
echo " test - Only compile and run tests"
echo " all - Build everything and run tests (default)"
}
# Function to compile for a specific board
compile_for_board() {
local fqbn=$1
local sketch=$2
echo "📦 Compiling $sketch for $fqbn..."
arduino-cli compile --fqbn $fqbn "$sketch" --library .
}
# Function to build library and examples
build() {
echo "🔨 Building library and examples..."
# Compile all examples
echo "🔍 Compiling examples..."
for example in examples/*/*.ino; do
if [ -f "$example" ]; then
echo "Building example: $example"
compile_for_board "arduino:avr:uno" "$example"
fi
done
}
# Function to run tests
run_tests() {
echo "🧪 Running tests..."
for test in test/*/*.ino; do
if [ -f "$test" ]; then
echo "Running test: $test"
compile_for_board "arduino:avr:uno" "$test"
fi
done
}
# Main execution
case "${1:-all}" in
"build")
build
;;
"test")
run_tests
;;
"all")
build
run_tests
;;
*)
show_usage
exit 1
;;
esac
echo "✅ Process completed!"

Einige Dateien werden nicht angezeigt, da zu viele Dateien in diesem Diff geändert wurden Mehr anzeigen