Skip to content
Draft
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
5 changes: 4 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -68,4 +68,7 @@ check-metrics:
echo "✅ All Prometheus metrics are correctly prefixed."; \
fi

.PHONY: check-coverage check-json-tags check-metrics
test:
go test ./...

.PHONY: check-coverage check-json-tags check-metrics test
2 changes: 1 addition & 1 deletion pkg/decoder/decoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -190,5 +190,5 @@ type UplinkFeatureRotationState interface {
}

type UplinkFeatureSequenceNumber interface {
GetSequenceNumber() uint
GetSequenceNumber() *uint16
}
2 changes: 1 addition & 1 deletion pkg/decoder/decoder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,4 +175,4 @@ func (*dummyRotationState) GetDuration() time.Duration { return 0 }

type dummySequenceNumber struct{}

func (*dummySequenceNumber) GetSequenceNumber() uint { return 0 }
func (*dummySequenceNumber) GetSequenceNumber() *uint16 { return nil }
55 changes: 55 additions & 0 deletions pkg/decoder/smartlabel/v2/port180.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package smartlabel

import (
"time"

"github.com/truvami/decoder/pkg/decoder"
)

// +------+------+-------------------------------------------+------------------------+
// | Byte | Size | Description | Format |
// +------+------+-------------------------------------------+------------------------+
// | 0 | 1 | EOG (End of group) | uint1 |
// | | | RFU (Reserved for future use) | uint2 |
// | | | GRP_TOKEN (Group token) | uint5 |
// | 1 | n | U-GNSSLOC-NAV message(s) | |
// +------+------+-------------------------------------------+------------------------+

type Port180Payload struct {
EndOfGroup bool `json:"endOfGroup"`
GroupToken uint8 `json:"groupToken" validate:"gte=2, lte=31"`
NavMessage []byte `json:"navMessage"`
Latitude float64 `json:"latitude" validate:"gte=-90,lte=90"`
Longitude float64 `json:"longitude" validate:"gte=-180,lte=180"`
Altitude float64 `json:"altitude"`
}

var _ decoder.UplinkFeatureGNSS = &Port180Payload{}

func (p Port180Payload) GetLatitude() float64 {
return p.Latitude
}

func (p Port180Payload) GetLongitude() float64 {
return p.Longitude
}

func (p Port180Payload) GetAltitude() float64 {
return p.Altitude
}

func (p Port180Payload) GetAccuracy() *float64 {
return nil
}

func (p Port180Payload) GetTTF() *time.Duration {
return nil
}

func (p Port180Payload) GetPDOP() *float64 {
return nil
}

func (p Port180Payload) GetSatellites() *uint8 {
return nil
}
59 changes: 59 additions & 0 deletions pkg/decoder/smartlabel/v2/port180_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package smartlabel

import (
"testing"
"time"
)

func TestPort180Payload_GNSSMethods(t *testing.T) {
t.Parallel()

p := Port180Payload{
EndOfGroup: true,
GroupToken: 10,
NavMessage: []byte{0x01, 0x02, 0x03},
Latitude: 47.3769,
Longitude: 8.5417,
Altitude: 500.0,
}

if got := p.GetLatitude(); got != p.Latitude {
t.Fatalf("GetLatitude() = %v, want %v", got, p.Latitude)
}
if got := p.GetLongitude(); got != p.Longitude {
t.Fatalf("GetLongitude() = %v, want %v", got, p.Longitude)
}
if got := p.GetAltitude(); got != p.Altitude {
t.Fatalf("GetAltitude() = %v, want %v", got, p.Altitude)
}
if got := p.GetAccuracy(); got != nil {
t.Fatalf("GetAccuracy() = %v, want nil", got)
}
if got := p.GetTTF(); got != nil {
t.Fatalf("GetTTF() = %v, want nil", got)
}
if got := p.GetPDOP(); got != nil {
t.Fatalf("GetPDOP() = %v, want nil", got)
}
if got := p.GetSatellites(); got != nil {
t.Fatalf("GetSatellites() = %v, want nil", got)
}
}

