Compare commits
	
		
			8 Commits
		
	
	
		
			a576c7b70c
			...
			eaf2ad4933
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| eaf2ad4933 | |||
| 9c2e039bf8 | |||
| 3d7e798310 | |||
| e8a93a600e | |||
| be53089726 | |||
| e85eef271b | |||
| cc93236b8e | |||
| 51b80f08a5 | 
@@ -12,6 +12,7 @@
 | 
				
			|||||||
  <script src="static/js/bootstrap.min.js"></script>
 | 
					  <script src="static/js/bootstrap.min.js"></script>
 | 
				
			||||||
  <script src="static/js/websocket.js"></script>
 | 
					  <script src="static/js/websocket.js"></script>
 | 
				
			||||||
  <script src="static/js/dtc_table.js"></script>
 | 
					  <script src="static/js/dtc_table.js"></script>
 | 
				
			||||||
 | 
					  <script src="static/js/script.js" type="text/javascript"></script>
 | 
				
			||||||
  <link rel="apple-touch-icon" sizes="180x180" href="static/img/apple-touch-icon.png">
 | 
					  <link rel="apple-touch-icon" sizes="180x180" href="static/img/apple-touch-icon.png">
 | 
				
			||||||
  <link rel="icon" type="image/png" sizes="32x32" href="static/img/favicon-32x32.png">
 | 
					  <link rel="icon" type="image/png" sizes="32x32" href="static/img/favicon-32x32.png">
 | 
				
			||||||
  <link rel="icon" type="image/png" sizes="16x16" href="static/img/favicon-16x16.png">
 | 
					  <link rel="icon" type="image/png" sizes="16x16" href="static/img/favicon-16x16.png">
 | 
				
			||||||
@@ -71,7 +72,7 @@
 | 
				
			|||||||
        <hr />
 | 
					        <hr />
 | 
				
			||||||
        <p>
 | 
					        <p>
 | 
				
			||||||
        <h4>aktueller Modus</h4>
 | 
					        <h4>aktueller Modus</h4>
 | 
				
			||||||
        <input class="form-control" type="text" placeholder="%SYSTEM_STATUS%" readonly>
 | 
					        <input class="form-control" type="text" id="SystemStatus" readonly>
 | 
				
			||||||
        </p>
 | 
					        </p>
 | 
				
			||||||
        <!-- Div Group current Mode -->
 | 
					        <!-- Div Group current Mode -->
 | 
				
			||||||
        <!-- Div Group DTC Table -->
 | 
					        <!-- Div Group DTC Table -->
 | 
				
			||||||
@@ -129,10 +130,10 @@
 | 
				
			|||||||
        <h4>Entlüftung</h4>
 | 
					        <h4>Entlüftung</h4>
 | 
				
			||||||
        <form action="post.htm" method="POST" class="form-horizontal">
 | 
					        <form action="post.htm" method="POST" class="form-horizontal">
 | 
				
			||||||
          <div class="form-group row">
 | 
					          <div class="form-group row">
 | 
				
			||||||
            <label for="purgepulse" class="control-label col-4">Entlüftung Dosierung</label>
 | 
					            <label for="BleedingPulses" class="control-label col-4">Entlüftung Dosierung</label>
 | 
				
			||||||
            <div class="col-8">
 | 
					            <div class="col-8">
 | 
				
			||||||
              <div class="input-group">
 | 
					              <div class="input-group">
 | 
				
			||||||
                <input id="purgepulse" name="purgepulse" value="%BLEEDING_PULSES%" type="text" class="form-control">
 | 
					                <input id="BleedingPulses" name="BleedingPulses" value="0" type="text" class="form-control">
 | 
				
			||||||
                <div class="input-group-append">
 | 
					                <div class="input-group-append">
 | 
				
			||||||
                  <span class="input-group-text">Pulse</span>
 | 
					                  <span class="input-group-text">Pulse</span>
 | 
				
			||||||
                </div>
 | 
					                </div>
 | 
				
			||||||
