Ten post chciałbym poświęcić na opisanie sposobu odczytu danych Wiegand na mikrokontrolerze 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:
- #define WIEG_B0_PORT LPC_GPIO2
 - #define WIEG_B0_PORT_NUM 2
 - #define WIEG_B0_PIN ( 1 << 8 ) // P2.8
 - #define WIEG_B0_PIN_NUM 8
 - #define WIEG_B1_PORT LPC_GPIO2
 - #define WIEG_B1_PORT_NUM 2
 - #define WIEG_B1_PIN ( 1 << 9 ) // P2.9
 - #define WIEG_B1_PIN_NUM 9
 
Inicjalizacja pinów wraz z przerwaniami:
- static void initPins_Wiegand_B(void) {
 - WIEG_B0_PORT->FIODIR &= ~WIEG_B0_PIN;
 - WIEG_B1_PORT->FIODIR &= ~WIEG_B1_PIN;
 - }
 
- static void init_Wiegand_B(void) {
 - PINSEL_CFG_Type PinCfg;
 - initPins_Wiegand_B();
 - PinCfg.Funcnum = PINSEL_FUNC_0;
 - PinCfg.OpenDrain = PINSEL_PINMODE_NORMAL;
 - PinCfg.Pinmode = PINSEL_PINMODE_PULLUP;
 - PinCfg.Portnum = WIEG_B0_PORT_NUM;
 - PinCfg.Pinnum = WIEG_B0_PIN_NUM;
 - PINSEL_ConfigPin(&PinCfg);
 - PinCfg.Portnum = WIEG_B0_PORT_NUM;
 - PinCfg.Pinnum = WIEG_B1_PIN_NUM;
 - PINSEL_ConfigPin(&PinCfg);
 - LPC_GPIOINT->IO2IntEnF |= WIEG_B0_PIN;
 - LPC_GPIOINT->IO2IntEnF |= WIEG_B1_PIN;
 - LPC_SC->EXTPOLAR &= ~0x00000002; /* rising */
 - NVIC_SetPriority(EINT3_IRQn, NVIC_PRIO_WIEG);
 - NVIC_EnableIRQ(EINT3_IRQn);
 - }
 
Teraz główna struktura przechowująca wszystkie informacje o głowicy:
- typedef struct Wiegand_CardDataStruct{
 - volatile uint64_t fullData;
 - volatile uint64_t fullData_BigCards;
 - uint64_t facilityCode;
 - uint64_t cardNumber;
 - volatile uint8_t bitCounter;
 - volatile uint8_t thereIsCardToDecode:1;
 - volatile uint8_t flag_startReceivingData:1;
 - }Wiegand_CardDataTypeDef;
 - typedef struct Wiegand_Struct{
 - Wiegand_CardDataTypeDef readCardData;
 - uint8_t headerAddress;
 - volatile uint32_t timeoutCounter;
 - }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:
- void EINT3_IRQHandler(void) {
 - if((LPC_GPIOINT->IO2IntStatF & WIEG_B0_PIN))
 - {
 - if(wiegandData[0].readCardData.bitCounter < 64)
 - {
 - wiegandData[0].readCardData.fullData = (wiegandData[0].readCardData.fullData << 1);
 - wiegandData[0].readCardData.fullData |= 0;
 - }
 - else
 - {
 - wiegandData[0].readCardData.fullData_BigCards = (wiegandData[0].readCardData.fullData_BigCards << 1);
 - wiegandData[0].readCardData.fullData_BigCards |= 0;
 - }
 - wiegandData[0].readCardData.bitCounter++;
 - wiegandData[0].readCardData.flag_startReceivingData = 1;
 - }
 - else if ((LPC_GPIOINT->IO2IntStatF & WIEG_B1_PIN))
 - {
 - if(wiegandData[0].readCardData.bitCounter < 64)
 - {
 - wiegandData[0].readCardData.fullData = (wiegandData[0].readCardData.fullData << 1);
 - wiegandData[0].readCardData.fullData |= 1;
 - }
 - else
 - {
 - wiegandData[0].readCardData.fullData_BigCards = (wiegandData[0].readCardData.fullData_BigCards << 1);
 - wiegandData[0].readCardData.fullData_BigCards |= 1;
 - }
 - wiegandData[0].readCardData.bitCounter++;
 - wiegandData[0].readCardData.flag_startReceivingData = 1;
 - }
 - if(wiegandData[0].readCardData.bitCounter == 1)
 - {
 - wiegandData[0].timeoutCounter = WIEG_TIMOUT_COUNTER_1;
 - }
 - LPC_GPIOINT->IO2IntClr |= 0x300;
 - }
 
