RFID

RFID

RFID API allows you to read and write to and from an RFID peripheral device.


Note: This driver implements the Standard Driver Interface.

Members

(async) driverName

The name of this driver

Methods

(async) cancel() → {Promise.<undefined>}

Cancel any in progress read or write task

(async) deviceInfo() → {Promise.<module:RFID~RFIDDeviceInfo>}

Retrieve the device information about the attached RFID reader/writer peripheral.

Throws:
Example
// Query Device Information
window.Agent.onReadyAsync()
.then(() => window.Agent)
.then(agent => agent.RFID.deviceInfo())
.then(deviceInfo => console.log(deviceInfo))
.catch(ex => {
    console.error('Failed to query card state');
    console.error(ex);
});

// This should print something similair to this:
{
  "manufacturer": "Syncotek",
  "model": "SK288-K001",
  "vendorId": 9176,
  "productId": 645,
  "serial": "ABC1234K001",
  "capabilities": [
      "LOCK",
      "UNLOCK",
      "LED-RED",
      "LED-BLUE",
      "SENSE",
      "MIFARE-CLASSIC",
      "MIFARE-PLUS",
      "MIFARE-DESFIRE"
  ]
}

(async) getDeviceInfo()

Retrieve information about the device, driver and its state.

(async) isAttached() → {Promise.<Boolean>}

Is the device physically connected

(async) isCardPresent() → {Promise.<Boolean>}

Is a card present in the device

Throws:
Example
// Query Card Present
window.Agent.onReadyAsync()
.then(() => window.Agent)
.then(agent => agent.RFID.isCardPresent())
.then(isCardPresent => console.log(
    isCardPresent
         ? 'The card is present'
         : 'The card is not present'))
.catch(ex => {
    console.error('Failed to query card state');
    console.error(ex);
});

(async) isConnected() → {Promise.<Boolean>}

Is the device communication open and connected

(async) isEnabled() → {Promise.<Boolean>}

Is the device enabled

(async) isLocked() → {Promise.<Boolean>}

Is the latch locked

Throws:
Example
// Query lock state
window.Agent.onReadyAsync()
.then(() => window.Agent)
.then(agent => agent.RFID.isLocked())
.then(isLocked => console.log(
    isLocked
        ? 'The latch is locked'
        : 'The latch is not locked'))
.catch(ex => {
    console.error('Failed to query lock state');
    console.error(ex);
});

(async) ledOff(coloropt) → {Promise.<undefined>}

Toggle the attached peripheral LED to turn off.

Parameters:
Name Type Attributes Default Description
color LEDColor <optional>
0

The color of the LED to illuminate.

Throws:
Example
// Query Device Information
const RED_LED = 0;
window.Agent.onReadyAsync()
.then(() => window.Agent)
.then(agent => agent.RFID.deviceInfo()) // Check if the attached peripheral has a RED LED
.then(deviceInfo => {
     if (deviceInfo && deviceInfo.capabilities.includes('LED-RED')) return window.Agent;

     throw new Error('RED LED Not Available'); // Will throw an error an exit as we don't have an LED to control
})
.then(agent => agent.RFID.ledOff(RED_LED)) // Turn off the RED LED
.then(() => console.log('RED LED is now off'))
.catch(ex => {
    console.error('Failed to set LED state');
    console.error(ex);
});

(async) ledOn(coloropt, flashingopt) → {Promise.<undefined>}

Toggle the attached peripheral LED to turn on and optionally flash.

Parameters:
Name Type Attributes Default Description
color LEDColor <optional>
0

The color of the LED to illuminate.

flashing Boolean <optional>
false

If the LED should flash

Throws:
Example
// Query Device Information
const RED_LED = 0;
window.Agent.onReadyAsync()
.then(() => window.Agent)
.then(agent => agent.RFID.deviceInfo()) // Check if the attached peripheral has a RED LED
.then(deviceInfo => {
     if (deviceInfo && deviceInfo.capabilities.includes('LED-RED')) return window.Agent;

     throw new Error('RED LED Not Available'); // Will throw an error an exit as we don't have an LED to control
})
.then(agent => agent.RFID.ledOn(RED_LED, true)) // Turn on the RED LED and flash the LED
.then(() => console.log('RED LED is now on and flashing'))
.catch(ex => {
    console.error('Failed to set LED state');
    console.error(ex);
});

(async) lock() → {Promise.<undefined>}

Lock the latch

Throws:
Example
// Lock the latch
window.Agent.onReadyAsync()
.then(() => window.Agent)
.then(agent => agent.RFID.lock())
.then(() => console.log('Locked'))
.catch(ex => {
    console.error('Failed to Lock');
    console.error(ex);
});

(async) queryCard() → {Promise.<module:RFID~CardQueryResult>}

Query for details about the card, will return card type, uid and capacity

