wtorek, 23 kwietnia 2019

[31] STM32F7 - Czytnik linii papilarnych TFSD400

Ten post chciałbym poświęcić na opisanie obsługi czytnika linii papilarnych TFSD400 z mikrokontrolerem STM32F205 32-bit. Komunikacja z układem odbywa się poprzez port UART.

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

Program:


Poniżej przedstawię wykaz funkcji z biblioteki, po nim opiszę niektóre ważniejsze funkcje, oraz przedstawię przykładowy sposób użycia.

Poniżej przejdę przez funkcję zawarte w bibliotece. Co do funkcjonalności czytnika może się ona różnić w zależności od wgranego oprogramowania. Dodatkowo datasheet jest nie za bardzo dokładny, co oznacza, że najlepszym sposobem na sprawdzanie komend będzie wyszukiwanie ich w kodach źródłowych dla aplikacji komputerowej napisanej w C++, które zostały udostępnione przez producenta. Dane dla układu zostały zdefiniowane w plikach CommTestDlg.cpp oraz CmdHead.h.

Plik z kodem dla mikrokontrolera STM udostępnione od producenta są bardziej poglądowe niż stanowią dokładne informacje jakie zostały umieszczone.

Procedura inicjalizacji modułu opiera się na podłączeniu układu pod mikrokontroler oraz ustawieniu parametrów komunikacyjnych dla UART'a. Na płytce STM32F7 Discovery wykorzystałem UART7 z z prędkością 19200 baudrate. Pozostałe ustawienia bez zmian.

  1. void Init_Uart7(uint32_t baudRate)
  2. {
  3.     GPIO_InitTypeDef gpio_init_structure;
  4.     PORT_CLOCK_ENABLE(USART7_GPIOF);
  5.     Uart_Usart_Initialize_Clock(UART7);
  6.     gpio_init_structure.Pin         = USART7_TX2;
  7.     gpio_init_structure.Mode        = GPIO_MODE_AF_PP;
  8.     gpio_init_structure.Speed       = GPIO_SPEED_FAST;
  9.     gpio_init_structure.Pull        = GPIO_PULLUP;
  10.     gpio_init_structure.Alternate   = GPIO_AF8_UART7;
  11.     HAL_GPIO_Init(USART7_GPIOF, &gpio_init_structure);
  12.     // GPIO RX
  13.     gpio_init_structure.Pin         = USART7_RX2;
  14.     gpio_init_structure.Mode        = GPIO_MODE_AF_PP;
  15.     gpio_init_structure.Pull        = GPIO_PULLUP;
  16.     gpio_init_structure.Alternate   = GPIO_AF8_UART7;
  17.     HAL_GPIO_Init(USART7_GPIOF, &gpio_init_structure);
  18.     UART_Handle7.Instance                       = UART7;
  19.     UART_Handle7.Init.BaudRate                  = baudRate;
  20.     UART_Handle7.Init.WordLength                = UART_WORDLENGTH_8B;
  21.     UART_Handle7.Init.StopBits                  = UART_STOPBITS_1;
  22.     UART_Handle7.Init.Parity                    = UART_PARITY_NONE;
  23.     UART_Handle7.Init.HwFlowCtl                 = UART_HWCONTROL_NONE;
  24.     UART_Handle7.Init.Mode                      = UART_MODE_TX_RX;
  25.     UART_Handle7.Init.OverSampling              = UART_OVERSAMPLING_16;
  26.     UART_Handle7.Init.OneBitSampling            = UART_ONEBIT_SAMPLING_DISABLED;
  27.     UART_Handle7.AdvancedInit.AdvFeatureInit    = UART_ADVFEATURE_NO_INIT;
  28.     HAL_UART_Init(&UART_Handle7);
  29.     HAL_NVIC_DisableIRQ(UART7_IRQn);
  30.     HAL_NVIC_SetPriority(UART7_IRQn, 0, 1);
  31.     HAL_NVIC_EnableIRQ(UART7_IRQn);
  32.     HAL_NVIC_ClearPendingIRQ(UART7_IRQn);
  33.     __HAL_UART_ENABLE_IT(&UART_Handle7, UART_IT_RXNE);
  34.     UART7->CR1 |= USART_CR1_RXNEIE;
  35. }

Przerwania zostały utworzone tylko dla odbierania danych od modułu. Transmisja danych odbywa się w pollingu.

Po tej operacji należy sprawdzić komunikację z modułem. Wykonuje się to przez przesłanie komendy testowej:

  1. TFSD400_OperStat_StatusTypeDef TFSD400_TestCommWithModule(void){
  2.     uint8_t testCommFrame[] = { TFSD400_CMD_TEST_COMM_WITH_MODULE, 0x00, 0x00, 0x00 };
  3.     p_TFSD400_ClearReceiveUartBuffer();
  4.     TFSD400_WriteCommand(testCommFrame);
  5.     return testResponseFrame_BlockingExample(UartDataStruct.Buffer, testCommFrame, sizeof(testCommFrame));
  6. }

