czwartek, 24 sierpnia 2017

[20] STM32F7 - Wiegand

W tym poście chciałbym przedstawić implementację interfejsu Wiegand. Do tego celu wykorzystam płytkę z Discovery z mikrokontrolerem STM32F746VG oraz biblioteki HAL'a.

[Źródło: http://www.st.com/en/evaluation-tools/32f746gdiscovery.html]

Wiegand


Jest to trój-przewodowym interfejsem komunikacyjny, z czego jedno z wyprowadzeń jest wspólną masą. Pozostałe dwa przewody to data0 (D0) oraz data1 (D1). Linia D0 służy do informowania o wystąpieniu bitu o wartości 0. Linia D1 odwrotnie.

Najczęściej wykorzystywany jest w systemach RFID do przesyłania informacji pomiędzy urządzeniami.

Działanie protokołu jest dosyć proste, wygląda następująco:

Jeśli nie są przesyłane żadne dane to na obu liniach utrzymywany jest stan wysoki. Gdy wysyłana jest jedynka to linia D0 jest w stanie wysoki, natomiast linia D1 w stanie niskim. W przypadku przesłania 0 działanie jest odwrotne, czyli na linii D1 utrzymywany jest stan wysoki, natomiast D0 otrzymuje stan niski.

W celu zabezpieczenia danych wykorzystywana jest kontrola parzystości oraz kontrola nieparzystości.Obie metody sprawdzają ilości jedynek jakie występują w określonej części wiadomości.

Odbieranie danych można rozwiązać na dwa sposoby, albo następuje odliczanie zadanej ilości bitów do odebrania lub należy odczekać określony czas i po jego przeminięciu przerwać transmisję i sprawdzić odebraną ramkę.

Jeśli odlicza się czas pomiędzy impulsami należy przyjąć, że czas impulsu nie będzie przekraczał 100us, natomiast czas pomiędzy impulsami nie będzie dłuższy niż 50 - 100 ms. Wszystko zależy od rodzaju urządzenia jakie się wykorzystuje.

Standard card po przesyłanych danych przez wiegand wyglądają następująco:

Karta RFID 26 bitów:

Ramka danych wygląda następująco:

P FFFF FFFF CCCC CCCC CCCC CCCC O

Pierwszy bit P oznacza bit kontroli parzystości dla bitów na pozycjach od 1 do 12(czyli FFFF FFFF CCCC). Ostatni bit O odnosi się do kontroli nieparzystości bitów na pozycjach od 13 do 24 (czyli CCCC CCCC CCCC).

Bity oznaczone jako FFFF FFFF oznaczją tzw. Facility Code, który może przyjmować wartości od 0 do 255. Bity z numerem karty oznaczone są jako C. Mogą przyjmować dane z zakresu od 0 do 65535.

Poniżej przykładowy przebieg odczytu takiej karty zarejestrowany na analizatorze stanów logicznych:


Czas wygenerowania impulsu:


Jak widać na obrazku powyżej impuls generowany jest na około 40us.

Czas przerwy pomiędzy przesłaniem kolejnych bitów danych:


W tym przypadku czas przerwy wynosi ponad 2ms. 

Karta RFID 37 bitów:

Jest to podobny format co w przypadku 26 bitów, natomiast pozwala on na przechowywanie znacznie większych ilości danych.

Ramka danych wygląda następująco:

P FFFF FFFF FFFF FFFF CCC CCCC CCCC CCCC CCCC O

Jak widać na początku i na końcu występują bity parzystości oraz nieparzystości. Facility code może przyjmować wartości z zakresu od 0 do 65535 natomiast numer karty od 0 do 524287.

Poniżej przykładowy przebieg odczytu takiej karty zarejestrowany na analizatorze stanów logicznych:





Można też spotkać standardy 32, 34, 37 bitów w przypadku odczytu kart bądź w przypadku obsługiwania klawiatur formaty 4 czy 8 bitowe.


Program:


Kod został przygotowany w oparciu o przerwania na dwóch pinach transmitujących dane oraz z obsługa przekroczenia czasu odliczoną na timerze. Program odbiera wszystkie dane od wieganda, i wyświetla je na ekranie (jeśli został również uruchomiony usart).

Dane odnośnie odebranych informacji przechowywane są w strukturze:

  1.  enum wiegandReceiveDataNumber {
  2.         wiegandNoData = 0,
  3.         wiegandWrongFrame = 1,
  4.         wiegand37Bit = 2,
  5.         wiegand26Bit = 3,
  6.         wiegand32Bit = 4
  7. };
  8.  /* @brief: structure for wiegand data */
  9. typedef struct wiegandDataStruct {
  10.     volatile uint8_t wiegandDat[kWiegandData];          /* receive data, one field one bit */
  11.     volatile uint8_t wiegandDataPosition;               /* number of receive data */
  12.     uint32_t readCardNumber;                   /* card number read from receive data */
  13.     uint32_t facilityCode;                     /* facility code read from receive data*/
  14.     uint32_t oldReadCardNumber;                /* Old card number, it contain previous card, reset after timeout */
  15.     volatile uint16_t wiegandTimeout;                   /* calculate timeout for receiving data */
  16.     enum wiegandReceiveDataNumber wiegandDataType;      /* type of receive data, if receive 26 or 37 itp */
  17.     volatile uint8_t wiegandStartReceive:2;             /* set when first interrupt came, inform timer interrupt to start counting */
  18. } wiegandData_t;

Inicjalizacja pinów:

  1. void wiegandInitPins(uint8_t channel)
  2. {
  3.     GPIO_InitTypeDef   GPIO_InitStruct;
  4.     if(channel == 1)
  5.     {
  6.         kData0ClockCh1;
  7.         kData1ClockCh1;
  8.         GPIO_InitStruct.Pin = kData0PinCh1;
  9.         GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
  10.         GPIO_InitStruct.Pull = GPIO_NOPULL;
  11.         GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
  12.         HAL_GPIO_Init(kData0PortCh1, &GPIO_InitStruct);
  13.         GPIO_InitStruct.Pin = kData1PinCh1;
  14.         GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
  15.         GPIO_InitStruct.Pull = GPIO_NOPULL;
  16.         GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
  17.         HAL_GPIO_Init(kData1PortCh1, &GPIO_InitStruct);
  18.         // NVIC config
  19.         HAL_NVIC_SetPriority(kData0IrqnCh1, 0, 0);
  20.         HAL_NVIC_EnableIRQ(kData0IrqnCh1);
  21.         HAL_NVIC_SetPriority(kData1IrqnCh1, 0, 0);
  22.         HAL_NVIC_EnableIRQ(kData1IrqnCh1);
  23.     }
  24.     else if(channel == 2)
  25.     {
  26.         kData0ClockCh2;
  27.         kData1ClockCh2;
  28.         GPIO_InitStruct.Pin = kData0PinCh2;
  29.         GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
  30.         GPIO_InitStruct.Pull = GPIO_NOPULL;
  31.         GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
  32.         HAL_GPIO_Init(kData0PortCh2, &GPIO_InitStruct);
  33.         GPIO_InitStruct.Pin = kData1PinCh2;
  34.         GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
  35.         GPIO_InitStruct.Pull = GPIO_NOPULL;
  36.         GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
  37.         HAL_GPIO_Init(kData1PortCh2, &GPIO_InitStruct);
  38.         // NVIC config
  39.         HAL_NVIC_SetPriority(kData0IrqnCh2, 0, 0);
  40.         HAL_NVIC_EnableIRQ(kData0IrqnCh2);
  41.         HAL_NVIC_SetPriority(kData1IrqnCh2, 0, 0);
  42.         HAL_NVIC_EnableIRQ(kData1IrqnCh2);
  43.     }
  44. }

Biblioteka obsługuje dwa kanały wieganda. W związku z tym znajduje się w funkcji osobne włączenie dla każdego z nich. Domyślne pinu to:

  1. /* @brief: Definition of pins for wiegand CH1 */
  2. #define kData0PortCh1       GPIOA
  3. #define kData0PinCh1        GPIO_PIN_8
  4. #define kData0ClockCh1      __GPIOA_CLK_ENABLE()
  5. #define kData0IrqnCh1       EXTI9_5_IRQn
  6. #define kData1PortCh1       GPIOB
  7. #define kData1PinCh1        GPIO_PIN_15
  8. #define kData1ClockCh1      __GPIOB_CLK_ENABLE()
  9. #define kData1IrqnCh1       EXTI15_10_IRQn
  10. /* @brief: Definition of pins for wiegand CH2 */
  11. #define kData0PortCh2       GPIOB
  12. #define kData0PinCh2        GPIO_PIN_8
  13. #define kData0ClockCh2      __GPIOA_CLK_ENABLE()
  14. #define kData0IrqnCh2       EXTI9_5_IRQn
  15. #define kData1PortCh2       GPIOB
  16. #define kData1PinCh2        GPIO_PIN_9
  17. #define kData1ClockCh2      __GPIOB_CLK_ENABLE()
  18. #define kData1IrqnCh2       EXTI9_5_IRQn

Oprócz tego przygotowałem także funkcje pozwalającą na inicjalizacje pinów innych niż domyślne, natomiast trzeba do tego przygotować obsługę przerwań.

  1. void wiegandInitPinsCustom(GPIO_TypeDef  *GPIOxD0, uint16_t PinD0, GPIO_TypeDef  *GPIOxD1, uint16_t PinD1)
  2. {
  3.     uint16_t dataPin[2] = {PinD0, PinD1};
  4.     GPIO_InitTypeDef   GPIO_InitStruct;
  5.     PORT_CLOCK_ENABLE(GPIOxD0);
  6.     PORT_CLOCK_ENABLE(GPIOxD1);
  7.     GPIO_InitStruct.Pin = PinD0;
  8.     GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
  9.     GPIO_InitStruct.Pull = GPIO_NOPULL;
  10.     GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
  11.     HAL_GPIO_Init(GPIOxD0, &GPIO_InitStruct);
  12.     GPIO_InitStruct.Pin = PinD1;
  13.     GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
  14.     GPIO_InitStruct.Pull = GPIO_NOPULL;
  15.     GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
  16.     HAL_GPIO_Init(GPIOxD1, &GPIO_InitStruct);
  17.     for(uint8_t i = 0; i<2; i++)
  18.     {
  19.         /* Set proper NVIC for pins */
  20.         if(dataPin[i] == GPIO_PIN_0){
  21.             HAL_NVIC_SetPriority(EXTI0_IRQn, 0x01, 0);
  22.             HAL_NVIC_EnableIRQ(EXTI0_IRQn);
  23.         }
  24.         else if(dataPin[i] == GPIO_PIN_1){
  25.             HAL_NVIC_SetPriority(EXTI1_IRQn, 0x01, 0);
  26.             HAL_NVIC_EnableIRQ(EXTI1_IRQn);
  27.         }
  28.         else if(dataPin[i] == GPIO_PIN_2){
  29.             HAL_NVIC_SetPriority(EXTI2_IRQn, 0x01, 0);
  30.             HAL_NVIC_EnableIRQ(EXTI2_IRQn);
  31.         }
  32.         else if(dataPin[i] == GPIO_PIN_3){
  33.             HAL_NVIC_SetPriority(EXTI3_IRQn, 0x01, 0);
  34.             HAL_NVIC_EnableIRQ(EXTI3_IRQn);
  35.         }
  36.         else if(dataPin[i] == GPIO_PIN_4){
  37.             HAL_NVIC_SetPriority(EXTI4_IRQn, 0x01, 0);
  38.             HAL_NVIC_EnableIRQ(EXTI4_IRQn);
  39.         }
  40.         else if((dataPin[i] >= GPIO_PIN_5) && (dataPin[i] <= GPIO_PIN_9)){
  41.             HAL_NVIC_SetPriority(EXTI9_5_IRQn, 0x01, 0);
  42.             HAL_NVIC_EnableIRQ(EXTI9_5_IRQn);
  43.         }
  44.         else if((dataPin[i] >= GPIO_PIN_10) && (dataPin[i] <= GPIO_PIN_15)){
  45.             HAL_NVIC_SetPriority(EXTI15_10_IRQn, 0x01, 0);
  46.             HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);
  47.         }
  48.     }
  49. }

