piątek, 7 września 2018

LPC1769 - Wiegand

Ten post chciałbym poświęcić na opisanie sposobu odczytu danych Wiegand na mikrokontrolerze LPC1769.

Znalezione obrazy dla zapytania lpc1769
[Źródło: https://www.nxp.com]


Opis programu:


Działanie Wieganda jest dosyć proste i było opisywane już na tym blogu, wobec tego przejdę odrazu do opisu programu. Na samym początku deklaracja pinów:

  1. #define WIEG_B0_PORT            LPC_GPIO2
  2. #define WIEG_B0_PORT_NUM        2
  3. #define WIEG_B0_PIN             ( 1 << 8 )  // P2.8
  4. #define WIEG_B0_PIN_NUM         8
  5.  
  6. #define WIEG_B1_PORT            LPC_GPIO2
  7. #define WIEG_B1_PORT_NUM        2
  8. #define WIEG_B1_PIN             ( 1 << 9 )  // P2.9
  9. #define WIEG_B1_PIN_NUM         9

Inicjalizacja pinów wraz z przerwaniami:

  1. static void initPins_Wiegand_B(void) {
  2.     WIEG_B0_PORT->FIODIR &= ~WIEG_B0_PIN;
  3.     WIEG_B1_PORT->FIODIR &= ~WIEG_B1_PIN;
  4. }

  1. static void init_Wiegand_B(void) {
  2.     PINSEL_CFG_Type PinCfg;
  3.  
  4.     initPins_Wiegand_B();
  5.  
  6.     PinCfg.Funcnum = PINSEL_FUNC_0;
  7.     PinCfg.OpenDrain = PINSEL_PINMODE_NORMAL;
  8.     PinCfg.Pinmode = PINSEL_PINMODE_PULLUP;
  9.  
  10.     PinCfg.Portnum = WIEG_B0_PORT_NUM;
  11.     PinCfg.Pinnum = WIEG_B0_PIN_NUM;
  12.     PINSEL_ConfigPin(&PinCfg);
  13.  
  14.     PinCfg.Portnum = WIEG_B0_PORT_NUM;
  15.     PinCfg.Pinnum = WIEG_B1_PIN_NUM;
  16.     PINSEL_ConfigPin(&PinCfg);
  17.  
  18.     LPC_GPIOINT->IO2IntEnF |= WIEG_B0_PIN;
  19.     LPC_GPIOINT->IO2IntEnF |= WIEG_B1_PIN;
  20.  
  21.     LPC_SC->EXTPOLAR &= ~0x00000002;    /* rising */
  22.  
  23.     NVIC_SetPriority(EINT3_IRQn, NVIC_PRIO_WIEG);
  24.     NVIC_EnableIRQ(EINT3_IRQn);
  25. }

Teraz główna struktura przechowująca wszystkie informacje o głowicy:

  1. typedef struct Wiegand_CardDataStruct{
  2.     volatile uint64_t fullData
  3.     volatile uint64_t fullData_BigCards
  4.     uint64_t facilityCode;
  5.     uint64_t cardNumber;
  6.     volatile uint8_t bitCounter;
  7.     volatile uint8_t thereIsCardToDecode:1;
  8.     volatile uint8_t flag_startReceivingData:1;
  9. }Wiegand_CardDataTypeDef;
  10.  
  11. typedef struct Wiegand_Struct{
  12.     Wiegand_CardDataTypeDef readCardData;
  13.     uint8_t headerAddress;
  14.     volatile uint32_t timeoutCounter;
  15. }Wiegand_TypeDef;

W niej przechowują dane odnośnie wszystkich otrzymanych bitów, kodu pomieszczeń, numeru karty, licznika bitów, adresu głowicy, flag odnośnie odebranych danych itp.

Informacje o bitach są odbierane jednym przerwaniu, w którym sprawdzam od jakiego pinu zostało wygenerowane przerwanie:

  1. void EINT3_IRQHandler(void) {
  2.     if((LPC_GPIOINT->IO2IntStatF & WIEG_B0_PIN))
  3.     {
  4.         if(wiegandData[0].readCardData.bitCounter < 64)
  5.         {
  6.             wiegandData[0].readCardData.fullData = (wiegandData[0].readCardData.fullData << 1);
  7.             wiegandData[0].readCardData.fullData |= 0;
  8.         }
  9.         else
  10.         {
  11.             wiegandData[0].readCardData.fullData_BigCards = (wiegandData[0].readCardData.fullData_BigCards << 1);
  12.             wiegandData[0].readCardData.fullData_BigCards |= 0;
  13.         }
  14.  
  15.         wiegandData[0].readCardData.bitCounter++;
  16.         wiegandData[0].readCardData.flag_startReceivingData = 1;
  17.     }
  18.     else if ((LPC_GPIOINT->IO2IntStatF & WIEG_B1_PIN))
  19.     {
  20.         if(wiegandData[0].readCardData.bitCounter < 64)
  21.         {
  22.            wiegandData[0].readCardData.fullData = (wiegandData[0].readCardData.fullData << 1);
  23.             wiegandData[0].readCardData.fullData |= 1;
  24.         }
  25.         else
  26.         {
  27.             wiegandData[0].readCardData.fullData_BigCards = (wiegandData[0].readCardData.fullData_BigCards << 1);
  28.             wiegandData[0].readCardData.fullData_BigCards |= 1;
  29.         }
  30.         wiegandData[0].readCardData.bitCounter++;
  31.         wiegandData[0].readCardData.flag_startReceivingData = 1;
  32.     }
  33.  
  34.     if(wiegandData[0].readCardData.bitCounter == 1)
  35.     {
  36.         wiegandData[0].timeoutCounter = WIEG_TIMOUT_COUNTER_1;
  37.     }
  38.  
  39.     LPC_GPIOINT->IO2IntClr |= 0x300;
  40. }

Poniżej znajdują się funkcje dekodujące 26 bitowy numer karty wraz ze sprawdzaniem parzystości:

  1. static bool checkPartityBitsFor26BitHidFormat(Wiegand_TypeDef* wiegandData) {
  2.     Wiegand_TypeDef **pointer = &wiegandData;
  3.  
  4.     uint8_t oddParityFromFrame = 0;
  5.     uint16_t dataForOddParity = 0;
  6.  
  7.     uint8_t evenParityFromFrame = 0;
  8.     uint16_t dataForEvenParity = 0;
  9.  
  10.     oddParityFromFrame = (uint8_t)((**pointer).readCardData.fullData & 0x0000001);
  11.     evenParityFromFrame = (uint8_t)(((**pointer).readCardData.fullData) >> 25);
  12.  
  13.     dataForOddParity = (uint16_t)(((**pointer).readCardData.fullData & 0x0000001FFF) >> 1);
  14.     dataForEvenParity = (uint16_t)(((**pointer).readCardData.fullData) >> 13) & 0x0000000FFF;
  15.  
  16.     if(((dataForOddParity % 2) > 0) && oddParityFromFrame == 0)
  17.     {
  18.         return false;
  19.     }
  20.  
  21.     if(((dataForEvenParity % 2) > 0) && evenParityFromFrame == 1)
  22.     {
  23.         return false;
  24.     }
  25.  
  26.     return true;
  27. }
  28.  
  29. static void decode26BitCardNumberWithFacCode(Wiegand_TypeDef* wiegandData) { /* TEST WRITED */
  30.     uint64_t tmpData = 0;
  31.     Wiegand_TypeDef **pointer = &wiegandData;
  32.  
  33.     tmpData = (**pointer).readCardData.fullData & 0x1FFFFFE;
  34.  
  35.     (**pointer).readCardData.facilityCode = (tmpData & 0x1FE0000) >> 0x11;
  36.     (**pointer).readCardData.cardNumber = (tmpData & 0x1FFFE) >> 1;
  37. }
  38.  
  39. static void decode26BitCardNumberNoFacCode(Wiegand_TypeDef* wiegandData) { /* TEST WRITED */
  40.     volatile uint64_t tmpData;
  41.     Wiegand_TypeDef **pointer = &wiegandData;
  42.  
  43.     tmpData = (**pointer).readCardData.fullData & 0x1FFFFFE;
  44.     (**pointer).readCardData.facilityCode = 0;
  45.     (**pointer).readCardData.cardNumber = (tmpData & 0x1FFFFFE) >> 1;
  46. }

Dekodowanie karty 37 bitowej:

  1. static void decode37BitCardNumberWithFacCode(Wiegand_TypeDef* wiegandData) { /* TEST WRITED */
  2.     uint64_t tmpData = 0;
  3.     Wiegand_TypeDef **pointer = &wiegandData;
  4.  
  5.     tmpData = (**pointer).readCardData.fullData & 0xFFFFFFFFE;
  6.     (**pointer).readCardData.facilityCode = (tmpData & 0xFFFF00000) >> 0x14;
  7.     (**pointer).readCardData.cardNumber = (tmpData & 0xFFFFE) >> 1;
  8. }

Sprawdzenie odebranych danych oraz zdekodowanie ramki:

  1. void checkWiegandData(Wiegand_TypeDef* wiegandData)
  2. {
  3.     for(uint8_t i=0; i<2;i++)
  4.     {
  5.         Wiegand_TypeDef *pointer = wiegandData;
  6.  
  7.         if((*(pointer + i)).readCardData.flag_startReceivingData == 1 &&
  8.                 (*(pointer + i)).timeoutCounter == 0)
  9.         {
  10.             if(checkIfReceiveEnoughBits(wiegandData[i].readCardData.bitCounter, 26))
  11.             {
  12.                 (*(pointer + i)).readCardData.thereIsCardToDecode = 1;
  13.  
  14.                 if(checkPartityBitsFor26BitHidFormat(&(*(pointer + i))) == true)
  15.                 {
  16.                     if(wiegand_Flags_t.useFacilityCode || wiegand_Flags_t.interprateFacilityCode)
  17.                     {
  18.                         decode26BitCardNumberWithFacCode(&(*(pointer + i)));
  19.                     }
  20.                     else
  21.                     {
  22.                         decode26BitCardNumberNoFacCode(&(*(pointer + i)));
  23.                     }
  24.                 }
  25.             }
  26.             else if(checkIfReceiveEnoughBits((*(pointer + i)).readCardData.bitCounter, 37))
  27.             {
  28.                 (*(pointer + i)).readCardData.thereIsCardToDecode = 1;
  29.                 decode37BitCardNumberWithFacCode(&(*(pointer + i)));
  30.             }
  31.  
  32.             /* Clear data after decoding */
  33.             (*(pointer + i)).readCardData.flag_startReceivingData = 0;
  34.             (*(pointer + i)).timeoutCounter = 10;
  35.             (*(pointer + i)).readCardData.bitCounter = 0;
  36.             (*(pointer + i)).readCardData.fullData = 0;
  37.             (*(pointer + i)).readCardData.fullData_BigCards = 0;
  38.             (*(pointer + i)).readCardData.thereIsCardToDecode = 0;
  39.             (*(pointer + i)).readCardData.facilityCode = 0;
  40.             (*(pointer + i)).readCardData.cardNumber = 0;
  41.         }
  42.     }
  43. }

Sprawdzanie danych wystarczy wywoływać w funkcji while gdzie jako parametr podajemy wskaźnik do struktury z danymi.