Skip to content

Commit 592921d

Browse files
committed
feat: add IDTECK PSK1 tag type support
Adds IDTECK to the supported LF protocols on the GUI side, matching the firmware support added upstream. - TagType.idteck (310) in the PSK range, matching the firmware enum - IdteckCard model (8-byte 64-bit frame: 32-bit preamble + 32-bit payload) - ChameleonCommand entries: writeIdteckToT5577 (3017), setIdteckEmulatorID (5010), getIdteckEmulatorID (5011) - Bridge RPC wrappers following the Viking pattern - Wired into the LF type list, display name, card factory, and slot manager "add card" flow, plus the T55xx write helper - uidSizeForLfTag returns 8 for IDTECK No read path: firmware-side PSK demodulation is not implemented yet (the tag-emulation ADC is envelope-only at 125kHz), so the GUI does not expose a "read IDTECK" action. Emulation and T55xx clone work. Depends on firmware PR #407 landing for the command IDs.
1 parent bfa3318 commit 592921d

10 files changed

Lines changed: 98 additions & 5 deletions

File tree

chameleonultragui/lib/bridge/chameleon.dart

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -611,6 +611,10 @@ class ChameleonCommunicator {
611611
await sendCmd(ChameleonCommand.setIoProxEmulatorID, data: uid);
612612
}
613613

614+
Future<void> setIdteckEmulatorID(Uint8List uid) async {
615+
await sendCmd(ChameleonCommand.setIdteckEmulatorID, data: uid);
616+
}
617+
614618
Future<void> writeEM410XtoT55XX(
615619
Uint8List uid, Uint8List newKey, List<Uint8List> oldKeys) async {
616620
List<int> keys = [];
@@ -687,6 +691,20 @@ class ChameleonCommunicator {
687691
data: Uint8List.fromList([...uid, ...newKey, ...keys]));
688692
}
689693