Funkcje odbierające dane w przerwaniach:

  1. void EXTI9_5_IRQHandler(void)
  2. {
  3.   if(__HAL_GPIO_EXTI_GET_IT(kData0PinCh1) != RESET)
  4.   {
  5.     __HAL_GPIO_EXTI_CLEAR_IT(kData0PinCh1);
  6.     if((HAL_GPIO_ReadPin(kData0PortCh1, kData0PinCh1)==GPIO_PIN_RESET) &&
  7.         (HAL_GPIO_ReadPin(kData1PortCh1, kData1PinCh1)==GPIO_PIN_SET))
  8.     {
  9.         if(wiegandData.wiegandDataPosition < (kWiegandCard37Bits - 1))
  10.         {
  11.             wiegandData.wiegandStartReceive = 1;
  12.             wiegandData.wiegandTimeout = 0;
  13.    
  14.             *(wiegandData.wiegandDat + wiegandData.wiegandDataPosition) = 0;
  15.    
  16.             wiegandData.wiegandDataPosition++;
  17.         }
  18.      }
  19.   }
  20.   if(__HAL_GPIO_EXTI_GET_IT(kData0PortCh2) != RESET)
  21.   {
  22.     __HAL_GPIO_EXTI_CLEAR_IT(kData0PortCh2);
  23.     if((HAL_GPIO_ReadPin(kData0PortCh2, kData0PortCh2)==GPIO_PIN_RESET) &&
  24.         (HAL_GPIO_ReadPin(kData1PortCh2, kData1PortCh2)==GPIO_PIN_SET))
  25.     {
  26.         if(wiegandDataCh2.wiegandDataPosition < (kWiegandCard37Bits - 1))
  27.         {
  28.             wiegandDataCh2.wiegandStartReceive = 1;
  29.             wiegandDataCh2.wiegandTimeout = 0;
  30.    
  31.             *(wiegandDataCh2.wiegandDat + wiegandDataCh2.wiegandDataPosition) = 0;
  32.    
  33.             wiegandDataCh2.wiegandDataPosition++;
  34.         }
  35.      }
  36.   }
  37.   if(__HAL_GPIO_EXTI_GET_IT(kData1PortCh2) != RESET)
  38.   {
  39.     __HAL_GPIO_EXTI_CLEAR_IT(kData1PortCh2);
  40.     if((HAL_GPIO_ReadPin(kData1PortCh2, kData1PortCh2)==GPIO_PIN_RESET) &&
  41.         (HAL_GPIO_ReadPin(kData0PortCh2, kData0PortCh2)==GPIO_PIN_SET))
  42.     {
  43.         if(wiegandDataCh2.wiegandDataPosition < (kWiegandCard37Bits - 1))
  44.         {
  45.             wiegandDataCh2.wiegandStartReceive = 1;
  46.             wiegandDataCh2.wiegandTimeout = 0;
  47.    
  48.             *(wiegandDataCh2.wiegandDat + wiegandDataCh2.wiegandDataPosition) = 0;
  49.             wiegandDataCh2.wiegandDataPosition++;
  50.         }
  51.      }
  52.   }
  53. }
  54. void EXTI15_10_IRQHandler(void)
  55. {
  56.   if(__HAL_GPIO_EXTI_GET_IT(kData1PinCh1) != RESET)
  57.   {
  58.     __HAL_GPIO_EXTI_CLEAR_IT(kData1PinCh1);
  59.     if((HAL_GPIO_ReadPin(kData1PortCh1, kData1PinCh1)==GPIO_PIN_RESET) &&
  60.         (HAL_GPIO_ReadPin(kData0PortCh1, kData0PinCh1)==GPIO_PIN_SET))
  61.     {
  62.         if(wiegandData.wiegandDataPosition < (kWiegandCard37Bits - 1))
  63.         {
  64.             wiegandData.wiegandStartReceive = 1;
  65.             wiegandData.wiegandTimeout = 0;
  66.    
  67.             *(wiegandData.wiegandDat + wiegandData.wiegandDataPosition) = 1;
  68.            
  69.             wiegandData.wiegandDataPosition++;
  70.         }
  71.     }
  72.   }
  73. }