// Compile-time like assertion helpers (executed to ensure method signatures remain compatible).
func TestPort180Payload_InterfaceSatisfaction(t *testing.T) {
t.Parallel()

var _ = func() any {
var _ interface {
GetLatitude() float64
GetLongitude() float64
GetAltitude() float64
GetAccuracy() *float64
GetTTF() *time.Duration
GetPDOP() *float64
GetSatellites() *uint8
} = Port180Payload{}
return nil
}()
}
175 changes: 175 additions & 0 deletions pkg/decoder/smartlabel/v2/port190.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
package smartlabel

import (
"time"

"github.com/truvami/decoder/pkg/decoder"
)

// Moving / Steady
// +------+------+-----------------------------------------------+------------+
// | Byte | Size | Description | Format |
// +------+------+-----------------------------------------------+------------+
// | 0 | 1 | tag (0x10 = moving, 0x18 = steady) | byte |
// | 1 | 1 | rssi signal 1 | int8 |
// | 2 | 6 | mac address signal 1 | byte[6] |
// | 8 | 1 | rssi signal 2 | int8 |
// | 9 | 6 | mac address signal 2 | byte[6] |
// | 15 | 1 | rssi signal 3 | int8 |
// | 16 | 6 | mac address signal 3 | byte[6] |
// | 22 | 1 | rssi signal 4 | int8 |
// | 23 | 6 | mac address signal 4 | byte[6] |
// | 29 | 1 | rssi signal 5 | int8 |
// | 30 | 6 | mac address signal 5 | byte[6] |
// +------+------+-----------------------------------------------+------------+
//
// Moving / Steady with timestamp
// +------+------+-----------------------------------------------+------------+
// | Byte | Size | Description | Format |
// +------+------+-----------------------------------------------+------------+
// | 0 | 1 | tag (0x14 = moving, 0x1C = steady) | byte |
// | 1 | 4 | timestamp | uint32 |
// | 5 | 1 | rssi signal 1 | int8 |
// | 6 | 6 | mac address signal 1 | byte[6] |
// | 12 | 1 | rssi signal 2 | int8 |
// | 13 | 6 | mac address signal 2 | byte[6] |
// | 19 | 1 | rssi signal 3 | int8 |
// | 20 | 6 | mac address signal 3 | byte[6] |
// | 26 | 1 | rssi signal 4 | int8 |
// | 27 | 6 | mac address signal 4 | byte[6] |
// | 33 | 1 | rssi signal 5 | int8 |
// | 34 | 6 | mac address signal 5 | byte[6] |
// +------+------+-----------------------------------------------+------------+
//
// Moving / Steady with sequence number
// +------+------+-----------------------------------------------+------------+
// | Byte | Size | Description | Format |
// +------+------+-----------------------------------------------+------------+
// | 0 | 1 | tag (0x80 = moving, 0x88 = steady) | byte |
// | 1 | 2 | sequence number | uint16 |
// | 3 | 1 | rssi signal 1 | int8 |
// | 4 | 6 | mac address signal 1 | byte[6] |
// | 10 | 1 | rssi signal 2 | int8 |
// | 11 | 6 | mac address signal 2 | byte[6] |
// | 17 | 1 | rssi signal 3 | int8 |
// | 18 | 6 | mac address signal 3 | byte[6] |
// | 24 | 1 | rssi signal 4 | int8 |
// | 25 | 6 | mac address signal 4 | byte[6] |
// | 31 | 1 | rssi signal 5 | int8 |
// | 32 | 6 | mac address signal 5 | byte[6] |
// +------+------+-----------------------------------------------+------------+
//
// Moving / Steady with sequence number and timestamp
// +------+------+-----------------------------------------------+------------+
// | Byte | Size | Description | Format |
// +------+------+-----------------------------------------------+------------+
// | 0 | 1 | tag (0x84 = moving, 0x8C = steady) | byte |
// | 1 | 2 | sequence number | uint16 |
// | 3 | 4 | timestamp | uint32 |
// | 7 | 1 | rssi signal 1 | int8 |
// | 8 | 6 | mac address signal 1 | byte[6] |
// | 14 | 1 | rssi signal 2 | int8 |
// | 15 | 6 | mac address signal 2 | byte[6] |
// | 21 | 1 | rssi signal 3 | int8 |
// | 22 | 6 | mac address signal 3 | byte[6] |
// | 28 | 1 | rssi signal 4 | int8 |
// | 29 | 6 | mac address signal 4 | byte[6] |
// | 35 | 1 | rssi signal 5 | int8 |
// | 36 | 6 | mac address signal 5 | byte[6] |
// +------+------+-----------------------------------------------+------------+

