Die Geschichte läuft bei mir seit einigen Monaten stabil und erfüllt unsere Anforderungen. Konkret sieht's so aus: AVR (Türknoten) hört auf der RS485 mit, extrahiert den Fingerhash und verschickt diesen auf CAN. Der Garagenknoten kennt die Liste der Ringfinger-Fingerhashes, und wenn er einen davon sieht, betätigt er den Öffner. Parallel geht der CAN-Traffic zum Raspberry zwecks Logging und Sprachansage ala "Der Uwe kommt nach Hause."
Für diesen Use-Case genügt es, den Fingerhash zu extrahieren (siehe mein Posting vom 15.10.). Das der Fingerhash eine CRC ist und wo im Originaldatenstrom User und Finger liegen, ist nur von Interesse, wenn man noch weiter forschen will.
Was ich bisher nicht geschafft hab (aber auch nicht mehr weiter verfolge) ist die Information "Finger abgelehnt" rauszufischen. Der Original-UDP-Konverter kann das offenbar, aber ich hatte irgendwann aufgegeben. Hab noch einige Tage Tracedaten vorrätig, falls jemand weiter analysieren will ;-)
Die Lösung hat den schon diskutierten Nachteil, dass beim "Garagenfinger" auch das original verkabelte Türschloss mit geöffnet wird, und je nach Windrichtung die Haustür öffnet oder auch nicht. Aber daran haben sich alle schnell gewöhnt und wir kommen sehr gut klar damit.
Hier der Quellcode des Decoders. Jedes empfangene Byte muss an die Funktion keyDec_receivedByte() übergeben werden. Bei erkanntem Finger werden die ekeyFingerOkTimer und message_HAUSTUER1 befüllt. Diverse Debugging-Ausgaben und -Zähler sind noch enthalten, werden für die Funktionalität nicht benötigt.
Und das Headerfile:
Für diesen Use-Case genügt es, den Fingerhash zu extrahieren (siehe mein Posting vom 15.10.). Das der Fingerhash eine CRC ist und wo im Originaldatenstrom User und Finger liegen, ist nur von Interesse, wenn man noch weiter forschen will.
Was ich bisher nicht geschafft hab (aber auch nicht mehr weiter verfolge) ist die Information "Finger abgelehnt" rauszufischen. Der Original-UDP-Konverter kann das offenbar, aber ich hatte irgendwann aufgegeben. Hab noch einige Tage Tracedaten vorrätig, falls jemand weiter analysieren will ;-)
Die Lösung hat den schon diskutierten Nachteil, dass beim "Garagenfinger" auch das original verkabelte Türschloss mit geöffnet wird, und je nach Windrichtung die Haustür öffnet oder auch nicht. Aber daran haben sich alle schnell gewöhnt und wir kommen sehr gut klar damit.
Hier der Quellcode des Decoders. Jedes empfangene Byte muss an die Funktion keyDec_receivedByte() übergeben werden. Bei erkanntem Finger werden die ekeyFingerOkTimer und message_HAUSTUER1 befüllt. Diverse Debugging-Ausgaben und -Zähler sind noch enthalten, werden für die Funktionalität nicht benötigt.
Code:
#include <avr/io.h> #include <stdio.h> #include <avr/pgmspace.h> #include <avr/interrupt.h> #include "board.h" #include "globals.h" #include "can_def.h" #include "Can_Appl.h" #include "house_events.h" #include "ekey_decoder.h" #include "uart.h" #define setInfo(x) uint8_t nDecoderState; uint8_t iDecoder; uint8_t DEC_Length; uint8_t DEC_Buffer[DEC_BUFFER_MAX]; uint16_t ekey_nFingerCounter; uint16_t ekey_nFrameCounter; uint8_t ekeyFingerOkTimer; void DEC_Unstuffing(void) { uint16_t k; uint16_t i; uint8_t blMove; //DEBUG_PA1_ON(); /* Byte-Stuffing rückgängig machen. Zum Transport wurden die Daten aufgeblasen, um das Auftreten der Beginn- und Endekennung innerhalb der Nutzdaten zu vermeiden: 02 --> 3F 41 03 --> 3F 81 3F --> 3F C1 */ /* Gehen wir mal davon aus, dass im Addressierungsteil (Index 0 bis 14) kein Byte-Stuffing verwendet wird. Das spart hier etwas Zeit zum Durchlaufen. */ if (DEC_Length<=15) { //DEBUG_PA1_OFF(); /* bis hierhin haben wir nur 2µs verbracht */ return; } k=15; while (1) { if (DEC_Buffer[k]==0x3F) { blMove=0; switch (DEC_Buffer[k+1]) { case 0x41: DEC_Buffer[k]=0x02; blMove=1; break; case 0x81: DEC_Buffer[k]=0x03; blMove=1; break; case 0xC1: DEC_Buffer[k]=0x3F; blMove=1; break; /* Default: Falls irgend etwas anderes der 3F folgt, dann scheint die 3F ein normales Datenbyte zu sein --> kein Unstuffing. */ } if (blMove) { //DEBUG_PA1_OFF(); //DEBUG_PA1_ON(); /* Wir müssen unstuffen --> - Das Byte an Index k+1 fällt weg. - Alles nachfolgende nach links ranrutschen. - Die Länge verringert sich um eins. */ for (i=k+1; i<DEC_Length; i++) { DEC_Buffer[i]=DEC_Buffer[i+1]; } DEC_Length--; } } k++; if (k>=DEC_Length) { //DEBUG_PA1_OFF(); /* bis hierhin haben wir - 15..20µs: Request ohne unstuffing - 20..30µs: Request mit ein bis zweimaligem Unstuffing */ return; } } } void DEC_frameReceived(void) { message_HAUSTUER2.s.ekeyFrameCounter++; /* Plausibilisierungen */ if (DEC_Buffer[0]!=0x02) { /* Anfang falsch */ //message_EKEY_DEBUG01.s.cnt_wrongStartOfFrame++; } if (DEC_Buffer[DEC_Length-1]!=0x03) { /* Ende falsch */ message_EKEY_DEBUG02.s.cnt_wrongEndOfFrame++; if (DEC_Buffer[DEC_Length-3]==0x03) message_EKEY_DEBUG02.s.cnt_H++; if (DEC_Buffer[DEC_Length-2]==0x03) message_EKEY_DEBUG02.s.cnt_J++; if (DEC_Buffer[DEC_Length-0]==0x03) message_EKEY_DEBUG02.s.cnt_K++; } message_EKEY_DEBUG02.s.cnt_L = uart_cnt_dataoverrun; DEC_Unstuffing(); if (DEC_Length == 0x10) { message_EKEY_DEBUG01.s.cnt_len_0x10++; } else if (DEC_Length == 0x1E) { message_EKEY_DEBUG01.s.cnt_len_0x1E++; } else if (DEC_Length == 0x1F) { message_EKEY_DEBUG01.s.cnt_len_0x1F++; } else if (DEC_Length == 0x56) { message_EKEY_DEBUG01.s.cnt_len_0x56++; } else{ message_EKEY_DEBUG01.s.cnt_D=DEC_Length; } if (DEC_Length == 47) { ekeyFingerOkTimer=200; /* 200*5ms = 1 Sekunde "aktiv" melden */ message_HAUSTUER1.s.ekeyFingerCounter++; message_HAUSTUER1.s.ekeyFingerHash=DEC_Buffer[17]; message_EKEY_FINGER_HIST.s.history[7]=message_EKEY_FINGER_HIST.s.history[6]; message_EKEY_FINGER_HIST.s.history[6]=message_EKEY_FINGER_HIST.s.history[5]; message_EKEY_FINGER_HIST.s.history[5]=message_EKEY_FINGER_HIST.s.history[4]; message_EKEY_FINGER_HIST.s.history[4]=message_EKEY_FINGER_HIST.s.history[3]; message_EKEY_FINGER_HIST.s.history[3]=message_EKEY_FINGER_HIST.s.history[2]; message_EKEY_FINGER_HIST.s.history[2]=message_EKEY_FINGER_HIST.s.history[1]; message_EKEY_FINGER_HIST.s.history[1]=message_EKEY_FINGER_HIST.s.history[0]; message_EKEY_FINGER_HIST.s.history[0]=DEC_Buffer[17]; } } void ekeyDec_receivedByte(uint8_t n) { uart_transmitByte(n); switch (nDecoderState) { case DEC_WaitingForStart: if (n == 2) { nDecoderState = DEC_WaitingForLength; DEC_Buffer[0] = n; setInfo("Waiting for length"); DEBUG_PA0_ON(); } break; case DEC_WaitingForLength: // Längenbyte ist angekommen. Die eigentliche Länge // der Nutzdaten ist (n-1)/4. // Weitere Teile der Längeninformation stecken im nächsten Byte. DEC_Length = (n - 1) >> 2; // Zusätzlich zur Nutzdatenlänge wollen wir noch "StartOfFrame" und // Längenbyte im Trace haben --> zwei Byte mehr. DEC_Length = DEC_Length + 2; nDecoderState = DEC_WaitingForLengthExtension; DEC_Buffer[1] = n; setInfo("Waiting for LengthExtension"); break; case DEC_WaitingForLengthExtension: // Zweites Längenbyte ist angekommen. Bit 0 bedeutet 64. // Ob Bit 1 dann 128 bedeutet ist noch nicht klar. if (n & 1) { DEC_Length = DEC_Length + 64; } nDecoderState = DEC_WaitingForContent; DEC_Buffer[2] = n; setInfo("Waiting for " & DEC_Length & " Bytes") iDecoder = 3; break; case DEC_WaitingForContent: DEC_Buffer[iDecoder] = n; iDecoder++; setInfo("Received " & i & " bytes"); if (iDecoder == DEC_Length) { DEC_frameReceived(); nDecoderState = DEC_WaitingForStart; DEBUG_PA0_OFF(); } break; default: setInfo("wrong state"); nDecoderState = DEC_WaitingForStart; } }
Code:
#define DEC_BUFFER_MAX 200 /* Puffergröße für empfangene RS485 Frames */ #define DEC_WaitingForStart 1 #define DEC_WaitingForLength 2 #define DEC_WaitingForLengthExtension 3 #define DEC_WaitingForContent 4 extern uint8_t nDecoderState; extern uint8_t DEC_Buffer[DEC_BUFFER_MAX]; extern void ekeyDec_receivedByte(uint8_t c); extern uint8_t ekeyFingerOkTimer;
Kommentar