BWP-SS19-01/Fein Design/BLEundLogging: Unterschied zwischen den Versionen

Aus Verteilte Systeme - Wiki
Zur Navigation springen Zur Suche springen
 
(17 dazwischenliegende Versionen desselben Benutzers werden nicht angezeigt)
Zeile 1: Zeile 1:
  +
= Bluetooth-Low-Energy (BLE) und Logging =
Mittels der Funktion '''void BLE_SendData(void * Data, int Art_des_Inhaltes)''' kann jedes Modul eine Nachricht absenden.<br>
 
  +
Das BLE und Logging Modul besteht aus einem Header-File (BLE_and_Logging.h) und einem C-File (BLE_and_Logging.c).<br><br>
Intern arbeitet die Funktion mit einem Switch-case, um je nach Inhalt die ersten 4 Bits in der Bluetooth-Nachricht entsprechend zu setzen.<br>
 
   
  +
Die Aufgaben des BLE Moduls sind:
  +
* Alle anfallenden Daten als Nachricht verpacken und diese versenden
  +
* Unterscheidung welches Modul welche Daten versendet
  +
* Logging der versendeten Daten
  +
* Aufbereitung der Logging-Daten
   
  +
== BLE_and_Logging.h ==
''Protokoll-Flags''<br>
 
  +
Das Header-File besteht im Wesentlichen aus den Funktions-Deklarationen und Konstanten.<br>
- '''"AA FF"''' - Übertragung des aktuellen Akkustands mittels Float.<br><br>
 
  +
Funktions-Deklarationen:
  +
<pre>
  +
void bt_ready(int err);
  +
void ble_and_logging(void* arg1, void* arg2, void* arg3);
  +
void ble_set_data(char *data, int art_der_daten);
  +
void send_ble_msg(char *data);
  +
</pre>
  +
Zusätzlich sind verschiedene System-Konstante und ein Include der Bluetooth-Bibliotheken notwendig, um Bluetooth auf dem Feather nutzen zu können:
  +
Die Buffergröße, der Name des Devices und die Länge des Namens. Zusätzlich werden die notwendigen Bluetooth-Bibliotheken eingebunden.
  +
<pre>
  +
#ifndef CONFIG_NET_BUF_USER_DATA_SIZE
  +
#define CONFIG_NET_BUF_USER_DATA_SIZE 8
  +
#endif
   
  +
#ifndef CONFIG_BT_DEVICE_NAME
- '''"FE A0"''' - Übertragung eines SUCCESS<br>
 
  +
#define CONFIG_BT_DEVICE_NAME "ITSE"
- '''"FE A1"''' - Übertragung eines WARNINGs (Stufe 1)<br>
 
  +
#endif
- '''"FE A2"''' - Übertragung eines ERRORs (Stufe 2)<br>
 
- '''"FE A3"''' - Übertragung eines FATAL_ERRORs (Stufe 3)<br><br>
 
   
  +
#ifndef DEVICE_NAME_LEN
- '''"EE EE"''' - Nachricht "Sleepmodus aktiv"<br>
 
  +
#define DEVICE_NAME_LEN 4
- '''"EE EF"''' - Nachricht "Sleepmodus inaktiv"<br><br>
 
  +
#endif
   
  +
#include <bluetooth/hci.h>
Weitere Protokoll-Flags kommen im Laufe der weiteren Entwicklung dazu.<br>
 
  +
#include <bluetooth/bluetooth.h>
Außerdem wird in der weiteren Entwicklung ein Timestamp und von welchem Modul die Nachricht versendet wurde hinzukommen, sodass das Filtern der Daten einfacher und eindeutiger gestaltet werden kann.<br>
 
  +
</pre>
Beispielsweise wird der Log-Eintrag wie folgt aussehen:<br>
 
  +
'''2018-12-25 09:27:53 Energiemanagement AKKU: 33.6'''<br>
 
  +
Desweiteren befinden sich in diesem Header-File Konstante, die lediglich zur Dokumentation dienen:
  +
<pre>
  +
/* BLE Logging IDs and text */
  +
#define ITSELOGTYPE_ENERGIEMANAGEMENTSYSTEM_SUCCESS 0
  +
#define ITSELOGTYPE_ENERGIEMANAGEMENTSYSTEM_WARNING 1
  +
#define ITSELOGTYPE_ENERGIEMANAGEMENTSYSTEM_ERROR 2
  +
#define ITSELOGTYPE_ENERGIEMANAGEMENTSYSTEM_FATAL_ERROR 3
  +
#define ITSELOGTYPE_ENERGIEMANAGEMENTSYSTEM_AKKU 4
  +
#define ITSELOGTYPE_ENERGIEMANAGEMENTSYSTEM_SLEEP 5
  +