Przerwanie odbiera maksymalnie 37 bitów. Wcześniejsze przerwanie programu następuje po przekroczeniu czasu oczekiwania.

Sprawdzanie poprawności transmisji, jeśli w kodzie występują bity parzystości oraz nieparzystości. Na pozycji zerowej sprawdzany jest bit parzystości, ostatnia pozycja sprawdza bit nieparzystości. Należy pamiętać, że przed rozpoczęciem obsługi ramki danych należy wiedzieć jakie ilości danych mogą przyjść od układu do mikrokontrolera. Pozwoli to na bezpieczniejszą obsługę interfejsu, niż obsługiwanie jakiejkolwiek odebranej ramki, której długość będzie nieznana.

Poniżej znajdują się funkcje sprawdzające odebraną ramkę danych:

  1. static uint8_t wiegandCheckDataFrame(wiegandData_t * wiegandInfo,
  2.                                         enum wiegandReceiveDataNumber receiveFormat)
  3. {
  4.     if(receiveFormat == wiegand37Bit)
  5.     {
  6.         /* Check data frame */
  7.         if(wiegandCheckEvenParity(wiegandInfo, 0, wiegand37Bit) == 0){
  8.             return 0; /* Error wrong frame */
  9.         }
  10.         if(wiegandCheckOddParity(wiegandInfo, 36, wiegand37Bit) == 0){
  11.             return 0; /* Error wrong frame */
  12.         }
  13.     }
  14.     else if(receiveFormat == wiegand26Bit)
  15.     {
  16.         /* Check data frame */
  17.         if(wiegandCheckEvenParity(wiegandInfo, 0, wiegand26Bit) == 0){
  18.             return 0; /* Error wrong frame */
  19.         }
  20.         if(wiegandCheckOddParity(wiegandInfo, 25, wiegand26Bit) == 0){
  21.             return 0; /* Error wrong frame */
  22.         }
  23.     }
  24.     return 1; /* Frame OK */
  25. }
  26. static uint8_t wiegandCheckEvenParity(wiegandData_t * wiegandInfo, uint8_t evenParityPosition,enum wiegandReceiveDataNumber receiveFormat)
  27. {
  28.     uint8_t number_of_one = 0;
  29.     uint8_t even_parity_bit = 0;
  30.     if(receiveFormat == wiegand37Bit)
  31.     {
  32.         for(uint8_t i=1; i<=18; i++)
  33.         {
  34.             if(wiegandInfo->wiegandDat[i] == 1) { number_of_one++; }
  35.         }
  36.         if(number_of_one % 2 == 0) { even_parity_bit = 0; }
  37.         else                       { even_parity_bit = 1; }
  38.         if(wiegandInfo->wiegandDat[evenParityPosition] == even_parity_bit)
  39.         {
  40.             return 1;
  41.         }
  42.     }
  43.     else if(receiveFormat == wiegand26Bit)
  44.     {
  45.         for(uint8_t i=1; i<=12; i++)
  46.         {
  47.             if(wiegandInfo->wiegandDat[i] == 1) { number_of_one++; }
  48.         }
  49.         if(number_of_one % 2 == 0) { even_parity_bit = 0; }
  50.         else                       { even_parity_bit = 1; }
  51.         if(wiegandInfo->wiegandDat[evenParityPosition] == even_parity_bit)
  52.         {
  53.             return 1;
  54.         }
  55.     }
  56.     return 0; /* Error */
  57. }
  58. static uint8_t wiegandCheckOddParity(wiegandData_t * wiegandInfo, uint8_t oddParityPositionenum wiegandReceiveDataNumber receiveFormat)
  59. {
  60.     uint8_t number_of_one = 0;
  61.     uint8_t odd_parity_bit = 0;
  62.     if(receiveFormat == wiegand37Bit)
  63.     {
  64.         for(uint8_t i=18; i<=35; i++)
  65.         {
  66.             if(wiegandInfo->wiegandDat[i] == 1) {   number_of_one++;    }
  67.         }
  68.         if(number_of_one % 2 == 0)  {   odd_parity_bit = 1; }
  69.         else                        {   odd_parity_bit = 0; }
  70.         if(wiegandInfo->wiegandDat[oddParityPosition] == odd_parity_bit)
  71.         {
  72.             return 1;
  73.         }
  74.     }
  75.     else if(receiveFormat == wiegand26Bit)
  76.     {
  77.         for(uint8_t i=13; i<=24; i++)
  78.         {
  79.             if(wiegandInfo->wiegandDat[i] == 1) { number_of_one++; }
  80.         }
  81.         if(number_of_one % 2 == 0) { odd_parity_bit = 1; }
  82.         else                       { odd_parity_bit = 0; }
  83.         if(wiegandInfo->wiegandDat[oddParityPosition] == odd_parity_bit)
  84.         {
  85.             return 1;
  86.         }
  87.     }
  88.     return 0; /* Error */
  89. }