const (
Port190Moving = 0x10
Port190MovingTimestamp = 0x14
Port190Steady = 0x18
Port190SteadyTimestamp = 0x1c
Port190SeqMoving = 0x80
Port190SeqMovingTimestamp = 0x84
Port190SeqSteady = 0x88
Port190SeqSteadyTimestamp = 0x8c
)

type Port190Payload struct {
Tag byte `json:"tag" validate:"gte=0,lte=1"`
SequenceNumber *uint16 `json:"sequenceNumber"`
Timestamp *time.Time `json:"timestamp"`
Rssi1 *int8 `json:"rssi1" validate:"gte=-120,lte=-20"`
Mac1 string `json:"mac1"`
Rssi2 *int8 `json:"rssi2" validate:"gte=-120,lte=-20"`
Mac2 *string `json:"mac2"`
Rssi3 *int8 `json:"rssi3" validate:"gte=-120,lte=-20"`
Mac3 *string `json:"mac3"`
Rssi4 *int8 `json:"rssi4" validate:"gte=-120,lte=-20"`
Mac4 *string `json:"mac4"`
Rssi5 *int8 `json:"rssi5" validate:"gte=-120,lte=-20"`
Mac5 *string `json:"mac5"`
}

var _ decoder.UplinkFeatureWiFi = &Port190Payload{}
var _ decoder.UplinkFeatureMoving = &Port190Payload{}
var _ decoder.UplinkFeatureSequenceNumber = &Port190Payload{}
var _ decoder.UplinkFeatureTimestamp = &Port190Payload{}

func (p Port190Payload) GetAccessPoints() []decoder.AccessPoint {
accessPoints := []decoder.AccessPoint{}

if p.Mac1 != "" {
accessPoints = append(accessPoints, decoder.AccessPoint{
MAC: p.Mac1,
RSSI: p.Rssi1,
})
}

if p.Mac2 != nil {
accessPoints = append(accessPoints, decoder.AccessPoint{
MAC: *p.Mac2,
RSSI: p.Rssi2,
})
}

if p.Mac3 != nil {
accessPoints = append(accessPoints, decoder.AccessPoint{
MAC: *p.Mac3,
RSSI: p.Rssi3,
})
}

if p.Mac4 != nil {
accessPoints = append(accessPoints, decoder.AccessPoint{
MAC: *p.Mac4,
RSSI: p.Rssi4,
})
}

if p.Mac5 != nil {
accessPoints = append(accessPoints, decoder.AccessPoint{
MAC: *p.Mac5,
RSSI: p.Rssi5,
})
}

return accessPoints
}

func (p Port190Payload) IsMoving() bool {
switch p.Tag {
case Port190Moving:
return true
case Port190MovingTimestamp:
return true
case Port190SeqMoving:
return true
case Port190SeqMovingTimestamp:
return true
}

return false
}

func (p Port190Payload) GetTimestamp() *time.Time {
return p.Timestamp
}

func (p Port190Payload) GetSequenceNumber() *uint16 {
return p.SequenceNumber
}
5 changes: 3 additions & 2 deletions pkg/decoder/tagxl/v1/port152.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,9 @@ func (p Port152Payload) GetDuration() time.Duration {
return time.Duration(int64(p.ElapsedSeconds)) * time.Second
}

func (p Port152Payload) GetSequenceNumber() uint {
return uint(p.SequenceNumber)
func (p Port152Payload) GetSequenceNumber() *uint16 {
v := uint16(p.SequenceNumber)
return &v
}

func byteToRotationState(b uint8) decoder.RotationState {
Expand Down
Loading