#define ITSELOGTYPE_ODOMETRY_SUCCESS 6
  +
#define ITSELOGTYPE_ODOMETRY_WARNING 7
  +
#define ITSELOGTYPE_ODOMETRY_ERROR 8
  +
#define ITSELOGTYPE_ODOMETRY_FATAL_ERROR 9
  +
#define ITSELOGTYPE_MAINCONTROL_SUCCESS 10
  +
#define ITSELOGTYPE_MAINCONTROL_WARNING 11
  +
#define ITSELOGTYPE_MAINCONTROL_ERROR 12
  +
#define ITSELOGTYPE_MAINCONTROL_FATAL_ERROR 13
  +
  +
#define ITSELOGTEXT_ENERGIEMANAGEMENTSYSTEM_SUCCESS "ENERGIEMANAGEMENT SUCCESS"
  +
#define ITSELOGTEXT_ENERGIEMANAGEMENTSYSTEM_WARNING "ENERGIEMANAGEMENT WARNING"
  +
#define ITSELOGTEXT_ENERGIEMANAGEMENTSYSTEM_ERROR "ENERGIEMANAGEMENT ERROR"
  +
#define ITSELOGTEXT_ENERGIEMANAGEMENTSYSTEM_FATAL_ERROR "ENERGIEMANAGEMENT FATAL_ERROR"
  +
#define ITSELOGTEXT_ENERGIEMANAGEMENTSYSTEM_AKKU "ENERGIEMANAGEMENT AKKU"
  +
#define ITSELOGTEXT_ENERGIEMANAGEMENTSYSTEM_SLEEP "ENERGIEMANAGEMENT SLEEP"
  +
#define ITSELOGTEXT_ODOMETRY_SUCCESS "ODOMETRY SUCCESS"
  +
#define ITSELOGTEXT_ODOMETRY_WARNING "ODOMETRY WARNING"
  +
#define ITSELOGTEXT_ODOMETRY_ERROR "ODOMETRY ERROR"
  +
#define ITSELOGTEXT_ODOMETRY_FATAL_ERROR "ODOMETRY FATAL_ERROR"
  +
#define ITSELOGTEXT_MAINCONTROL_SUCCESS "MAINCONTROL SUCCESS"
  +
#define ITSELOGTEXT_MAINCONTROL_WARNING "MAINCONTROL WARNING"
  +
#define ITSELOGTEXT_MAINCONTROL_ERROR "MAINCONTROL ERROR"
  +
#define ITSELOGTEXT_MAINCONTROL_FATAL_ERROR "MAINCONTROL FATAL_ERROR"
  +
#define ITSELOGTEXT_UNDEFINED "UNDEFINED NACHRICHT"
  +
  +
#define ITSELOGFLAGS_ENERGIEMANAGEMENTSYSTEM_SUCCESS "F1 A0"
  +
#define ITSELOGFLAGS_ENERGIEMANAGEMENTSYSTEM_WARNING "F1 A1"
  +
#define ITSELOGFLAGS_ENERGIEMANAGEMENTSYSTEM_ERROR "F1 A2"
  +
#define ITSELOGFLAGS_ENERGIEMANAGEMENTSYSTEM_FATAL_ERROR "F1 A3"
  +
#define ITSELOGFLAGS_ENERGIEMANAGEMENTSYSTEM_AKKU "F1 A4"
  +
#define ITSELOGFLAGS_ENERGIEMANAGEMENTSYSTEM_SLEEP "F1 A5"
  +
#define ITSELOGFLAGS_ODOMETRY_SUCCESS "F2 A0"
  +
#define ITSELOGFLAGS_ODOMETRY_WARNING "F2 A1"
  +
#define ITSELOGFLAGS_ODOMETRY_ERROR "F2 A2"
  +
#define ITSELOGFLAGS_ODOMETRY_FATAL_ERROR "F2 A3"
  +
#define ITSELOGFLAGS_MAINCONTROL_SUCCESS "F3 A0"
  +
#define ITSELOGFLAGS_MAINCONTROL_WARNING "F3 A1"
  +
#define ITSELOGFLAGS_MAINCONTROL_ERROR "F3 A2"
  +
#define ITSELOGFLAGS_MAINCONTROL_FATAL_ERROR "F3 A3"
  +
#define ITSELOGFLAGS_UNDEFINED_NACHRICHT "FF FF"
  +
</pre>
  +
  +
== BLE_and_Logging.c ==
  +
Die Funktion '''void ble_and_logging(void* arg1, void* arg2, void* arg3) {...}''' startet den Thread und initialisiert das Bluetooth-Modul auf dem Feather.<br><br>
  +
  +
