Init repository für Z21PG nach Ph. Gahtow
5
.gitignore
vendored
Normale Datei
@ -0,0 +1,5 @@
|
||||
**/logs
|
||||
ZIP
|
||||
CAD/Z21PG/Z21PG-backups
|
||||
CAD/Z21PG/fp-info-cache
|
||||
Documents
|
22388
CAD/Z21PG/3D-Models/CUI_DEVICES_UJ2-MIBH2-4-SMT.step
Normale Datei
120
CAD/Z21PG/Footprints/CUI_UJ2-MIBH2-4-SMT.kicad_mod
Normale Datei
@ -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
@ -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
@ -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
@ -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
23081
CAD/Z21PG/booster.kicad_sch
Normale Datei
28806
CAD/Z21PG/cpu.kicad_sch
Normale Datei
2430
CAD/Z21PG/docu.kicad_sch
Normale Datei
4624
CAD/Z21PG/power.kicad_sch
Normale Datei
3258
CAD/Z21PG/untitled.kicad_sch
Normale Datei
BIN
Datasheets/74AHC_AHCT244-191948.pdf
Normale Datei
BIN
Datasheets/DS_FT230X.pdf
Normale Datei
BIN
Datasheets/G2R.pdf
Normale Datei
BIN
Datasheets/Gehäuse 1455T1601.pdf
Normale Datei
BIN
Datasheets/Hammond Gehäuse.pdf
Normale Datei
BIN
Datasheets/IXDF604PI.pdf
Normale Datei
BIN
Datasheets/Infineon-BTS462T-DS-v01_01-EN.pdf
Normale Datei
BIN
Datasheets/Infineon-IFX007T-DS-v01_00-EN.pdf
Normale Datei
BIN
Datasheets/W5500_ds_v110e.pdf
Normale Datei
BIN
Datasheets/WIZ850io-Dateien/Jy_Q3d0PHUZzgJUDjtx-y.png
Normale Datei
Nachher Breite: | Höhe: | Größe: 54 KiB |
2
Datasheets/WIZ850io-Dateien/a.html
Normale Datei
@ -0,0 +1,2 @@
|
||||
<html><head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=UTF-8"></head><body></body></html>
|
96
Datasheets/WIZ850io-Dateien/analytics.js
Normale Datei
@ -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) { }
|
||||
}
|
||||
}
|
||||
})();
|
1
Datasheets/WIZ850io-Dateien/ch-plugin-web.js
Normale Datei
@ -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
2
Datasheets/WIZ850io-Dateien/main.eac8367f.js
Normale Datei
1
Datasheets/WIZ850io-Dateien/runtime~main.3d0e97ba.js
Normale Datei
Nachher Breite: | Höhe: | Größe: 41 KiB |
1
Datasheets/WIZ850io-Dateien/styles.547e05fd.css
Normale Datei
Nachher Breite: | Höhe: | Größe: 373 KiB |
3
Datasheets/WIZ850io-Dateien/wiz850io.html
Normale Datei
@ -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>
|
Nachher Breite: | Höhe: | Größe: 46 KiB |
Nachher Breite: | Höhe: | Größe: 397 KiB |
1
Datasheets/WIZ850io-Dateien/wiznet_logo.svg
Normale Datei
Nachher Breite: | Höhe: | Größe: 29 KiB |
135
Datasheets/WIZ850io.html
Normale Datei
BIN
Datasheets/arduino-mega2560-schematic.pdf
Normale Datei
BIN
Datasheets/ina180.pdf
Normale Datei
BIN
Datasheets/ina226.pdf
Normale Datei
BIN
Datasheets/sn74hc00.pdf
Normale Datei
BIN
Datasheets/tps281c30.pdf
Normale Datei
BIN
Datasheets/tsr1_datasheet.pdf
Normale Datei
BIN
Pictures/SOaIN.jpg
Normale Datei
Nachher Breite: | Höhe: | Größe: 129 KiB |
BIN
Pictures/w5500-breakout-pinout-.png
Normale Datei
Nachher Breite: | Höhe: | Größe: 51 KiB |
BIN
Pictures/wiz850io_dimension-6218f42df83dba3fc2ebceef2a08383b.png
Normale Datei
Nachher Breite: | Höhe: | Größe: 46 KiB |
BIN
Pictures/z21pg Original Schaltplan.jpg
Normale Datei
Nachher Breite: | Höhe: | Größe: 916 KiB |
6
README.md
Normale Datei
@ -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!
|
18
z21pg/Z21_Ethernet_DCC_Zentrale_v498/.theia/launch.json
Normale Datei
@ -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"
|
||||
}
|
||||
]
|
||||
}
|
78
z21pg/Z21_Ethernet_DCC_Zentrale_v498/CONFIG.h
Normale Datei
@ -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
|
132
z21pg/Z21_Ethernet_DCC_Zentrale_v498/DCCGlobal.h
Normale Datei
@ -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
|
||||
//--------------------------------------------------------------
|
206
z21pg/Z21_Ethernet_DCC_Zentrale_v498/LNHwSerial.h
Normale Datei
@ -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
|
1302
z21pg/Z21_Ethernet_DCC_Zentrale_v498/LNInterface.h
Normale Datei
58
z21pg/Z21_Ethernet_DCC_Zentrale_v498/MCU_config.h
Normale Datei
@ -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
|
531
z21pg/Z21_Ethernet_DCC_Zentrale_v498/OLEDdisplay.h
Normale Datei
@ -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
|
411
z21pg/Z21_Ethernet_DCC_Zentrale_v498/POWER.h
Normale Datei
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
323
z21pg/Z21_Ethernet_DCC_Zentrale_v498/Webpage.h
Normale Datei
@ -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
|
338
z21pg/Z21_Ethernet_DCC_Zentrale_v498/XBusInterface.h
Normale Datei
@ -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
|
104
z21pg/Z21_Ethernet_DCC_Zentrale_v498/Z21EEPROM.h
Normale Datei
@ -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
|
||||
}
|
||||
//--------------------------------------------------------------
|
459
z21pg/Z21_Ethernet_DCC_Zentrale_v498/Z21Include.h
Normale Datei
@ -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
|
||||
//--------------------------------------------------------------
|
782
z21pg/Z21_Ethernet_DCC_Zentrale_v498/Z21_Ethernet_DCC_Zentrale_v498.ino
Normale Datei
@ -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
|
||||
|
||||
}
|
||||
//--------------------------------------------------------------------------------------------
|
1454
z21pg/Z21_Ethernet_DCC_Zentrale_v498/Z21_LAN.h
Normale Datei
185
z21pg/Z21_Ethernet_DCC_Zentrale_v498/Z21_RailCom.h
Normale Datei
@ -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
|
34
z21pg/Z21_Ethernet_DCC_Zentrale_v498/Z21type.h
Normale Datei
@ -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
|
@ -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
|
||||
}
|
@ -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__
|
@ -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);
|
||||
}
|
@ -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__
|
@ -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;
|
||||
}
|
||||
|
@ -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__
|
@ -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__
|
@ -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
|
@ -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
|
Nachher Breite: | Höhe: | Größe: 8.6 KiB |
@ -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();
|
||||
}
|
@ -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!
|
||||
}
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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();
|
||||
|
||||
}
|
@ -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
|
||||
}
|
||||
|
Nachher Breite: | Höhe: | Größe: 46 KiB |
Nachher Breite: | Höhe: | Größe: 46 KiB |
Nachher Breite: | Höhe: | Größe: 71 KiB |
Nachher Breite: | Höhe: | Größe: 78 KiB |
Nachher Breite: | Höhe: | Größe: 42 KiB |
@ -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
|
@ -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
|
Nachher Breite: | Höhe: | Größe: 44 KiB |
@ -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
|
||||
)
|
@ -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);
|
||||
}
|
@ -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
|
@ -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.
|
||||
|
@ -0,0 +1,123 @@
|
||||
|
||||
# 🌡️ Arduino Temperature Control Library
|
||||
|
||||
[](https://github.com/marketplace/actions/arduino_ci)
|
||||
[](https://github.com/RobTillaart/AS5600/actions/workflows/arduino-lint.yml)
|
||||
[](https://github.com/RobTillaart/AS5600/actions/workflows/jsoncheck.yml)
|
||||
[](https://github.com/milesburton/Arduino-Temperature-Control-Library/blob/master/LICENSE)
|
||||
[](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.
|
@ -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
|
@ -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!"
|