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.