Files
s1d3sw1ped b38f7f643b Add bambu-nfc dump parse, Key-A HKDF, and spool merge.
Parse filanfc-dump/v1 zip/JSON, Bambu 1K images, and merge stickers by tray UID. dump and mifare packages stay importable for a later common library.
2026-08-23 15:23:11 -05:00

108 lines
2.3 KiB
Go

package bambunfc
import (
"fmt"
"slices"
)
// Spool is one physical filament roll (both stickers merged).
type Spool struct {
Brand string
TrayUID string
ChipUIDs []string
Type string
Material string
MaterialID string
VariantID string
Color Color
WeightG int
DiameterMM float32
LengthM int
MinHotendC int
MaxHotendC int
BedC int
DryC int
DryHours int
Produced string
SpoolWidthRaw uint16
}
func spoolKey(t Tag) string {
return t.Brand + "\x00" + t.TrayUID
}
func sameFilament(a, b Tag) bool {
return a.Type == b.Type &&
a.Material == b.Material &&
a.Color == b.Color &&
a.WeightG == b.WeightG
}
func tagToSpool(t Tag) Spool {
return Spool{
Brand: t.Brand,
TrayUID: t.TrayUID,
ChipUIDs: []string{t.ChipUID},
Type: t.Type,
Material: t.Material,
MaterialID: t.MaterialID,
VariantID: t.VariantID,
Color: t.Color,
WeightG: t.WeightG,
DiameterMM: t.DiameterMM,
LengthM: t.LengthM,
MinHotendC: t.MinHotendC,
MaxHotendC: t.MaxHotendC,
BedC: t.BedC,
DryC: t.DryC,
DryHours: t.DryHours,
Produced: t.Produced,
SpoolWidthRaw: t.SpoolWidthRaw,
}
}
// Merge groups tags by brand + tray UID into spools.
func Merge(tags []Tag) ([]Spool, error) {
order := make([]string, 0)
groups := make(map[string][]Tag)
for _, t := range tags {
if t.TrayUID == "" {
return nil, fmt.Errorf("%w: empty tray uid chip %s", ErrIncomplete, t.ChipUID)
}
k := spoolKey(t)
if _, ok := groups[k]; !ok {
order = append(order, k)
}
groups[k] = append(groups[k], t)
}
spools := make([]Spool, 0, len(order))
for _, k := range order {
g := groups[k]
s := tagToSpool(g[0])
uids := map[string]struct{}{g[0].ChipUID: {}}
for _, t := range g[1:] {
if !sameFilament(g[0], t) {
return nil, fmt.Errorf("%w: tray %s", ErrConflict, t.TrayUID)
}
uids[t.ChipUID] = struct{}{}
}
s.ChipUIDs = make([]string, 0, len(uids))
for u := range uids {
s.ChipUIDs = append(s.ChipUIDs, u)
}
slices.Sort(s.ChipUIDs)
spools = append(spools, s)
}
slices.SortFunc(spools, func(a, b Spool) int {
if a.TrayUID < b.TrayUID {
return -1
}
if a.TrayUID > b.TrayUID {
return 1
}
return 0
})
return spools, nil
}