Jest to podstawowa operacja, dzięki której można określić czy posiadamy jakąś komunikację czyli czy kable są podłączone poprawnie, moduł jest skonfigurowany pod ustawione prędkości itp.

Cała procedura jest dosyć prosta na początku przygotowujemy ramkę testową, która bezie przesyłana do układu TFSD400. Taka sama ramka będzie przesłana w odpowiedzi od czytnika.

W celu zmiany baudrat'a można posłużyć się następującą komendą:

  1. TFSD400_OperStat_StatusTypeDef TFSD400_ChangeBaudRate(TFSD400_BaudRateTypeDef selectedBaudrate){
  2.     uint8_t baudarateFrameToSend[]  = { TFSD400_CMD_BAUD, 0x00, 0x00, selectedBaudrate };
  3.     uint8_t baudrateFrameToReceive[] = { TFSD400_CMD_BAUD, 0x00, 0x00 };
  4.     p_TFSD400_ClearReceiveUartBuffer();
  5.     TFSD400_WriteCommand(baudarateFrameToSend);
  6.     return testResponseFrame_BlockingExample(UartDataStruct.Buffer, baudrateFrameToReceive, 3);
  7. }

Do wyboru są następujące prędkości:

  • 9600 - wartość parametru 0x01,
  • 19200 - wartość parametru 0x02,
  • 38400 - wartość parametru 0x03,
  • 57600 - wartość parametru 0x04,
  • 115200 - wartość parametru 0x05.

Uśpienie układu możliwe jest przez następującą komendę:

  1. TFSD400_OperStat_StatusTypeDef TFSD400_SleepDevice(void){
  2.     uint8_t sendFrame[] = { TFSD400_CMD_SLEEP, 0x00, 0x00, 0x00 };
  3.     uint8_t responseFrame[] = { TFSD400_CMD_SLEEP, 0x00, 0x00 };
  4.     p_TFSD400_ClearReceiveUartBuffer();
  5.     TFSD400_WriteCommand(sendFrame);
  6.     return testResponseFrame_BlockingExample(UartDataStruct.Buffer, responseFrame, sizeof(responseFrame));
  7. }

Niestety nie ma możliwości wybudzenia go odpowiednim rozkazem. Co oznacza, że w celu wybudzenia należy wykonać sterowanie pinem reset układu TFSD400.

Kolejna z dostępnych funkcji pozwala na usunięcie wszystkich użytkowników z  bazy danych pamięci układu.

  1. TFSD400_OperStat_StatusTypeDef TFSD400_DeleteAllUsers(){
  2.     uint8_t sendFrame[]     = { TFSD400_CMD_DEL_ALL, 0x00, 0x00, 0x00 };
  3.     uint8_t responseFrame[] = { TFSD400_CMD_DEL_ALL, 0x00, 0x00 };
  4.     p_TFSD400_ClearReceiveUartBuffer();
  5.     TFSD400_WriteCommand(sendFrame);
  6.     return testResponseFrame_BlockingExample(UartDataStruct.Buffer, responseFrame, sizeof(responseFrame));
  7. }

Usunięcie pojedynczego użytkownika z bazy danych przebiega w następujący sposób:

  1. TFSD400_OperStat_StatusTypeDef TFSD400_DeleteAllUsers(){
  2.     uint8_t sendFrame[]     = { TFSD400_CMD_DEL_ALL, 0x00, 0x00, 0x00 };
  3.     uint8_t responseFrame[] = { TFSD400_CMD_DEL_ALL, 0x00, 0x00 };
  4.     p_TFSD400_ClearReceiveUartBuffer();
  5.     TFSD400_WriteCommand(sendFrame);
  6.     return testResponseFrame_BlockingExample(UartDataStruct.Buffer, responseFrame, sizeof(responseFrame));
  7. }

Każdy z zapisanych użytkowników dostaje osobny numer ID 16 bitowy. Po tym numerze możemy usunąć z pamięci użytkownika. Przesłanie go w ramce danych podając najpierw wyższy bajt, następnie w kolejnej wartości niższą cześć.

Sprawdzenie wersji oprogramowania umieszczonego w czytniku:

  1. TFSD400_OperStat_StatusTypeDef TFSD400_GetSoftwareVersion(uint8_t *firmawareVersionPtr)
  2. {
  3.     uint8_t sendFrame[]     = { TFSD400_CMD_DSP_VER, 0x00, 0x00, 0x00 };
  4.     uint8_t responseFrame[] = { TFSD400_CMD_DSP_VER };
  5.     p_TFSD400_ClearReceiveUartBuffer();
  6.     TFSD400_WriteCommand(sendFrame);
  7.     int8_t positionInBuffer = testResponseFrame_ReturnBufferPosition(UartDataStruct.Buffer, responseFrame, sizeof(responseFrame));
  8.     if(positionInBuffer == -1)
  9.     {
  10.         return TFSD400_ERROR;
  11.     }
  12.     *(firmawareVersionPtr + 0) = UartDataStruct.Buffer[positionInBuffer + 1];
  13.     *(firmawareVersionPtr + 1) = UartDataStruct.Buffer[positionInBuffer + 2];
  14.     return TFSD400_OK;
  15. }

