Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 31 additions & 31 deletions .secrets.baseline
Original file line number Diff line number Diff line change
Expand Up @@ -1421,239 +1421,239 @@
"filename": "pkg/decoder/tagxl/v1/decoder_test.go",
"hashed_secret": "32179884041e9ddc27e1c5e0e45ccc6e81637d65",
"is_verified": false,
"line_number": 331,
"line_number": 366,
"is_secret": false
},
{
"type": "Hex High Entropy String",
"filename": "pkg/decoder/tagxl/v1/decoder_test.go",
"hashed_secret": "10e8fe5b6a5342c5ead45cffec2d001a28e0c1bb",
"is_verified": false,
"line_number": 344,
"line_number": 379,
"is_secret": false
},
{
"type": "Hex High Entropy String",
"filename": "pkg/decoder/tagxl/v1/decoder_test.go",
"hashed_secret": "b0771e36dfb55414a423ca9c0ceb087b03ea3cfc",
"is_verified": false,
"line_number": 349,
"line_number": 384,
"is_secret": false
},
{
"type": "Hex High Entropy String",
"filename": "pkg/decoder/tagxl/v1/decoder_test.go",
"hashed_secret": "5cbb5bf20d8b56d849c06d5e0474a3cd42e6bc16",
"is_verified": false,
"line_number": 354,
"line_number": 389,
"is_secret": false
},
{
"type": "Hex High Entropy String",
"filename": "pkg/decoder/tagxl/v1/decoder_test.go",
"hashed_secret": "632ee27a7e117b634cb0fb234f7f7d199db5d5d1",
"is_verified": false,
"line_number": 359,
"line_number": 394,
"is_secret": false
},
{
"type": "Hex High Entropy String",
"filename": "pkg/decoder/tagxl/v1/decoder_test.go",
"hashed_secret": "9e1335b0e4c10057a072e6aa67e5cfb9d0e5d324",
"is_verified": false,
"line_number": 364,
"line_number": 399,
"is_secret": false
},
{
"type": "Hex High Entropy String",
"filename": "pkg/decoder/tagxl/v1/decoder_test.go",
"hashed_secret": "55472b68d8a8560add30831739dd3552e63d5b33",
"is_verified": false,
"line_number": 385,
"line_number": 420,
"is_secret": false
},
{
"type": "Hex High Entropy String",
"filename": "pkg/decoder/tagxl/v1/decoder_test.go",
"hashed_secret": "463609dcc13b7b90fcf29ca237191ad5bf977c46",
"is_verified": false,
"line_number": 396,
"line_number": 431,
"is_secret": false
},
{
"type": "Hex High Entropy String",
"filename": "pkg/decoder/tagxl/v1/decoder_test.go",
"hashed_secret": "4c35a80282e5237761aeb3b9b2c8d422b16df653",
"is_verified": false,
"line_number": 408,
"line_number": 443,
"is_secret": false
},
{
"type": "Hex High Entropy String",
"filename": "pkg/decoder/tagxl/v1/decoder_test.go",
"hashed_secret": "5bcf7c2f08e382a84f0a78f1c6aa91f711806aa8",
"is_verified": false,
"line_number": 421,
"line_number": 456,
"is_secret": false
},
{
"type": "Hex High Entropy String",
"filename": "pkg/decoder/tagxl/v1/decoder_test.go",
"hashed_secret": "0560cb6af09786d2305b91018ca587c93c0d7dbd",
"is_verified": false,
"line_number": 435,
"line_number": 470,
"is_secret": false
},
{
"type": "Hex High Entropy String",
"filename": "pkg/decoder/tagxl/v1/decoder_test.go",
"hashed_secret": "66cd8eba7181b16377a615d793be286a3aacb087",
"is_verified": false,
"line_number": 445,
"line_number": 480,
"is_secret": false
},
{
"type": "Hex High Entropy String",
"filename": "pkg/decoder/tagxl/v1/decoder_test.go",
"hashed_secret": "a6c92fb0cd83e9a6f6f2bd5bfdb1a297dfe7a502",
"is_verified": false,
"line_number": 457,
"line_number": 492,
"is_secret": false
},
{
"type": "Hex High Entropy String",
"filename": "pkg/decoder/tagxl/v1/decoder_test.go",
"hashed_secret": "c0e35b955de71e6fe09016adf1216ed73f1d7a8b",
"is_verified": false,
"line_number": 471,
"line_number": 506,
"is_secret": false
},
{
"type": "Hex High Entropy String",
"filename": "pkg/decoder/tagxl/v1/decoder_test.go",
"hashed_secret": "5a0861255e90d61193afbc62ee5b7924739d1b54",
"is_verified": false,
"line_number": 487,
"line_number": 522,
"is_secret": false
},
{
"type": "Hex High Entropy String",
"filename": "pkg/decoder/tagxl/v1/decoder_test.go",
"hashed_secret": "1aa68aee442b8b1c5c9fdca3fc2e18ed2f84a637",
"is_verified": false,
"line_number": 505,
"line_number": 540,
"is_secret": false
},
{
"type": "Hex High Entropy String",
"filename": "pkg/decoder/tagxl/v1/decoder_test.go",
"hashed_secret": "bb265a97223c679953c85c60d61907ee7683468e",
"is_verified": false,
"line_number": 659,
"line_number": 694,
"is_secret": false
},
{
"type": "Hex High Entropy String",
"filename": "pkg/decoder/tagxl/v1/decoder_test.go",
"hashed_secret": "4df89cb03f258ca60c13bf53e3442d60826bacf7",
"is_verified": false,
"line_number": 665,
"line_number": 700,
"is_secret": false
},
{
"type": "Hex High Entropy String",
"filename": "pkg/decoder/tagxl/v1/decoder_test.go",
"hashed_secret": "f5188ea01f60dd0e30b8ff8126123c81f38ba425",
"is_verified": false,
"line_number": 676,
"line_number": 711,
"is_secret": false
},
{
"type": "Hex High Entropy String",
"filename": "pkg/decoder/tagxl/v1/decoder_test.go",
"hashed_secret": "164c11e5bb3bdbb53a3682942846936da8006274",
"is_verified": false,
"line_number": 688,
"line_number": 723,
"is_secret": false
},
{
"type": "Hex High Entropy String",
"filename": "pkg/decoder/tagxl/v1/decoder_test.go",
"hashed_secret": "39e57284237493c8386cbfebd10364b4f25b86bd",
"is_verified": false,
"line_number": 701,
"line_number": 736,
"is_secret": false
},
{
"type": "Hex High Entropy String",
"filename": "pkg/decoder/tagxl/v1/decoder_test.go",
"hashed_secret": "d4fc2a168f60a698eef5c40e42f7147798791b70",
"is_verified": false,
"line_number": 715,
"line_number": 750,
"is_secret": false
},
{
"type": "Hex High Entropy String",
"filename": "pkg/decoder/tagxl/v1/decoder_test.go",
"hashed_secret": "0c24951224219592f4f044aa8c1a43cd87d14bae",
"is_verified": false,
"line_number": 730,
"line_number": 765,
"is_secret": false
},
{
"type": "Hex High Entropy String",
"filename": "pkg/decoder/tagxl/v1/decoder_test.go",
"hashed_secret": "67dfa780930cf12323bf6d3a2737f8be7168d2e7",
"is_verified": false,
"line_number": 741,
"line_number": 776,
"is_secret": false
},
{
"type": "Hex High Entropy String",
"filename": "pkg/decoder/tagxl/v1/decoder_test.go",
"hashed_secret": "b821604371f934e1ce969c042520adc0f69859bf",
"is_verified": false,
"line_number": 754,
"line_number": 789,
"is_secret": false
},
{
"type": "Hex High Entropy String",
"filename": "pkg/decoder/tagxl/v1/decoder_test.go",
"hashed_secret": "737544481bcf878548b5d3cef6898ebaaa307e35",
"is_verified": false,
"line_number": 769,
"line_number": 804,
"is_secret": false
},
{
"type": "Hex High Entropy String",
"filename": "pkg/decoder/tagxl/v1/decoder_test.go",
"hashed_secret": "56bdd17763f2ca6b25584e70ca4888acd267da77",
"is_verified": false,
"line_number": 786,
"line_number": 821,
"is_secret": false
},
{
"type": "Hex High Entropy String",
"filename": "pkg/decoder/tagxl/v1/decoder_test.go",
"hashed_secret": "56f27e2c927e138a36b3cb7d07b942da7667b8f2",
"is_verified": false,
"line_number": 811,
"line_number": 846,
"is_secret": false
},
{
"type": "Hex High Entropy String",
"filename": "pkg/decoder/tagxl/v1/decoder_test.go",
"hashed_secret": "516dead2735f9bcd1eced3f678aa6dbb0ed87c86",
"is_verified": false,
"line_number": 1045,
"line_number": 1080,
"is_secret": false
},
{
"type": "Hex High Entropy String",
"filename": "pkg/decoder/tagxl/v1/decoder_test.go",
"hashed_secret": "884f72cf02528dcd37a031e2af8575273d4394e2",
"is_verified": false,
"line_number": 1228,
"line_number": 1263,
"is_secret": false
}
],
Expand Down Expand Up @@ -2228,5 +2228,5 @@
}
]
},
"generated_at": "2025-09-24T19:16:14Z"
"generated_at": "2026-01-01T19:55:45Z"
}
5 changes: 5 additions & 0 deletions pkg/common/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,11 @@ func TimePointer(timestamp float64) *time.Time {
return &time
}