Mittels der Funktion '''void ble_set_data(char *data, int art_der_daten);''' kann jedes Modul eine Nachricht absenden.<br>
  +
Intern arbeitet die Funktion mit einem Switch-case, um je nach Inhalt die ersten 4 Bits in der Bluetooth-Nachricht entsprechend zu setzen.<br>
  +
Um eine Nachricht des Energiemanagementsystems (SUCCESS) zu setzen, wird folgender Code-Abschnitt verwendet:
  +
<pre>
  +
switch(art_der_daten) {
  +
case 0:
  +
new_string[0] = 0xF1;
  +
new_string[1] = 0XA0;
  +
strcat(new_string, s_string);
  +
break;
  +
</pre>
  +
  +
  +
Beispielsweise sieht ein Log-Eintrag wie folgt aus:<br>
  +
'''12 2018-12-25 09:27:53 ENERGIEMANAGEMENT SUCCESS: AKKU: 33.6'''<br>
  +
  +
Nach dem setzen der Nachricht wird innerhalb der o.g. Funktion die Sende-Funktion '''void send_ble_msg(char *data);''' aufgerufen und mittels '''bt_le_adv_start(...);''' das Senden gestartet.<br>
  +
Die Funktion ist Teil des Zephyr-Systems und befindet sich unter '''bluetooth/bluetooth.h'''.<br>
 
<br>
 
<br>
  +
<br>
 
  +
== ble.py ==
HIER '''void BLE_SendData(void * Data, int Art_des_Inhaltes)''' Code einfügen.
 
<br><br><br>
 
 
Auf der anderen Seite wird das gesendete Signal empfangen. Dies passiert mittels einem BLE-USB-Stick, einem Laptop und einem Python-Script. <br>
 
Auf der anderen Seite wird das gesendete Signal empfangen. Dies passiert mittels einem BLE-USB-Stick, einem Laptop und einem Python-Script. <br>
 
Das Python-Script nutzt die ''''bluepy''''-Bibliothek, welches [[https://github.com/IanHarvey/bluepy | hier]] verfügbar ist.<br>
 
Das Python-Script nutzt die ''''bluepy''''-Bibliothek, welches [[https://github.com/IanHarvey/bluepy | hier]] verfügbar ist.<br>
   
 
Das Script empfängt zum Einen die Nachricht und zum Anderen werden die übermittelten Hex-Zeichen in ASCII-Zeichen umgewandelt, damit es für den Mensch besser lesbar ist.<br>
 
Das Script empfängt zum Einen die Nachricht und zum Anderen werden die übermittelten Hex-Zeichen in ASCII-Zeichen umgewandelt, damit es für den Mensch besser lesbar ist.<br>
Hier werden die ersten 4 Bits berücksichtigt und je nach Flag die Nachricht entsprechende dekodiert.
+
Hier werden die ersten 4 Bits berücksichtigt und je nach Flag die Nachricht entsprechende dekodiert.<br>
  +
Zusätzlich werden die geloggten Informationen mittels mehreren .txt zu einer finalen, sortierten Version zusammengefasst. <br>
  +
Da das Senden zwischen Server und Client nicht synchronisiert wird, kommen hier "Sende-IDs" zum Einsatz, um die korrekte Reihenfolge zwischen senden und empfangen zu erhalten.<br>
  +
Beim Absenden der BLE-Nachricht wird am Ende ein Trennzeichen (&) eingefügt, dahinter wird die eine fortlaufende ID angehangen. Diese ID wird erst nach einem Neustart/Reset des Feathers resettet.<br>
 
<br>
 
<br>
 
<br>
 
<br>
Zeile 37: Zeile 129:
 
import datetime
 
import datetime
 
import struct
 
import struct
  +
import os
 
textFile = ""
 
textFile = ""
  +
removeFiles = 0
 
class ScanDelegate(DefaultDelegate):
 
class ScanDelegate(DefaultDelegate):
 
def __init__(self):
 
def __init__(self):
Zeile 51: Zeile 145:
   
 
scanner = Scanner().withDelegate(ScanDelegate())
 
scanner = Scanner().withDelegate(ScanDelegate())
  +
# how long should this scan run? (in seconds)
devices = scanner.scan(10.0)
 
  +
devices = scanner.scan(60.0)
 
f = open(textFile + ".txt", "w+")
 
f = open(textFile + ".txt", "w+")
 
for dev in devices:
 
for dev in devices:
 
print "Device %s (%s), RSSI=%d dB" % (dev.addr, dev.addrType, dev.rssi)
 
print "Device %s (%s), RSSI=%d dB" % (dev.addr, dev.addrType, dev.rssi)
#print "Test %s" % (dev.getValueText())
 
 
for (adtype, desc, value) in dev.getScanData():
 
for (adtype, desc, value) in dev.getScanData():
#print " %s = %s = %s" % (adtype, desc, value)
 
#print " %s = %s" % (adtype, value)
 
 
f.write("%s = %s\n" % (adtype, value))
 
f.write("%s = %s\n" % (adtype, value))
 
f.close()
 
f.close()
Zeile 68: Zeile 160:
 
# now, lets read this file
 
# now, lets read this file
 
fIn = open(textFile + ".txt", "r")
 
fIn = open(textFile + ".txt", "r")
fOut = open(textFileNew, "a+")
+
fOut = open(textFile + "New" + ".txt", "a+")
  +
# check if append-open works
  +
# if file was not created yet, create it
 
if fIn.mode == 'r' and fOut.mode == "a+":
 
if fIn.mode == 'r' and fOut.mode == "a+":
  +
# read first line
print "OK.. lets read\n"
 
 
contents = fIn.readline()
 
contents = fIn.readline()
  +
timestamp = datetime.datetime.now()
 
 
while contents:
 
while contents:
  +
# content starting with 255 is the message
 
if "255" in contents:
 
if "255" in contents:
  +
# slice the message (remove "255 = ")
 
msg = contents[6:]
 
msg = contents[6:]
  +
# check first two bits and bit 3 and 4
#print "MSG: ",msg
 
  +
if "f1" in msg[:2] and "a0" in msg[2:4]:
 
  +
timestamp = datetime.datetime.now()
if "ff" in msg[:2] and "a0" in msg[2:4]:
 
fOut.write("SUCCESS: ")
+
toWrite = str(timestamp)+" ENERGIEMANAGEMENT SUCCESS: "
  +
# write to file
if "ff" in msg[:2] and "a1" in msg[2:4]:
 
fOut.write("WARNING: ")
+
fOut.write(toWrite)
if "ff" in msg[:2] and "a2" in msg[2:4]:
+
if "f1" in msg[:2] and "a1" in msg[2:4]:
  +
timestamp = datetime.datetime.now()
fOut.write("ERROR: ")
 
  +
toWrite = str(timestamp)+" ENERGIEMANAGEMENT WARNING: "
if "ff" in msg[:2] and "a3" in msg[2:4]:
 
fOut.write("FATAL ERROR: ")
+
fOut.write(toWrite)
if "ee" in msg[:2] and "ee" in msg[2:4]:
+
if "f1" in msg[:2] and "a2" in msg[2:4]:
  +
timestamp = datetime.datetime.now()
fOut.write("MSG: ")
 
  +
toWrite = str(timestamp)+" ENERGIEMANAGEMENT ERROR: "
if "ee" in msg[:2] and "ef" in msg[2:4]:
 
fOut.write("MSG: ")
+
fOut.write(toWrite)
if "aa" in msg[:2] and "ff" in msg[2:4]:
+
if "f1" in msg[:2] and "a3" in msg[2:4]:
  +
timestamp = datetime.datetime.now()
fOut.write("AKKU: ")
 
  +
toWrite = str(timestamp)+" ENERGIEMANAGEMENT FATAL_ERROR: "
 
  +
fOut.write(toWrite)
  +
if "f1" in msg[:2] and "a4" in msg[2:4]:
  +
timestamp = datetime.datetime.now()
  +
toWrite = str(timestamp)+" ENERGIEMANAGEMENT AKKU: "
  +
fOut.write(toWrite)
  +
if "f2" in msg[:2] and "a0" in msg[2:4]:
  +
timestamp = datetime.datetime.now()
  +
toWrite = str(timestamp)+" ODOMETRY SUCCESS: "
  +
fOut.write(toWrite)
  +
if "f2" in msg[:2] and "a1" in msg[2:4]:
  +
timestamp = datetime.datetime.now()
  +
toWrite = str(timestamp)+" ODOMETRY WARNING: "
  +
fOut.write(toWrite)
  +
if "f2" in msg[:2] and "a2" in msg[2:4]:
  +
timestamp = datetime.datetime.now()
  +
toWrite = str(timestamp)+" ODOMETRY ERROR: "
  +
fOut.write(toWrite)
  +
if "f2" in msg[:2] and "a3" in msg[2:4]:
  +
timestamp = datetime.datetime.now()
  +
toWrite = str(timestamp)+" ODOMETRY FATAL_ERROR: "
  +
fOut.write(toWrite)
  +
if "f3" in msg[:2] and "a0" in msg[2:4]:
  +
timestamp = datetime.datetime.now()
  +
toWrite = str(timestamp)+" MAINCONTROL SUCCESS: "
  +
fOut.write(toWrite)
  +
if "f3" in msg[:2] and "a1" in msg[2:4]:
  +
timestamp = datetime.datetime.now()
  +
toWrite = str(timestamp)+" MAINCONTROL WARNING: "
  +
fOut.write(toWrite)
  +
if "f3" in msg[:2] and "a2" in msg[2:4]:
  +
timestamp = datetime.datetime.now()
  +
toWrite = str(timestamp)+" MAINCONTROL ERROR: "
  +
fOut.write(toWrite)
  +
if "f3" in msg[:2] and "a3" in msg[2:4]:
  +
timestamp = datetime.datetime.now()
  +
toWrite = str(timestamp)+" MAINCONTROL FATAL_ERROR: "
  +
fOut.write(toWrite)
  +
if "ff" in msg[:2] and "ff" in msg[2:4]:
  +
timestamp = datetime.datetime.now()
  +
toWrite = str(timestamp)+" UNDEFINED NACHRICHT: "
  +
fOut.write(toWrite)
  +
# slice the message from bit 5 to the end
 
newMsg = msg[4:]
 
newMsg = msg[4:]
 
# the first appear of the "00" string shows the end of the message!
 
# the first appear of the "00" string shows the end of the message!
 
findMsg = newMsg.find("00")
 
findMsg = newMsg.find("00")
 
 
for i in range(0, findMsg, 2):
 
for i in range(0, findMsg, 2):
  +
# slice every 2 bits
 
toConvert = newMsg[i:i+2]
 
toConvert = newMsg[i:i+2]
 
zahl = int(setHex+toConvert,16)
 
zahl = int(setHex+toConvert,16)
print zahl,'=>',chr(zahl)
+
#print zahl,'=>',chr(zahl)
  +
# write ASCII text to the file
 
fOut.write(chr(zahl))
 
fOut.write(chr(zahl))
 
fOut.write("\n")
 
fOut.write("\n")
Zeile 107: Zeile 246:
 
fOut.close()
 
fOut.close()
   
  +
fIn = open(textFile + "New.txt", "r")
</pre>
 
  +
fOut = open(textFile + "NewSorted.txt", "a+")
  +
if fIn.mode == 'r' and fOut.mode == "a+":
  +
contents = fIn.readline()
  +
while contents:
  +
# find & at the end of the message
  +
# the & declares the beginning of the id number
  +
findSplit = contents.find("&")
  +
# split message to get id
  +
toWrite = contents[findSplit+1:]+contents[:findSplit]
  +
replaceBN = toWrite.replace("\n"," ")
  +
fOut.write(replaceBN)
  +
fOut.write("\n")
  +
contents = fIn.readline()
  +
fIn.close()
  +
# linux sort command
  +
linuxCMDSort = "sudo sort -n -o " + "sorted.txt " + textFile + "NewSorted.txt"
  +
fOut.close()
  +
# run sort command
  +
os.system(linuxCMDSort)
  +
if removeFiles == 1:
  +
linuxCMDRM1 = textFile + ".txt"
  +
linuxCMDRM2 = textFile + "New.txt"
  +
linuxCMDRM3 = textFile + "NewSorted.txt"
  +
os.remove(linuxCMDRM1)
  +
os.remove(linuxCMDRM2)
  +
os.remove(linuxCMDRM3)
  +
print ".txt files are removed..\n"
  +
else:
  +
print ".txt files are not removed..\n"</pre>
 
<br>
 
<br>

Aktuelle Version vom 24. August 2019, 12:14 Uhr

Bluetooth-Low-Energy (BLE) und Logging

Das BLE und Logging Modul besteht aus einem Header-File (BLE_and_Logging.h) und einem C-File (BLE_and_Logging.c).

Die Aufgaben des BLE Moduls sind:

  • Alle anfallenden Daten als Nachricht verpacken und diese versenden
  • Unterscheidung welches Modul welche Daten versendet
  • Logging der versendeten Daten
  • Aufbereitung der Logging-Daten

BLE_and_Logging.h

Das Header-File besteht im Wesentlichen aus den Funktions-Deklarationen und Konstanten.
Funktions-Deklarationen:

void bt_ready(int err);
void ble_and_logging(void* arg1, void* arg2, void* arg3);
void ble_set_data(char *data, int art_der_daten);
void send_ble_msg(char *data);

Zusätzlich sind verschiedene System-Konstante und ein Include der Bluetooth-Bibliotheken notwendig, um Bluetooth auf dem Feather nutzen zu können: Die Buffergröße, der Name des Devices und die Länge des Namens. Zusätzlich werden die notwendigen Bluetooth-Bibliotheken eingebunden.

#ifndef CONFIG_NET_BUF_USER_DATA_SIZE
#define CONFIG_NET_BUF_USER_DATA_SIZE 8
#endif

#ifndef CONFIG_BT_DEVICE_NAME
#define CONFIG_BT_DEVICE_NAME "ITSE"
#endif

#ifndef DEVICE_NAME_LEN
#define DEVICE_NAME_LEN 4
#endif

#include <bluetooth/hci.h>
#include <bluetooth/bluetooth.h>

Desweiteren befinden sich in diesem Header-File Konstante, die lediglich zur Dokumentation dienen:

/* BLE Logging IDs and text */
#define ITSELOGTYPE_ENERGIEMANAGEMENTSYSTEM_SUCCESS 0
#define ITSELOGTYPE_ENERGIEMANAGEMENTSYSTEM_WARNING 1
#define ITSELOGTYPE_ENERGIEMANAGEMENTSYSTEM_ERROR 2
#define ITSELOGTYPE_ENERGIEMANAGEMENTSYSTEM_FATAL_ERROR 3
#define ITSELOGTYPE_ENERGIEMANAGEMENTSYSTEM_AKKU 4
#define ITSELOGTYPE_ENERGIEMANAGEMENTSYSTEM_SLEEP 5
#define ITSELOGTYPE_ODOMETRY_SUCCESS 6
#define ITSELOGTYPE_ODOMETRY_WARNING 7
#define ITSELOGTYPE_ODOMETRY_ERROR 8
#define ITSELOGTYPE_ODOMETRY_FATAL_ERROR 9
#define ITSELOGTYPE_MAINCONTROL_SUCCESS 10
#define ITSELOGTYPE_MAINCONTROL_WARNING 11
#define ITSELOGTYPE_MAINCONTROL_ERROR 12
#define ITSELOGTYPE_MAINCONTROL_FATAL_ERROR 13

#define ITSELOGTEXT_ENERGIEMANAGEMENTSYSTEM_SUCCESS "ENERGIEMANAGEMENT SUCCESS"
#define ITSELOGTEXT_ENERGIEMANAGEMENTSYSTEM_WARNING "ENERGIEMANAGEMENT WARNING"
#define ITSELOGTEXT_ENERGIEMANAGEMENTSYSTEM_ERROR "ENERGIEMANAGEMENT ERROR"
#define ITSELOGTEXT_ENERGIEMANAGEMENTSYSTEM_FATAL_ERROR "ENERGIEMANAGEMENT FATAL_ERROR"
#define ITSELOGTEXT_ENERGIEMANAGEMENTSYSTEM_AKKU "ENERGIEMANAGEMENT AKKU"
#define ITSELOGTEXT_ENERGIEMANAGEMENTSYSTEM_SLEEP "ENERGIEMANAGEMENT SLEEP"
#define ITSELOGTEXT_ODOMETRY_SUCCESS "ODOMETRY SUCCESS"
#define ITSELOGTEXT_ODOMETRY_WARNING "ODOMETRY WARNING"
#define ITSELOGTEXT_ODOMETRY_ERROR "ODOMETRY ERROR"
#define ITSELOGTEXT_ODOMETRY_FATAL_ERROR "ODOMETRY FATAL_ERROR"
#define ITSELOGTEXT_MAINCONTROL_SUCCESS "MAINCONTROL SUCCESS"
#define ITSELOGTEXT_MAINCONTROL_WARNING "MAINCONTROL WARNING"
#define ITSELOGTEXT_MAINCONTROL_ERROR "MAINCONTROL ERROR"
#define ITSELOGTEXT_MAINCONTROL_FATAL_ERROR "MAINCONTROL FATAL_ERROR"
#define ITSELOGTEXT_UNDEFINED "UNDEFINED NACHRICHT"

#define ITSELOGFLAGS_ENERGIEMANAGEMENTSYSTEM_SUCCESS "F1 A0"
#define ITSELOGFLAGS_ENERGIEMANAGEMENTSYSTEM_WARNING "F1 A1"
#define ITSELOGFLAGS_ENERGIEMANAGEMENTSYSTEM_ERROR "F1 A2"
#define ITSELOGFLAGS_ENERGIEMANAGEMENTSYSTEM_FATAL_ERROR "F1 A3"
#define ITSELOGFLAGS_ENERGIEMANAGEMENTSYSTEM_AKKU "F1 A4"
#define ITSELOGFLAGS_ENERGIEMANAGEMENTSYSTEM_SLEEP "F1 A5"
#define ITSELOGFLAGS_ODOMETRY_SUCCESS "F2 A0"
#define ITSELOGFLAGS_ODOMETRY_WARNING "F2 A1"
#define ITSELOGFLAGS_ODOMETRY_ERROR "F2 A2"
#define ITSELOGFLAGS_ODOMETRY_FATAL_ERROR "F2 A3"
#define ITSELOGFLAGS_MAINCONTROL_SUCCESS "F3 A0"
#define ITSELOGFLAGS_MAINCONTROL_WARNING "F3 A1"
#define ITSELOGFLAGS_MAINCONTROL_ERROR "F3 A2"
#define ITSELOGFLAGS_MAINCONTROL_FATAL_ERROR "F3 A3"
#define ITSELOGFLAGS_UNDEFINED_NACHRICHT "FF FF"

BLE_and_Logging.c

Die Funktion void ble_and_logging(void* arg1, void* arg2, void* arg3) {...} startet den Thread und initialisiert das Bluetooth-Modul auf dem Feather.

Mittels der Funktion void ble_set_data(char *data, int art_der_daten); kann jedes Modul eine Nachricht absenden.
Intern arbeitet die Funktion mit einem Switch-case, um je nach Inhalt die ersten 4 Bits in der Bluetooth-Nachricht entsprechend zu setzen.
Um eine Nachricht des Energiemanagementsystems (SUCCESS) zu setzen, wird folgender Code-Abschnitt verwendet:

switch(art_der_daten) {
   case 0:
	new_string[0] = 0xF1;
	new_string[1] = 0XA0;
	strcat(new_string, s_string);
	break;


Beispielsweise sieht ein Log-Eintrag wie folgt aus:
12 2018-12-25 09:27:53 ENERGIEMANAGEMENT SUCCESS: AKKU: 33.6

Nach dem setzen der Nachricht wird innerhalb der o.g. Funktion die Sende-Funktion void send_ble_msg(char *data); aufgerufen und mittels bt_le_adv_start(...); das Senden gestartet.
Die Funktion ist Teil des Zephyr-Systems und befindet sich unter bluetooth/bluetooth.h.

ble.py

Auf der anderen Seite wird das gesendete Signal empfangen. Dies passiert mittels einem BLE-USB-Stick, einem Laptop und einem Python-Script.
Das Python-Script nutzt die 'bluepy'-Bibliothek, welches [| hier] verfügbar ist.

Das Script empfängt zum Einen die Nachricht und zum Anderen werden die übermittelten Hex-Zeichen in ASCII-Zeichen umgewandelt, damit es für den Mensch besser lesbar ist.
Hier werden die ersten 4 Bits berücksichtigt und je nach Flag die Nachricht entsprechende dekodiert.
Zusätzlich werden die geloggten Informationen mittels mehreren .txt zu einer finalen, sortierten Version zusammengefasst.
Da das Senden zwischen Server und Client nicht synchronisiert wird, kommen hier "Sende-IDs" zum Einsatz, um die korrekte Reihenfolge zwischen senden und empfangen zu erhalten.
Beim Absenden der BLE-Nachricht wird am Ende ein Trennzeichen (&) eingefügt, dahinter wird die eine fortlaufende ID angehangen. Diese ID wird erst nach einem Neustart/Reset des Feathers resettet.


# only runs with sudo
# sudo ble.py filename (without .txt)
import bluepy
from bluepy.btle import Scanner, DefaultDelegate
import sys
import datetime
import struct
import os
textFile = ""
removeFiles = 0
class ScanDelegate(DefaultDelegate):
    def __init__(self):
        DefaultDelegate.__init__(self)
        global textFile
        textFile = sys.argv[1]

    def handleDiscovery(self, dev, isNewDev, isNewData):
        if isNewDev:
            print "Discovered device", dev.addr
        elif isNewData:
            print "Received new data from", dev.addr

scanner = Scanner().withDelegate(ScanDelegate())
# how long should this scan run? (in seconds)
devices = scanner.scan(60.0)
f = open(textFile + ".txt", "w+")
for dev in devices:
    print "Device %s (%s), RSSI=%d dB" % (dev.addr, dev.addrType, dev.rssi)
    for (adtype, desc, value) in dev.getScanData():
        f.write("%s = %s\n" % (adtype, value))
f.close()

# lets copy the file to keep the full information
textFileNew = textFile + "New" + ".txt"

setHex = "0x"
# now, lets read this file
fIn = open(textFile + ".txt", "r")
fOut = open(textFile + "New" + ".txt", "a+")
# check if append-open works 
# if file was not created yet, create it
if fIn.mode == 'r' and fOut.mode == "a+":
	# read first line
	contents = fIn.readline()
	timestamp = datetime.datetime.now()
	while contents:
		# content starting with 255 is the message
		if "255" in contents:
			# slice the message (remove "255 = ")
			msg = contents[6:]
			# check first two bits and bit 3 and 4 
			if "f1" in msg[:2] and "a0" in msg[2:4]:
				timestamp = datetime.datetime.now()
				toWrite = str(timestamp)+" ENERGIEMANAGEMENT SUCCESS: "
				# write to file
				fOut.write(toWrite)
			if "f1" in msg[:2] and "a1" in msg[2:4]:
				timestamp = datetime.datetime.now()
				toWrite = str(timestamp)+" ENERGIEMANAGEMENT WARNING: "
				fOut.write(toWrite)
			if "f1" in msg[:2] and "a2" in msg[2:4]:
				timestamp = datetime.datetime.now()
				toWrite = str(timestamp)+" ENERGIEMANAGEMENT ERROR: "
				fOut.write(toWrite)
			if "f1" in msg[:2] and "a3" in msg[2:4]:
				timestamp = datetime.datetime.now()
				toWrite = str(timestamp)+" ENERGIEMANAGEMENT FATAL_ERROR: "
				fOut.write(toWrite)
			if "f1" in msg[:2] and "a4" in msg[2:4]:
				timestamp = datetime.datetime.now()
				toWrite = str(timestamp)+" ENERGIEMANAGEMENT AKKU: "
				fOut.write(toWrite)			
			if "f2" in msg[:2] and "a0" in msg[2:4]:
				timestamp = datetime.datetime.now()
				toWrite = str(timestamp)+" ODOMETRY SUCCESS: "
				fOut.write(toWrite)
			if "f2" in msg[:2] and "a1" in msg[2:4]:
				timestamp = datetime.datetime.now()
				toWrite = str(timestamp)+" ODOMETRY WARNING: "
				fOut.write(toWrite)
			if "f2" in msg[:2] and "a2" in msg[2:4]:
				timestamp = datetime.datetime.now()
				toWrite = str(timestamp)+" ODOMETRY ERROR: "
				fOut.write(toWrite)
			if "f2" in msg[:2] and "a3" in msg[2:4]:
				timestamp = datetime.datetime.now()
				toWrite = str(timestamp)+" ODOMETRY FATAL_ERROR: "
				fOut.write(toWrite)
			if "f3" in msg[:2] and "a0" in msg[2:4]:
				timestamp = datetime.datetime.now()
				toWrite = str(timestamp)+" MAINCONTROL SUCCESS: "
				fOut.write(toWrite)
			if "f3" in msg[:2] and "a1" in msg[2:4]:
				timestamp = datetime.datetime.now()
				toWrite = str(timestamp)+" MAINCONTROL WARNING: "
				fOut.write(toWrite)
			if "f3" in msg[:2] and "a2" in msg[2:4]:
				timestamp = datetime.datetime.now()
				toWrite = str(timestamp)+" MAINCONTROL ERROR: "
				fOut.write(toWrite)
			if "f3" in msg[:2] and "a3" in msg[2:4]:
				timestamp = datetime.datetime.now()
				toWrite = str(timestamp)+" MAINCONTROL FATAL_ERROR: "
				fOut.write(toWrite)
			if "ff" in msg[:2] and "ff" in msg[2:4]:
				timestamp = datetime.datetime.now()
				toWrite = str(timestamp)+" UNDEFINED NACHRICHT: "
				fOut.write(toWrite)
			# slice the message from bit 5 to the end
			newMsg = msg[4:]
			# the first appear of the "00" string shows the end of the message!
			findMsg = newMsg.find("00")
			for i in range(0, findMsg, 2):
				# slice every 2 bits
				toConvert = newMsg[i:i+2]
				zahl = int(setHex+toConvert,16)
				#print zahl,'=>',chr(zahl)
				# write ASCII text to the file
		       		fOut.write(chr(zahl))
			fOut.write("\n")
		contents = fIn.readline()
fIn.close()
fOut.close()

fIn = open(textFile + "New.txt", "r")
fOut = open(textFile + "NewSorted.txt", "a+")
if fIn.mode == 'r' and fOut.mode == "a+":
	contents = fIn.readline()
	while contents:
		# find & at the end of the message
		# the & declares the beginning of the id number
		findSplit = contents.find("&")
		# split message to get id
		toWrite = contents[findSplit+1:]+contents[:findSplit]
		replaceBN = toWrite.replace("\n"," ")
		fOut.write(replaceBN)
		fOut.write("\n")		
		contents = fIn.readline()
fIn.close()
# linux sort command
linuxCMDSort = "sudo sort -n -o " + "sorted.txt " + textFile + "NewSorted.txt"
fOut.close()
# run sort command
os.system(linuxCMDSort)
if removeFiles == 1:
	linuxCMDRM1 = textFile + ".txt"
	linuxCMDRM2 = textFile + "New.txt"
	linuxCMDRM3 = textFile + "NewSorted.txt"
	os.remove(linuxCMDRM1)
	os.remove(linuxCMDRM2)
	os.remove(linuxCMDRM3)
	print ".txt files are removed..\n"
else:
	print ".txt files are not removed..\n"