Pobrana wersja oprogramowania składa się z dwóch bajtów danych, które są wpisywane do wskaźnika na tablicę przechowującą wynik.

Ustawienie oraz pobranie intensywności podświetlenia:

  1. TFSD400_OperStat_StatusTypeDef TFSD400_SetLumAdjust(uint8_t backLightIntensity){
  2.     uint8_t sendFrame[] = { TFSD400_CMD_SET_LUM, 0x00, 0x00, backLightIntensity  };
  3.     uint8_t responseFrame[] = { TFSD400_CMD_SET_LUM };
  4.     p_TFSD400_ClearReceiveUartBuffer();
  5.     TFSD400_WriteCommand(sendFrame);
  6.     return testResponseFrame_SearchPosition_BlockingExample(UartDataStruct.Buffer, responseFrame, sizeof(responseFrame), 3);
  7. }

Funkcja nie jest wspomniana w dokumentacji, natomiast można ją znaleźć w projekcie C++. Niestety nie wykonuje ona żadnych operacji na module. Prawdopodobnie w tej wersji oprogramowania, którą posiadam nie jest ona zdefiniowana. Możliwe że w wersjach z nowszym softem bądź innym modułem od tej firmy będzie ona działać bez problemów.

Odczytanie ustawionej intensywności podświetlenia:

  1. uint8_t TFSD400_GetLumAdjust(uint8_t *pointerToLumDataArray){
  2.     uint8_t sendFrame[]     = { TFSD400_CMD_GET_LUM, 0x00, 0x00, 0x00 };
  3.     uint8_t responseFrame[] = { TFSD400_CMD_GET_LUM };
  4.     p_TFSD400_ClearReceiveUartBuffer();
  5.     TFSD400_WriteCommand(sendFrame);
  6.     volatile int8_t positionInBuffer = testResponseFrame_ReturnBufferPosition(UartDataStruct.Buffer, responseFrame, sizeof(responseFrame));
  7.     if(positionInBuffer == (-1))
  8.     {
  9.         return TFSD400_ERROR;
  10.     }
  11.     *(pointerToLumDataArray + 0) = UartDataStruct.Buffer[positionInBuffer + 3];
  12.     *(pointerToLumDataArray + 1) = UartDataStruct.Buffer[positionInBuffer + 4];
  13.     *(pointerToLumDataArray + 2) = UartDataStruct.Buffer[positionInBuffer + 5];
  14.     return positionInBuffer;
  15. }

Ustaw czas potrzebny na odczytanie stanu przycisku:

  1. TFSD400_OperStat_StatusTypeDef TFSD400_SetCaptureTimeout(uint8_t timeoutToSet){
  2.     uint8_t sendFrame[] = { TFSD400_CMD_TIMEOUT, 0x00, timeoutToSet, 0x00 };
  3.     uint8_t responseFrame[] = { TFSD400_CMD_TIMEOUT, 0x00 };
  4.     p_TFSD400_ClearReceiveUartBuffer();
  5.     TFSD400_WriteCommand(sendFrame);
  6.     return testResponseFrame_SearchPosition_BlockingExample(UartDataStruct.Buffer, responseFrame, sizeof(responseFrame), 3);
  7. }

Tą funkcję można bezproblemowemu znaleźć w dokumentacji do układu czytnika palca. Wartość oczekiwania na odczyt palca może być wybierany z przedziału od 0 do 255. Gdzie ilość czasu obliczana jest ze wzoru:

Czas = (Przesłana Wartość) * 0,3;

W przypadku ustawienia tego parametru na 0. Czujnik będzie oczekiwał aż uda się odczytać numer dane.

Odczytanie ustawionej wartości czasu oczekiwania na przyłożenie palca:

  1. uint8_t TFSD400_ReadCaptureTimeout(){
  2.     uint8_t sendFrame[]     = { TFSD400_CMD_TIMEOUT, 0x00, 0x00, 0x01 };
  3.     uint8_t responseFrame[] = { TFSD400_CMD_TIMEOUT, 0x00 };
  4.     p_TFSD400_ClearReceiveUartBuffer();
  5.     TFSD400_WriteCommand(sendFrame);
  6.     int8_t positionInBuffer = testResponseFrame_ReturnBufferPosition(UartDataStruct.Buffer, responseFrame, sizeof(responseFrame));
  7.     if(positionInBuffer == (-1) || UartDataStruct.Buffer[positionInBuffer + 3] != TFSD400_OK)
  8.     {
  9.         return retTFSD400Code(UartDataStruct.Buffer[positionInBuffer + 3]);
  10.     }
  11.     return UartDataStruct.Buffer[positionInBuffer + 2];
  12. }

