B4R Question [SOLVED]Repetitive authentication problem MFRC522...

rbghongade

Active Member
Licensed User
Longtime User
Dear Friends,
I am trying an experiment with RFID reader MFRC522 library with WEMos mini as follows:
1.I have a Mifare 1K card with some amount of credit money stored on it say Rs.10000 at sector 12
2. I am writing a code to detect the card, read the credit and send it to serial terminal
3. The serial terminal ( here B4J serial connector ) sends back the amount to be deducted from credit back to the wemos
4. The received amount has to be deducted from credit and the new balance has to be written back to sector 12

The reading of credit is OK, the deduct amount reaches the Wemos and the new balance is correctly computed. The problem starts when this new amount has to be written back to sector 12. As required I use authenticate again before write, but it returns authentication failure and does not complete the write.
Since I an very new to RFID cards , I am unable to debug it. Can any of you guys point out whats going on?
My code is as follows:
B4X:
Sub Process_Globals
    Public Serial1 As Serial
    Private rfid As MFRC522
    Private bc As ByteConverter
    Dim d1 As D1Pins
    Dim credit,deduct As Double
    Dim authenticated As Boolean
  
    Dim astream As AsyncStreams
    'RST->D4
    'SDA(SS)->D3
    'MOSI->D7
    'MISO->D6
    'SCK->D5
End Sub

Private Sub AppStart
    Serial1.Initialize(115200)
    Log("AppStart")
    rfid.Initialize(d1.D3, d1.D4, "rfid_CardPresent")
    astream.Initialize(Serial1.Stream, "astream_newdata", Null)
    rfid.LogVersion
  
End Sub

Sub rfid_CardPresent (UID() As Byte, CardType As Byte)
    Log("UID: ", bc.HexFromBytes(UID))
    Log("Type: ", CardType, ", Is it Mifare: ", rfid.IsMifare)
    Dim txt As String
    If rfid.IsMifare Then
         txt=card_read(12)
         Log(txt)
            'astream.Write(bc.StringToBytes(txt))
         credit=txt

        Else
            Log("Failed to read")
    End If
End Sub

Sub card_read(sector As Int) As String
    Dim msg As String
    Dim buffer(18) As Byte
    authenticated=card_authenticate(sector)
     If rfid.MifareRead(sector, buffer) > 0 Then
    Dim read_buffer(7) As Byte
    For i=0 To 6
        read_buffer(i)=buffer(i)
    Next
    msg=bc.stringFromBytes(read_buffer)
    Else
        msg=""
    End If
    Return msg
End Sub

Sub card_write(sector As Int,msg As String)
    Dim buffer(18) As Byte
    msg=JoinStrings(Array As String(msg,"            "))
    Log(msg)
    buffer=bc.stringToBytes(msg)
    authenticated=card_authenticate(sector)
    Log("Write:", rfid.MifareWrite(sector, buffer))
End Sub

Sub card_authenticate(sector As Int) As Boolean
    If rfid.MifareAuthenticate(sector) = False Then
        Log("Failed to authenticate")
        authenticated=False
    Else
        authenticated=True
    End If
    Return authenticated
  
End Sub

Sub astream_newdata (Buffer() As Byte)
    Dim msg As String
    msg=bc.stringFromBytes(Buffer)
    amt_deduct(msg)
End Sub

Sub amt_deduct(msg As String)
    deduct=msg
    Dim new_balance As Double=credit-deduct
    Dim new_balance_txt As String=new_balance
    card_write(12,new_balance_txt)
    Log("New balance:",card_read(12))
End Sub

regards,
 

Cableguy

Expert
Licensed User
Longtime User
Are you sure the card was not set as read-only?
There is a write protect bit that can be set when writing and renders the card... Well, read-only
 
Upvote 0

rbghongade

Active Member
Licensed User
Longtime User
Dear Cableguy,
The card was first written with the amount using another B4R code! Hence it is surely not write protected!
 
Upvote 0

Cableguy

Expert
Licensed User
Longtime User
Does the code you used still writes the card?
I.e, can you write a different amount into block 12 with that code?
 
Upvote 0

rbghongade

Active Member
Licensed User
Longtime User
Yes it writes OK.
My preliminary diagnosis (maybe wrong!) is that the UID is lost once it gets out of the sub rfid_CardPresent as it seems to be a local variable , hence the subsequent authentications fail.
 
Upvote 0

rbghongade

Active Member
Licensed User
Longtime User
Dear Erel,
Tried the following with your suggestions but still the authentication fails!
B4X:
Sub Process_Globals
    Public Serial1 As Serial
    Private rfid As MFRC522
    Private bc As ByteConverter
    Dim d1 As D1Pins
    Dim credit,deduct,balance As Double
    Dim authenticated,updated As Boolean
    Dim card_type As Byte
    Dim astream As AsyncStreams
    Dim mode As Int
    'RST->D4
    'SDA(SS)->D3
    'MOSI->D7
    'MISO->D6
    'SCK->D5
End Sub

Private Sub AppStart
    Serial1.Initialize(115200)
    Log("AppStart")
    rfid.Initialize(d1.D3, d1.D4, "rfid_CardPresent")
    astream.Initialize(Serial1.Stream, "astream_newdata", Null)
    rfid.LogVersion
    updated=False
    mode=0
       
   
End Sub

