Daten aus CBCharacteristic auslesen

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

  • TheFuriousLion schrieb:

    Ich hatte nebenbei immer diese Seite (developer.bluetooth.org/gatt/c…eart_rate_measurement.xml) offen.

    Kann es sein, dass ich mit dem & 0x01 auf den ersten Bit zugreife und vergleiche, ob dieser den Key 0 hat?


    nein du greifst auf kein bit zu und liest dessen key aus (gibts nicht), sondern machst eine binäre operation (&) mit dem wert 1 und vergleichst das resultat mit 0 (wenn & höhere priorität hat als == denn sonst passiert was anderes (dank fehlender klammerung))
  • TheFuriousLion schrieb:

    Du bist ein Wahnsinn, Michael! Danke! :)

    Durch deine Antwort hab ich es geschafft:

    Quellcode

    1. if let data = characteristic.value {
    2. let bytes = data.bytes
    3. let reportData = UnsafePointer<UInt8>(bytes)
    4. var bpm: UInt16 = 0
    5. if reportData[0] & 0x01 == 0 {
    6. bpm = UInt16(reportData[1])
    7. } else {
    8. bpm = CFSwapInt16LittleToHost(UInt16(reportData[1]))
    9. }
    10. }

    Musste deinen Code etwas abändern, da ich sonst 18.000 bpm gehabt hätte, was glaub ich nicht gesund wäre.

    Ok, ich bin davon ausgegangen, dass das erste Byte bzw. das niederwertigste Bit davon anzeigt, ob die Daten Big oder Little Endian sind. Aber es zeigt an, ob die Daten in UINT8 oder UINT16 sind.

    TheFuriousLion schrieb:

    Jetzt wo's funktioniert, würd ich's auch gerne verstehen. Aber ich verstehe nur Bahnhof wenn ich das & 0x01 sehe. Viel schlimmer ist der << Operator.

    Dann hast du ja auch schon den Objective-C Code nicht verstanden. ;)
    Das '&' ist eine bitweise Und-Verknüpfung. 0x01 ist einfach die Hexadezimale Angabe der Zahl 1. Der << Operator verschiebt Bits. Genauere Erklärungen gibt's zum Beispiel hier.

    TheFuriousLion schrieb:

    Außerdem dieser UnsafePointer, ich dache in Swift gibt es keine Pointer mehr.

    Dann hättest du aber ein Problem mit C-APIs umzugehen. Hier steht was zum Thema.
  • TheFuriousLion schrieb:

    gritsch schrieb:

    ich dachte CFSwapInt16LittleToHost gibts nicht?
    Man muss vorher CoreFoundation importieren. :)

    Auf der verlinkten Seite ist doch die Rede von einem Key. Es gibt die Keys 0 und 1, bei Bit 1.


    die ist auch nicht sehr passend.

    meiner meinung nach sollte anstatt "key" eben "value" stehen und anstelle von "value" sollte "descirption" oder sowas in der art stehen.
  • TheFuriousLion schrieb:

    Michael schrieb:

    Dann hast du ja auch schon den Objective-C Code nicht verstanden.
    Das '&' ist eine bitweise Und-Verknüpfung. 0x01 ist einfach die Hexadezimale Angabe der Zahl 1. Der << Operator verschiebt Bits.
    Okay, soweit hab ich das nun verstanden. Aber wozu ist das Verschieben von Bits überhaupt gut?


    würdest du etwas einführendes gelesen haben dann wüsstest du es.
    zwei 8 bit werte zu addieren ist was anderes als sie hintereinander zu setzen...
  • gritsch schrieb:

    TheFuriousLion schrieb:

    Michael schrieb:

    Dann hast du ja auch schon den Objective-C Code nicht verstanden.
    Das '&' ist eine bitweise Und-Verknüpfung. 0x01 ist einfach die Hexadezimale Angabe der Zahl 1. Der << Operator verschiebt Bits.
    Okay, soweit hab ich das nun verstanden. Aber wozu ist das Verschieben von Bits überhaupt gut?


    würdest du etwas einführendes gelesen haben dann wüsstest du es.
    zwei 8 bit werte zu addieren ist was anderes als sie hintereinander zu setzen...


    und man kann sau schnell damit in zweier Potenzen multiplizieren und dividieren. Aber das ist interessiert heute eh keinen mehr.

    Gruß

    Claus
    2 Stunden Try & Error erspart 10 Minuten Handbuchlesen.

    Pre-Kaffee-Posts sind mit Vorsicht zu geniessen :)
  • Thallius schrieb:

    gritsch schrieb:

    TheFuriousLion schrieb:

    Michael schrieb:

    Dann hast du ja auch schon den Objective-C Code nicht verstanden.
    Das '&' ist eine bitweise Und-Verknüpfung. 0x01 ist einfach die Hexadezimale Angabe der Zahl 1. Der << Operator verschiebt Bits.
    Okay, soweit hab ich das nun verstanden. Aber wozu ist das Verschieben von Bits überhaupt gut?


    würdest du etwas einführendes gelesen haben dann wüsstest du es.
    zwei 8 bit werte zu addieren ist was anderes als sie hintereinander zu setzen...


    und man kann sau schnell damit in zweier Potenzen multiplizieren und dividieren. Aber das ist interessiert heute eh keinen mehr.

    Gruß

    Claus


    eben, da macht man zwei mal NSDecimalNumber draus und ruft dann decimalNumberByMultiplyingBy auf...
  • gritsch schrieb:

    Thallius schrieb:

    gritsch schrieb:

    TheFuriousLion schrieb:

    Michael schrieb:

    Dann hast du ja auch schon den Objective-C Code nicht verstanden.
    Das '&' ist eine bitweise Und-Verknüpfung. 0x01 ist einfach die Hexadezimale Angabe der Zahl 1. Der << Operator verschiebt Bits.
    Okay, soweit hab ich das nun verstanden. Aber wozu ist das Verschieben von Bits überhaupt gut?


    würdest du etwas einführendes gelesen haben dann wüsstest du es.
    zwei 8 bit werte zu addieren ist was anderes als sie hintereinander zu setzen...


    und man kann sau schnell damit in zweier Potenzen multiplizieren und dividieren. Aber das ist interessiert heute eh keinen mehr.

    Gruß

    Claus


    eben, da macht man zwei mal NSDecimalNumber draus und ruft dann decimalNumberByMultiplyingBy auf...


    ROFL der war gut :D

    Claus
    2 Stunden Try & Error erspart 10 Minuten Handbuchlesen.

    Pre-Kaffee-Posts sind mit Vorsicht zu geniessen :)
  • Thallius schrieb:


    und man kann sau schnell damit in zweier Potenzen multiplizieren und dividieren. Aber das ist interessiert heute eh keinen mehr.
    Gruß
    Claus


    Mein Hardware-Ingenieur macht immer noch fleissig auf nem Microcontroller in Assembler... wenn ich dem Code skizziere in "Hochsprache" für eine Umsetzung, dann verlangt er immer von mir genau auf solche Kleinigkeiten zu achten und den Code dementsprechend vor zu optimieren... aber heute sieht man ja vor lauter Objekten die Bits nicht mehr ;) Dabei ist es ja doch nicht solange her, als man noch Ringkernspeicher und Co selber wickeln konnte ...

    Gruß, volker
  • volker schrieb:

    Thallius schrieb:


    und man kann sau schnell damit in zweier Potenzen multiplizieren und dividieren. Aber das ist interessiert heute eh keinen mehr.
    Gruß
    Claus


    Mein Hardware-Ingenieur macht immer noch fleissig auf nem Microcontroller in Assembler... wenn ich dem Code skizziere in "Hochsprache" für eine Umsetzung, dann verlangt er immer von mir genau auf solche Kleinigkeiten zu achten und den Code dementsprechend vor zu optimieren... aber heute sieht man ja vor lauter Objekten die Bits nicht mehr ;) Dabei ist es ja doch nicht solange her, als man noch Ringkernspeicher und Co selber wickeln konnte ...

    Gruß, volker


    Der Punkt ist, dass man bei einem modernen Compiler ja gar nicht mehr x=x<<1 schreiben muss sondern durchaus x=x*2 schreiben kann. Das wird dann automatisch optimiert. Aber trotzdem ist es gut zu wissen, dass es sowas gibt.

    Gruß

    Claus
    2 Stunden Try & Error erspart 10 Minuten Handbuchlesen.

    Pre-Kaffee-Posts sind mit Vorsicht zu geniessen :)
  • Thallius schrieb:

    volker schrieb:

    Thallius schrieb:


    und man kann sau schnell damit in zweier Potenzen multiplizieren und dividieren. Aber das ist interessiert heute eh keinen mehr.
    Gruß
    Claus


    Mein Hardware-Ingenieur macht immer noch fleissig auf nem Microcontroller in Assembler... wenn ich dem Code skizziere in "Hochsprache" für eine Umsetzung, dann verlangt er immer von mir genau auf solche Kleinigkeiten zu achten und den Code dementsprechend vor zu optimieren... aber heute sieht man ja vor lauter Objekten die Bits nicht mehr ;) Dabei ist es ja doch nicht solange her, als man noch Ringkernspeicher und Co selber wickeln konnte ...

    Gruß, volker


    Der Punkt ist, dass man bei einem modernen Compiler ja gar nicht mehr x=x<<1 schreiben muss sondern durchaus x=x*2 schreiben kann. Das wird dann automatisch optimiert. Aber trotzdem ist es gut zu wissen, dass es sowas gibt.

    Gruß

    Claus


    und vor allem sollte man verstehen was passiert wenn man sowas in fremdem code vorfindet... (und warum das eben so gemcht wurde)
  • Also, ich habe mich jetzt etwas in die Materie eingelesen. Ausgangspunkt ist dieses Code-Snippet:

    Quellcode

    1. if let data = characteristic.value {
    2. let reportData = UnsafePointer<UInt8>(data.bytes)
    3. var bpm: UInt16 = 0
    4. if reportData[0] & 0b00000001 == 0 {
    5. bpm = UInt16(reportData[1])
    6. } else {
    7. bpm = CFSwapInt16LittleToHost(UInt16(reportData[1]))
    8. }
    9. }


    Lasst mich das Snippet in Einzelteile zerlegen und darauf eingehen. Bitte korrigiert mich, wenn ich etwas falsch verstanden habe.

    Quellcode

    1. if let data = characteristic.value {}
    Hier verwende ich Optional Binding um an das NSData-Objekt zu kommen.

    Quellcode

    1. let reportData = UnsafePointer<UInt8>(data.bytes)
    Ich bin an den Bytes des NSData-Objekts data interessiert. Der Rückgabewert ist COpaquePointer (void *). Der Void-Zeiger ist ein generischer Zeiger, der in jeden anderen Zeiger umgewandelt werden kann. In diesem Beispiel wird er in einen UnsafePointer<UInt8> (UInt8 *) gecastet und in der Konstante reportData gespeichert.

    Quellcode

    1. var bpm: UInt16 = 0
    Hier wird einfach nur eine Variable vom Typ UInt16 mit einem Initalwert von 0 deklariert.

    Quellcode

    1. if reportData[0] & 0b00000001 == 0 {}
    UnsafePointer<T> implementiert ein Subscript, mit diesem wird auf den ersten Bit zugegriffen, bei Little-Endian-Byte-Reihenfolge. Mit dem Bitweisen-UND-Operator wird die Bitmaske (1) addiert (0 + 1 = 0, 1 + 1 = 1). Ist das Ergebnis 0 ist laut dieser Seite der Typ UInt8, sonst UInt16.
    Frage 1: Wenn auf den ersten Bit zugegriffen wird, weshalb braucht man dann noch eine Bitmaske? Wieso kann man nicht gleich den ersten Bit mit 0 vergleichen?

    Quellcode

    1. bpm = UInt16(reportData[1])
    Ist der erste Bit 0, ist der Typ UInt8. Da die Variable bpm aber als UInt16 deklariert ist, muss vorher gecastet werden.
    Frage 2: Wieso greift man auf den zweiten Bit zu? Laut der oben verlinkten Seite speichert Bit 2 Informationen über den 'Sensor Contact Status'.
    Frage 3: Was bedeutet in diesem Fall die Bit-Größe 2?

    Quellcode

    1. bpm = CFSwapInt16LittleToHost(UInt16(reportData[1]))
    Bei einem einzelnen Byte ist die Byte-Reihenfolge egal. Da aber im else-Block der Wert UInt16 ist (2 Bytes), spielt die Byte-Reihenfolge eine Rolle. Diese wird von Little-Endian in die Host-Reihenfolge gebracht.
  • TheFuriousLion schrieb:

    Frage 1: Wenn auf den ersten Bit zugegriffen wird, weshalb braucht man dann noch eine Bitmaske? Wieso kann man nicht gleich den ersten Bit mit 0 vergleichen?

    reportData[0] greift auf ein Byte zu, und mit reportData[0] & 0b00000001 == 0 testest Du, ob das niedrigste Bit im ersten Byte nicht gesetzt ist. Das gibt es einen Unterschied zwischen Bits und Bytes.
    „Meine Komplikation hatte eine Komplikation.“
  • TheFuriousLion schrieb:

    Quellcode

    1. let reportData = UnsafePointer<UInt8>(data.bytes)
    Ich bin an den Bytes des NSData-Objekts data interessiert. Der Rückgabewert ist COpaquePointer (void *). Der Void-Zeiger ist ein generischer Zeiger, der in jeden anderen Zeiger umgewandelt werden kann. In diesem Beispiel wird er in einen UnsafePointer<UInt8> (UInt8 *) gecastet und in der Konstante reportData gespeichert.

    Streng genommen wird hier ein neuer Pointer auf Basis eines COpaquePointer erzeugt.

    TheFuriousLion schrieb:

    Quellcode

    1. if reportData[0] & 0b00000001 == 0 {}
    UnsafePointer<T> implementiert ein Subscript, mit diesem wird auf den ersten Bit zugegriffen, bei Little-Endian-Byte-Reihenfolge. Mit dem Bitweisen-UND-Operator wird die Bitmaske (1) addiert (0 + 1 = 0, 1 + 1 = 1). Ist das Ergebnis 0 ist laut dieser Seite der Typ UInt8, sonst UInt16.
    Frage 1: Wenn auf den ersten Bit zugegriffen wird, weshalb braucht man dann noch eine Bitmaske? Wieso kann man nicht gleich den ersten Bit mit 0 vergleichen?

    Wie macmoonshine schon sagte, es gibt eine Unterschied zwischen Bit und Bytes. Die Zeile sieht aufgedröselt so aus:

    Quellcode

    1. ​let byte0: UInt8 = reportData[0] // das Byte 0 im NSData Objekt wird ausgelesen
    2. let bit0: UInt8 = byte0 & 0b00000001 // als Ergebnis dieser UND Verknüpfung erhält man ein Byte in dem das Bit 0 unverändert und die Bits 1 bis 7 auf 0 gesetzt sind.
    3. if bit0 == 0 { // es wird ein UInt8 mit 0 verglichen, bit0 kann wegen der vorhergehenden UND Verknüpfung nur den Wert 0 oder 1 haben
    4. ...
    5. }


    TheFuriousLion schrieb:

    Quellcode

    1. bpm = UInt16(reportData[1])
    Ist der erste Bit 0, ist der Typ UInt8. Da die Variable bpm aber als UInt16 deklariert ist, muss vorher gecastet werden.
    Frage 2: Wieso greift man auf den zweiten Bit zu?

    Hier greift man auf das Byte 1, das Byte nach Byte 0, im NSData Objekt zu.

    TheFuriousLion schrieb:

    Laut der oben verlinkten Seite speichert Bit 2 Informationen über den 'Sensor Contact Status'.
    Frage 3: Was bedeutet in diesem Fall die Bit-Größe 2?

    Das zweite und dritte Bit (deshalb Bit-Größe 2) des Byte 0 vom NSData Objekt speichern den 'Sensor Contact Status'. In der Tabelle da spielt sich alles, was unter „Flags“ steht, im Byte 0 ab.

    TheFuriousLion schrieb:

    Quellcode

    1. bpm = CFSwapInt16LittleToHost(UInt16(reportData[1]))
    Bei einem einzelnen Byte ist die Byte-Reihenfolge egal. Da aber im else-Block der Wert UInt16 ist (2 Bytes), spielt die Byte-Reihenfolge eine Rolle. Diese wird von Little-Endian in die Host-Reihenfolge gebracht.

    Ein einzelnes Byte hat ja keine Reihenfolge. :)
  • Michael schrieb:

    In der Tabelle da spielt sich alles, was unter „Flags“ steht, im Byte 0 ab.
    Ah, jetzt ergibt vieles einen Sinn. :)
    Mich hat 'let reportData = UnsafePointer<UInt8>(data.bytes)' verwirrt, da ich dachte der Pointer zeigt auf nur ein Byte. Und ein Byte besteht bekanntlich ja aus 8 Bits. Kann der UnsafePointer<UInt8> aus mehreren Bytes bestehen? Und warum nimmt man überhaupt UInt8, wenn auch UInt16 vorkommen kann?

    Michael schrieb:

    Das zweite und dritte Bit (deshalb Bit-Größe 2) des Byte 0 vom NSData Objekt speichern den 'Sensor Contact Status'.
    Das würde auch erklären, weshalb das nächste Bit in der Tabelle die Nummer 3 hat. Das hab ich übersehen.

    Michael schrieb:

    Quellcode

    1. let bit0: UInt8 = byte0 & 0b00000001
    Ist das nicht auch ein Byte? Eines bei dem halt nur aufgrund des Bitweisen-UND-Operators nur ein Bit 1 ist?

    Wenn ich den 'Sensor Contact Status' auslesen will, sehe der Code dann folgendermaßen aus?

    Quellcode

    1. if ((reportData[0] & 0b00000110) >> 1) == 3 {
    2. // Sensor Contact feature is supported and contact is detected
    3. }