Ustawienie poziomu porównywania odcisku palca z wprowadzonym wzorcem:

  1. TFSD400_OperStat_StatusTypeDef TFSD400_SetCompairisionLevel(uint8_t level){
  2.     if(level > 9) {
  3.         return TFSD400_FAIL;
  4.     }
  5.    
  6.     uint8_t sendFrame[] = { TFSD400_CMD_CMP_LVL, 0x00, level, 0x00 };
  7.     uint8_t responseFrame[] = { TFSD400_CMD_CMP_LVL, 0x00 };
  8.     p_TFSD400_ClearReceiveUartBuffer();
  9.     TFSD400_WriteCommand(sendFrame);
  10.     return testResponseFrame_SearchPosition_BlockingExample(UartDataStruct.Buffer, responseFrame, sizeof(responseFrame), 3);
  11. }

W przypadku przekroczenia dopuszczalnego poziomu zwracany jest błąd bez przesyłania ramki danych do czytnika.

Odczytywanie poziomu porównywania odcisku palca:

  1. uint8_t TFSD400_ReadCompairisionLevel(){
  2.     uint8_t sendFrame[] = { TFSD400_CMD_CMP_LVL, 0x00, 0x00, 0x01 };
  3.     uint8_t responseFrame[] = { TFSD400_CMD_CMP_LVL, 0x00 };
  4.     p_TFSD400_ClearReceiveUartBuffer();
  5.     TFSD400_WriteCommand(sendFrame);
  6.     int8_t positionInBuffer = testResponseFrame_ReturnBufferPosition(UartDataStruct.Buffer, responseFrame, sizeof(responseFrame));
  7.     if(positionInBuffer == (-1) || UartDataStruct.Buffer[positionInBuffer + 3] != TFSD400_OK)
  8.     {
  9.         return TFSD400_ERROR;
  10.     }
  11.     return UartDataStruct.Buffer[positionInBuffer + 2];
  12. }

Odczytanie ustawionego trybu dodawania palca (repeat mode / prohibit repeat mode). W drugiej funkcji możliwe jest tylko dodawanie pojedynczego użytkowania do pamięci. W przypadku ustawiania drugiego użytkownika zostanie zwrócona wartość błędu.

  1. uint8_t TFSD400_ReadFingerprintAddMode(){
  2.     uint8_t sendFrame[] = { TFSD400_CMD_MODE, 0x00, 0x00, 0x01 };
  3.     uint8_t responseFrame[] = { TFSD400_CMD_MODE, 0x00 };
  4.     p_TFSD400_ClearReceiveUartBuffer();
  5.     TFSD400_WriteCommand(sendFrame);
  6.     int8_t positionInBuffer = testResponseFrame_ReturnBufferPosition(UartDataStruct.Buffer, responseFrame, sizeof(responseFrame));
  7.     if(positionInBuffer == (-1) || UartDataStruct.Buffer[positionInBuffer + 3] != TFSD400_OK)
  8.     {
  9.         return TFSD400_ERROR;
  10.     }
  11.     return UartDataStruct.Buffer[positionInBuffer + 2];
  12. }

Gdy funkcja zwróci wartość 1 to ustawiono tryb prohibit repeat mode, 0 gdy wybrano repeat mode. W przypadku błędu zwrócona zostanie wartość 0xFF.

Ustawienie trybu dodawania palca:

  1. TFSD400_OperStat_StatusTypeDef TFSD400_SetFingerprintAddMode(uint8_t mode){
  2.     if(mode != 0x00 && mode != 0x01) { return 0xFF; }
  3.    
  4.     uint8_t sendFrame[]     =   { TFSD400_CMD_MODE, 0x00, mode, 0x00 };
  5.     uint8_t responseFrame[] =   { TFSD400_CMD_MODE, 0x00 };
  6.     p_TFSD400_ClearReceiveUartBuffer();
  7.     TFSD400_WriteCommand(sendFrame);
  8.     int8_t positionInBuffer = testResponseFrame_ReturnBufferPosition(UartDataStruct.Buffer, responseFrame, sizeof(responseFrame));
  9.     if(positionInBuffer == (-1) || UartDataStruct.Buffer[positionInBuffer + 3] != TFSD400_OK)
  10.     {
  11.         return TFSD400_ERROR;
  12.     }
  13.     return retTFSD400Code( UartDataStruct.Buffer[positionInBuffer + 3] );
  14. }

Podobnie jak poprzednio wybieramy parametr z odpowiednim trybem i przesyłamy do urządzenia.

