Add initial bits of working Yubikey NEO support.
6 files changed, 183 insertions(+), 30 deletions(-)

M avr-i2c.ads
M generic_pn532.adb
M ndef.adb
M ndef.ads
M nfc_tags.adb
M pn532_bus_i2c.adb
M avr-i2c.ads +2 -2
@@ 47,8 47,8 @@ package AVR.I2C is
 
    type I2C_Address is new Nat8 range 0 .. 127;
 
-   subtype Buffer_Index is Nat8 range 0 .. 64;
-   subtype Buffer_Range is Nat8 range 1 .. 64;
+   subtype Buffer_Index is Nat8 range 0 .. 81;
+   subtype Buffer_Range is Nat8 range 1 .. 81;
    type Data_Buffer is array (Buffer_Range range <>) of Nat8;
 
 end AVR.I2C;

          
M generic_pn532.adb +24 -10
@@ 115,7 115,7 @@ package body Generic_PN532 is
                            20, -- timeout (50 * 20) ms
                            1);
       Status : Boolean;
-      Reply : PN532_Buf (1..1) := (1 => 0);
+      Reply : PN532_Buf (1..5);
       Len : Unsigned_8;
    begin
       Status := PN532_Send_Command (Cmd, PN532_TIMEOUT_VALUE);

          
@@ 125,7 125,6 @@ package body Generic_PN532 is
       
       Status := PN532_Wait_For_Ready (PN532_TIMEOUT_VALUE);
       if not Status then
-         Log ("timeout2");
          return False;
       end if;
 

          
@@ 336,23 335,23 @@ package body Generic_PN532 is
       end if;
 
       if not PN532_Wait_For_Ready (PN532_TIMEOUT_VALUE) then
-         Log ("timeout");
+         -- Log ("timeout");
          Status := False;
          return;
       end if;
 
       PN532_Read_Data (Reply, Reply_Len, Ok);
-      Log ("Reply:");
-      Log (Reply (1..Reply_Len));
+      -- Log ("Reply:");
+      -- Log (Reply (1..Reply_Len));
 
       if (not Ok) or (Reply_Len < 3) then
-         Log ("Read data failed");
+         -- Log ("Read data failed");
          Status := False;
          return;
       end if;
 
       if Reply (2) = 16#14# then -- Mifare authentication error
-         Log ("Mifare auth error");
+         -- Log ("Mifare auth error");
          Status := False;
          return;
       elsif Reply (2) /= 0 then -- status code not ok?

          
@@ 387,17 386,20 @@ package body Generic_PN532 is
          return False;
       end if;
 
-      if not PN532_Wait_For_Ready (PN532_TIMEOUT_VALUE) then
+      if not PN532_Wait_For_Ready (PN532_TIMEOUT_VALUE * 30) then
+         -- Log ("select: PN532_Wait_For_Ready failed");
          return False;
       end if;
 
       PN532_Read_Data (Data, Reply_Len, Ok);
 
       if (not Ok) or (Reply_Len < 5) then
+         -- Log ("select: PN532_Read_Data failed");
          return False;
       end if;
 
       if Data (2) /= 0 then -- status code not ok?
+         Log ("select: PN532_Read_Data - status code invalid");
          return False;
       end if;
 

          
@@ 406,7 408,11 @@ package body Generic_PN532 is
          return True;
       elsif Data (Reply_Len - 2) = 16#6A# and Data (Reply_Len - 1) = 16#82# then
          -- application not found
+         Log ("select: application not found");
          null;
+      else
+         Log ("select: unknown status");
+         Log (Data (1..Reply_Len));
       end if;
 
       return False;

          
@@ 473,7 479,7 @@ package body Generic_PN532 is
       Cmd : PN532_Buf (1..7);
       Len : Unsigned_8;
       Reply : PN532_Buf (1..70);
-      Reply_Len : Unsigned_8;
+      Reply_Len : Unsigned_8 := 0;
       Ok    : Boolean;
    begin
       Len := Buf'Length;

          
@@ 494,7 500,8 @@ package body Generic_PN532 is
          return;
       end if;
 
-      if not PN532_Wait_For_Ready (PN532_TIMEOUT_VALUE) then
+      if not PN532_Wait_For_Ready (PN532_TIMEOUT_VALUE * 30) then
+         Log ("read binary: timeout");
          Status := False;
          return;
       end if;

          