Example
// Example for Querying card
const queryCard = async() => {
 console.log("QUERY CARD: Insert");
 const result = await agent.RFID.queryCard();
 console.log(result);
}
// Console Output: {
     type: 'Mifare S50 1K Card',
     uid: '02b921de',
     capacity: 1024
}

(async) read(configopt, keysopt, outEncodingopt, optionsopt) → {Promise.<module:RFID~ReadResult>}

Read data from the RFID Card

Parameters:
Name Type Attributes Default Description
config ReadConfiguration <optional>
defaultReadConfig

The configuration of the read task defines which sectors and blocks to read

keys Keys <optional>
{a: [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF], b: [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]}

The RFID a and b keys. Required only for Mifare Classic cards.

outEncoding OutputEncoding <optional>
'DEFAULT'

Output encoding defaults to MeldCX Format

options ReadOptions <optional>
{skipInsert: false, skipRemove: false}

Optional configuration params, skipInsert to skip waiting for a card to be inserted and skipRemove to skip waiting for a card to be removed.

Throws:
Examples
//Read Data from Ultralight cards
window.Agent.onReadyAsync()
.then(() => window.Agent)
.then(agent => agent.RFID.read(
     [
         {
             index: 5,
             blocks: [{index: 0}]
         },
         {
             index: 6
             blocks: [{index: 0}]
         }
     ],
     undefined,
     undefined,
     { skipRemove: true, skipRelease: true }
))
.then(result => {
      console.log(result);
})
.catch(ex => {
    console.error('Failed to read card data');
    console.error(ex);
});

Console Output:  {
     sectors: [
          { 
            index: 5, 
            blocks: [{index: 0, data: [1, 2, 3, 4]}]
          },
          { 
            index: 6, 
            blocks: [{index: 0, data: [5, 6, 7, 8]}]
          }
      ],
      uid: '0a0b0304050607',
      capacity: 48,
      type: 'Mifare Ultralight MF0UL11',
};
//Read Data from Mifare Classic cards
window.Agent.onReadyAsync()
.then(() => window.Agent)
.then(agent => agent.RFID.read([
    {
        index: 0,
        keys: { a: [0, 0, 0, 0, 0, 0] }
    }
]))
.then(result => {
    console.log('NUID', result.nuid);
    console.log('UID', result.uid);
    console.log('Capacity', result.capacity);

    console.log('Sectors');
    for (const sector of result.payload.sectors) {
        console.log('\tSector', sector.index);
        console.log('\t\tBlocks:');

        for (const block of sector.blocks) {
            console.log(
                '\t\t\tBlock',
                block.index,
                block.type,
                JSON.stringify(block.data),
                JSON.stringify(block.access));
        }
    }
})
.catch(ex => {
    console.error('Failed to read card data');
    console.error(ex);
});
// Example for reading with skipReadData = true
const read = async() => {
 const result = await agent.RFID.read(undefined, undefined, undefined, {
     skipInsert: true,
     skipRemove: true,
     skipRelease: true,
     skipReadData: true
 });

 console.log(result)
}

read()

Console Output:  {
 sectors: [],
 type: 'Mifare S50 1K Card',
 capacity: 1024
});

(async) setTimeout(timeout) → {Promise.<undefined>}

Set the default timeout value in milliseconds, this may be set to a number up to 120 seconds (2 minutes)

Parameters:
Name Type Description
timeout Number

The length of time to wait before timing out in Milliseconds

(async) unlock() → {Promise.<undefined>}

Unlock the latch

Throws:
Example
// Unlock the latch
window.Agent.onReadyAsync()
.then(() => window.Agent)
.then(agent => agent.RFID.unlock())
.then(() => console.log('Unlocked'))
.catch(ex => {
    console.error('Failed to Unlock');
    console.error(ex);
});

(async) write(configopt, keysopt, inEncodingopt, optionsopt) → {Promise.<undefined>}

Write data to the RFID Card

Parameters:
Name Type Attributes Default Description
config WriteConfiguration | Buffer | String | ArrayBuffer | UInt8Array <optional>
defaultWriteConfig

The configuration of the write task defines which sectors and blocks to write, this may also be a buffer of data

keys Keys <optional>
{a: [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF], b: [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]}

The RFID a and b keys. Required only for Mifare Classic cards.

inEncoding OutputEncoding <optional>
'DEFAULT'

Input encoding

options WriteOptions <optional>
{skipSectorZeroBlockZero: true, skipInsert: false, skipRemove: false}

Optional configuration for the write command, skipSectorZeroBlockZero, will skip the first 16 bytes of the provided binary payload, skipInsert will skip waiting for the card to be inserted, skipRemove will skip waiting for the card to be removed.