Pobranie liczby użytkowników zapisanych w pamięci urządzenia:

  1. TFSD400_OperStat_StatusTypeDef TFSD400_GetNumberOfRegUserId(uint8_t *numberOfUserPtr){
  2.     uint8_t sendFrame[]     = { TFSD400_CMD_USER_SUM_DB, 0x00, 0x00, 0x00 };
  3.     uint8_t responseFrame[] = { TFSD400_CMD_USER_SUM_DB };
  4.     p_TFSD400_ClearReceiveUartBuffer();
  5.     TFSD400_WriteCommand(sendFrame);
  6.     int8_t positionInBuffer = testResponseFrame_ReturnBufferPosition(UartDataStruct.Buffer, responseFrame, sizeof(responseFrame));
  7.     if(positionInBuffer == (-1) || UartDataStruct.Buffer[positionInBuffer + 3] != TFSD400_OK)
  8.     {
  9.         return TFSD400_ERROR;
  10.     }
  11.    
  12.     *(numberOfUserPtr + 0) = (UartDataStruct.Buffer[positionInBuffer + 1] << 8);
  13.     *(numberOfUserPtr + 1) = (UartDataStruct.Buffer[positionInBuffer + 2]);
  14.     return TFSD400_OK;
  15. }

Pobranie informacji o wgranych użytkownikach oraz ich uprawnieniach:

  1. uint32_t TFSD400_CompareFingerWithDatabase(){
  2.     uint8_t sendFrame[]     = { TFSD400_CMD_MATCH, 0x00, 0x00, 0x00 };
  3.     uint8_t responseFrame[] = { TFSD400_CMD_MATCH   };
  4.     p_TFSD400_ClearReceiveUartBuffer();
  5.     TFSD400_WriteCommand(sendFrame);
  6.     int8_t positionInBuffer = testResponseFrame_ReturnBufferPosition_ReadFingerTimeout(UartDataStruct.Buffer, responseFrame, sizeof(responseFrame));
  7.     if(positionInBuffer == (-1))
  8.     {
  9.         return 0xFFFFFFFF;;
  10.     }
  11.     if( (UartDataStruct.Buffer[positionInBuffer + 1] == 0x00) &
  12.             (UartDataStruct.Buffer[positionInBuffer + 2] == 0x00) &
  13.             (UartDataStruct.Buffer[positionInBuffer + 3] != 0x00))
  14.     {
  15.         return 0xFFFFFFFF;
  16.     }
  17.     return UartDataStruct.Buffer[positionInBuffer + 1] << 16 | UartDataStruct.Buffer[positionInBuffer + 2] << 8 |UartDataStruct.Buffer[positionInBuffer + 3];
  18. }

Wykonanie porównania przyłożonego palca z konkretnym użytkownikiem zapisanym w pamięci modułu odczytu linii papilarnych:

  1. TFSD400_OperStat_StatusTypeDef TFSD400_CompareUserWithFinger(uint16_t user){
  2.     uint8_t sendFrame[]     = { TFSD400_CMD_USER_CMP, user >> 8, user, 0x00 };
  3.     uint8_t responseFrame[] = { TFSD400_CMD_USER_CMP, 0x00, 0x00 };
  4.     p_TFSD400_ClearReceiveUartBuffer();
  5.    
  6.     TFSD400_WriteCommand(sendFrame);
  7.     return testResponseFrame_SearchPosition_BlockingExample(UartDataStruct.Buffer, responseFrame, sizeof(responseFrame), 3);
  8. }