@@ 502,11 509,16 @@ package body Generic_PN532 is
       PN532_Read_Data (Reply, Reply_Len, Ok);
 
       if (not Ok) or (Reply_Len < 5) then
+         if not Ok then
+            Log ("read binary: not ok");
+         end if;
+         Log (Reply (1..Reply_Len));
          Status := False;
          return;
       end if;
 
       if Reply (2) /= 0 then -- status code not ok?
+         Log ("status invalid");
          Status := False;
          return;
       end if;

          
@@ 520,6 532,8 @@ package body Generic_PN532 is
          Status := True;
       else
          Status := False;
+         -- Log ("read binary: reply invalid");
+         Log (Reply (1..Reply_Len));
          -- AVR.UART.Put ("Read failed"); AVR.UART.CRLF;
       end if;
    end PN532_NFC_Forum_Type_4_Read_Binary;

          
M ndef.adb +91 -0
@@ 77,4 77,95 @@ package body NDEF is
       Found    := False;
       Location := Pos;
    end Find_NDEF_TLV;
+   
+--   type NDEF_Record is record
+--      Message_Location : NDEF_Message_Location;
+--      Chunked : Boolean;
+--      Short_Record : Boolean;
+--      ID_Length_Present : Boolean;
+--      TNF : Type_Name_Format;
+--      Payload_Offset : Interfaces.Unsigned_8;
+--      Payload_Length : Interfaces.Unsigned_8;
+--   end record;
+   
+   -- Parse the NDEF record from the data
+   -- Header format:
+   --    MB|ME|CF|SR|IL|TNF
+   --    Type Length
+   --    Payload len 4  
+   --    Payload len 3
+   --    Payload len 2
+   --    Payload len 1
+   --    ID Len
+   --    Type
+   --    ID
+   --    Payload
+   procedure Read_NDEF_Record (Data        : NDEF_Array;
+                               Start       : Interfaces.Unsigned_8;
+                               NDEF_Header : out NDEF_Record;
+                               Status      : out Boolean)
+   is
+      CF_Mask     : constant Unsigned_8 := 2#0010_0000#;
+      SR_Mask     : constant Unsigned_8 := 2#0001_0000#;
+      ID_Len_Mask : constant Unsigned_8 := 2#0000_1000#;
+      TNF_Mask    : constant Unsigned_8 := 2#0000_0111#;
+      
+      Current_Location : Unsigned_8 := Start;
+      Type_Len : Unsigned_8;
+      ID_Len : Unsigned_8 := 0;
+   begin
+      if Start > Data'Last then
+         Status := False;
+         return;
+      end if;
+      
+      declare
+         Header_Bits : constant Unsigned_8 := Data (Current_Location);
+      begin
+         NDEF_Header.Chunked := (Header_Bits and CF_Mask) = CF_Mask;
+         NDEF_Header.Short_Record := (Header_Bits and SR_Mask) = SR_Mask;
+         NDEF_Header.ID_Length_Present := (Header_Bits and ID_Len_Mask) = ID_Len_Mask;
+         NDEF_Header.TNF := To_TNF (ID_Len_Mask and TNF_Mask);
+      end;
+      Current_Location := Current_Location + 1;
+      
+      -- Read Type length
+      Type_Len := Data (Current_Location);
+      Current_Location := Current_Location + 1;
+      
+      -- Read Payload length
+      if NDEF_Header.Short_Record then
+         NDEF_Header.Payload_Length := Data (Current_Location);
+      else
+         -- Long payload length not supported (not enough memory)
+         Status := False;
+         return;
+      end if;
+      Current_Location := Current_Location + 1;
+      
+      -- ID Length
+      if NDEF_Header.ID_Length_Present then
+         ID_Len := Data (Current_Location);
+         Current_Location := Current_Location + 1;
+      else
+         ID_Len := 0;
+      end if;
+     
+      -- Type
+      if Type_Len > 1 then -- types longer than 1 byte not supported
+         Status := False;
+         return;
+      else
+         NDEF_Header.NDEF_Type := Data (Current_Location);
+      end if;
+      Current_Location := Current_Location + 1;
+      
+      -- ID, skip it
+      Current_Location := Current_Location + ID_Len;
+      
+      NDEF_Header.Payload_Offset := Current_Location;
+      
+      Status := True;
+      return;
+   end Read_NDEF_Record;
 end NDEF;

          
M ndef.ads +6 -0
@@ 52,6 52,7 @@ package NDEF is
       Short_Record : Boolean;
       ID_Length_Present : Boolean;
       TNF : Type_Name_Format;
+      NDEF_Type : Interfaces.Unsigned_8;
       Payload_Offset : Interfaces.Unsigned_8;
       Payload_Length : Interfaces.Unsigned_8;
    end record;

          
@@ 61,4 62,9 @@ package NDEF is
                             Location : out Interfaces.Unsigned_8;
                             TLV_Len  : out Interfaces.Unsigned_8;
                             Found    : out Boolean);
+                            
+   procedure Read_NDEF_Record (Data        : NDEF_Array;
+                               Start       : Interfaces.Unsigned_8;
+                               NDEF_Header : out NDEF_Record;
+                               Status      : out Boolean);
 end NDEF;

          
M nfc_tags.adb +34 -16
@@ 18,7 18,7 @@ 
 with System;
 with PM_Strings;
 with NDEF;
-with PN532_BUS_SPI;
+with PN532_BUS_I2C;
 with Generic_PN532;
 with AVR.UART;
 with AVR.Interrupts;

          
@@ 32,20 32,20 @@ package body NFC_Tags is
    use Interfaces;
    use PN532_Types;
 
+--   package PN532 is new Generic_PN532
+--     (PN532_Init => PN532_BUS_SPI.PN532_Init,
+--      PN532_Busy => PN532_BUS_SPI.PN532_Busy,
+--      PN532_Write => PN532_BUS_SPI.PN532_Write,
+--      PN532_Read_Reply => PN532_BUS_SPI.PN532_Read_Reply,
+--      PN532_Read_Raw => PN532_BUS_SPI.PN532_Read_Raw,
+--      PN532_Read_Data => PN532_BUS_SPI.PN532_Read_Data);
    package PN532 is new Generic_PN532
-     (PN532_Init => PN532_BUS_SPI.PN532_Init,
-      PN532_Busy => PN532_BUS_SPI.PN532_Busy,
-      PN532_Write => PN532_BUS_SPI.PN532_Write,
-      PN532_Read_Reply => PN532_BUS_SPI.PN532_Read_Reply,
-      PN532_Read_Raw => PN532_BUS_SPI.PN532_Read_Raw,
-      PN532_Read_Data => PN532_BUS_SPI.PN532_Read_Data);
---   package PN532 is new Generic_PN532
---     (PN532_Init => PN532_BUS_I2C.PN532_Init,
---      PN532_Busy => PN532_BUS_I2C.PN532_Busy,
---      PN532_Write => PN532_BUS_I2C.PN532_Write,
---      PN532_Read_Reply => PN532_BUS_I2C.PN532_Read_Reply,
---      PN532_Read_Raw => PN532_BUS_I2C.PN532_Read_Raw,
---      PN532_Read_Data => PN532_BUS_I2C.PN532_Read_Data);
+     (PN532_Init => PN532_BUS_I2C.PN532_Init,
+      PN532_Busy => PN532_BUS_I2C.PN532_Busy,
+      PN532_Write => PN532_BUS_I2C.PN532_Write,
+      PN532_Read_Reply => PN532_BUS_I2C.PN532_Read_Reply,
+      PN532_Read_Raw => PN532_BUS_I2C.PN532_Read_Raw,
+      PN532_Read_Data => PN532_BUS_I2C.PN532_Read_Data);
 
    procedure Print_Str (Place : System.Address);
 

          
@@ 130,8 130,6 @@ package body NFC_Tags is
          end loop;
          AVR.UART.CRLF;
       end loop;
-
-
    end Read_Mifare_Classic_Tag;
 
    -- Read NFC Forum type 2 tag (like NXP Mifare Ultralight or NXP NTAG)

          
@@ 276,6 274,7 @@ package body NFC_Tags is
       Len : Unsigned_8;
       NDEF_ID : Unsigned_16;
       NDEF_Len : Unsigned_16;
+      NDEF_Header : NDEF.NDEF_Record;
    begin
       if not PN532.PN532_NFC_Forum_Type_4_Select_Application then
          Print_Str (PM_Strings.Type_4_Tag_Failed_PM'Address); AVR.UART.CRLF;

          
@@ 332,6 331,20 @@ package body NFC_Tags is
          AVR.UART.Put (" ");
       end loop;
       AVR.UART.CRLF;
+      
+      -- Read first record
+      NDEF.Read_NDEF_Record (NDEF.NDEF_Array (NFC_Data), 3, NDEF_Header, Status);
+      if Status then
+         AVR.UART.Put ("NDEF record at ");
+         AVR.UART.Put (Data => NDEF_Header.Payload_Offset, Base => 10);
+         AVR.UART.CRLF;
+         AVR.UART.Put ("NDEF type: ");
+         AVR.UART.Put (Data => NDEF_Header.NDEF_Type, Base => 16);
+         AVR.UART.CRLF;
+      else
+         AVR.UART.Put ("Failed to parse NDEF record");
+         AVR.UART.CRLF;
+      end if;
    end Read_Forum_Type_4_Tag;
 
    procedure Update_Forum_Type_4_Tag (New_Content : PN532_Buf)

          
@@ 438,6 451,10 @@ package body NFC_Tags is
                  (NFC_ID (NFC_ID'First..NFC_ID'First + NFC_ID_Len - 1));
             elsif Sel_Res = 16#20# and Sens_Res = 16#4403# then
                Read_Forum_Type_4_Tag;
+            elsif Sel_Res = 16#28# and Sens_Res = 16#4400# then -- Yubikey NEO
+               -- Read_Mifare_Classic_Tag
+               --   (NFC_ID (NFC_ID'First..NFC_ID'First + NFC_ID_Len - 1));
+               Read_Forum_Type_4_Tag;
             else
                AVR.UART.Put ("Unknown tag detected: ");
                AVR.UART.Put (Sel_Res, 16);

          
@@ 576,6 593,7 @@ package body NFC_Tags is
             AVR.UART.CRLF;
             -- AVR.UART.Put ("No reader detected, exiting");
             -- AVR.UART.CRLF;
+            Counter := 0;
          end if;
       end loop;
       Print_Str (PM_Strings.Emulation_Over_PM'Address);

          
M pn532_bus_i2c.adb +26 -2
@@ 3,6 3,8 @@ with AVR.MCU;
 with AVR.I2C;
 with AVR.I2C.Master;
 
+with AVR.UART;
+
 package body PN532_BUS_I2C is
    use AVR;
 

          
@@ 137,7 139,8 @@ package body PN532_BUS_I2C is
       Msg_Len : Unsigned_8;
       Ready_Status : Unsigned_8;
    begin
-      AVR.I2C.Master.Request (PN532_I2C_ADDRESS, 60);
+      AVR.I2C.Master.Request (PN532_I2C_ADDRESS, 80);
+      
       loop
          exit when AVR.I2C.Master.Data_Is_Available;
       end loop;

          
@@ 150,17 153,24 @@ package body PN532_BUS_I2C is
       if not (Header (2) = 0 and Header (3) = 16#FF#) then
          -- invalid header
          Status := False;
+         
+         -- AVR.UART.Put("inv. head"); AVR.UART.CRLF;
          return;
       end if;
 
       Msg_Len := Header (4);
       if Msg_Len + Header (5) /= 0 then
          Status := False;
+         -- AVR.UART.Put("inv. head len crc"); AVR.UART.CRLF;
          return;
       end if;
 
       Checksum := Checksum + Header (6);
 
+      if Buf'Length < Msg_Len then
+         AVR.UART.Put ("Buffer too small");
+         AVR.UART.CRLF;
+      end if;
       Msg_Len := Unsigned_8'Min (Buf'Length, Msg_Len);
 
       for I in Unsigned_8 range 1 .. Msg_Len loop

          
@@ 173,7 183,21 @@ package body PN532_BUS_I2C is
       Header (1) := not Header (1);
 
       if Checksum /= Header (1) then
-         -- Log ("PN532_Read_Data: Invalid checksum");
+--         -- Log ("PN532_Read_Data: Invalid checksum");
+--         AVR.UART.Put("inv. head crc"); AVR.UART.CRLF;
+--         
+--         AVR.UART.Put ("Msg_Len: ");
+--         AVR.UART.Put (Data => Msg_Len, Base => 10);
+--         AVR.UART.CRLF;
+--         AVR.UART.Put ("Buf'Length: ");
+--         AVR.UART.Put (Data => Unsigned_8 (Buf'Length), Base => 10);
+--         AVR.UART.CRLF;
+--
+--         for I in Unsigned_8 range 1 .. Msg_Len loop
+--            AVR.UART.Put (Data => Buf (I), Base => 16);
+--            AVR.UART.Put (" ");
+--         end loop;
+--         AVR.UART.CRLF;
          Status := False;
       else
          Status := True;