Wypisanie odebranych danych na ekranie:

  1. static void wiegandDecode37BitNumber(wiegandData_t *wiegandInfo)
  2. {
  3.     #if DEBUG_USART == 1
  4.     char data[50] = {0};
  5.     #endif
  6.     /* Get facility code */
  7.     for(uint8_t i=1; i<=16; i++)
  8.     {
  9.         if(*(wiegandInfo->wiegandDat + i) == 1){
  10.             wiegandInfo->facilityCode = wiegandInfo->facilityCode << 1;
  11.             wiegandInfo->facilityCode = wiegandInfo->facilityCode + 0x01;
  12.         }
  13.         else{
  14.             wiegandInfo->facilityCode = wiegandInfo->facilityCode << 1;
  15.         }
  16.     }
  17.     /* Get card number */
  18.     for(uint8_t i=17; i<=35; i++)
  19.     {
  20.         if(*(wiegandInfo->wiegandDat + i) == 1){
  21.             wiegandInfo->readCardNumber = wiegandInfo->readCardNumber << 1;
  22.             wiegandInfo->readCardNumber = wiegandInfo->readCardNumber + 0x01;
  23.         }
  24.         else{
  25.             wiegandInfo->readCardNumber = wiegandInfo->readCardNumber << 1;
  26.         }
  27.     }
  28.     #if DEBUG_USART == 1
  29.     sprintf(data, "FacilityCode %lu", wiegandInfo->facilityCode);
  30.     DebugMsg(data);
  31.     sprintf(data, "CardNumber %lu", wiegandInfo->readCardNumber);
  32.     DebugMsg(data);
  33.     #endif
  34. }
  35. static void wiegandDecode26BitNumber(wiegandData_t *wiegandInfo)
  36. {
  37.     #if DEBUG_USART == 1
  38.     char data[50] = {0};
  39.     #endif
  40.     /* Get facility code */
  41.     for(uint8_t i=1; i<=12; i++)
  42.     {
  43.         if(*(wiegandInfo->wiegandDat + i) == 1){
  44.             wiegandInfo->facilityCode = wiegandInfo->facilityCode << 1;
  45.             wiegandInfo->facilityCode = wiegandInfo->facilityCode + 0x01;
  46.         }
  47.         else{
  48.             wiegandInfo->facilityCode = wiegandInfo->facilityCode << 1;
  49.         }
  50.     }
  51.     /* Get card number */
  52.     for(uint8_t i=13; i<=24; i++)
  53.     {
  54.         if(*(wiegandInfo->wiegandDat + i) == 1){
  55.             wiegandInfo->readCardNumber = wiegandInfo->facilityCode << 1;
  56.             wiegandInfo->readCardNumber = wiegandInfo->facilityCode + 0x01;
  57.         }
  58.         else{
  59.             wiegandInfo->readCardNumber = wiegandInfo->facilityCode << 1;
  60.         }
  61.     }
  62.     #if DEBUG_USART == 1
  63.     sprintf(data, "FacilityCode %lu", wiegandInfo->facilityCode);
  64.     DebugMsg(data);
  65.     sprintf(data, "cardNumber %lu", wiegandInfo->facilityCode);
  66.     DebugMsg(data);
  67.     #endif
  68. }