Dodawanie użytkownika wraz z uprawnieniem. Jako argument podawana jest wartość ID oraz poziom uprawnień dla danego użytkownika. Znaczenie tego ostatniego jest definiowane przez użytkownika.

  1. TFSD400_OperStat_StatusTypeDef TFSD400_AddFingerprint(uint16_t userId, uint8_t userPrivilage){
  2.     if(userId < 0x01 || userId > 0xFFF) { return TFSD400_ERROR; }
  3.     if(userPrivilage < 1 || userPrivilage > 3){ return TFSD400_ERROR; }
  4.     uint8_t sendFrame[] = { TFSD400_CMD_ADD_1, userId >> 8, userId, userPrivilage };
  5.     uint8_t responseFrame[] = { TFSD400_CMD_ADD_1, 0x00, 0x00 };
  6.     p_TFSD400_ClearReceiveUartBuffer();
  7.     //Send first Add Command
  8.     p_TFSD400_ClearReceiveUartBuffer();
  9.     TFSD400_WriteCommand(sendFrame);
  10.     volatile int8_t positionInBuffer = testResponseFrame_ReturnBufferPosition_ReadFingerTimeout(UartDataStruct.Buffer, responseFrame,sizeof(responseFrame));
  11.     if(positionInBuffer == (-1)) {
  12.         return TFSD400_ERROR;
  13.     }
  14.     if(retTFSD400Code(UartDataStruct.Buffer[positionInBuffer + 3]) != TFSD400_OK )
  15.     {
  16.         return retTFSD400Code( UartDataStruct.Buffer[positionInBuffer + 3] );
  17.     }
  18.     //Send second command
  19.     sendFrame[0] = TFSD400_CMD_ADD_2;
  20.     responseFrame[0] = TFSD400_CMD_ADD_2;
  21.     p_TFSD400_ClearReceiveUartBuffer();
  22.     TFSD400_WriteCommand(sendFrame);
  23.     positionInBuffer = testResponseFrame_ReturnBufferPosition_ReadFingerTimeout(UartDataStruct.Buffer, responseFrame, sizeof(responseFrame));
  24.     if(positionInBuffer == (-1)) {
  25.         return TFSD400_ERROR;
  26.     }
  27.     if(retTFSD400Code(UartDataStruct.Buffer[positionInBuffer + 3]) != TFSD400_OK )
  28.     {
  29.         return retTFSD400Code( UartDataStruct.Buffer[positionInBuffer + 3] );
  30.     }
  31.     //Send third command
  32.     sendFrame[0] = TFSD400_CMD_ADD_3;
  33.     responseFrame[0] = TFSD400_CMD_ADD_3;
  34.     p_TFSD400_ClearReceiveUartBuffer();
  35.     TFSD400_WriteCommand(sendFrame);
  36.     positionInBuffer = testResponseFrame_ReturnBufferPosition_ReadFingerTimeout(UartDataStruct.Buffer, responseFrame, sizeof(responseFrame));
  37.     if(positionInBuffer == (-1)) {
  38.         return TFSD400_ERROR;
  39.     }
  40.     if(retTFSD400Code(UartDataStruct.Buffer[positionInBuffer + 3]) != TFSD400_OK )
  41.     {
  42.         return retTFSD400Code(UartDataStruct.Buffer[positionInBuffer + 3]);
  43.     }
  44.     return TFSD400_OK;
  45. }

Numery użytkowników możliwe są z zakresu od 0 do 0xFFF. Uprawnienia dla użytkownika od 1 do 3. Pozostałe wartości są pomijalne. W przypadku gdy użytkownik istnieje to wywołanie funkcji spowoduje zwrócenie kodu o numerze 6.

Pobranie odcisku palca dla użytkownika. Tworzy nowego użytkownika wraz z nowym numerem ID:

  1. TFSD400_OperStat_StatusTypeDef TFSD400_DownloadEigenSaveAsUser(uint8_t* fingerBuffer, uint16_t buffer_len, uint16_t user, uint8_t priv){
  2.     uint16_t len = 0;
  3.     uint8_t sendFrame[] = { TFSD400_CMD_DOWN_SAVEUSR, user >> 8, user, priv, [197]=0 };
  4.     uint8_t responseFrame[] = { TFSD400_CMD_DOWN_SAVEUSR };
  5.     p_TFSD400_ClearReceiveUartBuffer();
  6.     if(buffer_len > 192) { len = 192; }
  7.     else                 { len = buffer_len; }
  8.     //Prepare frame
  9.     for(uint8_t i=0; i<len; i++) { sendFrame[4+i] = *(fingerBuffer + i); }
  10.    
  11.     writeCommandFrame(sendFrame, 197);
  12.     return testResponseFrame_SearchPosition_BlockingExample(UartDataStruct.Buffer, responseFrame, sizeof(responseFrame), 3);
  13. }

Wgrywanie danych dla użytkownika:

  1. TFSD400_OperStat_StatusTypeDef TFSD400_UploadImagesAndEigenvalues(uint8_t* outputDataBuffer, uint16_t bufferSize){
  2.     uint8_t sendFrame[]     = { TFSD400_CMD_UP_IMG_EIGVAL, 0x00, 0x00, 0x00 };
  3.     uint8_t responseFrame[] = { TFSD400_CMD_UP_IMG_EIGVAL };
  4.     uint8_t endFrame[]      = { TFSD400_CMD_TAIL, 0xFF };
  5.     uint16_t len = 0;
  6.     if(bufferSize > 192) { len = 192;        }
  7.     else                 { len = bufferSize; }
  8.     p_TFSD400_ClearReceiveUartBuffer();
  9.     TFSD400_WriteCommand(sendFrame);
  10.     //wait for start response frame:
  11.     int8_t positionInBuffer = testResponseFrame_ReturnBufferPosition(UartDataStruct.Buffer, responseFrame, sizeof(responseFrame));
  12.     if(positionInBuffer == (-1)) { return TFSD400_ERROR; }
  13.     //Delay to receive full frame from TFSD400
  14.     HAL_Delay(50);
  15.     //Search for frame and for end of transfer
  16.     positionInBuffer = testResponseFrame_ReturnBufferPosition(UartDataStruct.Buffer, endFrame, sizeof(endFrame));
  17.     //Check if operation was ok
  18.     if(UartDataStruct.Buffer[positionInBuffer + 3] != TFSD400_OK) {
  19.         return retTFSD400Code(UartDataStruct.Buffer[positionInBuffer + 3]);
  20.     }
  21.     for( uint8_t i=0; i<len; i++ ) {
  22.         *(outputDataBuffer+i) = UartDataStruct.Buffer[positionInBuffer + i + 11];
  23.     }
  24.     return TFSD400_OK;
  25. }