// DataRatePtr is a generic helper to create a pointer to any DataRate value.
func DataRatePtr[T any](value T) *T {
return &value
}

func TimePointerCompare(alpha *time.Time, bravo *time.Time) bool {
if alpha == nil && bravo == nil {
return true
Expand Down
12 changes: 12 additions & 0 deletions pkg/decoder/data_rate.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,15 @@ const DataRateGlacial DataRate = "glacial"

const DataRateAutomaticNarrow DataRate = "automatic-narrow"
const DataRateAutomaticWide DataRate = "automatic-wide"

const DataRateUnknown DataRate = "unknown"

// TagXL specific data rates
const DataRateTagXLDR5 DataRate = "dr5-sf7" // 0: DR5 (EU868 SF7)
const DataRateTagXLDR4 DataRate = "dr4-sf8" // 1: DR4 (EU868 SF8)
const DataRateTagXLDR3 DataRate = "dr3-sf9" // 2: DR3 (EU868 SF9, US915 SF7)
const DataRateTagXLDR2 DataRate = "dr2-sf10" // 3: DR2 (EU868 SF10, US915 SF8)
const DataRateTagXLDR1 DataRate = "dr1-sf11" // 4: DR1 (EU868 SF11, US915 SF9)
const DataRateTagXLDR0 DataRate = "dr0-sf12" // 5: DR0 (EU868 SF12)
const DataRateTagXLDR1To3 DataRate = "dr1-3-array" // 6: DR1-3 array (EU868 SF9-11, US915 SF7-9)
const DataRateTagXLADR DataRate = "adr" // 7: ADR (SF7-12) for EU868
1 change: 1 addition & 0 deletions pkg/decoder/decoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ const (
FeatureHardwareVersion Feature = "hardwareVersion"
FeatureRotationState Feature = "rotationState"
FeatureSequenceNumber Feature = "sequenceNumber"
FeatureDataRate Feature = "dataRate"
)

type DecodedUplink struct {
Expand Down
8 changes: 7 additions & 1 deletion pkg/decoder/tagxl/v1/decoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,9 +136,15 @@ func (t TagXLv1Decoder) getConfig(port uint8, payload []byte) (common.PayloadCon
{Name: "WifiScans", Tag: 0x4b, Optional: true, Transform: func(v any) any {
return uint16(common.BytesToUint32(v.([]byte)) & 0xffff)
}},
{Name: "DataRate", Tag: 0x4e, Optional: true, Transform: func(v any) any {
if b, ok := v.([]byte); ok && len(b) > 0 {
return DataRateFromUint8(b[0])
}
return nil
}},
},
TargetType: reflect.TypeOf(Port151Payload{}),
Features: []decoder.Feature{},
Features: []decoder.Feature{decoder.FeatureDataRate},
}, nil
case 152:
if len(payload) < 1 {
Expand Down
35 changes: 35 additions & 0 deletions pkg/decoder/tagxl/v1/decoder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,41 @@ func TestDecode(t *testing.T) {
ResetCount: helpers.Uint16Ptr(3),
},
},
{
port: 151,
payload: "4c04014e0107",
expected: Port151Payload{
DataRate: helpers.DataRatePtr(decoder.DataRateTagXLADR), // 7: ADR (SF7-12) for EU868
},
},
{
port: 151,
payload: "4c04014e0100",
expected: Port151Payload{
DataRate: helpers.DataRatePtr(decoder.DataRateTagXLDR5), // 0: DR5 (EU868 SF7)
},
},
{
port: 151,
payload: "4c04014e0103",
expected: Port151Payload{
DataRate: helpers.DataRatePtr(decoder.DataRateTagXLDR2), // 3: DR2 (EU868 SF10, US915 SF8)
},
},
{
port: 151,
payload: "4c04014e0105",
expected: Port151Payload{
DataRate: helpers.DataRatePtr(decoder.DataRateTagXLDR0), // 5: DR0 (EU868 SF12)
},
},
{
port: 151,
payload: "4c0401", // No DataRate field
expected: Port151Payload{
DataRate: nil,
},
},
{
port: 152,
payload: "ff",
Expand Down
Loading
Loading