b67b37dc59
Drop zip/JSON from the root API. dump remains an adapter for the Android app format; inventory and an AMS wand both call Parse(uid, image).
110 lines
2.6 KiB
Go
110 lines
2.6 KiB
Go
package bambunfc
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/binary"
|
|
"encoding/hex"
|
|
"fmt"
|
|
"math"
|
|
|
|
"git.s1d3sw1ped.com/s1d3sw1ped/bambu-nfc/mifare"
|
|
)
|
|
|
|
const BrandBambuLab = "Bambu Lab"
|
|
|
|
// Tag is one Bambu sticker parsed from a raw MIFARE Classic 1K image.
|
|
type Tag struct {
|
|
Brand string
|
|
ChipUID string // lowercase hex of the ISO UID
|
|
TrayUID string // 32 lowercase hex chars (block 9)
|
|
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 block(image []byte, n int) []byte {
|
|
off := n * mifare.BlockSize
|
|
return image[off : off+mifare.BlockSize]
|
|
}
|
|
|
|
func cstr(b []byte) string {
|
|
if i := bytes.IndexByte(b, 0); i >= 0 {
|
|
b = b[:i]
|
|
}
|
|
return string(b)
|
|
}
|
|
|
|
func allZero(b []byte) bool {
|
|
for _, v := range b {
|
|
if v != 0 {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
// Parse reads a Bambu tag from raw NFC: ISO chip UID and the 1024-byte Classic 1K image.
|
|
func Parse(uid, image []byte) (Tag, error) {
|
|
var zero Tag
|
|
if len(uid) == 0 {
|
|
return zero, fmt.Errorf("%w: empty", ErrUID)
|
|
}
|
|
if len(image) != mifare.Size1K {
|
|
return zero, fmt.Errorf("%w: want %d got %d", ErrImageSize, mifare.Size1K, len(image))
|
|
}
|
|
|
|
b1 := block(image, 1)
|
|
b2 := block(image, 2)
|
|
b4 := block(image, 4)
|
|
b5 := block(image, 5)
|
|
b6 := block(image, 6)
|
|
b9 := block(image, 9)
|
|
b10 := block(image, 10)
|
|
b12 := block(image, 12)
|
|
b14 := block(image, 14)
|
|
|
|
material := cstr(b2)
|
|
typ := cstr(b4)
|
|
if material == "" && typ == "" {
|
|
return zero, ErrNotBambu
|
|
}
|
|
if allZero(b9) {
|
|
return zero, fmt.Errorf("%w: tray uid", ErrIncomplete)
|
|
}
|
|
|
|
return Tag{
|
|
Brand: BrandBambuLab,
|
|
ChipUID: hex.EncodeToString(uid),
|
|
VariantID: cstr(b1[0:8]),
|
|
MaterialID: cstr(b1[8:16]),
|
|
Material: material,
|
|
Type: typ,
|
|
Color: Color{
|
|
R: b5[0], G: b5[1], B: b5[2], A: b5[3],
|
|
},
|
|
WeightG: int(binary.LittleEndian.Uint16(b5[4:6])),
|
|
DiameterMM: math.Float32frombits(binary.LittleEndian.Uint32(b5[8:12])),
|
|
TrayUID: hex.EncodeToString(b9),
|
|
DryC: int(binary.LittleEndian.Uint16(b6[0:2])),
|
|
DryHours: int(binary.LittleEndian.Uint16(b6[2:4])),
|
|
BedC: int(binary.LittleEndian.Uint16(b6[6:8])),
|
|
MaxHotendC: int(binary.LittleEndian.Uint16(b6[8:10])),
|
|
MinHotendC: int(binary.LittleEndian.Uint16(b6[10:12])),
|
|
SpoolWidthRaw: binary.LittleEndian.Uint16(b10[4:6]),
|
|
Produced: cstr(b12),
|
|
LengthM: int(binary.LittleEndian.Uint16(b14[4:6])),
|
|
}, nil
|
|
}
|