Przesłanie danych z odciskiem do modułu wraz z porównaniem z danymi wejściowymi:

  1. TFSD400_OperStat_StatusTypeDef TFSD400_DownloadEigenAcqFingerComp(uint8_t* fingerBuffer, uint16_t bufferSize){
  2.     uint16_t dataLength = 0;
  3.     uint8_t sendFrame[] = { TFSD400_CMD_DOWN_EIGVAL, [197]=0 };
  4.     uint8_t responseFrame[] = { TFSD400_CMD_DOWN_EIGVAL, 0x00, 0x00};
  5.     uint8_t tailFrame[] = { TFSD400_CMD_TAIL, 0xFF, 0xFF};
  6.    
  7.     //Buffer Length is too low
  8.     if(bufferSize < 192) { return TFSD400_ERROR; }
  9.    
  10.     if(bufferSize > 192) { dataLength = 192;            }
  11.     else                 { dataLength = bufferSize;     }
  12.    
  13.     p_TFSD400_ClearReceiveUartBuffer();
  14.     for(uint8_t i=0; i<dataLength; i++) { sendFrame[4+i] = *(fingerBuffer + i); }
  15.    
  16.     writeCommandFrame(sendFrame, 197);
  17.    
  18.     //wait for start response frame:
  19.     int8_t positionInBuffer = testResponseFrame_ReturnBufferPosition(UartDataStruct.Buffer, responseFrame, sizeof(responseFrame));
  20.    
  21.     if(positionInBuffer == (-1)) { return TFSD400_ERROR; }
  22.    
  23.     if(testResponseFrame_SearchPosition_BlockingExample(UartDataStruct.Buffer, tailFrame, sizeof(tailFrame), 3) == TFSD400_OP_ERROR)
  24.     {
  25.         return TFSD400_ERROR;
  26.     }
  27.    
  28.     return retTFSD400Code(UartDataStruct.Buffer[positionInBuffer + 3]);
  29. }

Przesłanie danych z odciskiem palca do modułu w celu porównania ich z konkretnym użytkownikiem podanym w argumencie funkcji:

  1. TFSD400_OperStat_StatusTypeDef TFSD400_DownloadFingerprinyEigenCompWithUser(uint8_t* fingerBuffer,
  2.                                                    uint16_t userData, uint16_t bufferSize)
  3. {
  4.     uint8_t sendFrame[] = { TFSD400_CMD_DOWN_COMP11, userData>>8, userData, [197]=0 };
  5.     uint8_t responseFrame[] = { TFSD400_CMD_DOWN_COMP11, 0x00, 0x00};
  6.     uint16_t dataLength = bufferSize;
  7.     if(bufferSize < 192) { return TFSD400_ERROR; }
  8.     if(bufferSize > 192) { dataLength = 192; }
  9.     for(uint8_t i=0; i<dataLength; i++) {
  10.         sendFrame[4+i] = *(fingerBuffer + i);
  11.     }
  12.     p_TFSD400_ClearReceiveUartBuffer();
  13.     writeCommandFrame(sendFrame, 197);
  14.     int8_t positionInBuffer =
  15.             testResponseFrame_ReturnBufferPosition(UartDataStruct.Buffer, responseFrame, sizeof(responseFrame));
  16.     if(positionInBuffer == -1){ return TFSD400_TIMEOUT; }
  17.     return retTFSD400Code(UartDataStruct.Buffer[positionInBuffer + 3]);
  18. }

Przesłanie do czytnika odczytów z odcisku palca i porównanie ich z wszystkimi danymi przechowywanymi w bazie danych. Funkcja zwraca Id użytkownika oraz rodzaj uprawnień jakie zostały do niego przypisane:

  1. uint16_t TFSD400_DownloadFingerprintEigenComp1NDatabase(uint8_t* fingerBuffer, uint16_t bufferSize,
  2.                                                                                 uint8_t* receiveData){
  3.     uint8_t sendFrame[] = { TFSD400_CMD_DOWN_COMP1N, [197]=0 };
  4.     uint8_t responseFrame[] = { TFSD400_CMD_DOWN_COMP1N };
  5.     uint16_t dataLength = bufferSize;
  6.     //Buffer Length is too low
  7.     if(bufferSize < 192) { return TFSD400_ERROR; }
  8.     if(bufferSize > 192) { dataLength = 192; }
  9.     for(uint8_t i=0; i<dataLength; i++) { sendFrame[4+i] = *(fingerBuffer + i); }
  10.     p_TFSD400_ClearReceiveUartBuffer();
  11.     writeCommandFrame(sendFrame, 197);
  12.     int8_t positionInBuffer =
  13.             testResponseFrame_ReturnBufferPosition(UartDataStruct.Buffer, responseFrame, sizeof(responseFrame));
  14.     if(UartDataStruct.Buffer[dataLength + 3] == TFSD400_ACK_NO_USER)
  15.     {
  16.         return 0xFFFF;
  17.     }
  18.     *(receiveData + 0) = UartDataStruct.Buffer[positionInBuffer + 1]; //UserId
  19.     *(receiveData + 1) = UartDataStruct.Buffer[positionInBuffer + 2]; //UserId
  20.     *(receiveData + 2) = UartDataStruct.Buffer[positionInBuffer + 3]; //User privilege
  21.     return UartDataStruct.Buffer[dataLength + 1] << 8 | UartDataStruct.Buffer[dataLength + 2];
  22. }