@@ -791,48 +792,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  <!-- Modal Dialog -->
 | 
					  <!-- Modal Dialog -->
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  <script>
 | 
					 | 
				
			||||||
    $('.navbar-nav>li>a').on('click', function () {
 | 
					 | 
				
			||||||
      $('.navbar-collapse').collapse('hide');
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    document.querySelector('.custom-file-input').addEventListener('change', function (e) {
 | 
					 | 
				
			||||||
      var fileName = document.getElementById("fw-update-file").files[0].name;
 | 
					 | 
				
			||||||
      var nextSibling = e.target.nextElementSibling
 | 
					 | 
				
			||||||
      nextSibling.innerText = fileName
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    $('table').on('click', 'tr[data-dtc]', function () {
 | 
					 | 
				
			||||||
      var dtc = $(this).data('dtc');
 | 
					 | 
				
			||||||
      var debugval = $(this).data('debugval');
 | 
					 | 
				
			||||||
      var modal = $('#dtcModal');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      getDescriptionForDTCNumber(dtc, function (error, title, description) {
 | 
					 | 
				
			||||||
        if (error)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
          console.error("Fehler beim Abrufen der Beschreibung:", error);
 | 
					 | 
				
			||||||
          modal.find('.modal-title').text("Fehler")
 | 
					 | 
				
			||||||
          modal.find('.dtc-desc').text("DTC-Beschreibung konnte nicht geladen werden")
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        else
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
          modal.find('.modal-title').text(title)
 | 
					 | 
				
			||||||
          modal.find('.dtc-desc').text(description)
 | 
					 | 
				
			||||||
          if (debugval > 0)
 | 
					 | 
				
			||||||
          {
 | 
					 | 
				
			||||||
            modal.find('.dtc-debugval').text("Debugvalue: " + debugval)
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
          else
 | 
					 | 
				
			||||||
          {
 | 
					 | 
				
			||||||
            modal.find('.dtc-debugval').remove()
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      });
 | 
					 | 
				
			||||||
      // Modal anzeigen
 | 
					 | 
				
			||||||
      modal.modal('show');
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  </script>
 | 
					 | 
				
			||||||
 
 | 
					 
 | 
				
			||||||
</body>
 | 
					</body>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,82 @@
 | 
				
			|||||||
const jsonFilePath = "static/dtc_table.json";
 | 
					const jsonFilePath = "static/dtc_table.json";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var dtcState = {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function processDTCNotifications(dtcArray) {
 | 
				
			||||||
 | 
					  for (var i = 0; i < dtcArray.length; i++) {
 | 
				
			||||||
 | 
					    var dtcInfo = dtcArray[i].split(",");
 | 
				
			||||||
 | 
					    var errorCode = dtcInfo[1];
 | 
				
			||||||
 | 
					    var activity = parseInt(dtcInfo[3]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (dtcState[errorCode]) {
 | 
				
			||||||
 | 
					      // Überprüfen, ob sich der Zustand von "previous" auf "active" geändert hat
 | 
				
			||||||
 | 
					      if (activity !== dtcState[errorCode]) {
 | 
				
			||||||
 | 
					        dtcState[errorCode] = activity;
 | 
				
			||||||
 | 
					        if (activity === 1) showDTCNotification(errorCode);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      // DTC ist neu, Zustand speichern und Benachrichtigung anzeigen
 | 
				
			||||||
 | 
					      dtcState[errorCode] = activity;
 | 
				
			||||||
 | 
					      showDTCNotification(errorCode);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function showDTCNotification(dtctext, severity) {
 | 
				
			||||||
 | 
					  // Überprüfen, ob der Browser die Notification API unterstützt
 | 
				
			||||||
 | 
					  if ("Notification" in window) {
 | 
				
			||||||
 | 
					    // Überprüfen, ob der Benutzer bereits Berechtigungen erteilt hat
 | 
				
			||||||
 | 
					    if (Notification.permission === "granted") {
 | 
				
			||||||
 | 
					      // Benachrichtigung anzeigen
 | 
				
			||||||
 | 
					      showNotification(dtctext, severity);
 | 
				
			||||||
 | 
					    } else if (Notification.permission !== "denied") {
 | 
				
			||||||
 | 
					      // Aufforderung zur Erlaubnis einholen
 | 
				
			||||||
 | 
					      Notification.requestPermission().then(function (permission) {
 | 
				
			||||||
 | 
					        if (permission === "granted") {
 | 
				
			||||||
 | 
					          // Benachrichtigung anzeigen
 | 
				
			||||||
 | 
					          showNotification(dtctext, severity);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					          // Der Benutzer hat die Berechtigung abgelehnt oder das Dialogfeld geschlossen
 | 
				
			||||||
 | 
					          console.log("Benachrichtigungsberechtigung wurde verweigert.");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      // Der Benutzer hat die Berechtigung bereits verweigert
 | 
				
			||||||
 | 
					      console.log("Benachrichtigungsberechtigung wurde bereits verweigert.");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Funktion zum Anzeigen der Benachrichtigung
 | 
				
			||||||
 | 
					function showNotification(dtctext, severity) {
 | 
				
			||||||
 | 
					  var severityIcon;
 | 
				
			||||||
 | 
					  switch (severity) {
 | 
				
			||||||
 | 
					    case 1:
 | 
				
			||||||
 | 
					      severityIcon = "static/img/info.png";
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    case 2:
 | 
				
			||||||
 | 
					      severityIcon = "static/img/warn.png";
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    case 3:
 | 
				
			||||||
 | 
					      severityIcon = "static/img/critical.png";
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					      severityIcon = "static/img/none.png";
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  var options = {
 | 
				
			||||||
 | 
					    body: dtctext,
 | 
				
			||||||
 | 
					    icon: severityIcon,
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  var notification = new Notification("KTM Chain Oiler DTC", options);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Optional: Handle Click-Event
 | 
				
			||||||
 | 
					  notification.onclick = function () {
 | 
				
			||||||
 | 
					    console.log("Benachrichtigung wurde angeklickt.");
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function getDescriptionForDTCNumber(number, callback) {
 | 
					function getDescriptionForDTCNumber(number, callback) {
 | 
				
			||||||
  fetch(jsonFilePath)
 | 
					  fetch(jsonFilePath)
 | 
				
			||||||
    .then((response) => response.json())
 | 
					    .then((response) => response.json())
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										37
									
								
								Software/data_src/static/js/script.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								Software/data_src/static/js/script.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,37 @@
 | 
				
			|||||||
 | 
					$(".navbar-nav>li>a").on("click", function () {
 | 
				
			||||||
 | 
					  $(".navbar-collapse").collapse("hide");
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					document
 | 
				
			||||||
 | 
					  .querySelector(".custom-file-input")
 | 
				
			||||||
 | 
					  .addEventListener("change", function (e) {
 | 
				
			||||||
 | 
					    var fileName = document.getElementById("fw-update-file").files[0].name;
 | 
				
			||||||
 | 
					    var nextSibling = e.target.nextElementSibling;
 | 
				
			||||||
 | 
					    nextSibling.innerText = fileName;
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$("table").on("click", "tr[data-dtc]", function () {
 | 
				
			||||||
 | 
					  var dtc = $(this).data("dtc");
 | 
				
			||||||
 | 
					  var debugval = $(this).data("debugval");
 | 
				
			||||||
 | 
					  var modal = $("#dtcModal");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  getDescriptionForDTCNumber(dtc, function (error, title, description) {
 | 
				
			||||||
 | 
					    if (error) {
 | 
				
			||||||
 | 
					      console.error("Fehler beim Abrufen der Beschreibung:", error);
 | 
				
			||||||
 | 
					      modal.find(".modal-title").text("Fehler");
 | 
				
			||||||
 | 
					      modal
 | 
				
			||||||
 | 
					        .find(".dtc-desc")
 | 
				
			||||||
 | 
					        .text("DTC-Beschreibung konnte nicht geladen werden");
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      modal.find(".modal-title").text(title);
 | 
				
			||||||
 | 
					      modal.find(".dtc-desc").text(description);
 | 
				
			||||||
 | 
					      if (debugval > 0) {
 | 
				
			||||||
 | 
					        modal.find(".dtc-debugval").text("Debugvalue: " + debugval);
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        modal.find(".dtc-debugval").remove();
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					  // Modal anzeigen
 | 
				
			||||||
 | 
					  modal.modal("show");
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
@@ -1,6 +1,9 @@
 | 
				
			|||||||
var gateway = `ws://${window.location.hostname}/ws`;
 | 
					var gateway = `ws://${window.location.hostname}/ws`;
 | 
				
			||||||
var websocket;
 | 
					var websocket;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var statusMapping;
 | 
				
			||||||
 | 
					var staticMapping;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
window.addEventListener("load", onLoad);
 | 
					window.addEventListener("load", onLoad);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function initWebSocket() {
 | 
					function initWebSocket() {
 | 
				
			||||||
@@ -31,25 +34,79 @@ function onClose(event) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
function onMessage(event) {
 | 
					function onMessage(event) {
 | 
				
			||||||
  var data = event.data;
 | 
					  var data = event.data;
 | 
				
			||||||
 | 
					  console.log("ws_msg:" + event.data + "\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (data.startsWith("DEBUG:")) {
 | 
					  if (data.startsWith("DEBUG:")) {
 | 
				
			||||||
    var addtext = data.slice(6);
 | 
					    var addtext = data.slice(6);
 | 
				
			||||||
    var livedebug_out = document.getElementById("livedebug-out");
 | 
					    var livedebug_out = document.getElementById("livedebug-out");
 | 
				
			||||||
    livedebug_out.value += addtext;
 | 
					    livedebug_out.value += addtext;
 | 
				
			||||||
    livedebug_out.scrollTop = livedebug_out.scrollHeight;
 | 
					    livedebug_out.scrollTop = livedebug_out.scrollHeight;
 | 
				
			||||||
    do_resize(livedebug_out);
 | 
					    do_resize(livedebug_out);
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (data.startsWith("DTC:")) {
 | 
					  if (data.startsWith("DTC:")) {
 | 
				
			||||||
    const dtcs = data.slice(4);
 | 
					    const dtcs = data.slice(4);
 | 
				
			||||||
    const dtcArray = dtcs.trim() !== "" ? dtcs.split(";").filter(Boolean) : [];
 | 
					    const dtcArray = dtcs.trim() !== "" ? dtcs.split(";").filter(Boolean) : [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if(dtcArray[0] != "0")
 | 
					    if (dtcArray[0] != "0") {
 | 
				
			||||||
    {
 | 
					      processDTCNotifications(dtcArray);
 | 
				
			||||||
      notifyMe();
 | 
					 | 
				
			||||||
      fillDTCTable(dtcArray);
 | 
					      fillDTCTable(dtcArray);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    console.log(dtcArray + "\n");
 | 
					    return;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  console.log("ws_msg:" + event.data + "\n");
 | 
					
 | 
				
			||||||
 | 
					  if (data.startsWith("MAPPING_STATUS:")) {
 | 
				
			||||||
 | 
					    const data_sliced = data.slice(15);
 | 
				
			||||||
 | 
					    statusMapping = createMapping(data_sliced);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (data.startsWith("MAPPING_STATIC:")) {
 | 
				
			||||||
 | 
					    const data_sliced = data.slice(15);
 | 
				
			||||||
 | 
					    staticMapping = createMapping(data_sliced);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (data.startsWith("STATUS:")) {
 | 
				
			||||||
 | 
					    const data_sliced = data.slice(7);
 | 
				
			||||||
 | 
					    const result = processDataString(data_sliced, statusMapping);
 | 
				
			||||||
 | 
					    console.log("STATUS:");
 | 
				
			||||||
 | 
					    console.log(JSON.stringify(result, null, 2));
 | 
				
			||||||
 | 
					    fillValuestoHTML(result);
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (data.startsWith("STATIC:")) {
 | 
				
			||||||
 | 
					    const data_sliced = data.slice(7);
 | 
				
			||||||
 | 
					    const result = processDataString(data_sliced, staticMapping);
 | 
				
			||||||
 | 
					    console.log("STATIC:");
 | 
				
			||||||
 | 
					    console.log(JSON.stringify(result, null, 2));
 | 
				
			||||||
 | 
					    fillValuestoHTML(result);
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function createMapping(mappingString) {
 | 
				
			||||||
 | 
					  const mappingArray = mappingString.split(";");
 | 
				
			||||||
 | 
					  const mapping = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  mappingArray.forEach((variable) => {
 | 
				
			||||||
 | 
					    if (variable !== null) mapping.push(variable.trim());
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					  return mapping;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function processDataString(dataString, mapping) {
 | 
				
			||||||
 | 
					  const valuesArray = dataString.split(";");
 | 
				
			||||||
 | 
					  const dataObject = {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  valuesArray.forEach((value, index) => {
 | 
				
			||||||
 | 
					    const variable = mapping[index];
 | 
				
			||||||
 | 
					    if (variable) {
 | 
				
			||||||
 | 
					      dataObject[variable] = value.trim();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return dataObject;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function onLoad(event) {
 | 
					function onLoad(event) {
 | 
				
			||||||
@@ -82,18 +139,11 @@ function do_resize(textbox) {
 | 
				
			|||||||
  else textbox.rows = rows;
 | 
					  else textbox.rows = rows;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function notifyMe() {
 | 
					function fillValuestoHTML(dataset) {
 | 
				
			||||||
  if (!("Notification" in window)) {
 | 
					  for (var key in dataset) {
 | 
				
			||||||
    alert("This browser does not support desktop notification");
 | 
					    var inputElement = document.getElementById(key);
 | 
				
			||||||
  } else if (Notification.permission === "granted") {
 | 
					    if (inputElement) {
 | 
				
			||||||
    const notification = new Notification("Hi there!");
 | 
					      inputElement.value = dataset[key];
 | 
				
			||||||
    // …
 | 
					    }
 | 
				
			||||||
  } else if (Notification.permission !== "denied") {
 | 
					 | 
				
			||||||
    Notification.requestPermission().then((permission) => {
 | 
					 | 
				
			||||||
      if (permission === "granted") {
 | 
					 | 
				
			||||||
        const notification = new Notification("Hi there!");
 | 
					 | 
				
			||||||
        // …
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,12 +20,8 @@ typedef enum SpeedSource_e
 | 
				
			|||||||
  SOURCE_TIME,
 | 
					  SOURCE_TIME,
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
  SOURCE_IMPULSE,
 | 
					  SOURCE_IMPULSE,
 | 
				
			||||||
#ifdef FEATURE_ENABLE_GPS
 | 
					 | 
				
			||||||
  SOURCE_GPS,
 | 
					  SOURCE_GPS,
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
#if FEATURE_ENABLE_CAN
 | 
					 | 
				
			||||||
  SOURCE_CAN
 | 
					  SOURCE_CAN
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
} SpeedSource_t;
 | 
					} SpeedSource_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const char SpeedSourceString[][8] = {
 | 
					const char SpeedSourceString[][8] = {
 | 
				
			||||||
@@ -33,15 +29,10 @@ const char SpeedSourceString[][8] = {
 | 
				
			|||||||
    "Timer",
 | 
					    "Timer",
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
    "Impuls",
 | 
					    "Impuls",
 | 
				
			||||||
#ifdef FEATURE_ENABLE_GPS
 | 
					 | 
				
			||||||
    "GPS",
 | 
					    "GPS",
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
#if FEATURE_ENABLE_CAN
 | 
					 | 
				
			||||||
    "CAN-Bus"
 | 
					    "CAN-Bus"
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef FEATURE_ENABLE_GPS
 | 
					 | 
				
			||||||
typedef enum GPSBaudRate_e
 | 
					typedef enum GPSBaudRate_e
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  BAUD_9600,
 | 
					  BAUD_9600,
 | 
				
			||||||
@@ -53,9 +44,7 @@ const char GPSBaudRateString[][7] = {
 | 
				
			|||||||
    "115200"};
 | 
					    "115200"};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const size_t GPSBaudRateString_Elements = sizeof(GPSBaudRateString) / sizeof(GPSBaudRateString[0]);
 | 
					const size_t GPSBaudRateString_Elements = sizeof(GPSBaudRateString) / sizeof(GPSBaudRateString[0]);
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef FEATURE_ENABLE_CAN
 | 
					 | 
				
			||||||
typedef enum CANSource_e
 | 
					typedef enum CANSource_e
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  KTM_890_ADV_R_2021,
 | 
					  KTM_890_ADV_R_2021,
 | 
				
			||||||
@@ -67,7 +56,6 @@ const char CANSourceString[][30] = {
 | 
				
			|||||||
    "KTM 1290 Superduke R (2023)"};
 | 
					    "KTM 1290 Superduke R (2023)"};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const size_t CANSourceString_Elements = sizeof(CANSourceString) / sizeof(CANSourceString[0]);
 | 
					const size_t CANSourceString_Elements = sizeof(CANSourceString) / sizeof(CANSourceString[0]);
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
const size_t SpeedSourceString_Elements = sizeof(SpeedSourceString) / sizeof(SpeedSourceString[0]);
 | 
					const size_t SpeedSourceString_Elements = sizeof(SpeedSourceString) / sizeof(SpeedSourceString[0]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -96,12 +84,8 @@ typedef struct
 | 
				
			|||||||
  uint32_t DistancePerRevolution_mm = 2000;
 | 
					  uint32_t DistancePerRevolution_mm = 2000;
 | 
				
			||||||
  uint16_t BleedingPulses = 25;
 | 
					  uint16_t BleedingPulses = 25;
 | 
				
			||||||
  SpeedSource_t SpeedSource = SOURCE_IMPULSE;
 | 
					  SpeedSource_t SpeedSource = SOURCE_IMPULSE;
 | 
				
			||||||
#ifdef FEATURE_ENABLE_GPS
 | 
					 | 
				
			||||||
  GPSBaudRate_t GPSBaudRate = BAUD_115200;
 | 
					  GPSBaudRate_t GPSBaudRate = BAUD_115200;
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
#ifdef FEATURE_ENABLE_CAN
 | 
					 | 
				
			||||||
  CANSource_t CANSource = KTM_890_ADV_R_2021;
 | 
					  CANSource_t CANSource = KTM_890_ADV_R_2021;
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
  bool LED_Mode_Flash = false;
 | 
					  bool LED_Mode_Flash = false;
 | 
				
			||||||
  uint8_t LED_Max_Brightness = 255;
 | 
					  uint8_t LED_Max_Brightness = 255;
 | 
				
			||||||
  uint8_t LED_Min_Brightness = 5;
 | 
					  uint8_t LED_Min_Brightness = 5;
 | 
				
			||||||
@@ -110,12 +94,8 @@ typedef struct
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const LubeConfig_t LubeConfig_defaults = {
 | 
					const LubeConfig_t LubeConfig_defaults = {
 | 
				
			||||||
    0, 8000, 4000, 320, DEFAULT_PUMP_DOSE, 30, 1, 150, 70, 18, 2000, 25, SOURCE_IMPULSE,
 | 
					    0, 8000, 4000, 320, DEFAULT_PUMP_DOSE, 30, 1, 150, 70, 18, 2000, 25, SOURCE_IMPULSE,
 | 
				
			||||||
#ifdef FEATURE_ENABLE_GPS
 | 
					 | 
				
			||||||
    BAUD_115200,
 | 
					    BAUD_115200,
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
#ifdef FEATURE_ENABLE_CAN
 | 
					 | 
				
			||||||
    KTM_890_ADV_R_2021,
 | 
					    KTM_890_ADV_R_2021,
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
    false,
 | 
					    false,
 | 
				
			||||||
    255,
 | 
					    255,
 | 
				
			||||||
    5,
 | 
					    5,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,6 +5,7 @@
 | 
				
			|||||||
#include "config.h"
 | 
					#include "config.h"
 | 
				
			||||||
#include "common.h"
 | 
					#include "common.h"
 | 
				
			||||||
#include "dtc.h"
 | 
					#include "dtc.h"
 | 
				
			||||||
 | 
					#include "debugger.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Init_GPS();
 | 
					void Init_GPS();
 | 
				
			||||||
uint32_t Process_GPS_WheelSpeed();
 | 
					uint32_t Process_GPS_WheelSpeed();
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,12 +16,6 @@
 | 
				
			|||||||
    #endif
 | 
					    #endif
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CAN_DEBUG_MESSAGE
 | 
					 | 
				
			||||||
    #ifndef FEATURE_ENABLE_CAN
 | 
					 | 
				
			||||||
        #error "You cannot enable CAN-Debug-Message without FEATURE_ENABLE_CAN"
 | 
					 | 
				
			||||||
    #endif
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifndef ADMIN_PASSWORD
 | 
					#ifndef ADMIN_PASSWORD
 | 
				
			||||||
    #error "You need to define ADMIN_PASSWORD for OTA-Update"
 | 
					    #error "You need to define ADMIN_PASSWORD for OTA-Update"
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,8 +20,6 @@
 | 
				
			|||||||
void initWebUI();
 | 
					void initWebUI();
 | 
				
			||||||
void Webserver_Process();
 | 
					void Webserver_Process();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef FEATURE_ENABLE_WEBSOCKETS
 | 
					 | 
				
			||||||
void Websocket_PushLiveDebug(String Message);
 | 
					void Websocket_PushLiveDebug(String Message);
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
@@ -18,6 +18,15 @@ platform = espressif8266
 | 
				
			|||||||
board = d1_mini
 | 
					board = d1_mini
 | 
				
			||||||
framework = arduino
 | 
					framework = arduino
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					upload_speed = 921600 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					upload_protocol = espota
 | 
				
			||||||
 | 
					upload_port = 10.0.1.14
 | 
				
			||||||
 | 
					upload_flags =
 | 
				
			||||||
 | 
					  --port=8266
 | 
				
			||||||
 | 
					  --auth=${wifi_cred.admin_password}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
build_flags =
 | 
					build_flags =
 | 
				
			||||||
  !python git_rev_macro.py
 | 
					  !python git_rev_macro.py
 | 
				
			||||||
  -DWIFI_SSID_CLIENT=${wifi_cred.wifi_ssid_client}
 | 
					  -DWIFI_SSID_CLIENT=${wifi_cred.wifi_ssid_client}
 | 
				
			||||||
@@ -52,10 +61,7 @@ build_flags =
 | 
				
			|||||||
  ${env.build_flags}
 | 
					  ${env.build_flags}
 | 
				
			||||||
  ;-DFEATURE_ENABLE_WIFI_CLIENT
 | 
					  ;-DFEATURE_ENABLE_WIFI_CLIENT
 | 
				
			||||||
  ;-DFEATURE_ENABLE_TIMER
 | 
					  ;-DFEATURE_ENABLE_TIMER
 | 
				
			||||||
  ;-DFEATURE_ENABLE_GPS
 | 
					 | 
				
			||||||
  -DFEATURE_ENABLE_OLED
 | 
					  -DFEATURE_ENABLE_OLED
 | 
				
			||||||
  -DFEATURE_ENABLE_WEBSOCKETS
 | 
					 | 
				
			||||||
  -DFEATURE_ENABLE_CAN
 | 
					 | 
				
			||||||
  -DCAN_DEBUG_MESSAGE
 | 
					  -DCAN_DEBUG_MESSAGE
 | 
				
			||||||
  -DPCB_REV=${this.custom_pcb_revision}
 | 
					  -DPCB_REV=${this.custom_pcb_revision}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,9 +6,59 @@ import glob
 | 
				
			|||||||
import shutil
 | 
					import shutil
 | 
				
			||||||
import gzip
 | 
					import gzip
 | 
				
			||||||
import os
 | 
					import os
 | 
				
			||||||
 | 
					import subprocess
 | 
				
			||||||
Import("env")
 | 
					Import("env")
 | 
				
			||||||
Import("projenv")
 | 
					Import("projenv")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Setze die Pfade zu den Tools als Variablen
 | 
				
			||||||
 | 
					html_minifier_path = os.path.join(os.getenv("APPDATA"), "npm", "html-minifier.cmd")
 | 
				
			||||||
 | 
					uglifyjs_path = os.path.join(os.getenv("APPDATA"), "npm", "uglifyjs.cmd")
 | 
				
			||||||
 | 
					terser_path = os.path.join(os.getenv("APPDATA"), "npm", "terser.cmd")
 | 
				
			||||||
 | 
					cssnano_path = os.path.join(os.getenv("APPDATA"), "npm", "cssnano.cmd")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def minify_html(input_path, output_path):
 | 
				
			||||||
 | 
					    subprocess.run([html_minifier_path, '--collapse-whitespace', '--remove-comments', input_path, '-o', output_path])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def minify_js(input_path, output_path):
 | 
				
			||||||
 | 
					    subprocess.run([terser_path, input_path, '-o', output_path, '-c', '-m'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def minify_css(input_path, output_path):
 | 
				
			||||||
 | 
					    subprocess.run([cssnano_path, '--no-discardUnused', input_path, output_path])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def process_file(src_path, dest_path):
 | 
				
			||||||
 | 
					    _, file_extension = os.path.splitext(src_path)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Extrahiere den Ordnerpfad im Zielverzeichnis
 | 
				
			||||||
 | 
					    dest_dir = os.path.dirname(dest_path)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Erstelle den Ordner und alle dazugehörigen Unterordner, falls sie nicht existieren
 | 
				
			||||||
 | 
					    os.makedirs(dest_dir, exist_ok=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if file_extension.lower() == '.js':
 | 
				
			||||||
 | 
					        minify_js(src_path, dest_path)
 | 
				
			||||||
 | 
					    elif file_extension.lower() == '.css':
 | 
				
			||||||
 | 
					        minify_css(src_path, dest_path)
 | 
				
			||||||
 | 
					    elif file_extension.lower() in ['.html', '.htm']:
 | 
				
			||||||
 | 
					        minify_html(src_path, dest_path)
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        # Kopiere nicht bearbeitbare Dateien direkt in den Zielordner
 | 
				
			||||||
 | 
					        shutil.copy2(src_path, dest_path)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def strip_files(src_dir, dest_dir):
 | 
				
			||||||
 | 
					    # Erstelle den Zielordner und alle dazugehörigen Unterordner, falls sie nicht existieren
 | 
				
			||||||
 | 
					    os.makedirs(dest_dir, exist_ok=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Durchlaufe alle Dateien und Unterverzeichnisse im Quellordner
 | 
				
			||||||
 | 
					    for root, _, files in os.walk(src_dir):
 | 
				
			||||||
 | 
					        for filename in files:
 | 
				
			||||||
 | 
					            src_path = os.path.join(root, filename)
 | 
				
			||||||
 | 
					            dest_path = os.path.relpath(src_path, src_dir)
 | 
				
			||||||
 | 
					            dest_path = os.path.join(dest_dir, dest_path)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            # Verarbeite nur Dateien (keine Unterverzeichnisse)
 | 
				
			||||||
 | 
					            process_file(src_path, dest_path)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def gzip_file(src_path, dst_path):
 | 
					def gzip_file(src_path, dst_path):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -47,14 +97,16 @@ def gzip_webfiles(source, target, env):
 | 
				
			|||||||
    filetypes_to_gzip = ['.css', '.png', '.js', '.ico', '.woff2', '.json']
 | 
					    filetypes_to_gzip = ['.css', '.png', '.js', '.ico', '.woff2', '.json']
 | 
				
			||||||
    print('\nGZIP: Starting gzip-Process for LittleFS-Image...\n')
 | 
					    print('\nGZIP: Starting gzip-Process for LittleFS-Image...\n')
 | 
				
			||||||
    data_src_dir_path = os.path.join(env.get('PROJECT_DIR'), 'data_src')
 | 
					    data_src_dir_path = os.path.join(env.get('PROJECT_DIR'), 'data_src')
 | 
				
			||||||
 | 
					    data_temp_dir_path = os.path.join(env.get('PROJECT_DIR'), 'data_stripped')
 | 
				
			||||||
 | 
					    strip_files(data_src_dir_path, data_temp_dir_path)
 | 
				
			||||||
    data_dir_path = env.get('PROJECT_DATA_DIR')
 | 
					    data_dir_path = env.get('PROJECT_DATA_DIR')
 | 
				
			||||||
    # check if data and datasrc exist. If the first exists and not the second, it renames it
 | 
					    # check if data and datasrc exist. If the first exists and not the second, it renames it
 | 
				
			||||||
    if(os.path.exists(data_dir_path) and not os.path.exists(data_src_dir_path)):
 | 
					    if(os.path.exists(data_dir_path) and not os.path.exists(data_temp_dir_path)):
 | 
				
			||||||
        print('GZIP: Directory "'+data_dir_path +
 | 
					        print('GZIP: Directory "'+data_dir_path +
 | 
				
			||||||
              '" exists, "'+data_src_dir_path+'" is not found.')
 | 
					              '" exists, "'+data_temp_dir_path+'" is not found.')
 | 
				
			||||||
        print('GZIP: Renaming "' + data_dir_path +
 | 
					        print('GZIP: Renaming "' + data_dir_path +
 | 
				
			||||||
              '" to "' + data_src_dir_path + '"')
 | 
					              '" to "' + data_temp_dir_path + '"')
 | 
				
			||||||
        os.rename(data_dir_path, data_src_dir_path)
 | 
					        os.rename(data_dir_path, data_temp_dir_path)
 | 
				
			||||||
    # Delete the 'data' directory
 | 
					    # Delete the 'data' directory
 | 
				
			||||||
    if(os.path.exists(data_dir_path)):
 | 
					    if(os.path.exists(data_dir_path)):
 | 
				
			||||||
        print('GZIP: Deleting the "data" directory ' + data_dir_path)
 | 
					        print('GZIP: Deleting the "data" directory ' + data_dir_path)
 | 
				
			||||||
@@ -67,27 +119,27 @@ def gzip_webfiles(source, target, env):
 | 
				
			|||||||
    files_to_copy = []
 | 
					    files_to_copy = []
 | 
				
			||||||
    files_to_gzip = []
 | 
					    files_to_gzip = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    all_data_src = getListOfFiles(data_src_dir_path)
 | 
					    all_data_src = getListOfFiles(data_temp_dir_path)
 | 
				
			||||||
    for file in all_data_src:
 | 
					    for file in all_data_src:
 | 
				
			||||||
        file_name, file_extension = os.path.splitext(file)
 | 
					        file_name, file_extension = os.path.splitext(file)
 | 
				
			||||||
        print(file_name + " has filetype " + file_extension)
 | 
					        print(file_name + " has filetype " + file_extension)
 | 
				
			||||||
        if file_extension in filetypes_to_gzip:
 | 
					        if file_extension in filetypes_to_gzip:
 | 
				
			||||||
            files_to_gzip.append(file)
 | 
					            files_to_gzip.append(file)
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            filename_subdir = remove_prefix(file, data_src_dir_path)
 | 
					            filename_subdir = remove_prefix(file, data_temp_dir_path)
 | 
				
			||||||
            files_to_copy.append(filename_subdir)
 | 
					            files_to_copy.append(filename_subdir)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for file in files_to_copy:
 | 
					    for file in files_to_copy:
 | 
				
			||||||
        print('GZIP: Copying file from: ' + data_src_dir_path + file + ' to: ' + data_dir_path + file)
 | 
					        print('GZIP: Copying file from: ' + data_temp_dir_path + file + ' to: ' + data_dir_path + file)
 | 
				
			||||||
        os.makedirs(os.path.dirname(data_dir_path + file), exist_ok=True)
 | 
					        os.makedirs(os.path.dirname(data_dir_path + file), exist_ok=True)
 | 
				
			||||||
        shutil.copy(data_src_dir_path + file, data_dir_path + file)
 | 
					        shutil.copy(data_temp_dir_path + file, data_dir_path + file)
 | 
				
			||||||
    # Compress and move files
 | 
					    # Compress and move files
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    was_error = False
 | 
					    was_error = False
 | 
				
			||||||
    try:
 | 
					    try:
 | 
				
			||||||
        for source_file_path in files_to_gzip:
 | 
					        for source_file_path in files_to_gzip:
 | 
				
			||||||
            print('GZIP: compressing... ' + source_file_path)
 | 
					            print('GZIP: compressing... ' + source_file_path)
 | 
				
			||||||
            filename_subdir = remove_prefix(source_file_path, data_src_dir_path)
 | 
					            filename_subdir = remove_prefix(source_file_path, data_temp_dir_path)
 | 
				
			||||||
            target_file_path = data_dir_path + filename_subdir
 | 
					            target_file_path = data_dir_path + filename_subdir
 | 
				
			||||||
            os.makedirs(os.path.dirname(target_file_path), exist_ok=True)
 | 
					            os.makedirs(os.path.dirname(target_file_path), exist_ok=True)
 | 
				
			||||||
            print('GZIP: Compressed... ' + target_file_path)
 | 
					            print('GZIP: Compressed... ' + target_file_path)
 | 
				
			||||||
@@ -100,6 +152,7 @@ def gzip_webfiles(source, target, env):
 | 
				
			|||||||
        print('GZIP: Failure/Incomplete.\n')
 | 
					        print('GZIP: Failure/Incomplete.\n')
 | 
				
			||||||
    else:
 | 
					    else:
 | 
				
			||||||
        print('GZIP: Compressed correctly.\n')
 | 
					        print('GZIP: Compressed correctly.\n')
 | 
				
			||||||
 | 
					        shutil.rmtree(data_temp_dir_path)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return
 | 
					    return
 | 
				
			||||||
 
 | 
					 
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,8 +1,8 @@
 | 
				
			|||||||
#ifdef FEATURE_ENABLE_CAN
 | 
					 | 
				
			||||||
#include "can.h"
 | 
					#include "can.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
MCP_CAN CAN0(GPIO_CS_CAN);
 | 
					MCP_CAN CAN0(GPIO_CS_CAN);
 | 
				
			||||||
#ifdef CAN_DEBUG_MESSAGE
 | 
					#ifdef CAN_DEBUG_MESSAGE
 | 
				
			||||||
 | 
					#define MAX_DEBUG_RETRIES 100
 | 
				
			||||||
void sendCANDebugMessage();
 | 
					void sendCANDebugMessage();
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -90,6 +90,7 @@ uint32_t Process_CAN_WheelSpeed()
 | 
				
			|||||||
void sendCANDebugMessage()
 | 
					void sendCANDebugMessage()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
#define MAX_DEBUG_MULTIPLEXER 6
 | 
					#define MAX_DEBUG_MULTIPLEXER 6
 | 
				
			||||||
 | 
					    static uint16_t DebugSendFailTimeout = 0;
 | 
				
			||||||
    static uint8_t debugMultiplexer = 0;
 | 
					    static uint8_t debugMultiplexer = 0;
 | 
				
			||||||
    byte data[8] = {debugMultiplexer, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
 | 
					    byte data[8] = {debugMultiplexer, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
 | 
				
			||||||
    uint32_t millisValue = millis();
 | 
					    uint32_t millisValue = millis();
 | 
				
			||||||
@@ -131,9 +132,19 @@ void sendCANDebugMessage()
 | 
				
			|||||||
    debugMultiplexer++;
 | 
					    debugMultiplexer++;
 | 
				
			||||||
    debugMultiplexer = debugMultiplexer > MAX_DEBUG_MULTIPLEXER ? 0 : debugMultiplexer;
 | 
					    debugMultiplexer = debugMultiplexer > MAX_DEBUG_MULTIPLEXER ? 0 : debugMultiplexer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (DebugSendFailTimeout < MAX_DEBUG_RETRIES)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
        byte sndStat = CAN0.sendMsgBuf(0x7FF, 0, 8, data);
 | 
					        byte sndStat = CAN0.sendMsgBuf(0x7FF, 0, 8, data);
 | 
				
			||||||
        if (sndStat != CAN_OK)
 | 
					        if (sndStat != CAN_OK)
 | 
				
			||||||
        Debug_pushMessage("failed sending CAN-DbgMsg: %d\n", sndStat);
 | 
					        {
 | 
				
			||||||
 | 
					            Debug_pushMessage("failed sending CAN-DbgMsg: %d, %d\n", sndStat, DebugSendFailTimeout);
 | 
				
			||||||
 | 
					            DebugSendFailTimeout++;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else if (DebugSendFailTimeout == MAX_DEBUG_RETRIES)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        Debug_pushMessage("disable CAN-DbgMsg due to timeout");
 | 
				
			||||||
 | 
					        DebugSendFailTimeout++;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
@@ -295,6 +295,8 @@ uint32_t ConfigSanityCheck(bool autocorrect)
 | 
				
			|||||||
      LubeConfig.TankRemindAtPercentage = LubeConfig_defaults.TankRemindAtPercentage;
 | 
					      LubeConfig.TankRemindAtPercentage = LubeConfig_defaults.TankRemindAtPercentage;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (LubeConfig.SpeedSource == SOURCE_IMPULSE)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
    if (!(LubeConfig.PulsePerRevolution > 0) || !(LubeConfig.PulsePerRevolution < 1000))
 | 
					    if (!(LubeConfig.PulsePerRevolution > 0) || !(LubeConfig.PulsePerRevolution < 1000))
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      SET_BIT(setting_reset_bits, 5);
 | 
					      SET_BIT(setting_reset_bits, 5);
 | 
				
			||||||
@@ -329,6 +331,7 @@ uint32_t ConfigSanityCheck(bool autocorrect)
 | 
				
			|||||||
      if (autocorrect)
 | 
					      if (autocorrect)
 | 
				
			||||||
        LubeConfig.DistancePerRevolution_mm = LubeConfig_defaults.DistancePerRevolution_mm;
 | 
					        LubeConfig.DistancePerRevolution_mm = LubeConfig_defaults.DistancePerRevolution_mm;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
  
 | 
					  
 | 
				
			||||||
  if (!(LubeConfig.BleedingPulses > 0) || !(LubeConfig.BleedingPulses < 1001))
 | 
					  if (!(LubeConfig.BleedingPulses > 0) || !(LubeConfig.BleedingPulses < 1001))
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
@@ -344,22 +347,18 @@ uint32_t ConfigSanityCheck(bool autocorrect)
 | 
				
			|||||||
      LubeConfig.SpeedSource = LubeConfig_defaults.SpeedSource;
 | 
					      LubeConfig.SpeedSource = LubeConfig_defaults.SpeedSource;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef FEATURE_ENABLE_GPS
 | 
					 | 
				
			||||||
  if (!(LubeConfig.GPSBaudRate >= 0) || !(LubeConfig.GPSBaudRate < GPSBaudRateString_Elements))
 | 
					  if (!(LubeConfig.GPSBaudRate >= 0) || !(LubeConfig.GPSBaudRate < GPSBaudRateString_Elements))
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    SET_BIT(setting_reset_bits, 12);
 | 
					    SET_BIT(setting_reset_bits, 12);
 | 
				
			||||||
    if (autocorrect)
 | 
					    if (autocorrect)
 | 
				
			||||||
      LubeConfig.GPSBaudRate = LubeConfig_defaults.GPSBaudRate;
 | 
					      LubeConfig.GPSBaudRate = LubeConfig_defaults.GPSBaudRate;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef FEATURE_ENABLE_CAN
 | 
					 | 
				
			||||||
  if (!(LubeConfig.CANSource >= 0) || !(LubeConfig.CANSource < CANSourceString_Elements))
 | 
					  if (!(LubeConfig.CANSource >= 0) || !(LubeConfig.CANSource < CANSourceString_Elements))
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    SET_BIT(setting_reset_bits, 13);
 | 
					    SET_BIT(setting_reset_bits, 13);
 | 
				
			||||||
    if (autocorrect)
 | 
					    if (autocorrect)
 | 
				
			||||||
      LubeConfig.CANSource = LubeConfig_defaults.CANSource;
 | 
					      LubeConfig.CANSource = LubeConfig_defaults.CANSource;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
  return setting_reset_bits;
 | 
					  return setting_reset_bits;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -242,12 +242,8 @@ void Debug_dumpConfig()
 | 
				
			|||||||
    Debug_pushMessage("DistancePerRevolution_mm: %d\n", LubeConfig.DistancePerRevolution_mm);
 | 
					    Debug_pushMessage("DistancePerRevolution_mm: %d\n", LubeConfig.DistancePerRevolution_mm);
 | 
				
			||||||
    Debug_pushMessage("BleedingPulses: %d\n", LubeConfig.BleedingPulses);
 | 
					    Debug_pushMessage("BleedingPulses: %d\n", LubeConfig.BleedingPulses);
 | 
				
			||||||
    Debug_pushMessage("SpeedSource: %d\n", LubeConfig.SpeedSource);
 | 
					    Debug_pushMessage("SpeedSource: %d\n", LubeConfig.SpeedSource);
 | 
				
			||||||
#ifdef FEATURE_ENABLE_GPS
 | 
					 | 
				
			||||||
    Debug_pushMessage("GPSBaudRate: %d\n", LubeConfig.GPSBaudRate);
 | 
					    Debug_pushMessage("GPSBaudRate: %d\n", LubeConfig.GPSBaudRate);
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
#ifdef FEATURE_ENABLE_CAN
 | 
					 | 
				
			||||||
    Debug_pushMessage("CANSource: %d\n", LubeConfig.CANSource);
 | 
					    Debug_pushMessage("CANSource: %d\n", LubeConfig.CANSource);
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
    Debug_pushMessage("checksum: 0x%08X\n", LubeConfig.checksum);
 | 
					    Debug_pushMessage("checksum: 0x%08X\n", LubeConfig.checksum);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,3 @@
 | 
				
			|||||||
#ifdef FEATURE_ENABLE_GPS
 | 
					 | 
				
			||||||
#include "gps.h"
 | 
					#include "gps.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
TinyGPSPlus gps;
 | 
					TinyGPSPlus gps;
 | 
				
			||||||
@@ -50,10 +49,7 @@ uint32_t Process_GPS_WheelSpeed()
 | 
				
			|||||||
            lastRecTimestamp = millis();
 | 
					            lastRecTimestamp = millis();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    MaintainDTC(DTC_NO_GPS_SERIAL, (millis() > lastRecTimestamp + 10000));
 | 
				
			||||||
    MaintainDTC(DTC_NO_GPS_SERIAL,DTC_CRITICAL, (millis() > lastRecTimestamp + 10000));
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
@@ -18,12 +18,8 @@
 | 
				
			|||||||
#include "config.h"
 | 
					#include "config.h"
 | 
				
			||||||
#include "globals.h"
 | 
					#include "globals.h"
 | 
				
			||||||
#include "debugger.h"
 | 
					#include "debugger.h"
 | 
				
			||||||
#ifdef FEATURE_ENABLE_CAN
 | 
					 | 
				
			||||||
#include "can.h"
 | 
					#include "can.h"
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
#ifdef FEATURE_ENABLE_GPS
 | 
					 | 
				
			||||||
#include "gps.h"
 | 
					#include "gps.h"
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
#include "dtc.h"
 | 
					#include "dtc.h"
 | 
				
			||||||
#include "led_colors.h"
 | 
					#include "led_colors.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -99,20 +95,24 @@ void setup()
 | 
				
			|||||||
  leds.begin();
 | 
					  leds.begin();
 | 
				
			||||||
  Serial.print("\nLED-Init done");
 | 
					  Serial.print("\nLED-Init done");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  switch (LubeConfig.SpeedSource)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					  case SOURCE_CAN:
 | 
				
			||||||
 | 
					    Init_CAN();
 | 
				
			||||||
 | 
					    Serial.print("\nCAN-Init done");
 | 
				
			||||||
 | 
					    break;
 | 
				
			||||||
 | 
					  case SOURCE_GPS:
 | 
				
			||||||
 | 
					    Init_GPS();
 | 
				
			||||||
 | 
					    Serial.print("\nGPS-Init done");
 | 
				
			||||||
 | 
					    break;
 | 
				
			||||||
 | 
					  case SOURCE_IMPULSE:
 | 
				
			||||||
    pinMode(GPIO_TRIGGER, INPUT_PULLUP);
 | 
					    pinMode(GPIO_TRIGGER, INPUT_PULLUP);
 | 
				
			||||||
    attachInterrupt(digitalPinToInterrupt(GPIO_TRIGGER), trigger_ISR, FALLING);
 | 
					    attachInterrupt(digitalPinToInterrupt(GPIO_TRIGGER), trigger_ISR, FALLING);
 | 
				
			||||||
    Serial.print("\nPulse-Input Init done");
 | 
					    Serial.print("\nPulse-Input Init done");
 | 
				
			||||||
#ifdef FEATURE_ENABLE_GPS
 | 
					    break;
 | 
				
			||||||
  Init_GPS();
 | 
					  default:
 | 
				
			||||||
  Serial.print("\nGPS-Init done");
 | 
					    break;
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
#ifdef FEATURE_ENABLE_CAN
 | 
					 | 
				
			||||||
  if (LubeConfig.SpeedSource != SOURCE_IMPULSE)
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    Init_CAN();
 | 
					 | 
				
			||||||
    Serial.print("\nCAN-Init done");
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Serial.print("\nSource-Init done");
 | 
					  Serial.print("\nSource-Init done");
 | 
				
			||||||
  pinMode(GPIO_BUTTON, INPUT_PULLUP);
 | 
					  pinMode(GPIO_BUTTON, INPUT_PULLUP);
 | 
				
			||||||
@@ -167,32 +167,27 @@ void loop()
 | 
				
			|||||||
  case SOURCE_IMPULSE:
 | 
					  case SOURCE_IMPULSE:
 | 
				
			||||||
    wheelDistance = Process_Impulse_WheelSpeed();
 | 
					    wheelDistance = Process_Impulse_WheelSpeed();
 | 
				
			||||||
    break;
 | 
					    break;
 | 
				
			||||||
#ifdef FEATURE_ENABLE_CAN
 | 
					 | 
				
			||||||
  case SOURCE_CAN:
 | 
					  case SOURCE_CAN:
 | 
				
			||||||
    wheelDistance = Process_CAN_WheelSpeed();
 | 
					    wheelDistance = Process_CAN_WheelSpeed();
 | 
				
			||||||
    break;
 | 
					    break;
 | 
				
			||||||
#endif
 | 
					
 | 
				
			||||||
#ifdef FEATURE_ENABLE_TIMER
 | 
					#ifdef FEATURE_ENABLE_TIMER
 | 
				
			||||||
  case SOURCE_TIME:
 | 
					  case SOURCE_TIME:
 | 
				
			||||||
    break;
 | 
					    break;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
#ifdef FEATURE_ENABLE_GPS
 | 
					 | 
				
			||||||
  case SOURCE_GPS:
 | 
					  case SOURCE_GPS:
 | 
				
			||||||
    wheelDistance = Process_GPS_WheelSpeed();
 | 
					    wheelDistance = Process_GPS_WheelSpeed();
 | 
				
			||||||
    break;
 | 
					    break;
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  RunLubeApp(wheelDistance);
 | 
					  RunLubeApp(wheelDistance);
 | 
				
			||||||
#ifdef FEATURE_ENABLE_OLED
 | 
					#ifdef FEATURE_ENABLE_OLED
 | 
				
			||||||
  Display_Process();
 | 
					  Display_Process();
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
#ifdef FEATURE_ENABLE_CAN
 | 
					 | 
				
			||||||
  if (LubeConfig.SpeedSource != SOURCE_IMPULSE)
 | 
					  if (LubeConfig.SpeedSource != SOURCE_IMPULSE)
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    CAN_Process();
 | 
					    CAN_Process();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
  Button_Process();
 | 
					  Button_Process();
 | 
				
			||||||
  LED_Process();
 | 
					  LED_Process();
 | 
				
			||||||
  EEPROM_Process();
 | 
					  EEPROM_Process();
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,15 +13,13 @@ void WebserverEERestore_Callback(AsyncWebServerRequest *request, const String &f
 | 
				
			|||||||
void WebServerEEJSON_Callback(AsyncWebServerRequest *request);
 | 
					void WebServerEEJSON_Callback(AsyncWebServerRequest *request);
 | 
				
			||||||
void GetFlashVersion(char *buff, size_t buff_size);
 | 
					void GetFlashVersion(char *buff, size_t buff_size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef FEATURE_ENABLE_WEBSOCKETS
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
AsyncWebSocket webSocket("/ws");
 | 
					AsyncWebSocket webSocket("/ws");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void WebsocketEvent_Callback(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len);
 | 
					void WebsocketEvent_Callback(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len);
 | 
				
			||||||
void Websocket_HandleMessage(void *arg, uint8_t *data, size_t len);
 | 
					void Websocket_HandleMessage(void *arg, uint8_t *data, size_t len);
 | 
				
			||||||
void Websocket_RefreshClientData_DTCs();
 | 
					void Websocket_RefreshClientData_DTCs(uint32_t client_id);
 | 
				
			||||||
 | 
					void Websocket_RefreshClientData_Status(uint32_t client_id, bool send_mapping = false);
 | 
				
			||||||
#endif
 | 
					void Websocket_RefreshClientData_Static(uint32_t client_id, bool send_mapping = false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void initWebUI()
 | 
					void initWebUI()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -44,10 +42,8 @@ void initWebUI()
 | 
				
			|||||||
  MDNS.begin(globals.DeviceName);
 | 
					  MDNS.begin(globals.DeviceName);
 | 
				
			||||||
  MDNS.addService("http", "tcp", 80);
 | 
					  MDNS.addService("http", "tcp", 80);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef FEATURE_ENABLE_WEBSOCKETS
 | 
					 | 
				
			||||||
  webSocket.onEvent(WebsocketEvent_Callback);
 | 
					  webSocket.onEvent(WebsocketEvent_Callback);
 | 
				
			||||||
  webServer.addHandler(&webSocket);
 | 
					  webServer.addHandler(&webSocket);
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  webServer.serveStatic("/static/", LittleFS, "/static/").setCacheControl("max-age=360000");
 | 
					  webServer.serveStatic("/static/", LittleFS, "/static/").setCacheControl("max-age=360000");
 | 
				
			||||||
  webServer.on("/", HTTP_GET, [](AsyncWebServerRequest *request)
 | 
					  webServer.on("/", HTTP_GET, [](AsyncWebServerRequest *request)
 | 
				
			||||||
@@ -66,17 +62,16 @@ void initWebUI()
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void Webserver_Process()
 | 
					void Webserver_Process()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
#ifdef FEATURE_ENABLE_WEBSOCKETS
 | 
					 | 
				
			||||||
  static uint32_t previousMillis = 0;
 | 
					  static uint32_t previousMillis = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  webSocket.cleanupClients();
 | 
					  webSocket.cleanupClients();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if ((webSocket.count() > 0) && (millis() - previousMillis >= 10000))
 | 
					  if ((webSocket.count() > 0) && (millis() - previousMillis >= 10000))
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    Websocket_RefreshClientData_DTCs();
 | 
					    Websocket_RefreshClientData_DTCs(0);
 | 
				
			||||||
 | 
					    Websocket_RefreshClientData_Status(0);
 | 
				
			||||||
    previousMillis = millis();
 | 
					    previousMillis = millis();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
String processor(const String &var)
 | 
					String processor(const String &var)
 | 
				
			||||||
@@ -110,17 +105,9 @@ String processor(const String &var)
 | 
				
			|||||||
  if (var == "SPEED_SOURCE")
 | 
					  if (var == "SPEED_SOURCE")
 | 
				
			||||||
    return String(SpeedSourceString[LubeConfig.SpeedSource]);
 | 
					    return String(SpeedSourceString[LubeConfig.SpeedSource]);
 | 
				
			||||||
  if (var == "GPS_BAUD")
 | 
					  if (var == "GPS_BAUD")
 | 
				
			||||||
#ifdef FEATURE_ENABLE_GPS
 | 
					 | 
				
			||||||
    return String(GPSBaudRateString[LubeConfig.GPSBaudRate]);
 | 
					    return String(GPSBaudRateString[LubeConfig.GPSBaudRate]);
 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
    return "Feature N/A";
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
  if (var == "CAN_SOURCE")
 | 
					  if (var == "CAN_SOURCE")
 | 
				
			||||||
#ifdef FEATURE_ENABLE_CAN
 | 
					 | 
				
			||||||
    return String(CANSourceString[LubeConfig.CANSource]);
 | 
					    return String(CANSourceString[LubeConfig.CANSource]);
 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
    return "Feature N/A";
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
  if (var == "LED_MODE_FLASH")
 | 
					  if (var == "LED_MODE_FLASH")
 | 
				
			||||||
    return String(LubeConfig.LED_Mode_Flash);
 | 
					    return String(LubeConfig.LED_Mode_Flash);
 | 
				
			||||||
  if (var == "LEDFLASHCHECKED")
 | 
					  if (var == "LEDFLASHCHECKED")
 | 
				
			||||||
@@ -158,17 +145,9 @@ String processor(const String &var)
 | 
				
			|||||||
  if (var == "SHOW_IMPULSE_SETTINGS")
 | 
					  if (var == "SHOW_IMPULSE_SETTINGS")
 | 
				
			||||||
    return LubeConfig.SpeedSource == SOURCE_IMPULSE ? "" : "hidden";
 | 
					    return LubeConfig.SpeedSource == SOURCE_IMPULSE ? "" : "hidden";
 | 
				
			||||||
  if (var == "SHOW_CAN_SETTINGS")
 | 
					  if (var == "SHOW_CAN_SETTINGS")
 | 
				
			||||||
#ifdef FEATURE_ENABLE_CAN
 | 
					 | 
				
			||||||
    return LubeConfig.SpeedSource == SOURCE_CAN ? "" : "hidden";
 | 
					    return LubeConfig.SpeedSource == SOURCE_CAN ? "" : "hidden";
 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
    return "hidden";
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
  if (var == "SHOW_GPS_SETTINGS")
 | 
					  if (var == "SHOW_GPS_SETTINGS")
 | 
				
			||||||
#ifdef FEATURE_ENABLE_GPS
 | 
					 | 
				
			||||||
    return LubeConfig.SpeedSource == SOURCE_GPS ? "" : "hidden";
 | 
					    return LubeConfig.SpeedSource == SOURCE_GPS ? "" : "hidden";
 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
    return "hidden";
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (var == "SOURCE_SELECT_OPTIONS")
 | 
					  if (var == "SOURCE_SELECT_OPTIONS")
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
@@ -181,7 +160,6 @@ String processor(const String &var)
 | 
				
			|||||||
    return temp;
 | 
					    return temp;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef FEATURE_ENABLE_CAN
 | 
					 | 
				
			||||||
  if (var == "CANSOURCE_SELECT_OPTIONS")
 | 
					  if (var == "CANSOURCE_SELECT_OPTIONS")
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    String temp;
 | 
					    String temp;
 | 
				
			||||||
@@ -192,8 +170,7 @@ String processor(const String &var)
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    return temp;
 | 
					    return temp;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
#endif
 | 
					
 | 
				
			||||||
#ifdef FEATURE_ENABLE_GPS
 | 
					 | 
				
			||||||
  if (var == "GPSBAUD_SELECT_OPTIONS")
 | 
					  if (var == "GPSBAUD_SELECT_OPTIONS")
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    String temp;
 | 
					    String temp;
 | 
				
			||||||
@@ -204,7 +181,6 @@ String processor(const String &var)
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    return temp;
 | 
					    return temp;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (var == "SYSTEM_STATUS")
 | 
					  if (var == "SYSTEM_STATUS")
 | 
				
			||||||
    return String(globals.systemStatustxt);
 | 
					    return String(globals.systemStatustxt);
 | 
				
			||||||
@@ -275,22 +251,18 @@ void WebserverPOST_Callback(AsyncWebServerRequest *request)
 | 
				
			|||||||
    if (p->name() == "pulsesave")
 | 
					    if (p->name() == "pulsesave")
 | 
				
			||||||
      globals.requestEEAction = EE_CFG_SAVE;
 | 
					      globals.requestEEAction = EE_CFG_SAVE;
 | 
				
			||||||
    // end: POST Form Source Pulse Settings
 | 
					    // end: POST Form Source Pulse Settings
 | 
				
			||||||
#ifdef FEATURE_ENABLE_GPS
 | 
					 | 
				
			||||||
    // begin: POST Form Source GPS Settings
 | 
					    // begin: POST Form Source GPS Settings
 | 
				
			||||||
    if (p->name() == "gpsbaud")
 | 
					    if (p->name() == "gpsbaud")
 | 
				
			||||||
      LubeConfig.GPSBaudRate = (GPSBaudRate_t)p->value().toInt();
 | 
					      LubeConfig.GPSBaudRate = (GPSBaudRate_t)p->value().toInt();
 | 
				
			||||||
    if (p->name() == "gpssave")
 | 
					    if (p->name() == "gpssave")
 | 
				
			||||||
      globals.requestEEAction = EE_CFG_SAVE;
 | 
					      globals.requestEEAction = EE_CFG_SAVE;
 | 
				
			||||||
    // end: POST Form Source GPS Settings
 | 
					    // end: POST Form Source GPS Settings
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
#ifdef FEATURE_ENABLE_CAN
 | 
					 | 
				
			||||||
    // begin: POST Form Source CAN Settings
 | 
					    // begin: POST Form Source CAN Settings
 | 
				
			||||||
    if (p->name() == "cansource")
 | 
					    if (p->name() == "cansource")
 | 
				
			||||||
      LubeConfig.CANSource = (CANSource_t)p->value().toInt();
 | 
					      LubeConfig.CANSource = (CANSource_t)p->value().toInt();
 | 
				
			||||||
    if (p->name() == "cansave")
 | 
					    if (p->name() == "cansave")
 | 
				
			||||||
      globals.requestEEAction = EE_CFG_SAVE;
 | 
					      globals.requestEEAction = EE_CFG_SAVE;
 | 
				
			||||||
    // end: POST Form Source CAN Settings
 | 
					    // end: POST Form Source CAN Settings
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
    // begin: POST Form Lubrication
 | 
					    // begin: POST Form Lubrication
 | 
				
			||||||
    if (p->name() == "lubedistancenormal")
 | 
					    if (p->name() == "lubedistancenormal")
 | 
				
			||||||
      LubeConfig.DistancePerLube_Default = p->value().toInt();
 | 
					      LubeConfig.DistancePerLube_Default = p->value().toInt();
 | 
				
			||||||
@@ -489,12 +461,8 @@ void WebserverEERestore_Callback(AsyncWebServerRequest *request, const String &f
 | 
				
			|||||||
        LubeConfig.DistancePerRevolution_mm = doc["config"]["DistancePerRevolution_mm"].as<uint32_t>();
 | 
					        LubeConfig.DistancePerRevolution_mm = doc["config"]["DistancePerRevolution_mm"].as<uint32_t>();
 | 
				
			||||||
        LubeConfig.BleedingPulses = doc["config"]["BleedingPulses"].as<uint16_t>();
 | 
					        LubeConfig.BleedingPulses = doc["config"]["BleedingPulses"].as<uint16_t>();
 | 
				
			||||||
        LubeConfig.SpeedSource = (SpeedSource_t)doc["config"]["SpeedSource"].as<int>();
 | 
					        LubeConfig.SpeedSource = (SpeedSource_t)doc["config"]["SpeedSource"].as<int>();
 | 
				
			||||||
#ifdef FEATURE_ENABLE_GPS
 | 
					 | 
				
			||||||
        LubeConfig.GPSBaudRate = (GPSBaudRate_t)doc["config"]["GPSBaudRate"].as<int>();
 | 
					        LubeConfig.GPSBaudRate = (GPSBaudRate_t)doc["config"]["GPSBaudRate"].as<int>();
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
#ifdef FEATURE_ENABLE_CAN
 | 
					 | 
				
			||||||
        LubeConfig.CANSource = (CANSource_t)doc["config"]["CANSource"].as<int>();
 | 
					        LubeConfig.CANSource = (CANSource_t)doc["config"]["CANSource"].as<int>();
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
        LubeConfig.LED_Mode_Flash = doc["config"]["LED_Mode_Flash"].as<bool>();
 | 
					        LubeConfig.LED_Mode_Flash = doc["config"]["LED_Mode_Flash"].as<bool>();
 | 
				
			||||||
        LubeConfig.LED_Max_Brightness = doc["config"]["LED_Max_Brightness"].as<uint8_t>();
 | 
					        LubeConfig.LED_Max_Brightness = doc["config"]["LED_Max_Brightness"].as<uint8_t>();
 | 
				
			||||||
        LubeConfig.LED_Min_Brightness = doc["config"]["LED_Min_Brightness"].as<uint8_t>();
 | 
					        LubeConfig.LED_Min_Brightness = doc["config"]["LED_Min_Brightness"].as<uint8_t>();
 | 
				
			||||||
@@ -522,9 +490,6 @@ void WebserverEERestore_Callback(AsyncWebServerRequest *request, const String &f
 | 
				
			|||||||
      Debug_pushMessage("Update complete");
 | 
					      Debug_pushMessage("Update complete");
 | 
				
			||||||
      globals.systemStatus = sysStat_Shutdown;
 | 
					      globals.systemStatus = sysStat_Shutdown;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    else
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -559,14 +524,10 @@ void WebServerEEJSON_Callback(AsyncWebServerRequest *request)
 | 
				
			|||||||
  config["BleedingPulses"] = LubeConfig.BleedingPulses;
 | 
					  config["BleedingPulses"] = LubeConfig.BleedingPulses;
 | 
				
			||||||
  config["SpeedSource"] = LubeConfig.SpeedSource;
 | 
					  config["SpeedSource"] = LubeConfig.SpeedSource;
 | 
				
			||||||
  config["SpeedSource_Str"] = SpeedSourceString[LubeConfig.SpeedSource];
 | 
					  config["SpeedSource_Str"] = SpeedSourceString[LubeConfig.SpeedSource];
 | 
				
			||||||
#ifdef FEATURE_ENABLE_GPS
 | 
					 | 
				
			||||||
  config["GPSBaudRate"] = LubeConfig.GPSBaudRate;
 | 
					  config["GPSBaudRate"] = LubeConfig.GPSBaudRate;
 | 
				
			||||||
  config["GPSBaudRate_Str"] = GPSBaudRateString[LubeConfig.GPSBaudRate];
 | 
					  config["GPSBaudRate_Str"] = GPSBaudRateString[LubeConfig.GPSBaudRate];
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
#ifdef FEATURE_ENABLE_CAN
 | 
					 | 
				
			||||||
  config["CANSource"] = LubeConfig.CANSource;
 | 
					  config["CANSource"] = LubeConfig.CANSource;
 | 
				
			||||||
  config["CANSource_Str"] = CANSourceString[LubeConfig.CANSource];
 | 
					  config["CANSource_Str"] = CANSourceString[LubeConfig.CANSource];
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
  config["LED_Mode_Flash"] = LubeConfig.LED_Mode_Flash;
 | 
					  config["LED_Mode_Flash"] = LubeConfig.LED_Mode_Flash;
 | 
				
			||||||
  config["LED_Max_Brightness"] = LubeConfig.LED_Max_Brightness;
 | 
					  config["LED_Max_Brightness"] = LubeConfig.LED_Max_Brightness;
 | 
				
			||||||
  config["LED_Min_Brightness"] = LubeConfig.LED_Min_Brightness;
 | 
					  config["LED_Min_Brightness"] = LubeConfig.LED_Min_Brightness;
 | 
				
			||||||
@@ -595,13 +556,15 @@ void WebServerEEJSON_Callback(AsyncWebServerRequest *request)
 | 
				
			|||||||
  request->send(response);
 | 
					  request->send(response);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef FEATURE_ENABLE_WEBSOCKETS
 | 
					 | 
				
			||||||
void WebsocketEvent_Callback(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len)
 | 
					void WebsocketEvent_Callback(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  switch (type)
 | 
					  switch (type)
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
  case WS_EVT_CONNECT:
 | 
					  case WS_EVT_CONNECT:
 | 
				
			||||||
    Debug_pushMessage("WebSocket client #%u connected from %s\n", client->id(), client->remoteIP().toString().c_str());
 | 
					    Debug_pushMessage("WebSocket client #%u connected from %s\n", client->id(), client->remoteIP().toString().c_str());
 | 
				
			||||||
 | 
					    Websocket_RefreshClientData_Status(client->id(), true);
 | 
				
			||||||
 | 
					    Websocket_RefreshClientData_Static(client->id(), true);
 | 
				
			||||||
 | 
					    Websocket_RefreshClientData_DTCs(client->id());
 | 
				
			||||||
    break;
 | 
					    break;
 | 
				
			||||||
  case WS_EVT_DISCONNECT:
 | 
					  case WS_EVT_DISCONNECT:
 | 
				
			||||||
    Debug_pushMessage("WebSocket client #%u disconnected\n", client->id());
 | 
					    Debug_pushMessage("WebSocket client #%u disconnected\n", client->id());
 | 
				
			||||||
@@ -644,30 +607,151 @@ void Websocket_PushLiveDebug(String Message)
 | 
				
			|||||||
  webSocket.textAll("DEBUG:" + Message);
 | 
					  webSocket.textAll("DEBUG:" + Message);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Websocket_RefreshClientData_DTCs()
 | 
					void Websocket_RefreshClientData_DTCs(uint32_t client_id)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  String temp = "";
 | 
					  String temp = "DTC:";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Build DTC-String
 | 
					  // Build DTC-String
 | 
				
			||||||
  if (globals.hasDTC != true)
 | 
					  if (globals.hasDTC != true)
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    temp = "DTC:" + String(DTC_NO_DTC) + ";";
 | 
					    temp.concat(String(DTC_NO_DTC) + ";");
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  else
 | 
					  else
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    temp = "DTC:";
 | 
					 | 
				
			||||||
    for (uint32_t i = 0; i < MAX_DTC_STORAGE; i++)
 | 
					    for (uint32_t i = 0; i < MAX_DTC_STORAGE; i++)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      if (DTCStorage[i].Number < DTC_LAST_DTC)
 | 
					      if (DTCStorage[i].Number < DTC_LAST_DTC)
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
        temp = temp + String(DTCStorage[i].timestamp) + ",";
 | 
					        temp.concat(String(DTCStorage[i].timestamp) + ",");
 | 
				
			||||||
        temp = temp + String(DTCStorage[i].Number) + ",";
 | 
					        temp.concat(String(DTCStorage[i].Number) + ",");
 | 
				
			||||||
        temp = temp + String(getSeverityForDTC(DTCStorage[i].Number)) + ",";
 | 
					        temp.concat(String(getSeverityForDTC(DTCStorage[i].Number)) + ",");
 | 
				
			||||||
        temp = temp + String(DTCStorage[i].active) + ",";
 | 
					        temp.concat(String(DTCStorage[i].active) + ",");
 | 
				
			||||||
        temp = temp + String(DTCStorage[i].debugVal) + ";";
 | 
					        temp.concat(String(DTCStorage[i].debugVal) + ";");
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					  if (client_id > 0)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    webSocket.text(client_id, temp);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  else
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
    webSocket.textAll(temp);
 | 
					    webSocket.textAll(temp);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
#endif
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Websocket_RefreshClientData_Status(uint32_t client_id, bool send_mapping)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (send_mapping)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    const char mapping[] = "MAPPING_STATUS:"
 | 
				
			||||||
 | 
					                           "SystemStatus;"
 | 
				
			||||||
 | 
					                           "TankRemain;"
 | 
				
			||||||
 | 
					                           "TravelDistance_hr;"
 | 
				
			||||||
 | 
					                           "Odometer;"
 | 
				
			||||||
 | 
					                           "Odometer_mm;"
 | 
				
			||||||
 | 
					                           "writeCycleCounter;"
 | 
				
			||||||
 | 
					                           "BleedingPulses;"
 | 
				
			||||||
 | 
					                           "TankPercent;";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (client_id > 0)
 | 
				
			||||||
 | 
					      webSocket.text(client_id, mapping);
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					      webSocket.textAll(mapping);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  String temp = "STATUS:";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  temp.concat(String(globals.systemStatustxt) + ";");
 | 
				
			||||||
 | 
					  temp.concat(String(PersistenceData.tankRemain_microL) + ";");
 | 
				
			||||||
 | 
					  temp.concat(String(PersistenceData.TravelDistance_highRes_mm) + ";");
 | 
				
			||||||
 | 
					  temp.concat(String(PersistenceData.odometer) + ";");
 | 
				
			||||||
 | 
					  temp.concat(String(PersistenceData.odometer_mm / 1000) + ";");
 | 
				
			||||||
 | 
					  temp.concat(String(PersistenceData.writeCycleCounter) + ";");
 | 
				
			||||||
 | 
					  temp.concat(String(LubeConfig.BleedingPulses) + ";");
 | 
				
			||||||
 | 
					  temp.concat(String((PersistenceData.tankRemain_microL / 10) / LubeConfig.tankCapacity_ml) + ";");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (client_id > 0)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    webSocket.text(client_id, temp);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  else
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    webSocket.textAll(temp);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Websocket_RefreshClientData_Static(uint32_t client_id, bool send_mapping)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (send_mapping)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    const char mapping[] = "MAPPING_STATIC:"
 | 
				
			||||||
 | 
					                           "DeviceName;"
 | 
				
			||||||
 | 
					                           "EEPROM_Version;"
 | 
				
			||||||
 | 
					                           "ConfigChecksum;"
 | 
				
			||||||
 | 
					                           "DistanceDefault;"
 | 
				
			||||||
 | 
					                           "DistanceRain;"
 | 
				
			||||||
 | 
					                           "tankCapacity;"
 | 
				
			||||||
 | 
					                           "amountPerDose;"
 | 
				
			||||||
 | 
					                           "TankRemindAtPercentage;"
 | 
				
			||||||
 | 
					                           "PulsePerRevolution;"
 | 
				
			||||||
 | 
					                           "TireWidth_mm;"
 | 
				
			||||||
 | 
					                           "TireWidthHeight_Ratio;"
 | 
				
			||||||
 | 
					                           "RimDiameter_Inch;"
 | 
				
			||||||
 | 
					                           "DistancePerRevolution_mm;"
 | 
				
			||||||
 | 
					                           "SpeedSourceString;"
 | 
				
			||||||
 | 
					                           "GPSBaudRateString;"
 | 
				
			||||||
 | 
					                           "CANSourceString;"
 | 
				
			||||||
 | 
					                           "LED_Mode_Flash;"
 | 
				
			||||||
 | 
					                           "LED_Max;"
 | 
				
			||||||
 | 
					                           "LED_Min;"
 | 
				
			||||||
 | 
					                           "eePersistanceAdress;"
 | 
				
			||||||
 | 
					                           "PersisChecksum";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (client_id > 0)
 | 
				
			||||||
 | 
					      webSocket.text(client_id, mapping);
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					      webSocket.textAll(mapping);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  String temp = "STATIC:";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  temp.concat(String(globals.DeviceName) + ";");
 | 
				
			||||||
 | 
					  temp.concat(String(LubeConfig.EEPROM_Version) + ";");
 | 
				
			||||||
 | 
					  temp.concat(String(LubeConfig.checksum) + ";");
 | 
				
			||||||
 | 
					  temp.concat(String(LubeConfig.DistancePerLube_Default) + ";");
 | 
				
			||||||
 | 
					  temp.concat(String(LubeConfig.DistancePerLube_Rain) + ";");
 | 
				
			||||||
 | 
					  temp.concat(String(LubeConfig.tankCapacity_ml) + ";");
 | 
				
			||||||
 | 
					  temp.concat(String(LubeConfig.amountPerDose_microL) + ";");
 | 
				
			||||||
 | 
					  temp.concat(String(LubeConfig.TankRemindAtPercentage) + ";");
 | 
				
			||||||
 | 
					  temp.concat(String(LubeConfig.PulsePerRevolution) + ";");
 | 
				
			||||||
 | 
					  temp.concat(String(LubeConfig.TireWidth_mm) + ";");
 | 
				
			||||||
 | 
					  temp.concat(String(LubeConfig.TireWidthHeight_Ratio) + ";");
 | 
				
			||||||
 | 
					  temp.concat(String(LubeConfig.RimDiameter_Inch) + ";");
 | 
				
			||||||
 | 
					  temp.concat(String(LubeConfig.DistancePerRevolution_mm) + ";");
 | 
				
			||||||
 | 
					  temp.concat(String(SpeedSourceString[LubeConfig.SpeedSource]) + ";");
 | 
				
			||||||
 | 
					  temp.concat(String(GPSBaudRateString[LubeConfig.GPSBaudRate]) + ";");
 | 
				
			||||||
 | 
					  temp.concat(String(CANSourceString[LubeConfig.CANSource]) + ";");
 | 
				
			||||||
 | 
					  temp.concat(String(LubeConfig.LED_Mode_Flash) + ";");
 | 
				
			||||||
 | 
					  temp.concat(String(LubeConfig.LED_Max_Brightness) + ";");
 | 
				
			||||||
 | 
					  temp.concat(String(LubeConfig.LED_Min_Brightness) + ";");
 | 
				
			||||||
 | 
					  temp.concat(String(globals.eePersistanceAdress) + ";");
 | 
				
			||||||
 | 
					  temp.concat(String(PersistenceData.checksum) + ";");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  for (uint32_t i = 0; i < SpeedSourceString_Elements; i++)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    temp.concat(String(SpeedSourceString[i]) + ",");
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  temp.concat(";");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (client_id > 0)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    webSocket.text(client_id, temp);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  else
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    webSocket.textAll(temp);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user