Główna funkcja programu którą należy wywoływać w pętli while wygląda następująco:

  1. void wiegandMainFunction(void)
  2. {
  3.     uint8_t returnValue = 0xFF;
  4.     returnValue = wiegandCheckReceiveDataFormat(&wiegandData);
  5.     /* Check first channel */
  6.     switch(returnValue) {
  7.         case wiegand37Bit:  /* card 37 bits */
  8.             wiegandDecode37BitNumber(&wiegandData);
  9.         break;
  10.         case wiegand26Bit: /* card 26 bits */
  11.             wiegandDecode26BitNumber(&wiegandData);
  12.         break;
  13.         default:
  14.             /* wrong card number */
  15.         break;
  16.     }
  17.     /* Check second channel */
  18.     returnValue = wiegandCheckReceiveDataFormat(&wiegandDataCh2);
  19.     switch(returnValue) {
  20.         case wiegandNoData:
  21.             return; /* No data  */
  22.         break;
  23.         case wiegandWrongFrame:
  24.             return;/* wiegandWrongFrame */
  25.         break;
  26.         case wiegand37Bit:  /* card 37 bits */
  27.             wiegandDecode37BitNumber(&wiegandDataCh2);
  28.         break;
  29.         case wiegand26Bit: /* card 26 bits */
  30.             wiegandDecode26BitNumber(&wiegandDataCh2);
  31.         break;
  32.         default:
  33.             /* wrong card number */
  34.         break;
  35.     }
  36.     ClearStructureData();
  37. }

