From ec89791101beba9f94822be3e8b4028ddcf99e76 Mon Sep 17 00:00:00 2001 From: Gilles Date: Mon, 1 Jun 2026 17:49:53 +0200 Subject: [PATCH 1/3] Fix: enum MaterialType conforme spec OpenPrintTag (ASA=4, PC=5, etc.) --- internal/openprinttag/openprinttag.go | 52 ++++++++++++++------------- 1 file changed, 27 insertions(+), 25 deletions(-) diff --git a/internal/openprinttag/openprinttag.go b/internal/openprinttag/openprinttag.go index ecdcb55..020ab16 100644 --- a/internal/openprinttag/openprinttag.go +++ b/internal/openprinttag/openprinttag.go @@ -25,26 +25,27 @@ const ( type MaterialType uint8 const ( - // FFF material types + // FFF material types — valeurs conformes spec OpenPrintTag (material_type_enum.yaml) MaterialTypePLA MaterialType = 0 - MaterialTypeABS MaterialType = 1 - MaterialTypePETG MaterialType = 2 - MaterialTypeASA MaterialType = 3 - MaterialTypePC MaterialType = 4 - MaterialTypeNylon MaterialType = 5 - MaterialTypeTPU MaterialType = 6 - MaterialTypePVA MaterialType = 7 - MaterialTypeHIPS MaterialType = 8 - MaterialTypePP MaterialType = 9 - MaterialTypePEI MaterialType = 10 - MaterialTypePEEK MaterialType = 11 - MaterialTypePA MaterialType = 12 - MaterialTypePACF MaterialType = 13 - MaterialTypePAGF MaterialType = 14 - MaterialTypePLACF MaterialType = 15 - MaterialTypePLAGF MaterialType = 16 - MaterialTypePETGCF MaterialType = 17 - MaterialTypePETGGF MaterialType = 18 + MaterialTypePETG MaterialType = 1 + MaterialTypeTPU MaterialType = 2 + MaterialTypeABS MaterialType = 3 + MaterialTypeASA MaterialType = 4 + MaterialTypePC MaterialType = 5 + MaterialTypePCTG MaterialType = 6 + MaterialTypePP MaterialType = 7 + MaterialTypePA MaterialType = 8 // PA6 + MaterialTypeHIPS MaterialType = 14 + MaterialTypePEI MaterialType = 17 + MaterialTypePVA MaterialType = 20 + MaterialTypePEEK MaterialType = 22 + MaterialTypeNylon MaterialType = 56 // générique, hors spec de base + MaterialTypePACF MaterialType = 100 // composite, valeur propriétaire + MaterialTypePAGF MaterialType = 101 + MaterialTypePLACF MaterialType = 102 + MaterialTypePLAGF MaterialType = 103 + MaterialTypePETGCF MaterialType = 104 + MaterialTypePETGGF MaterialType = 105 MaterialTypeOther MaterialType = 255 ) @@ -296,18 +297,19 @@ func materialClassToString(mc MaterialClass) string { func materialTypeToString(mt MaterialType) string { names := map[MaterialType]string{ MaterialTypePLA: "PLA", - MaterialTypeABS: "ABS", MaterialTypePETG: "PETG", + MaterialTypeTPU: "TPU", + MaterialTypeABS: "ABS", MaterialTypeASA: "ASA", MaterialTypePC: "PC", - MaterialTypeNylon: "Nylon", - MaterialTypeTPU: "TPU", - MaterialTypePVA: "PVA", - MaterialTypeHIPS: "HIPS", + MaterialTypePCTG: "PCTG", MaterialTypePP: "PP", + MaterialTypePA: "PA", + MaterialTypeHIPS: "HIPS", MaterialTypePEI: "PEI", + MaterialTypePVA: "PVA", MaterialTypePEEK: "PEEK", - MaterialTypePA: "PA", + MaterialTypeNylon: "Nylon", MaterialTypePACF: "PA-CF", MaterialTypePAGF: "PA-GF", MaterialTypePLACF: "PLA-CF", From b55a51fe64d8f449c488c89bc89428943400f3e5 Mon Sep 17 00:00:00 2001 From: Gilles Date: Tue, 2 Jun 2026 14:16:28 +0200 Subject: [PATCH 2/3] =?UTF-8?q?Fix:=20WriteDataWithURL=20=E2=80=94=20add?= =?UTF-8?q?=20ISO=2015693=20write=20path=20for=20ICode=20SLIX/SLIX2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit WriteDataWithURL was calling writeNTAGPages(card, 4, ...) for all non-MIFARE cards, including ISO 15693 (NFC-V) tags such as the NXP ICode SLIX2 used on Prusa filament spools. Two bugs for ISO 15693: 1. Wrong start block: NTAG user memory begins at page 4; ISO 15693 NDEF begins at block 1 (block 0 holds the Capability Container). 2. Padding to card.Size (320 bytes) caused writes to blocks 80-83, which are out of range for ICode SLIX2 (80 blocks, 0-79). Fix: detect NFC-V protocol and write CC to block 0 then NDEF TLV from block 1, mirroring the correct logic already present in WriteMultipleRecords. Tested on ACR1552U with blank NXP ICode SLIX2 tags and with Prusa-branded filament spool tags (write + readback verified). --- internal/core/card.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/internal/core/card.go b/internal/core/card.go index 227bf45..448c6d8 100644 --- a/internal/core/card.go +++ b/internal/core/card.go @@ -895,6 +895,16 @@ func WriteDataWithURL(readerName string, data []byte, dataType string, url strin if err := writeMifareClassic(card, ndefMessage); err != nil { return fmt.Errorf("failed to write NDEF message: %w", err) } + } else if cardInfo.Protocol == "NFC-V" { + // ISO 15693 (ICode SLI/SLIX/SLIX2): CC at block 0, NDEF TLV at block 1. + // Do NOT pad to card.Size — writing past block 79 causes errors on ICode SLIX2. + cc := []byte{0xE1, 0x40, 0x40, 0x00} + if err := writeNTAGPages(card, 0, cc); err != nil { + return fmt.Errorf("failed to write NDEF message: %w", err) + } + if err := writeNTAGPages(card, 1, ndefMessage); err != nil { + return fmt.Errorf("failed to write NDEF message: %w", err) + } } else { // NTAG and other cards use page-based writes. // Zero-fill remaining user pages after the NDEF data so leftover From cbcef1e9e32cc100b4b6e57046d60f49c9595dc1 Mon Sep 17 00:00:00 2001 From: Gilles Date: Tue, 2 Jun 2026 16:26:24 +0200 Subject: [PATCH 3/3] feat: expose brand-specific identifiers in OpenPrintTag Response Add BrandSpecificInstanceID, BrandSpecificPackageID and BrandSpecificMaterialID to the Response struct so they are included in the JSON output of the card read API endpoint. These fields are already decoded from the CBOR payload (MainSection keys 5-7) but were not propagated to the API response, making them invisible to consumers of the /v1/readers/{n}/card endpoint. Use cases: - BrandSpecificInstanceID: per-spool serial/lot number (e.g. Prusa instance ref) useful for traceability and inventory management systems - BrandSpecificPackageID: product/SKU reference for the package - BrandSpecificMaterialID: material reference identifier JSON keys follow the existing camelCase convention used by the other UUID fields (instanceUuid, packageUuid, etc.). --- internal/openprinttag/openprinttag.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/internal/openprinttag/openprinttag.go b/internal/openprinttag/openprinttag.go index 020ab16..2517239 100644 --- a/internal/openprinttag/openprinttag.go +++ b/internal/openprinttag/openprinttag.go @@ -174,6 +174,11 @@ type Response struct { MaterialUUID string `json:"materialUuid,omitempty"` BrandUUID string `json:"brandUuid,omitempty"` + // Brand-specific identifiers (MainSection keys 5-7) + BrandSpecificInstanceID string `json:"brandSpecificInstanceId,omitempty"` + BrandSpecificPackageID string `json:"brandSpecificPackageId,omitempty"` + BrandSpecificMaterialID string `json:"brandSpecificMaterialId,omitempty"` + // Weight information NominalWeight float32 `json:"nominalWeight,omitempty"` ConsumedWeight float32 `json:"consumedWeight,omitempty"` @@ -273,6 +278,11 @@ func (o *OpenPrintTag) ToResponse() *Response { resp.BrandUUID = formatUUID(o.Main.BrandUUID) } + // Brand-specific identifiers + resp.BrandSpecificInstanceID = o.Main.BrandSpecificInstanceID + resp.BrandSpecificPackageID = o.Main.BrandSpecificPackageID + resp.BrandSpecificMaterialID = o.Main.BrandSpecificMaterialID + // Convert color to hex string if len(o.Main.PrimaryColor) >= 3 { resp.PrimaryColor = colorToHex(o.Main.PrimaryColor)