Poniżej znajdują się funkcje dekodujące 26 bitowy numer karty wraz ze sprawdzaniem parzystości:
- static bool checkPartityBitsFor26BitHidFormat(Wiegand_TypeDef* wiegandData) {
 - Wiegand_TypeDef **pointer = &wiegandData;
 - uint8_t oddParityFromFrame = 0;
 - uint16_t dataForOddParity = 0;
 - uint8_t evenParityFromFrame = 0;
 - uint16_t dataForEvenParity = 0;
 - oddParityFromFrame = (uint8_t)((**pointer).readCardData.fullData & 0x0000001);
 - evenParityFromFrame = (uint8_t)(((**pointer).readCardData.fullData) >> 25);
 - dataForOddParity = (uint16_t)(((**pointer).readCardData.fullData & 0x0000001FFF) >> 1);
 - dataForEvenParity = (uint16_t)(((**pointer).readCardData.fullData) >> 13) & 0x0000000FFF;
 - if(((dataForOddParity % 2) > 0) && oddParityFromFrame == 0)
 - {
 - return false;
 - }
 - if(((dataForEvenParity % 2) > 0) && evenParityFromFrame == 1)
 - {
 - return false;
 - }
 - return true;
 - }
 - static void decode26BitCardNumberWithFacCode(Wiegand_TypeDef* wiegandData) { /* TEST WRITED */
 - uint64_t tmpData = 0;
 - Wiegand_TypeDef **pointer = &wiegandData;
 - tmpData = (**pointer).readCardData.fullData & 0x1FFFFFE;
 - (**pointer).readCardData.facilityCode = (tmpData & 0x1FE0000) >> 0x11;
 - (**pointer).readCardData.cardNumber = (tmpData & 0x1FFFE) >> 1;
 - }
 - static void decode26BitCardNumberNoFacCode(Wiegand_TypeDef* wiegandData) { /* TEST WRITED */
 - volatile uint64_t tmpData;
 - Wiegand_TypeDef **pointer = &wiegandData;
 - tmpData = (**pointer).readCardData.fullData & 0x1FFFFFE;
 - (**pointer).readCardData.facilityCode = 0;
 - (**pointer).readCardData.cardNumber = (tmpData & 0x1FFFFFE) >> 1;
 - }
 
Dekodowanie karty 37 bitowej:
- static void decode37BitCardNumberWithFacCode(Wiegand_TypeDef* wiegandData) { /* TEST WRITED */
 - uint64_t tmpData = 0;
 - Wiegand_TypeDef **pointer = &wiegandData;
 - tmpData = (**pointer).readCardData.fullData & 0xFFFFFFFFE;
 - (**pointer).readCardData.facilityCode = (tmpData & 0xFFFF00000) >> 0x14;
 - (**pointer).readCardData.cardNumber = (tmpData & 0xFFFFE) >> 1;
 - }
 
Sprawdzenie odebranych danych oraz zdekodowanie ramki:
- void checkWiegandData(Wiegand_TypeDef* wiegandData)
 - {
 - for(uint8_t i=0; i<2;i++)
 - {
 - Wiegand_TypeDef *pointer = wiegandData;
 - if((*(pointer + i)).readCardData.flag_startReceivingData == 1 &&
 - (*(pointer + i)).timeoutCounter == 0)
 - {
 - if(checkIfReceiveEnoughBits(wiegandData[i].readCardData.bitCounter, 26))
 - {
 - (*(pointer + i)).readCardData.thereIsCardToDecode = 1;
 - if(checkPartityBitsFor26BitHidFormat(&(*(pointer + i))) == true)
 - {
 - if(wiegand_Flags_t.useFacilityCode || wiegand_Flags_t.interprateFacilityCode)
 - {
 - decode26BitCardNumberWithFacCode(&(*(pointer + i)));
 - }
 - else
 - {
 - decode26BitCardNumberNoFacCode(&(*(pointer + i)));
 - }
 - }
 - }
 - else if(checkIfReceiveEnoughBits((*(pointer + i)).readCardData.bitCounter, 37))
 - {
 - (*(pointer + i)).readCardData.thereIsCardToDecode = 1;
 - decode37BitCardNumberWithFacCode(&(*(pointer + i)));
 - }
 - /* Clear data after decoding */
 - (*(pointer + i)).readCardData.flag_startReceivingData = 0;
 - (*(pointer + i)).timeoutCounter = 10;
 - (*(pointer + i)).readCardData.bitCounter = 0;
 - (*(pointer + i)).readCardData.fullData = 0;
 - (*(pointer + i)).readCardData.fullData_BigCards = 0;
 - (*(pointer + i)).readCardData.thereIsCardToDecode = 0;
 - (*(pointer + i)).readCardData.facilityCode = 0;
 - (*(pointer + i)).readCardData.cardNumber = 0;
 - }
 - }
 - }
 
Sprawdzanie danych wystarczy wywoływać w funkcji while gdzie jako parametr podajemy wskaźnik do struktury z danymi.