Pobranie wgranego odcisku palca wykonuje się za pomocą następującej funkcji:

  1. TFSD400_OperStat_StatusTypeDef TFSD400_UploadUsersFingerprintSpecifiedUserEigenvalue(uint8_t* fingerBuffer,
  2.                                     uint8_t user, uint8_t *responseCodes){
  3.     uint8_t sendFrame[] = { TFSD400_CMD_UP_U_EIGVAL, user >> 8, user, 0x00};
  4.     uint8_t responseStartFrame[] = { TFSD400_CMD_UP_U_EIGVAL};
  5.     uint8_t responseTailFrame[] = { TFSD400_CMD_TAIL, 0xFF };
  6.     uint8_t dataFrame[] = { 0xF5, user >> 8, user};
  7.     p_TFSD400_ClearReceiveUartBuffer();
  8.     TFSD400_WriteCommand(sendFrame);
  9.     volatile int8_t startPosition =
  10.             testResponseFrame_ReturnBufferPosition(UartDataStruct.Buffer, responseStartFrame, sizeof(responseStartFrame));
  11.     volatile int16_t endPosition = -1;
  12.     if(startPosition == -1){
  13.         return TFSD400_ERROR;
  14.     }
  15.     endPosition = testResponseFrame_ReturnBufferPosition(UartDataStruct.Buffer, responseTailFrame, sizeof(responseTailFrame));
  16.     if(endPosition == -1){
  17.         return TFSD400_ERROR;
  18.     }
  19.     if(retTFSD400Code(UartDataStruct.Buffer[startPosition + 3]) != TFSD400_OK )
  20.     {
  21.         return retTFSD400Code(UartDataStruct.Buffer[startPosition + 3]);
  22.     }
  23.     startPosition = -1;
  24.     endPosition = -1;
  25.     startPosition = testResponseFrame_ReturnBufferPosition(UartDataStruct.Buffer, dataFrame, sizeof(dataFrame));
  26.     if(startPosition == -1){
  27.         return TFSD400_ERROR;
  28.     }
  29.     endPosition = (uint8_t)testResponseFrame_ReturnBufferPosition(UartDataStruct.Buffer, responseTailFrame, sizeof(responseTailFrame));
  30.     if(endPosition == -1) {
  31.         return TFSD400_ERROR;
  32.     }
  33.     *(responseCodes + 0) = UartDataStruct.Buffer[startPosition + 1];   //UserId
  34.     *(responseCodes + 1) = UartDataStruct.Buffer[startPosition + 2];   //UserId
  35.     *(responseCodes + 2) = UartDataStruct.Buffer[startPosition + 3];   //User privilege
  36.     for(uint8_t i=0; i<193; i++) {
  37.         *(fingerBuffer+i) = UartDataStruct.Buffer[startPosition + i + 4];
  38.     }
  39.     return TFSD400_OK;
  40. }

W odpowiedzi (dla istniejącego użytkownika) moduł zwróci dwie ramki. Jedna z nich będzie zawierała informację o poprawnym znalezieniu danych dla wybranego użytkownika. Druga ramka będzie zawierała znaleziony numer użytkownika, poziom uprawnień oraz dane z odciskiem palca. W przypadku niepoprawnego ID użytkownika zostanie zwrócona  informacja o błędzie.

Aby zapisać odcisk palca w pamięci urządzenia należy wykorzystać opisaną wcześniej komendę TFSD400_AddFingerprint().

W celu załadowania odcisku do modułu należy przyłożyć trzykrotnie palec do modułu. Czas oczekiwania na przyłożenie został zdefiniowany w zmiennej

Ustawienie modułu do odczytu odcisku palca można wykonać za pomocą komendy TFSD400_CompareFingerWithDatabase(). Sprawdza ona czy przyłożony w zadanym czasie palec pasuje do jednego z odcisków zdefiniowanych w bazie danych.

Biblioteki można pobrać z dysku Google pod tym linkiem.