Throws:
Examples
// For Mifare Ultralight cards.
// Below example writes 8 bytes of data to sector 5 and 6 of the card.
// Ultralight card MF0UL11 contains 12 user sectors(sector index 4 to 15). Each sector has 1 block only.
// Each block contains 4 bytes of data.
window.Agent.onReadyAsync()
.then(() => window.Agent)
.then(agent => {
const writeConfig = [
          { 
            index: 5, 
            blocks: [{index: 0, data: [0x01,0x02,0x03,0x04]}]
          },
          { 
            index: 6, 
            blocks: [{index: 0, data: [0x05,0x06,0x07,0x08]}]
          },
     ];
const keys = undefined;
const inEncoding = undefined;
const writeOptions = {
            skipInsert: true,
            skipRemove: true,
            skipRelease: true,
         };
return agent.RFID.write(writeConfig, keys, inEncoding, writeOptions)

})
.then(() => console.log('Wrote to UL card successfully'))
.catch(ex => {
     if (ex instanceof AgentCancelledException) {
         console.error('It was cancelled, all is well :)');
         return;
     }
    console.error('Failed to write card data');
    console.error(ex);
});
// Write Data to Mifare Classic card Using the MeldCX Schema
window.Agent.onReadyAsync()
.then(() => window.Agent)
.then(agent => agent.RFID.write([
         {
              index: 1,
              keys: { a: [0, 0, 0, 0, 0, 0] }, // Key required to read or write.
              blocks: [
                   { index: 0, data: [4,3,2,1] }
              ],
              updateKeys: { a: [1, 2, 3, 4, 5, 6] }, // Optional update the key.
              access: {read: true, write: true, increment: true, decrement: true} // Optional update the access.
         }
    ]))
.then(() => console.log('Wrote to card successfully'))
.catch(ex => {
     if (ex instanceof AgentCancelledException) {
         console.error('It was cancelled, all is well :)');
         return;
     }
    console.error('Failed to write card data');
    console.error(ex);
});

// Write Data to Mifare Classic card Using a Base64 string of data
const base64 = 'AAECAwQFBgcIAAECAwQFBgcIAAECAwQFBgcIAAECAwQFBgcIAAECAwQFBgcIAAECAwQFBgcIAAECAwQFBgcIAAECAwQFB.....';
const keys = {a: [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF], b: [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]};

window.Agent.onReadyAsync()
.then(() => window.Agent)
.then(agent => agent.RFID.write(base64, keys, 'base64'))
.then(() => console.log('Wrote to card successfully'))
.catch(ex => {
    console.error('Failed to write card data');
    console.error(ex);
});
For Mifare Classic card
//   C3[4]   C2[2]   C1[1]   Total   Access
//   1       1       0       6       Can read with Key A/B but can only write with Key B
//   1       0       0       4       Can only read and write with Key A.
//   1       1       1       7       Access can only be read by Key A/B locked to changes *permanently*
// See here for a comprehensive guide: https://www.nxp.com/docs/en/data-sheet/MF1S50YYX_V1.pdf#page=12
await agent.RFID.write([{
    index: 1,
    access: [0, 0, 0, 6]
}], {a: [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]}
* @example
// Example for writing to key B to Mifare Classic card
const writeKeyB = async() => {
 const sector = 7;
 const newKeyB = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06];
 const result = await agent.RFID.write([
     {
         index: sector,
          updateKeys: {b: newKeyB}
      }
  ], undefined, undefined, {skipInsert: true, skipRemove: true, skipRelease: true});


 console.log(result);
};

writeKeyB();

// Console Output: Undefined (no error thrown, shows that key write was successful)
// For Mifare Classic card
// Example of writing to change the access bits of a particular sector
const writeAccessBits = async() => {
 const sector = 7;
 const newAccess = [ 0, 0, 0, 6 ];
 const newPermission = [127, 7, 136];
 await agent.RFID.write([{
        index: sector,
     access: newAccess
 }], {a: [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]}, undefined, {skipInsert: true, skipRemove: true, skipRelease: true});
 const readResult = await agent.RFID.read([{
        index: sector,
     blocks: [{index: 3}]
 }], {a: [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]}, undefined, {skipInsert: true, skipRemove: true, skipRelease: true});
 const originalAccess = readResult.sectors[0].blocks[0].data.slice(6, 9);

 console.log(originalAccess)
};

writeAccessBits();

Console Output: [127, 7, 136];
// For Mifare Classic card
// Example of reseting the access to default
const resetAccess = async() => {
    const sector = 7;
    const oldAccess = [ 0, 0, 0, 4 ];
    const oldPermission = [255, 7, 128];
    await agent.RFID.write([{
        index: sector,
        access: oldAccess
    }], {b: [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]}, undefined, {skipInsert: true, skipRemove: true, skipRelease: true});
    const readResult = await agent.RFID.read([{
        index: sector,
        blocks: [{index: 3}]
    }], {a: [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]}, undefined, {skipInsert: true, skipRemove: true, skipRelease: true});
    const originalAccess = readResult.sectors[0].blocks[0].data.slice(6, 9);
}

resetAccess();

Console Output: [255, 7, 128];