Skip to content

Commit c88e142

Browse files
committed
Add all OpenPrintTag spec fields (keys 0-56)
- Add missing secondary colors (keys 22-24) - Add transmission_distance (key 27) - Add shore_hardness_d (key 32), min_nozzle_diameter (key 33) - Add chamber temperature fields (keys 39-41) - Add container dimension fields (keys 42-45) - Add SLA viscosity fields (keys 46-49) - Add SLA container/curing fields (keys 50-51) - Add nominal_full_length (key 53) - Rename SecondaryColor -> SecondaryColor0, TertiaryColor -> SecondaryColor1 - Rename FilamentLength -> ActualFullLength - Fix staticcheck SA9003 empty branch warning
1 parent 92dd585 commit c88e142

File tree

3 files changed

+154
-29
lines changed

3 files changed

+154
-29
lines changed

internal/core/card.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1035,8 +1035,8 @@ done:
10351035
if mimeType == "application/json" {
10361036
cardInfo.Data = string(payload)
10371037
cardInfo.DataType = "json"
1038-
} else if mimeType == openprinttag.MIMEType {
1039-
// OpenPrintTag format (application/vnd.openprinttag)
1038+
} else if mimeType == openprinttag.MIMEType || mimeType == "application/cbor" {
1039+
// OpenPrintTag format (application/vnd.openprinttag or application/cbor)
10401040
opt, err := openprinttag.Decode(payload)
10411041
if err == nil {
10421042
resp := opt.ToResponse()

internal/openprinttag/codec.go

Lines changed: 94 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,10 @@ func init() {
2929
}
3030

3131
// Configure decoder
32+
// ExtraReturnErrors: ignore trailing data (NFC tags often have zero-padding)
3233
decMode, err = cbor.DecOptions{
33-
IntDec: cbor.IntDecConvertSigned,
34+
IntDec: cbor.IntDecConvertSigned,
35+
ExtraReturnErrors: cbor.ExtraDecErrorNone,
3436
}.DecMode()
3537
if err != nil {
3638
panic(fmt.Sprintf("failed to create CBOR decoder: %v", err))
@@ -174,24 +176,27 @@ func Decode(payload []byte) (*OpenPrintTag, error) {
174176
}
175177

176178
// Decode Main section - starts right after meta
179+
// Use streaming decoder to handle trailing zeros/padding on NFC tags
177180
mainStart := metaEnd
178181
mainEnd := int(opt.Meta.AuxOffset)
179182
if mainEnd > len(payload) {
180183
mainEnd = len(payload)
181184
}
182185
if mainStart < mainEnd {
183186
mainData := payload[mainStart:mainEnd]
184-
if err := decMode.Unmarshal(mainData, &opt.Main); err != nil {
187+
mainDecoder := decMode.NewDecoder(bytes.NewReader(mainData))
188+
if err := mainDecoder.Decode(&opt.Main); err != nil {
185189
return nil, fmt.Errorf("failed to decode main section: %w", err)
186190
}
187191
}
188192

189193
// Decode Auxiliary section
194+
// Use streaming decoder to handle trailing zeros/padding
190195
if int(opt.Meta.AuxOffset) < len(payload) {
191196
auxData := payload[opt.Meta.AuxOffset:]
192-
if err := decMode.Unmarshal(auxData, &opt.Aux); err != nil {
193-
// Aux section might be empty or malformed, ignore error
194-
}
197+
auxDecoder := decMode.NewDecoder(bytes.NewReader(auxData))
198+
// Aux section might be empty or malformed, ignore error
199+
_ = auxDecoder.Decode(&opt.Aux)
195200
}
196201

197202
return opt, nil
@@ -323,23 +328,37 @@ func (m *MainSection) toKeyValuePairs() []keyValue {
323328
kv = append(kv, keyValue{18, m.EmptyContainerWeight})
324329
}
325330

326-
// Colors (keys 19-21)
331+
// Colors (keys 19-24)
327332
if len(m.PrimaryColor) > 0 {
328333
kv = append(kv, keyValue{19, m.PrimaryColor})
329334
}
330-
if len(m.SecondaryColor) > 0 {
331-
kv = append(kv, keyValue{20, m.SecondaryColor})
335+
if len(m.SecondaryColor0) > 0 {
336+
kv = append(kv, keyValue{20, m.SecondaryColor0})
337+
}
338+
if len(m.SecondaryColor1) > 0 {
339+
kv = append(kv, keyValue{21, m.SecondaryColor1})
340+
}
341+
if len(m.SecondaryColor2) > 0 {
342+
kv = append(kv, keyValue{22, m.SecondaryColor2})
332343
}
333-
if len(m.TertiaryColor) > 0 {
334-
kv = append(kv, keyValue{21, m.TertiaryColor})
344+
if len(m.SecondaryColor3) > 0 {
345+
kv = append(kv, keyValue{23, m.SecondaryColor3})
346+
}
347+
if len(m.SecondaryColor4) > 0 {
348+
kv = append(kv, keyValue{24, m.SecondaryColor4})
349+
}
350+
351+
// Transmission distance (key 27)
352+
if m.TransmissionDistance != 0 {
353+
kv = append(kv, keyValue{27, m.TransmissionDistance})
335354
}
336355

337356
// Tags (key 28)
338357
if len(m.Tags) > 0 {
339358
kv = append(kv, keyValue{28, m.Tags})
340359
}
341360

342-
// Physical properties (keys 29-31)
361+
// Physical properties (keys 29-33)
343362
if m.Density != 0 {
344363
kv = append(kv, keyValue{29, m.Density})
345364
}
@@ -349,8 +368,14 @@ func (m *MainSection) toKeyValuePairs() []keyValue {
349368
if m.ShoreHardnessA != 0 {
350369
kv = append(kv, keyValue{31, m.ShoreHardnessA})
351370
}
371+
if m.ShoreHardnessD != 0 {
372+
kv = append(kv, keyValue{32, m.ShoreHardnessD})
373+
}
374+
if m.MinNozzleDiameter != 0 {
375+
kv = append(kv, keyValue{33, m.MinNozzleDiameter})
376+
}
352377

353-
// Temperature settings (keys 34-36)
378+
// Temperature settings (keys 34-41)
354379
if m.MinPrintTemp != 0 {
355380
kv = append(kv, keyValue{34, m.MinPrintTemp})
356381
}
@@ -360,11 +385,68 @@ func (m *MainSection) toKeyValuePairs() []keyValue {
360385
if m.PreheatTemp != 0 {
361386
kv = append(kv, keyValue{36, m.PreheatTemp})
362387
}
388+
if m.MinBedTemp != 0 {
389+
kv = append(kv, keyValue{37, m.MinBedTemp})
390+
}
391+
if m.MaxBedTemp != 0 {
392+
kv = append(kv, keyValue{38, m.MaxBedTemp})
393+
}
394+
if m.MinChamberTemp != 0 {
395+
kv = append(kv, keyValue{39, m.MinChamberTemp})
396+
}
397+
if m.MaxChamberTemp != 0 {
398+
kv = append(kv, keyValue{40, m.MaxChamberTemp})
399+
}
400+
if m.ChamberTemp != 0 {
401+
kv = append(kv, keyValue{41, m.ChamberTemp})
402+
}
403+
404+
// Container/spool dimensions (keys 42-45)
405+
if m.ContainerWidth != 0 {
406+
kv = append(kv, keyValue{42, m.ContainerWidth})
407+
}
408+
if m.ContainerOuterDiameter != 0 {
409+
kv = append(kv, keyValue{43, m.ContainerOuterDiameter})
410+
}
411+
if m.ContainerInnerDiameter != 0 {
412+
kv = append(kv, keyValue{44, m.ContainerInnerDiameter})
413+
}
414+
if m.ContainerHoleDiameter != 0 {
415+
kv = append(kv, keyValue{45, m.ContainerHoleDiameter})
416+
}
417+
418+
// SLA viscosity (keys 46-49)
419+
if m.Viscosity18C != 0 {
420+
kv = append(kv, keyValue{46, m.Viscosity18C})
421+
}
422+
if m.Viscosity25C != 0 {
423+
kv = append(kv, keyValue{47, m.Viscosity25C})
424+
}
425+
if m.Viscosity40C != 0 {
426+
kv = append(kv, keyValue{48, m.Viscosity40C})
427+
}
428+
if m.Viscosity60C != 0 {
429+
kv = append(kv, keyValue{49, m.Viscosity60C})
430+
}
431+
432+
// SLA container/curing (keys 50-51)
433+
if m.ContainerVolumetricCapacity != 0 {
434+
kv = append(kv, keyValue{50, m.ContainerVolumetricCapacity})
435+
}
436+
if m.CureWavelength != 0 {
437+
kv = append(kv, keyValue{51, m.CureWavelength})
438+
}
363439

364440
// Additional metadata (keys 52-56)
365441
if m.MaterialAbbreviation != "" {
366442
kv = append(kv, keyValue{52, m.MaterialAbbreviation})
367443
}
444+
if m.NominalFullLength != 0 {
445+
kv = append(kv, keyValue{53, m.NominalFullLength})
446+
}
447+
if m.ActualFullLength != 0 {
448+
kv = append(kv, keyValue{54, m.ActualFullLength})
449+
}
368450
if m.CountryOfOrigin != "" {
369451
kv = append(kv, keyValue{55, m.CountryOfOrigin})
370452
}

internal/openprinttag/openprinttag.go

Lines changed: 58 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -88,28 +88,59 @@ type MainSection struct {
8888
ActualNettoFullWeight float32 `cbor:"17,keyasint,omitempty"`
8989
EmptyContainerWeight float32 `cbor:"18,keyasint,omitempty"`
9090

91-
// Colors (keys 19-27) - RGB or RGBA as byte arrays
92-
PrimaryColor []byte `cbor:"19,keyasint,omitempty"`
93-
SecondaryColor []byte `cbor:"20,keyasint,omitempty"`
94-
TertiaryColor []byte `cbor:"21,keyasint,omitempty"`
91+
// Colors (keys 19-24) - RGB or RGBA as byte arrays
92+
PrimaryColor []byte `cbor:"19,keyasint,omitempty"`
93+
SecondaryColor0 []byte `cbor:"20,keyasint,omitempty"`
94+
SecondaryColor1 []byte `cbor:"21,keyasint,omitempty"`
95+
SecondaryColor2 []byte `cbor:"22,keyasint,omitempty"`
96+
SecondaryColor3 []byte `cbor:"23,keyasint,omitempty"`
97+
SecondaryColor4 []byte `cbor:"24,keyasint,omitempty"`
98+
99+
// Transmission distance (key 27) - HueForge TD value
100+
TransmissionDistance float32 `cbor:"27,keyasint,omitempty"`
95101

96102
// Tags (key 28)
97103
Tags []uint8 `cbor:"28,keyasint,omitempty"`
98104

99105
// Physical properties (keys 29-33)
100-
Density float32 `cbor:"29,keyasint,omitempty"`
101-
FilamentDiameter float32 `cbor:"30,keyasint,omitempty"`
102-
ShoreHardnessA uint8 `cbor:"31,keyasint,omitempty"`
103-
104-
// Temperature settings (keys 34-36)
105-
MinPrintTemp uint16 `cbor:"34,keyasint,omitempty"`
106-
MaxPrintTemp uint16 `cbor:"35,keyasint,omitempty"`
107-
PreheatTemp uint16 `cbor:"36,keyasint,omitempty"`
106+
Density float32 `cbor:"29,keyasint,omitempty"`
107+
FilamentDiameter float32 `cbor:"30,keyasint,omitempty"`
108+
ShoreHardnessA uint8 `cbor:"31,keyasint,omitempty"`
109+
ShoreHardnessD uint8 `cbor:"32,keyasint,omitempty"`
110+
MinNozzleDiameter float32 `cbor:"33,keyasint,omitempty"`
111+
112+
// Temperature settings (keys 34-41)
113+
MinPrintTemp uint16 `cbor:"34,keyasint,omitempty"`
114+
MaxPrintTemp uint16 `cbor:"35,keyasint,omitempty"`
115+
PreheatTemp uint16 `cbor:"36,keyasint,omitempty"`
116+
MinBedTemp uint16 `cbor:"37,keyasint,omitempty"`
117+
MaxBedTemp uint16 `cbor:"38,keyasint,omitempty"`
118+
MinChamberTemp uint16 `cbor:"39,keyasint,omitempty"`
119+
MaxChamberTemp uint16 `cbor:"40,keyasint,omitempty"`
120+
ChamberTemp uint16 `cbor:"41,keyasint,omitempty"`
121+
122+
// Container/spool dimensions (keys 42-45)
123+
ContainerWidth uint16 `cbor:"42,keyasint,omitempty"` // mm
124+
ContainerOuterDiameter uint16 `cbor:"43,keyasint,omitempty"` // mm
125+
ContainerInnerDiameter uint16 `cbor:"44,keyasint,omitempty"` // mm
126+
ContainerHoleDiameter uint16 `cbor:"45,keyasint,omitempty"` // mm
127+
128+
// SLA viscosity (keys 46-49) - mPa·s
129+
Viscosity18C float32 `cbor:"46,keyasint,omitempty"`
130+
Viscosity25C float32 `cbor:"47,keyasint,omitempty"`
131+
Viscosity40C float32 `cbor:"48,keyasint,omitempty"`
132+
Viscosity60C float32 `cbor:"49,keyasint,omitempty"`
133+
134+
// SLA container/curing (keys 50-51)
135+
ContainerVolumetricCapacity float32 `cbor:"50,keyasint,omitempty"` // ml (cm³)
136+
CureWavelength uint16 `cbor:"51,keyasint,omitempty"` // nm
108137

109138
// Additional metadata (keys 52-56)
110-
MaterialAbbreviation string `cbor:"52,keyasint,omitempty"`
111-
CountryOfOrigin string `cbor:"55,keyasint,omitempty"`
112-
Certifications []uint8 `cbor:"56,keyasint,omitempty"`
139+
MaterialAbbreviation string `cbor:"52,keyasint,omitempty"`
140+
NominalFullLength uint32 `cbor:"53,keyasint,omitempty"` // mm
141+
ActualFullLength uint32 `cbor:"54,keyasint,omitempty"` // mm
142+
CountryOfOrigin string `cbor:"55,keyasint,omitempty"`
143+
Certifications []uint8 `cbor:"56,keyasint,omitempty"`
113144
}
114145

115146
// AuxSection contains mutable runtime data that printers can update.
@@ -150,11 +181,18 @@ type Response struct {
150181
// Physical properties
151182
PrimaryColor string `json:"primaryColor,omitempty"` // hex #RRGGBB or #RRGGBBAA
152183
FilamentDiameter float32 `json:"filamentDiameter,omitempty"`
184+
FilamentLength uint32 `json:"filamentLength,omitempty"` // in mm
153185
Density float32 `json:"density,omitempty"`
154186

187+
// Weight details
188+
ActualWeight float32 `json:"actualWeight,omitempty"` // actual netto weight
189+
SpoolWeight float32 `json:"spoolWeight,omitempty"` // empty container weight
190+
155191
// Temperature settings
156192
MinPrintTemp uint16 `json:"minPrintTemp,omitempty"`
157193
MaxPrintTemp uint16 `json:"maxPrintTemp,omitempty"`
194+
MinBedTemp uint16 `json:"minBedTemp,omitempty"`
195+
MaxBedTemp uint16 `json:"maxBedTemp,omitempty"`
158196

159197
// Dates
160198
ManufacturedDate uint32 `json:"manufacturedDate,omitempty"`
@@ -197,11 +235,16 @@ func (o *OpenPrintTag) ToResponse() *Response {
197235
MaterialClass: materialClassToString(o.Main.MaterialClass),
198236
MaterialType: materialTypeToString(o.Main.MaterialType),
199237
NominalWeight: o.Main.NominalNettoFullWeight,
238+
ActualWeight: o.Main.ActualNettoFullWeight,
239+
SpoolWeight: o.Main.EmptyContainerWeight,
200240
ConsumedWeight: o.Aux.ConsumedWeight,
201241
FilamentDiameter: o.Main.FilamentDiameter,
242+
FilamentLength: o.Main.ActualFullLength,
202243
Density: o.Main.Density,
203244
MinPrintTemp: o.Main.MinPrintTemp,
204245
MaxPrintTemp: o.Main.MaxPrintTemp,
246+
MinBedTemp: o.Main.MinBedTemp,
247+
MaxBedTemp: o.Main.MaxBedTemp,
205248
ManufacturedDate: o.Main.ManufacturedDate,
206249
ExpirationDate: o.Main.ExpirationDate,
207250
Workgroup: o.Aux.Workgroup,

0 commit comments

Comments
 (0)