694+
Future<void> writeIdteckToT55XX(
695+
Uint8List uid, Uint8List newKey, List<Uint8List> oldKeys) async {
696+
List<int> keys = [];
697+
698+
keys.addAll(newKey);
699+
700+
for (var oldKey in oldKeys) {
701+
keys.addAll(oldKey);
702+
}
703+
704+
await sendCmd(ChameleonCommand.writeIdteckToT5577,
705+
data: Uint8List.fromList([...uid, ...newKey, ...keys]));
706+
}
707+
690708
Future<void> setSlotTagName(
691709
int index, String name, TagFrequency frequency) async {
692710
await sendCmd(ChameleonCommand.setSlotTagNick,
@@ -1029,6 +1047,11 @@ class ChameleonCommunicator {
10291047
(await sendCmd(ChameleonCommand.getIoProxEmulatorID))!.data);
10301048
}
10311049

1050+
Future<IdteckCard> getIdteckEmulatorID() async {
1051+
return IdteckCard.fromBytes(
1052+
(await sendCmd(ChameleonCommand.getIdteckEmulatorID))!.data);
1053+
}
1054+
10321055
Future<DeviceSettings> getDeviceSettings() async {
10331056
var resp = (await sendCmd(ChameleonCommand.getDeviceSettings))!.data;
10341057
if (resp[0] != 5) {

chameleonultragui/lib/gui/menu/dialogs/slot/edit.dart

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,12 @@ class SlotEditMenuState extends State<SlotEditMenu> {
104104
await appState.communicator!.getIoProxEmulatorID();
105105
uidController.text = bytesToHexSpace(ioProxCard.uid);
106106
} catch (_) {}
107+
} else if (selectedType! == TagType.idteck) {
108+
try {
109+
IdteckCard idteckCard =
110+
await appState.communicator!.getIdteckEmulatorID();
111+
uidController.text = bytesToHexSpace(idteckCard.uid);
112+
} catch (_) {}
107113
} else if (isMifareClassic(selectedType!) ||
108114
isMifareUltralight(selectedType!)) {
109115
try {
@@ -206,6 +212,9 @@ class SlotEditMenuState extends State<SlotEditMenu> {
206212
} else if (selectedType! == TagType.ioProx) {
207213
await appState.communicator!.setIoProxEmulatorID(
208214
hexToBytes(uidController.text.replaceAll(' ', '')));
215+
} else if (selectedType! == TagType.idteck) {
216+
await appState.communicator!.setIdteckEmulatorID(
217+
hexToBytes(uidController.text.replaceAll(' ', '')));
209218
} else if (isMifareClassic(selectedType!) ||
210219
isMifareUltralight(selectedType!)) {
211220
var cardData = CardData(

chameleonultragui/lib/gui/menu/dialogs/slot/export.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,12 @@ class SlotExportMenuState extends State<SlotExportMenu> {
7171
name: widget.names.lf,
7272
tag: widget.slotTypes.lf,
7373
);
74+
} else if (widget.slotTypes.lf == TagType.idteck) {
75+
return CardSave(
76+
uid: (await appState.communicator!.getIdteckEmulatorID()).toString(),
77+
name: widget.names.lf,
78+
tag: widget.slotTypes.lf,
79+
);
7480
}
7581
} else {
7682
CardData data = await appState.communicator!.mf1GetAntiCollData();

chameleonultragui/lib/gui/page/home.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,8 @@ class HomePageState extends State<HomePage> {
5353
// Checks that firmware supports all functions of current app
5454
// If not, prompt user to update firmware (as outdated firmware might break app)
5555

56-
int ultraCapability = ChameleonCommand.setIoProxEmulatorID.value;
57-
int liteCapability = ChameleonCommand.setIoProxEmulatorID.value;
56+
int ultraCapability = ChameleonCommand.setIdteckEmulatorID.value;
57+
int liteCapability = ChameleonCommand.setIdteckEmulatorID.value;
5858

5959
var appState = context.read<ChameleonGUIState>();
6060
List<int> capabilities;

chameleonultragui/lib/gui/page/read_card.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ class ReadCardPageState extends State<ReadCardPage> {
130130
card ??= await appState.communicator!.readPac();
131131
card ??= await appState.communicator!.readIoProx();
132132

133+
133134
if (card != null) {
134135
setState(() {
135136
lfInfo.card = card;

chameleonultragui/lib/gui/page/slot_manager.dart

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,22 @@ class SlotManagerPageState extends State<SlotManagerPage> {
234234
await appState.communicator!.saveSlotData();
235235
appState.changesMade();
236236
refreshSlot();
237+
} else if (card.tag == TagType.idteck) {
238+
close(context, card.name);
239+
await appState.communicator!.setReaderDeviceMode(false);
240+
await appState.communicator!
241+
.enableSlot(gridPosition, TagFrequency.lf, true);
242+
await appState.communicator!.activateSlot(gridPosition);
243+
await appState.communicator!.setSlotType(gridPosition, card.tag);
244+
await appState.communicator!.setDefaultDataToSlot(gridPosition, card.tag);
245+
await appState.communicator!.setIdteckEmulatorID(hexToBytes(card.uid));
246+
await appState.communicator!.setSlotTagName(
247+
gridPosition,
248+
(card.name.isEmpty) ? localizations.no_name : card.name,
249+
TagFrequency.lf);
250+
await appState.communicator!.saveSlotData();
251+
appState.changesMade();
252+
refreshSlot();
237253
} else if (isMifareUltralight(card.tag)) {
238254
close(context, card.name);
239255
setUploadState(0);

chameleonultragui/lib/helpers/definitions.dart

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ enum ChameleonCommand {
8787
writeIoProxToT5577(3011),
8888
scanPacTag(3014),
8989
writePacToT5577(3015),
90+
writeIdteckToT5577(3017),
9091

9192
mf1LoadBlockData(4000),
9293
mf1SetAntiCollision(4001),
@@ -146,7 +147,10 @@ enum ChameleonCommand {
146147
getPacEmulatorID(5007),
147148

148149
setIoProxEmulatorID(5008),
149-
getIoProxEmulatorID(5009);
150+
getIoProxEmulatorID(5009),
151+
152+
setIdteckEmulatorID(5010),
153+
getIdteckEmulatorID(5011);
150154

151155
const ChameleonCommand(this.value);
152156
final int value;
@@ -163,6 +167,7 @@ enum TagType {
163167
viking(170),
164168
hidProx(200),
165169
ioProx(201),
170+
idteck(310),
166171
mifareMini(1000),
167172
mifare1K(1001),
168173
mifare2K(1002),
@@ -618,3 +623,18 @@ class IoProxCard extends LFCard {
618623
required super.uid,
619624
});
620625
}
626+
627+
class IdteckCard extends LFCard {
628+
factory IdteckCard.fromBytes(Uint8List bytes) {
629+
return IdteckCard(uid: bytes);
630+
}
631+
632+
factory IdteckCard.fromUID(String uid) {
633+
return IdteckCard.fromBytes(hexToBytes(uid));
634+
}
635+
636+
IdteckCard({
637+
super.type = TagType.idteck,
638+
required super.uid,
639+
});
640+
}

chameleonultragui/lib/helpers/general.dart

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,8 @@ String chameleonTagToString(TagType tag, AppLocalizations localizations) {
169169
return "PAC/Stanley";
170170
} else if (tag == TagType.ioProx) {
171171
return "ioProx";
172+
} else if (tag == TagType.idteck) {
173+
return "IDTECK";
172174
} else if (tag == TagType.ntag210) {
173175
return "NTAG210";
174176
} else if (tag == TagType.ntag212) {
@@ -455,7 +457,8 @@ List<TagType> getTagTypesByFrequency(TagFrequency frequency) {
455457
TagType.hidProx,
456458
TagType.viking,
457459
TagType.pac,
458-
TagType.ioProx
460+
TagType.ioProx,
461+
TagType.idteck
459462
];
460463
}
461464

@@ -557,6 +560,10 @@ LFCard getLFCardFromUID(TagType type, String uid) {
557560
return IoProxCard.fromUID(uid);
558561
}
559562

563+
if (type == TagType.idteck) {
564+
return IdteckCard.fromUID(uid);
565+
}
566+
560567
return EM410XCard.fromUID(uid, type: type);
561568
}
562569

@@ -573,6 +580,8 @@ int uidSizeForLfTag(TagType type) {
573580
return 8;
574581
} else if (type == TagType.ioProx) {
575582
return 16;
583+
} else if (type == TagType.idteck) {
584+
return 8;
576585
}
577586

578587
return 0;

chameleonultragui/lib/helpers/t55xx/write/base.dart

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,14 @@ class BaseT55XXCardHelper extends AbstractWriteHelper {
171171
hexToBytes(newKey), [hexToBytes(currentKey), Uint8List(4)]);
172172
var newCard = await communicator.readIoProx();
173173
return newCard.toString() == card.uid;
174+
} else if (card.tag == TagType.idteck) {
175+
await communicator.writeIdteckToT55XX(hexToBytes(card.uid),
176+
hexToBytes(newKey), [hexToBytes(currentKey), Uint8List(4)]);
177+
// IDTECK read is not implemented in the firmware (PSK demodulation
178+
// on the envelope-only tag-emulation ADC path is a follow-up), so we
179+
// cannot read back the tag for verification. Assume the T55xx write
180+
// succeeded if the firmware did not raise an error.
181+
return true;
174182
}
175183

176184
return false;

chameleonultragui/lib/helpers/write.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,8 @@ abstract class AbstractWriteHelper {
6565
type == TagType.hidProx ||
6666
type == TagType.viking ||
6767
type == TagType.pac ||
68-
type == TagType.ioProx) {
68+
type == TagType.ioProx ||
69+
type == TagType.idteck) {
6970
return BaseT55XXCardHelper(appState.communicator!);
7071
}
7172

0 commit comments

Comments
 (0)