poz1 / NFCForms

Other
49 stars 41 forks source link

[Request] Format Tag when NdefFormatable is found #34

Open Gekidoku opened 5 years ago

Gekidoku commented 5 years ago

Like the title says. It would be grand if the WriteTag would include a check if NdefFormatable is present and write to the chip using Android.Nfc.Tech.NdefFormatable.Format.

Gekidoku commented 4 years ago

So i dove into your code and did it myself. Im sure it can be done in a cleaner way but this worked for me Droid/NfcForms.cs

public void WriteTag (NdefLibrary.Ndef.NdefMessage message)
        {
            if (droidTag == null) 
            {
                throw new Exception("Tag Error: No Tag to write, register to NewTag event before calling WriteTag()");
            }

            Ndef ndef = GetNdef (droidTag);

            //Check if the tag can be NDEFformatted
            var formatcheck = nfcTag.TechList.Contains(NFCTechs.NdefFormatable);

            //Previous check didnt compare both just ndef being null can also mean its not formatted
            if (ndef == null && formatcheck == false) 
            {
                throw new Exception("Tag Error: NDEF not supported");
            }
            //Not formatted but can be formatted
            if (ndef == null && formatcheck == true)
            {

                NdefFormatable formatable = NdefFormatable.Get(droidTag);
                //For some reason this could still give null even if formatcheck gave a true so /shrug
                if (formatable == null)
                {
                    throw new Exception("Tag Error: NDEFformat not supported");
                }
                try
                {
                    formatable.Connect();

                    RaiseTagConnected(nfcTag);
                }
                catch
                {
                    throw new Exception("Tag Error: No Tag nearby");
                }
                //old size check.
                //int size = message.ToByteArray().Length;

                try
                {
                    List<Android.Nfc.NdefRecord> records = new List<Android.Nfc.NdefRecord>();
                    for (int i = 0; i < message.Count; i++)
                    {
                        if (message[i].CheckIfValid())
                            records.Add(new Android.Nfc.NdefRecord(Android.Nfc.NdefRecord.TnfWellKnown, message[i].Type, message[i].Id, message[i].Payload));
                        else
                        {
                            throw new Exception("NDEFRecord number " + i + "is not valid");
                        }
                    };
                    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.
                    formatable.Format(msg);
                }

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

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

                catch (Android.Nfc.FormatException fe)
                {
                    throw new Exception("Tag Format Error: " + 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 (droidTag.GetTechList().Contains(NFCTechs.MifareUltralight))
                        {

                            MifareUltralight ultralight = MifareUltralight.Get(droidTag);
                            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.
                                    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 = GetNdef(droidTag);
                                        //Connect
                                        ndef.Connect();
                                        //Check the message again JIC
                                        List<Android.Nfc.NdefRecord> recordsFormat = new List<Android.Nfc.NdefRecord>();
                                        for (int i = 0; i < message.Count; i++)
                                        {
                                            if (message[i].CheckIfValid())
                                                recordsFormat.Add(new Android.Nfc.NdefRecord(Android.Nfc.NdefRecord.TnfWellKnown, message[i].Type, message[i].Id, message[i].Payload));
                                            else
                                            {
                                                throw new Exception("NDEFRecord number " + i + "is not valid");
                                            }
                                        };

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

                                    }

                                }
                            }
                        }

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

                }

                finally
                {
                    //Used to not have the ultralight code in so i had to close here
                    //formatable.Close();
                    RaiseTagTagDisconnected(nfcTag);
                }

            }
            else
            { 
                //Rest as normal
                try
                {
                    ndef.Connect();
                    RaiseTagConnected(nfcTag);
                }

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

                if (!ndef.IsWritable)
                {
                    ndef.Close();
                    throw new Exception("Tag Error: Tag is write locked");
                }

                int size = message.ToByteArray().Length;

                if (ndef.MaxSize < size)
                {
                    ndef.Close();
                    throw new Exception("Tag Error: Tag is too small");
                }
                else
                {
                    try
                    {
                        List<Android.Nfc.NdefRecord> records = new List<Android.Nfc.NdefRecord>();
                        for (int i = 0; i < message.Count; i++)
                        {
                            if (message[i].CheckIfValid())
                                records.Add(new Android.Nfc.NdefRecord(Android.Nfc.NdefRecord.TnfWellKnown, message[i].Type, message[i].Id, message[i].Payload));
                            else
                            {
                                throw new Exception("NDEFRecord number " + i + "is not valid");
                            }
                        };
                        Android.Nfc.NdefMessage msg = new Android.Nfc.NdefMessage(records.ToArray());
                        ndef.WriteNdefMessage(msg);
                    }

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

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

                    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();
                        RaiseTagTagDisconnected(nfcTag);
                    }
                }
            }

        }