Sub rfid_CardPresent (uid() As Byte, CardType As Byte )
   
    GlobalStore.Put(0,uid)
    card_type=CardType
   
    Select mode
        Case 0
            Log("UID: ", bc.HexFromBytes(uid))
            Log("Type: ", CardType, ", Is it Mifare: ", rfid.IsMifare)
            Dim txt As String
            If rfid.IsMifare Then
                authenticated=card_authenticate(12)
                If authenticated Then
               
                txt=card_read(12)
                Log(txt)
                'astream.Write(bc.StringToBytes(txt))
                credit=txt
               
               
                End If
       
            Else
                Log("Failed to read")
            End If
        Case 1
            Log("UID: ", bc.HexFromBytes(uid))
            If rfid.IsMifare Then
                card_authenticate(12)
                Dim balance_txt As String
                balance_txt=balance
                Log(balance_txt)
                card_write(12,balance_txt)
            mode=0
            Else
                Log("Failed to read")
            End If
           
    End Select
       
End Sub

Sub card_read(sector As Int) As String
    Dim msg As String
    Dim buffer(18) As Byte
    If rfid.MifareRead(sector, buffer) > 0 Then 'buffer size must be 18 bytes or more
        Dim read_buffer(8) As Byte
        For i=0 To 7
            read_buffer(i)=buffer(i)
        Next
        msg=bc.stringFromBytes(read_buffer)
    Else
        msg=""
    End If
    Return msg
End Sub

Sub card_write(sector As Int,msg As String)
    Dim buffer(18) As Byte
    msg=JoinStrings(Array As String(msg,"             "))
    'Log(msg)
    buffer=bc.stringToBytes(msg)
    Log("Write:", rfid.MifareWrite(sector, buffer))
End Sub

Sub card_authenticate(sector As Int) As Boolean
    If rfid.MifareAuthenticate(sector) = False Then
        Log("Failed to authenticate")
        authenticated=False
    Else
        authenticated=True
    End If
    Return authenticated
   
End Sub

Sub astream_newdata (Buffer() As Byte)
    Dim msg As String
    msg=bc.stringFromBytes(Buffer)
    Log(msg)
   
    deduct=msg
    balance=credit-deduct
    mode=1
    rfid_CardPresent(GlobalStore.Slot0,card_type)
   
   
End Sub
 
Upvote 0

rbghongade

Active Member
Licensed User
Longtime User
On going a little deep , I think the mfrc522 halts ( goes to sleep after executing first access (read/write)) and the authentication fails because we need to wake up the reader before we access it.
Requesting Erel to add the wake-up method in the library.
 
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
I've tested it with this code:
B4X:
Sub Process_Globals
   Public Serial1 As Serial
   Private rfid As MFRC522
   Private bc As ByteConverter
End Sub

Private Sub AppStart
   Serial1.Initialize(115200)
   Log("AppStart")
   rfid.Initialize(10, 9, "rfid_CardPresent")
   rfid.LogVersion
End Sub

Sub rfid_CardPresent (UID() As Byte, CardType As Byte)
   Log("UID: ", bc.HexFromBytes(UID))
   Log("Type: ", CardType, ", Is it Mifare: ", rfid.IsMifare)
   If rfid.IsMifare Then
     If rfid.MifareAuthenticate(1) = False Then
       Log("Failed to authenticate")
       Return
     End If
     Dim buffer(18) As Byte
     For i = 0 To buffer.Length - 1
       buffer(i) = i
     Next
     'write 16 bytes to block number 1
     Log("Write: ", rfid.MifareWrite(1, buffer))
     If rfid.MifareRead(1, buffer) > 0 Then 'buffer size must be 18 bytes or more
       Log(bc.HexFromBytes(buffer))
     Else
       Log("Failed to read")
     End If
   End If
End Sub
It successfully writes and reads multiple times.
 
Upvote 0

rbghongade

Active Member
Licensed User
Longtime User
Dear Erel,
Have you tested when you do not remove the card from the vicinity of the reader and then try to authenticate it again? That is where the problem occurs!
 
Upvote 0

rbghongade

Active Member
Licensed User
Longtime User
As posted earlier , the card is read first. Then using serial data as input ( asyncstreams newdata event) a number is computed and this number is written back to the card. Your code writes and reads in same event instance.
 
Upvote 0

rbghongade

Active Member
Licensed User
Longtime User
Precisely what I tried , but then the looper keeps repeating . As to the modification of library , my programming skills are minimal hence looking for help from coding gurus like you guys at B4X !
 
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
1. add this line to rMFRC522.h (after public)
int state;

2. Set state to 0 in B4MFRC522::Initialize (rMFRC522.cpp):
state = 0;

3. Change the looper code to:
B4X:
void B4MFRC522::looper(void* b) {
     B4MFRC522* me = (B4MFRC522*)b;
     if (me->state == 0) {
       if ( ! me->rfid.PICC_IsNewCardPresent())
         return;
       if ( ! me->rfid.PICC_ReadCardSerial())
         return;
       if (lastEvent + 500 > millis())
         return;
       lastEvent = millis();
       const UInt cp = B4R::StackMemory::cp;
       ArrayByte* arr = CreateStackMemoryObject(ArrayByte);
       arr->data = me->rfid.uid.uidByte;
       arr->length = me->rfid.uid.size;
       me->state = 1;
       me->CardPresentSub (arr, me->rfid.PICC_GetType(me->rfid.uid.sak));
       B4R::StackMemory::cp = cp;
     } else if (me->state == 2) {
       me->rfid.PICC_HaltA();
       me->rfid.PCD_StopCrypto1();
       me->state = 0;
     }
    
   }

You will need to use B4Rh2xml tool to update the library xml file: https://www.b4x.com/android/forum/threads/creating-libraries-for-b4r.65718/#content

With this change (which was not tested) the looper will only continue after you call MFRC522.state = 2.
 
Upvote 0
Top