Funkcja odpowiedzialna za sprawdzenie formatu i zwrócenie odpowiedniej informacji:

  1. static enum wiegandReceiveDataNumber wiegandCheckReceiveDataFormat(wiegandData_t * wiegandInfo)
  2. {
  3.     char data[50] = {0};
  4.  
  5.     /* check number of receive bits and calculate parity */
  6.     if(wiegandInfo->wiegandTimeout == kWiegandTimeoutMs && (wiegandInfo->wiegandStartReceive == 1))
  7.     {
  8.         /* Flag for block operation in HAL_TIM_PeriodElapsedCallback go zero */
  9.         wiegandInfo->wiegandStartReceive = 0;
  10.  
  11.         if(wiegandInfo->wiegandDataPosition == 0)   {
  12.             /* No data in buffer */
  13.         }
  14.         else if(wiegandInfo->wiegandDataPosition == (kWiegandCard37Bits))
  15.         {
  16.             #if DEBUG_USART == 1
  17.             for(uint8_t i=0; i<37; i++)
  18.             {
  19.                 sprintf(data, "[%u]", i);
  20.                 Usart_Uart_SendString(USART1, data, ZERO);
  21.                 Usart_Uart_SendNumber(USART1, (uint32_t)wiegandInfo->wiegandDat[i]);
  22.                 Usart_Uart_SendString(USART1, " ", CR_LF);
  23.             }
  24.             #endif
  25.  
  26.             if(wiegandCheckDataFrame(wiegandInfo, wiegand37Bit) == 1)
  27.             {
  28.                 wiegandInfo->wiegandDataType = wiegand37Bit;
  29.                 return wiegand37Bit;
  30.             }
  31.             wiegandInfo->wiegandDataType = wiegandWrongFrame;
  32.             wiegandInfo->wiegandDataPosition = 0;
  33.             return wiegandWrongFrame;
  34.         }
  35.         else if(wiegandInfo->wiegandDataPosition == kWiegandCard26Bits)
  36.         {
  37.             #if DEBUG_USART == 1
  38.             for(uint8_t i=0; i<26; i++)
  39.             {
  40.                 sprintf(data, "[%u]", i);
  41.                 Usart_Uart_SendString(USART1, data, ZERO);
  42.                 Usart_Uart_SendNumber(USART1, (uint32_t)wiegandInfo->wiegandDat[i]);
  43.                 Usart_Uart_SendString(USART1, " ", CR_LF);
  44.             }
  45.             #endif
  46.  
  47.             if(wiegandCheckDataFrame(wiegandInfo, wiegand26Bit) == 1)
  48.             {
  49.                 wiegandInfo->wiegandDataPosition = wiegand26Bit;
  50.                 return 3;
  51.             }
  52.             wiegandInfo->wiegandDataType = wiegandWrongFrame;
  53.             wiegandInfo->wiegandDataPosition = 0;
  54.             return wiegandWrongFrame;
  55.  
  56.         }
  57.         else
  58.         {
  59.             sprintf(data, "odebrane: %u", wiegandInfo->wiegandDataPosition);
  60.             DebugMsg(data);
  61.  
  62.             for(uint8_t i=0; i<37; i++)
  63.             {
  64.                 sprintf(data, "[%u]", i);
  65.                 Usart_Uart_SendString(USART1, data, ZERO);
  66.                 Usart_Uart_SendNumber(USART1, (uint32_t)wiegandInfo->wiegandDat[i]);
  67.                 Usart_Uart_SendString(USART1, " ", CR_LF);
  68.             }
  69.             wiegandInfo->wiegandDataPosition = 0;
  70.         }
  71.     }
  72.     return 1;
  73. }

Jest ona wywoływana po przekroczeniu czasu oczekiwania na kolejny bit oraz gdy rozpoczęto odbieranie danych.

Pliki z biblioteką do wieganda można pobrać pod tym linkiem.