Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

working on formatting #144

Open
Gekidoku opened this issue Sep 21, 2023 · 3 comments
Open

working on formatting #144

Gekidoku opened this issue Sep 21, 2023 · 3 comments

Comments

@Gekidoku
Copy link

Have an issue when writing to tags that are not initialized but are NDefFormattable.
For xamarin.forms i used to use my own modified version of https://github.com/poz1/NFCForms
This added both mifarelight format support and regular ndefformat support.
Currently attempting to replace the Publish command in a fork with his write function.
So far it seems to work. Just have to re-implement clear / readonly

@Gekidoku
Copy link
Author

https://github.com/Gekidoku/Plugin.NFC to track progress

@Gekidoku
Copy link
Author

Note i will only do this for android. as iOS NFC is a nightmare

@Gekidoku
Copy link
Author

internal void WriteMessageAndFormat(ITagInfo tagInfo, bool makeReadOnly = false)
{
    if (_currentTag == null)
    {
        throw new Exception(Configuration.Messages.NFCErrorMissingTag);
    }

    Ndef ndef = Ndef.Get(_currentTag);


    //Check if the tag can be NDEFformatted
    var formatcheck = _currentTag.GetTechList().Contains("android.nfc.tech.NdefFormatable");

    //Previous check didnt compare both just ndef being null can also mean its not formatted
    if (ndef == null && formatcheck == false)
    {
        throw new Exception(Configuration.Messages.NFCErrorNotCompliantTag);
    }
    //Not formatted but can be formatted
    if (ndef == null && formatcheck == true)
    {


        NdefFormatable formatable = NdefFormatable.Get(_currentTag);
        //For some reason this could still give null even if formatcheck gave a true so /shrug
        if (formatable == null)
        {
            throw new Exception(Configuration.Messages.NFCErrorNotCompliantTag);
        }
        try
        {
            formatable.Connect();

            OnTagConnected?.Invoke(null, EventArgs.Empty);
        }
        catch
        {
            throw new Exception(Configuration.Messages.NFCErrorMissingTag);
        }
        //old size check.
        //int size = message.ToByteArray().Length;


        try
        {
            List<Android.Nfc.NdefRecord> records = new List<Android.Nfc.NdefRecord>();
            for (int i = 0; i < tagInfo.Records.Length; i++)
            {
                var record = tagInfo.Records[i];
                if (GetAndroidNdefRecord(record) is NdefRecord ndefRecord)
                    records.Add(ndefRecord);
            };
            Android.Nfc.NdefMessage msg = new Android.Nfc.NdefMessage(records.ToArray());
            //This Format works with Mifare Classic and NTAG213. Fails with ultralight. these are the chips I tested it with.
            //Both with pre used ones and with factory new ones.
            if(makeReadOnly)
                formatable.FormatReadOnly(msg);
            else
                formatable.Format(msg);
        }

        catch (TagLostException tle)
        {
            throw new Exception(Configuration.Messages.NFCErrorMissingTag + " " + tle.Message);
        }

        catch (Android.Nfc.FormatException fe)
        {
            throw new Exception(Configuration.Messages.NFCErrorMissingTag + " " + fe.Message);
        }

        catch (Exception e)
        {
            //Assume that if we are here the tag is still touching the device, our message is correct, and the tag isnt busted.
            try
            {
                //we close this tech so we can open it as ultralight
                formatable.Close();
                //check if the connected chip is ultralight.
                if (_currentTag.GetTechList().Contains("android.nfc.tech.MifareUltralight"))
                {

                    MifareUltralight ultralight = MifareUltralight.Get(_currentTag);
                    if (ultralight != null)
                    {
                        try
                        {
                            //connect with ultralight tech
                            ultralight.Connect();
                            //Found this on a stackoverflow question that had the same problem, apparently this sets it up to be NFC Forum Type 2 tag.
                            //https://stackoverflow.com/questions/35985287/formatting-a-mifare-ultralight-to-ndef-throw-io-exception
                            ultralight.Transceive(new byte[]
                            {
                            (byte)0xA2,//Write
                            (byte)0x03,//Page Nr = 3
                            (byte)0xE1,(byte)0x10,(byte)0x06, (byte)0x00//capability container (mapping version 1.0, 48 bytes for data available, read/ write allowed)
                            });
                            ultralight.Transceive(new byte[]
                            {
                            (byte)0xA2,//Write 
                            (byte)0x04,//Page nr = 4
                            (byte)0x03, (byte)0x00,(byte)0xFE,(byte)0x00 // empty NDEF TLV, Terminator TLV
                            });
                        }
                        catch (Exception e1)
                        {

                        }
                        finally
                        {
                            //Now the tag is formatted to accept NDEF
                            try
                            {
                                //Close this tech connection as this one doesnt have WriteNdef
                                ultralight.Close();
                                //Get the tag as Ndef
                                ndef = Ndef.Get(_currentTag);
                                //Connect
                                ndef.Connect();
                                //Check the message again JIC
                                List<Android.Nfc.NdefRecord> recordsFormat = new List<Android.Nfc.NdefRecord>();
                                for (int i = 0; i < tagInfo.Records.Length; i++)
                                {
                                    var record = tagInfo.Records[i];
                                    if (GetAndroidNdefRecord(record) is NdefRecord ndefRecord)
                                        recordsFormat.Add(ndefRecord);
                                };

                                Android.Nfc.NdefMessage msg = new Android.Nfc.NdefMessage(recordsFormat.ToArray());
                                //Write and close
                               
                                ndef.WriteNdefMessage(msg);
                                if (makeReadOnly)
                                    ndef.MakeReadOnly();
                                ndef.Close();
                            }
                            catch
                            {

                            }

                        }
                    }
                }

            }
            catch (Exception eform)
            {
                 throw new Exception(Configuration.Messages.NFCErrorWrite + " " + eform.ToString());
                
            }

        }

        finally
        {
            //Used to not have the ultralight code in so i had to close here
            //formatable.Close();
            OnTagDisconnected?.Invoke(null, EventArgs.Empty);
        }

    }
    else
    {
        //Rest as normal
        try
        {
            ndef.Connect();
            OnTagConnected?.Invoke(null, EventArgs.Empty);
        }

        catch
        {
            throw new Exception("Tag Error: No Tag nearby");
        }

        if (!ndef.IsWritable)
        {
            ndef.Close();
            throw new Exception(Configuration.Messages.NFCWritingNotSupported + " Locked");
        }

        
            try
            {
                List<Android.Nfc.NdefRecord> records = new List<Android.Nfc.NdefRecord>();
                for (int i = 0; i < tagInfo.Records.Length; i++)
                {
                var record = tagInfo.Records[i];
                if (GetAndroidNdefRecord(record) is NdefRecord ndefRecord)
                    records.Add(ndefRecord);
                }
                Android.Nfc.NdefMessage msg = new Android.Nfc.NdefMessage(records.ToArray());
                ndef.WriteNdefMessage(msg);
                if (makeReadOnly)
                    ndef.MakeReadOnly();
            }

            catch (TagLostException tle)
            {
                throw new Exception("Tag Lost Error: " + tle.Message);
            }


          

            catch (Android.Nfc.FormatException fe)
            {
                throw new Exception("Tag Format Error: " + fe.Message);
            }

            catch (Exception e)
            {
                throw new Exception("Tag Error: " + e.ToString());
            }

            finally
            {
                ndef.Close();
                OnTagConnected?.Invoke(null, EventArgs.Empty);
            }
        
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant