nfctype2: Tag data blocks read
authorSamuel Ortiz <sameo@linux.intel.com>
Thu, 12 May 2011 14:41:24 +0000 (16:41 +0200)
committerMarcel Holtmann <marcel@holtmann.org>
Fri, 21 Oct 2011 06:54:03 +0000 (23:54 -0700)
Compile tested only, due to missing formatted type 2 tags.

plugins/nfctype2.c

index a58853a..d989a7a 100644 (file)
 
 #define CMD_READ         0x30
 #define CMD_WRITE        0xA2
+
+#define READ_SIZE  16
+#define BLOCK_SIZE 4
+
 #define META_BLOCK_START 0
 #define DATA_BLOCK_START 4
+#define TYPE2_MAGIC 0xe1
+
+#define TAG_DATA_LENGTH(cc) ((cc)[2] * 8)
+#define TAG_DATA_NFC(cc) ((cc)[0] & TYPE2_MAGIC)
 
 static GHashTable *tag_hash;
 
@@ -52,10 +60,12 @@ struct type2_cmd {
 } __attribute__((packed));
 
 struct type2_tag {
+       uint32_t adapter_idx;
        uint32_t target_idx;
        uint8_t uid[8];
        uint8_t lock[4];
        uint8_t cc[4];
+       uint16_t current_block;
        uint16_t data_length;
        uint8_t *data;
 };
@@ -68,6 +78,67 @@ static void free_tag(gpointer data)
        g_free(tag);
 }
 
+static int data_recv(uint8_t *resp, int length, void *data)
+{
+       struct type2_tag *tag = data;
+       struct type2_cmd cmd;
+       uint16_t current_length, length_read;
+       int read_blocks;
+
+       DBG("%d", length);
+
+       if (length < 0)
+               return  length;
+
+       length_read = length;
+       current_length = tag->current_block * BLOCK_SIZE;
+       if (current_length + length > tag->data_length)
+               length_read = tag->data_length - current_length;
+
+       memcpy(data + current_length, resp, length_read);
+
+       if (current_length + length_read == tag->data_length) {
+               /* TODO parse tag->data for NDEFS, and notify target.c */
+               near_adapter_disconnect(tag->adapter_idx);
+               tag->current_block = 0;
+               return 0;
+       }
+
+       read_blocks = length / BLOCK_SIZE;
+       tag->current_block += read_blocks;
+
+       cmd.cmd = CMD_READ;
+       cmd.block = DATA_BLOCK_START + tag->current_block;
+
+       return near_adapter_send(tag->adapter_idx,
+                               (uint8_t *)&cmd, sizeof(cmd),
+                                       data_recv, tag);
+}
+
+static int data_read(struct type2_tag *tag)
+{
+       uint32_t adapter_idx;
+       struct type2_cmd cmd;
+
+       if (tag->data == NULL) {
+               g_hash_table_remove(tag_hash, GINT_TO_POINTER(tag->target_idx));
+
+               return -ENOMEM;
+       }
+
+       DBG("%d", tag->data_length);
+
+       adapter_idx = tag->adapter_idx;
+       tag->current_block = 0;
+
+       cmd.cmd = CMD_READ;
+       cmd.block = DATA_BLOCK_START;
+
+       return near_adapter_send(adapter_idx,
+                               (uint8_t *)&cmd, sizeof(cmd),
+                                       data_recv, tag);
+}
+
 static int meta_recv(uint8_t *resp, int length, void *data)
 {
        int i;
@@ -88,7 +159,13 @@ static int meta_recv(uint8_t *resp, int length, void *data)
 
        DBG("0x%x 0x%x 0x%x 0x%x", tag->cc[0], tag->cc[1], tag->cc[2], tag->cc[3]);
 
-       return 0;
+       if (tag->data != NULL)
+               g_free(tag->data);
+
+       tag->data_length = TAG_DATA_LENGTH(tag->cc);
+       tag->data = g_try_malloc0(tag->data_length);
+
+       return data_read(tag);
 }
 
 static int nfctype2_read_meta(uint32_t adapter_idx, uint32_t target_idx, struct type2_tag *tag)
@@ -115,6 +192,7 @@ static int nfctype2_read_tag(uint32_t adapter_idx,
                if (tag == NULL)
                        return -ENOMEM;
 
+               tag->adapter_idx = adapter_idx;
                tag->target_idx = target_idx;
 
                g_hash_table_insert(tag_hash, GINT_TO_POINTER(target_idx), tag);