Skip to content

Commit 5eb4d67

Browse files
committed
Fix ICode SLI/SLIX/SLIX2 detection using UID type indicator bits
Previously all NXP ICode tags were detected as "ICode SLIX". Now properly differentiates between SLI, SLIX, and SLIX2 by checking bits 36 and 37 in UID4 per NXP datasheet (SL2S2602): - Bits (0,0) -> ICode SLI (112 bytes) - Bits (1,0) -> ICode SLIX (896 bytes) - Bits (0,1) -> ICode SLIX2 (320 bytes) This fixes an issue where SLIX2 tags (like Prusa OpenPrintTag) were incorrectly reported as SLIX.
1 parent a3c113a commit 5eb4d67

File tree

2 files changed

+91
-11
lines changed

2 files changed

+91
-11
lines changed

internal/core/card.go

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"encoding/hex"
88
"encoding/json"
99
"fmt"
10+
"strconv"
1011
"sync"
1112
"time"
1213

@@ -426,10 +427,38 @@ func detectCardType(card *scard.Card, cardInfo *Card) {
426427
// 0xE0 = NXP (ICode SLI/Slix/Slix-2)
427428
uid := cardInfo.UID
428429
if len(uid) >= 16 && uid[14:16] == "e0" {
429-
// NXP ICode family (SLI, Slix, Slix2)
430-
cardInfo.Type = "ICode SLIX"
430+
// NXP ICode family - differentiate SLI/SLIX/SLIX2 using type indicator bits
431+
// Per NXP datasheet (SL2S2602), UID4 (hex position 8-9) contains bits 40:33
432+
// Bits 37 and 36 indicate the ICODE type:
433+
// Bit 37=0, Bit 36=0: ICODE SLI
434+
// Bit 37=1, Bit 36=0: ICODE SLIX
435+
// Bit 37=0, Bit 36=1: ICODE SLIX2
436+
// Bit 37=1, Bit 36=1: RFU
431437
cardInfo.Writable = true
432-
cardInfo.Size = 896 // ICode SLIX2 has 2560 bits = 320 bytes, SLIX has 896 bytes
438+
if len(uid) >= 10 {
439+
uid4Byte, err := strconv.ParseUint(uid[8:10], 16, 8)
440+
if err == nil {
441+
bit37 := (uid4Byte >> 4) & 1 // bit 4 of the byte
442+
bit36 := (uid4Byte >> 3) & 1 // bit 3 of the byte
443+
switch {
444+
case bit37 == 0 && bit36 == 1:
445+
cardInfo.Type = "ICode SLIX2"
446+
cardInfo.Size = 320 // SLIX2 has 2560 bits = 320 bytes
447+
return
448+
case bit37 == 1 && bit36 == 0:
449+
cardInfo.Type = "ICode SLIX"
450+
cardInfo.Size = 896 // SLIX has 896 bytes
451+
return
452+
case bit37 == 0 && bit36 == 0:
453+
cardInfo.Type = "ICode SLI"
454+
cardInfo.Size = 112 // SLI has 896 bits = 112 bytes
455+
return
456+
}
457+
}
458+
}
459+
// Fallback if we couldn't parse type bits
460+
cardInfo.Type = "ICode SLIX"
461+
cardInfo.Size = 896
433462
return
434463
}
435464
// Generic ISO 15693
@@ -1161,7 +1190,7 @@ func readNDEFData(card *scard.Card, cardInfo *Card) {
11611190
}
11621191
}
11631192
}
1164-
} else if cardInfo.Type == "ICode SLIX" || cardInfo.Type == "ISO 15693" {
1193+
} else if cardInfo.Type == "ICode SLIX" || cardInfo.Type == "ICode SLIX2" || cardInfo.Type == "ICode SLI" || cardInfo.Type == "ISO 15693" {
11651194
// ISO 15693 (Type 5) tags: NDEF starts at block 1 (after CC at block 0)
11661195
maxBlocks := 79 // 80 blocks total, skip CC at block 0
11671196
for blockNum := 1; blockNum < 1+maxBlocks; blockNum++ {

internal/core/card_detection_test.go

Lines changed: 58 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package core
22

33
import (
4+
"strconv"
45
"testing"
56
)
67

@@ -409,25 +410,49 @@ func TestCCBasedDetection(t *testing.T) {
409410
}
410411
}
411412

412-
// TestICodeSLIXDetection tests ICode SLIX detection from UID manufacturer byte
413+
// TestICodeSLIXDetection tests ICode SLI/SLIX/SLIX2 detection from UID type indicator bits
414+
// Per NXP datasheet (SL2S2602), UID4 (hex position 8-9) contains bits 40:33
415+
// Bits 37 and 36 indicate the ICODE type:
416+
//
417+
// Bit 37=0, Bit 36=0: ICODE SLI
418+
// Bit 37=1, Bit 36=0: ICODE SLIX
419+
// Bit 37=0, Bit 36=1: ICODE SLIX2
420+
// Bit 37=1, Bit 36=1: RFU
413421
func TestICodeSLIXDetection(t *testing.T) {
414422
tests := []struct {
415423
name string
416424
uid string
417425
atr string
418426
expectedType string
427+
expectedSize int
419428
}{
420429
{
421-
name: "ICode SLIX with NXP manufacturer (0xE0)",
422-
uid: "80391566080104e0",
430+
name: "ICode SLIX2 - bits (0,1)",
431+
uid: "80391566080104e0", // UID4=08: bit37=0, bit36=1 -> SLIX2
432+
atr: "3b8f8001804f0ca0000003060b00140000000077",
433+
expectedType: "ICode SLIX2",
434+
expectedSize: 320,
435+
},
436+
{
437+
name: "ICode SLIX - bits (1,0)",
438+
uid: "80391566100104e0", // UID4=10: bit37=1, bit36=0 -> SLIX
423439
atr: "3b8f8001804f0ca0000003060b00140000000077",
424440
expectedType: "ICode SLIX",
441+
expectedSize: 896,
442+
},
443+
{
444+
name: "ICode SLI - bits (0,0)",
445+
uid: "80391566000104e0", // UID4=00: bit37=0, bit36=0 -> SLI
446+
atr: "3b8f8001804f0ca0000003060b00140000000077",
447+
expectedType: "ICode SLI",
448+
expectedSize: 112,
425449
},
426450
{
427451
name: "Generic ISO 15693 (non-NXP)",
428-
uid: "8039156608010400",
452+
uid: "8039156608010400", // Manufacturer != 0xE0
429453
atr: "3b8f8001804f0ca0000003060b00140000000077",
430454
expectedType: "ISO 15693",
455+
expectedSize: 1024,
431456
},
432457
}
433458

@@ -438,17 +463,43 @@ func TestICodeSLIXDetection(t *testing.T) {
438463
t.Fatal("ATR should contain ISO 15693 pattern '03060b'")
439464
}
440465

441-
// Check UID manufacturer byte (last 2 chars in UID)
466+
// Simulate the detection logic
442467
var detectedType string
443-
if len(tt.uid) >= 16 && tt.uid[14:16] == "e0" {
444-
detectedType = "ICode SLIX"
468+
var detectedSize int
469+
uid := tt.uid
470+
471+
if len(uid) >= 16 && uid[14:16] == "e0" {
472+
// NXP ICode family - check type indicator bits
473+
if len(uid) >= 10 {
474+
uid4Byte, _ := strconv.ParseUint(uid[8:10], 16, 8)
475+
bit37 := (uid4Byte >> 4) & 1
476+
bit36 := (uid4Byte >> 3) & 1
477+
switch {
478+
case bit37 == 0 && bit36 == 1:
479+
detectedType = "ICode SLIX2"
480+
detectedSize = 320
481+
case bit37 == 1 && bit36 == 0:
482+
detectedType = "ICode SLIX"
483+
detectedSize = 896
484+
case bit37 == 0 && bit36 == 0:
485+
detectedType = "ICode SLI"
486+
detectedSize = 112
487+
default:
488+
detectedType = "ICode SLIX"
489+
detectedSize = 896
490+
}
491+
}
445492
} else {
446493
detectedType = "ISO 15693"
494+
detectedSize = 1024
447495
}
448496

449497
if detectedType != tt.expectedType {
450498
t.Errorf("expected type %s, got %s", tt.expectedType, detectedType)
451499
}
500+
if detectedSize != tt.expectedSize {
501+
t.Errorf("expected size %d, got %d", tt.expectedSize, detectedSize)
502+
}
452503
})
453504
}
454505
}

0 commit comments

Comments
 (0)