From d0d22facf684f0ed2ea778e615df71a28225eadc Mon Sep 17 00:00:00 2001 From: laoboli <1293528695@qq.com> Date: Wed, 8 Jul 2026 15:31:58 +0800 Subject: [PATCH] feat: mqtt v3 --- controllers/system_debug.go | 116 ++ main.go | 1 + mqtt/debug_service_v3.go | 797 +++++++++++++ proto/v3/hr_packet_v3.pb.go | 2120 +++++++++++++++++++++++++++++++++++ proto/v3/hr_packet_v3.proto | 193 ++++ routes/routes.go | 4 + 6 files changed, 3231 insertions(+) create mode 100644 mqtt/debug_service_v3.go create mode 100644 proto/v3/hr_packet_v3.pb.go create mode 100644 proto/v3/hr_packet_v3.proto diff --git a/controllers/system_debug.go b/controllers/system_debug.go index 050f4a5..f5abe62 100644 --- a/controllers/system_debug.go +++ b/controllers/system_debug.go @@ -96,6 +96,66 @@ func (sc *SystemDebugController) StopMqtt(c *gin.Context) { writeSuccess(c, http.StatusOK, "stop success", service.Status()) } +// @Summary 获取MQTT V3调试状态 +// @Description 获取MQTT V3调试服务的当前运行状态 +// @Tags 系统调试 +// @Produce json +// @Security BearerAuth +// @Success 200 {object} SwagAPIResponse "查询成功" +// @Router /admin/system-debug/mqtt-v3/status [get] +func (sc *SystemDebugController) MqttV3Status(c *gin.Context) { + service := mqtt.GetDebugV3Service() + if service == nil { + writeError(c, http.StatusServiceUnavailable, "mqtt v3 debug service unavailable") + return + } + writeSuccess(c, http.StatusOK, "query success", service.Status()) +} + +// @Summary 启动MQTT V3调试 +// @Description 启动MQTT V3调试服务 +// @Tags 系统调试 +// @Accept json +// @Produce json +// @Param persist body mqttDebugStartRequest false "是否持久化到数据库" +// @Security BearerAuth +// @Success 200 {object} SwagAPIResponse "启动成功" +// @Router /admin/system-debug/mqtt-v3/start [post] +func (sc *SystemDebugController) StartMqttV3(c *gin.Context) { + service := mqtt.GetDebugV3Service() + if service == nil { + writeError(c, http.StatusServiceUnavailable, "mqtt v3 debug service unavailable") + return + } + var payload mqttDebugStartRequest + if err := c.ShouldBindJSON(&payload); err != nil && !errors.Is(err, http.ErrBodyNotAllowed) { + writeError(c, http.StatusBadRequest, err.Error()) + return + } + if err := service.Start(payload.PersistToDatabase); err != nil { + writeError(c, http.StatusInternalServerError, err.Error()) + return + } + writeSuccess(c, http.StatusOK, "start success", service.Status()) +} + +// @Summary 停止MQTT V3调试 +// @Description 停止MQTT V3调试服务 +// @Tags 系统调试 +// @Produce json +// @Security BearerAuth +// @Success 200 {object} SwagAPIResponse "停止成功" +// @Router /admin/system-debug/mqtt-v3/stop [post] +func (sc *SystemDebugController) StopMqttV3(c *gin.Context) { + service := mqtt.GetDebugV3Service() + if service == nil { + writeError(c, http.StatusServiceUnavailable, "mqtt v3 debug service unavailable") + return + } + service.Stop() + writeSuccess(c, http.StatusOK, "stop success", service.Status()) +} + // @Summary 获取MQTT重放状态 // @Description 获取心率历史数据 MQTT 重放状态 // @Tags 系统调试 @@ -215,3 +275,59 @@ func (sc *SystemDebugController) MqttWebSocket(c *gin.Context) { } } } + +// @Summary MQTT V3 WebSocket连接 +// @Description 通过WebSocket实时监听MQTT V3消息(需要SuperAdmin权限) +// @Tags 系统调试 +// @Param token query string true "JWT Token" +// @Success 101 "切换为WebSocket协议" +// @Router /admin/system-debug/mqtt-v3/ws [get] +func (sc *SystemDebugController) MqttV3WebSocket(c *gin.Context) { + service := mqtt.GetDebugV3Service() + if service == nil { + c.JSON(http.StatusServiceUnavailable, gin.H{"error": "mqtt v3 debug service unavailable"}) + return + } + + token := strings.TrimSpace(c.Query("token")) + if token == "" { + c.JSON(http.StatusUnauthorized, gin.H{"error": "missing token"}) + return + } + claims, err := util.ParseToken(token) + if err != nil { + c.JSON(http.StatusUnauthorized, gin.H{"error": "invalid token"}) + return + } + + var user models.User + if err := config.DB.First(&user, claims.UserID).Error; err != nil { + c.JSON(http.StatusUnauthorized, gin.H{"error": "user not found"}) + return + } + if !user.IsActive { + c.JSON(http.StatusForbidden, gin.H{"error": "user is disabled"}) + return + } + if util.IsTokenRevoked(&user, claims) { + c.JSON(http.StatusUnauthorized, gin.H{"error": "token has been revoked"}) + return + } + if user.Role != models.UserRoleSuperAdmin { + c.JSON(http.StatusForbidden, gin.H{"error": "super admin required"}) + return + } + + conn, err := debugUpgrader.Upgrade(c.Writer, c.Request, nil) + if err != nil { + return + } + service.AddSubscriber(conn) + defer service.RemoveSubscriber(conn) + + for { + if _, _, err := conn.ReadMessage(); err != nil { + break + } + } +} diff --git a/main.go b/main.go index 4899cca..88b8cbf 100644 --- a/main.go +++ b/main.go @@ -87,6 +87,7 @@ func main() { log.Printf("mqtt listener start failed: %v", err) } mqtt.InitDebugService(config.DB, config.App.MQTT) + mqtt.InitDebugV3Service(config.DB, config.App.MQTT) mqtt.InitReplayService(config.DB, config.App.MQTT) controllers.StartLessonPlanCleanupJob(config.DB) controllers.StartMqttMeasurementCleanupJob(config.DB) diff --git a/mqtt/debug_service_v3.go b/mqtt/debug_service_v3.go new file mode 100644 index 0000000..2bdf8e9 --- /dev/null +++ b/mqtt/debug_service_v3.go @@ -0,0 +1,797 @@ +package mqtt + +import ( + "crypto/tls" + "encoding/binary" + "encoding/hex" + "encoding/json" + "fmt" + "hr_receiver/config" + "hr_receiver/models" + whgwv3pb "hr_receiver/proto/v3" + "log" + "strings" + "sync" + "time" + + mqtt "github.com/eclipse/paho.mqtt.golang" + "github.com/gorilla/websocket" + "google.golang.org/protobuf/proto" + "gorm.io/gorm" + "gorm.io/gorm/clause" +) + +const ( + wearableSampleEncodingCompactV1 = 1 + wearableUlHasHr = 1 << 0 + wearableUlHasStep = 1 << 1 + wearableRecordHasTimingError = 1 << 2 + wearableRecordReservedMask = 1 << 3 + wearableUlBatteryShift = 4 + wearableHrConfMask = 0x03 + wearableHrActive = 1 << 2 + wearableHrOnSkin = 1 << 3 + wearableHrReservedMask = 0xF0 +) + +type DebugV3Status struct { + Active bool `json:"active"` + ClientConnected bool `json:"clientConnected"` + PersistToDatabase bool `json:"persistToDatabase"` + Region string `json:"region"` + SubscriberCount int `json:"subscriberCount"` +} + +type DebugV3GatewayStatusRecord struct { + Identifier string `json:"identifier"` + Topic string `json:"topic"` + ProtocolVersion int `json:"protocolVersion"` + RegionID uint32 `json:"regionId"` + GatewayMAC string `json:"gatewayMac"` + GatewayIPv4Addr string `json:"gatewayIpv4Addr"` + GatewayActiveUplink int32 `json:"gatewayActiveUplink"` + GatewayCellularIMEI string `json:"gatewayCellularImei"` + GatewayCellularRSSI int32 `json:"gatewayCellularRssi"` + GatewayCellularBER int32 `json:"gatewayCellularBer"` + BootCount uint32 `json:"bootCount"` + UptimeMs uint32 `json:"uptimeMs"` + DurationMsSinceLastPacket uint32 `json:"durationMsSinceLastPacket"` + RxCount uint32 `json:"rxCount"` + BatteryVoltageMV uint32 `json:"batteryVoltageMv"` + BatterySOCPercentage uint32 `json:"batterySocPercentage"` + ChargingRatePercentage int32 `json:"chargingRatePercentage"` + ReceivedAt int64 `json:"receivedAt"` +} + +type DebugV3WearableSampleRecord struct { + Identifier string `json:"identifier"` + Topic string `json:"topic"` + ProtocolVersion int `json:"protocolVersion"` + RegionID uint32 `json:"regionId"` + GatewayMAC string `json:"gatewayMac"` + GatewayIPv4Addr string `json:"gatewayIpv4Addr"` + GatewayActiveUplink int32 `json:"gatewayActiveUplink"` + GatewayCellularIMEI string `json:"gatewayCellularImei"` + GatewayCellularRSSI int32 `json:"gatewayCellularRssi"` + GatewayCellularBER int32 `json:"gatewayCellularBer"` + ReportSeq uint32 `json:"reportSeq"` + FrameID uint32 `json:"frameId"` + FrameUnixTimeUs uint64 `json:"frameUnixTimeUs"` + RadioSubDevID uint32 `json:"radioSubDevId"` + RfFrequencyHz uint32 `json:"rfFrequencyHz"` + SampleEncoding uint32 `json:"sampleEncoding"` + SampleCount uint32 `json:"sampleCount"` + SampleIndex int `json:"sampleIndex"` + NodeID uint32 `json:"nodeId"` + BeltAddr string `json:"beltAddr"` + Flags uint32 `json:"flags"` + Battery uint32 `json:"battery"` + HasTimingError bool `json:"hasTimingError"` + TimingErrorUs int32 `json:"timingErrorUs"` + HasHeartRate bool `json:"hasHeartRate"` + HeartRate uint32 `json:"heartRate"` + HrConfidence int `json:"hrConfidence"` + IsActive bool `json:"isActive"` + IsOnSkin bool `json:"isOnSkin"` + HasStepCount bool `json:"hasStepCount"` + StepCount uint32 `json:"stepCount"` + RssiSyncX2Neg uint32 `json:"rssiSyncX2Neg"` + SignalRSSINeg float64 `json:"signalRssiNeg"` + ReceivedAt int64 `json:"receivedAt"` +} + +type DebugV3RadioFrameRecord struct { + Identifier string `json:"identifier"` + Topic string `json:"topic"` + ProtocolVersion int `json:"protocolVersion"` + Kind string `json:"kind"` + GatewayMAC string `json:"gatewayMac"` + HubBusID uint32 `json:"hubBusId"` + HubSubDevID uint32 `json:"hubSubDevId"` + PacketStatusKind string `json:"packetStatusKind"` + SignalRSSINeg float64 `json:"signalRssiNeg"` + SNR float64 `json:"snr"` + RawSignalRSSIX2Neg uint32 `json:"rawSignalRssiX2Neg"` + RawSnrPktX4 int32 `json:"rawSnrPktX4"` + RawFskRssiSyncX2Neg uint32 `json:"rawFskRssiSyncX2Neg"` + RawFskRssiAvgX2Neg uint32 `json:"rawFskRssiAvgX2Neg"` + HubRadioMode string `json:"hubRadioMode"` + HubRadioBW int32 `json:"hubRadioBw"` + HubRadioSF uint32 `json:"hubRadioSf"` + HubRadioFrequencyMHz float64 `json:"hubRadioFrequencyMHz"` + HubGfskBitrateBps uint32 `json:"hubGfskBitrateBps"` + HubGfskDeviationHz uint32 `json:"hubGfskDeviationHz"` + HubGfskRxBandwidthHz uint32 `json:"hubGfskRxBandwidthHz"` + HubGfskPayloadLength uint32 `json:"hubGfskPayloadLength"` + DataHex string `json:"dataHex"` + DataLength int `json:"dataLength"` + GatewayUptimeMs uint32 `json:"gatewayUptimeMs"` + RxSeq uint32 `json:"rxSeq"` + RxDoneHubUptimeUs uint64 `json:"rxDoneHubUptimeUs"` + IrqToForwardUs uint32 `json:"irqToForwardUs"` + ReceivedAt int64 `json:"receivedAt"` +} + +type DebugV3Event struct { + CardKey string `json:"cardKey"` + Kind string `json:"kind"` + RegionID uint32 `json:"regionId"` + ReceivedAt int64 `json:"receivedAt"` + Topic string `json:"topic"` + GatewayStatus *DebugV3GatewayStatusRecord `json:"gatewayStatus,omitempty"` + WearableHealthSample *DebugV3WearableSampleRecord `json:"wearableHealthSample,omitempty"` + RadioNodeGeneralRsp *DebugV3RadioFrameRecord `json:"radioNodeGeneralRsp,omitempty"` + RadioUnrecognizedFrame *DebugV3RadioFrameRecord `json:"radioUnrecognizedFrame,omitempty"` +} + +type packetStatusSnapshotV3 struct { + kind string + signalRSSINeg float64 + snr float64 + rawSignalRSSIX2Neg uint32 + rawSnrPktX4 int32 + rawFskRssiSyncX2Neg uint32 + rawFskRssiAvgX2Neg uint32 +} + +type radioParametersSnapshotV3 struct { + mode string + loraBw int32 + loraSf uint32 + loraFrequencyMHz float64 + gfskBitrateBps uint32 + gfskFrequencyMHz float64 + gfskDeviationHz uint32 + gfskRxBandwidthHz uint32 + gfskPayloadLength uint32 +} + +type DebugV3Service struct { + cfg config.MQTTConfig + client mqtt.Client + db *gorm.DB + mu sync.RWMutex + persistToDatabase bool + subscribers map[*websocket.Conn]struct{} + active bool +} + +var globalDebugV3Service *DebugV3Service + +func InitDebugV3Service(db *gorm.DB, cfg config.MQTTConfig) { + globalDebugV3Service = &DebugV3Service{ + cfg: cfg, + db: db, + subscribers: make(map[*websocket.Conn]struct{}), + } +} + +func GetDebugV3Service() *DebugV3Service { + return globalDebugV3Service +} + +func (s *DebugV3Service) Status() DebugV3Status { + s.mu.RLock() + defer s.mu.RUnlock() + return DebugV3Status{ + Active: s.active, + ClientConnected: s.client != nil && s.client.IsConnected(), + PersistToDatabase: s.persistToDatabase, + Region: s.cfg.Region, + SubscriberCount: len(s.subscribers), + } +} + +func (s *DebugV3Service) Start(persistToDatabase bool) error { + s.mu.Lock() + defer s.mu.Unlock() + + if s.active && s.client != nil && s.client.IsConnected() { + s.persistToDatabase = persistToDatabase + return nil + } + if err := validateConfig(s.cfg); err != nil { + return err + } + + client, err := s.connectLocked(persistToDatabase) + if err != nil { + return err + } + s.client = client + s.persistToDatabase = persistToDatabase + s.active = true + return nil +} + +func (s *DebugV3Service) Stop() { + s.mu.Lock() + defer s.mu.Unlock() + if s.client != nil && s.client.IsConnected() { + s.client.Disconnect(250) + } + s.client = nil + s.active = false + s.persistToDatabase = false +} + +func (s *DebugV3Service) AddSubscriber(conn *websocket.Conn) { + s.mu.Lock() + s.subscribers[conn] = struct{}{} + s.mu.Unlock() +} + +func (s *DebugV3Service) RemoveSubscriber(conn *websocket.Conn) { + s.mu.Lock() + delete(s.subscribers, conn) + s.mu.Unlock() + _ = conn.Close() +} + +func (s *DebugV3Service) connectLocked(persistToDatabase bool) (mqtt.Client, error) { + opts := mqtt.NewClientOptions() + scheme := "tcp" + if s.cfg.UseTLS { + scheme = "ssl" + opts.SetTLSConfig(&tls.Config{MinVersion: tls.VersionTLS12}) + } + broker := fmt.Sprintf("%s://%s:%d", scheme, s.cfg.Host, s.cfg.Port) + opts.AddBroker(broker) + opts.SetClientID(fmt.Sprintf("%s-debug-v3-%d", s.cfg.ClientIDPrefix, time.Now().UnixNano())) + opts.SetUsername(s.cfg.Username) + opts.SetPassword(s.cfg.Password) + opts.SetKeepAlive(60 * time.Second) + opts.SetAutoReconnect(false) + opts.SetConnectRetry(false) + opts.SetDefaultPublishHandler(s.handleMessage) + opts.SetOnConnectHandler(func(client mqtt.Client) { + if err := s.subscribe(client); err != nil { + log.Printf("mqtt v3 debug subscribe failed: %v", err) + return + } + log.Printf("mqtt v3 debug connected to %s persist=%v", broker, persistToDatabase) + }) + opts.SetConnectionLostHandler(func(client mqtt.Client, err error) { + log.Printf("mqtt v3 debug connection lost: %v", err) + s.mu.Lock() + if s.client == client { + s.client = nil + s.active = false + } + s.mu.Unlock() + }) + + client := mqtt.NewClient(opts) + token := client.Connect() + if !token.WaitTimeout(15 * time.Second) { + return nil, fmt.Errorf("mqtt v3 debug connect timeout") + } + if err := token.Error(); err != nil { + return nil, err + } + return client, nil +} + +func (s *DebugV3Service) subscribe(client mqtt.Client) error { + topics := []string{ + fmt.Sprintf("/whgw/v3/region/%s/gateway/+/telemetry/wearable-health-telemetry", s.cfg.Region), + "/whgw/v3/gateway/+/telemetry/status", + "/whgw/v3/gateway/+/telemetry/radio-node-general-rsp", + "/whgw/v3/gateway/+/telemetry/radio-unrecognized-frame", + } + for _, topic := range topics { + token := client.Subscribe(topic, byte(s.cfg.QoS), s.handleMessage) + if !token.WaitTimeout(10 * time.Second) { + return fmt.Errorf("mqtt v3 debug subscribe timeout for topic %s", topic) + } + if err := token.Error(); err != nil { + return fmt.Errorf("mqtt v3 debug subscribe topic %s: %w", topic, err) + } + log.Printf("mqtt v3 debug subscribed: %s", topic) + } + return nil +} + +func (s *DebugV3Service) handleMessage(_ mqtt.Client, msg mqtt.Message) { + defer func() { + if r := recover(); r != nil { + log.Printf("mqtt v3 debug handle panic topic=%s err=%v", msg.Topic(), r) + } + }() + if len(msg.Payload()) == 0 { + return + } + + now := time.Now().UnixMilli() + if strings.Contains(msg.Topic(), "/telemetry/wearable-health-telemetry") { + s.handleWearableHealthTelemetry(msg.Topic(), msg.Payload(), now) + return + } + + var packet whgwv3pb.GatewayTelemetryMsg + if err := proto.Unmarshal(msg.Payload(), &packet); err != nil { + log.Printf("mqtt v3 debug payload parse failed topic=%s err=%v", msg.Topic(), err) + return + } + + switch payload := packet.Choice.(type) { + case *whgwv3pb.GatewayTelemetryMsg_NtfGatewayStatus: + record := buildGatewayStatusRecordV3(payload.NtfGatewayStatus, msg.Topic(), now) + s.maybePersistGatewayStatus(record) + s.broadcast(DebugV3Event{ + CardKey: fmt.Sprintf("%d-%s", record.RegionID, record.GatewayMAC), + GatewayStatus: &record, + Kind: "gateway_status", + ReceivedAt: now, + RegionID: record.RegionID, + Topic: msg.Topic(), + }) + case *whgwv3pb.GatewayTelemetryMsg_NtfRadioNodeGeneralRsp: + record := buildRadioFrameRecordV3("radio_node_general_rsp", payload.NtfRadioNodeGeneralRsp.GetFrame(), msg.Topic(), now) + s.broadcast(DebugV3Event{ + CardKey: record.Identifier, + Kind: "radio_node_general_rsp", + ReceivedAt: now, + Topic: msg.Topic(), + RadioNodeGeneralRsp: &record, + }) + case *whgwv3pb.GatewayTelemetryMsg_NtfRadioUnrecognizedFrame: + record := buildRadioFrameRecordV3("radio_unrecognized_frame", payload.NtfRadioUnrecognizedFrame, msg.Topic(), now) + s.broadcast(DebugV3Event{ + CardKey: record.Identifier, + Kind: "radio_unrecognized_frame", + ReceivedAt: now, + Topic: msg.Topic(), + RadioUnrecognizedFrame: &record, + }) + default: + log.Printf("mqtt v3 debug payload ignored topic=%s", msg.Topic()) + } +} + +func (s *DebugV3Service) handleWearableHealthTelemetry(topic string, payload []byte, now int64) { + var batch whgwv3pb.WearableHealthTelemetryBatch + if err := proto.Unmarshal(payload, &batch); err != nil { + log.Printf("mqtt v3 wearable batch parse failed topic=%s err=%v", topic, err) + return + } + + samples, err := decodeWearableHealthSamples(&batch, topic, now) + if err != nil { + log.Printf("mqtt v3 wearable batch decode failed topic=%s err=%v", topic, err) + return + } + + for _, sample := range samples { + s.maybePersistWearableSample(sample) + event := DebugV3Event{ + CardKey: fmt.Sprintf("%d-%d", sample.RegionID, sample.NodeID), + Kind: "wearable_health_sample", + ReceivedAt: now, + RegionID: sample.RegionID, + Topic: topic, + WearableHealthSample: &sample, + } + s.broadcast(event) + } +} + +func (s *DebugV3Service) maybePersistWearableSample(sample DebugV3WearableSampleRecord) { + if sample.HasHeartRate { + record := models.MqttHeartRateRecord{ + Identifier: sample.Identifier + ":hr", + Topic: sample.Topic, + RegionID: sample.RegionID, + GatewayMAC: sample.GatewayMAC, + GatewaySchemaVersion: 0, + GatewayActiveUplink: sample.GatewayActiveUplink, + GatewayCellularIMEI: sample.GatewayCellularIMEI, + GatewayCellularRSSI: sample.GatewayCellularRSSI, + GatewayCellularBER: sample.GatewayCellularBER, + BandID: sample.NodeID, + BeltAddr: sample.BeltAddr, + PacketNum: sample.FrameID, + HeartRate: int(sample.HeartRate), + HrConfidence: sample.HrConfidence, + IsActive: sample.IsActive, + IsOnSkin: sample.IsOnSkin, + Battery: sample.Battery, + PacketStatusSource: "wearable_batch_v1", + SignalRSSINeg: sample.SignalRSSINeg, + SNR: 0, + RawSignalRSSIX2Neg: sample.RssiSyncX2Neg, + RawSnrPktX4: 0, + HubBusID: 0, + HubSubDevID: sample.RadioSubDevID, + HubRadioBW: 0, + HubRadioSF: 0, + HubRadioFrequencyMHz: float64(sample.RfFrequencyHz) / 1_000_000, + ReceivedAt: sample.ReceivedAt, + } + s.maybePersist(&record) + } + if sample.HasStepCount { + record := models.MqttStepCountRecord{ + Identifier: sample.Identifier + ":step", + Topic: sample.Topic, + RegionID: sample.RegionID, + GatewayMAC: sample.GatewayMAC, + GatewaySchemaVersion: 0, + GatewayActiveUplink: sample.GatewayActiveUplink, + GatewayCellularIMEI: sample.GatewayCellularIMEI, + GatewayCellularRSSI: sample.GatewayCellularRSSI, + GatewayCellularBER: sample.GatewayCellularBER, + BandID: sample.NodeID, + BeltAddr: sample.BeltAddr, + PacketNum: sample.FrameID, + StepCount: sample.StepCount, + PacketStatusSource: "wearable_batch_v1", + SignalRSSINeg: sample.SignalRSSINeg, + SNR: 0, + RawSignalRSSIX2Neg: sample.RssiSyncX2Neg, + RawSnrPktX4: 0, + HubBusID: 0, + HubSubDevID: sample.RadioSubDevID, + HubRadioBW: 0, + HubRadioSF: 0, + HubRadioFrequencyMHz: float64(sample.RfFrequencyHz) / 1_000_000, + ReceivedAt: sample.ReceivedAt, + } + s.maybePersist(&record) + } +} + +func (s *DebugV3Service) maybePersistGatewayStatus(record DebugV3GatewayStatusRecord) { + modelRecord := models.MqttGatewayStatusRecord{ + Identifier: record.Identifier, + Topic: record.Topic, + RegionID: record.RegionID, + GatewayMAC: record.GatewayMAC, + GatewaySchemaVersion: 0, + GatewayActiveUplink: record.GatewayActiveUplink, + GatewayCellularIMEI: record.GatewayCellularIMEI, + GatewayCellularRSSI: record.GatewayCellularRSSI, + GatewayCellularBER: record.GatewayCellularBER, + BootCount: record.BootCount, + UptimeMs: record.UptimeMs, + DurationMsSinceLastPacket: record.DurationMsSinceLastPacket, + RxCount: record.RxCount, + BatteryVoltageMV: record.BatteryVoltageMV, + BatterySOCPercentage: record.BatterySOCPercentage, + ChargingRatePercentage: record.ChargingRatePercentage, + ReceivedAt: record.ReceivedAt, + } + s.maybePersist(&modelRecord) +} + +func (s *DebugV3Service) maybePersist(record interface{}) { + s.mu.RLock() + enabled := s.persistToDatabase + s.mu.RUnlock() + if !enabled { + return + } + tx := s.db.Clauses(clause.OnConflict{DoNothing: true}).Create(record) + if tx.Error != nil { + log.Printf("mqtt v3 debug persist failed type=%T err=%v", record, tx.Error) + } +} + +func (s *DebugV3Service) broadcast(event DebugV3Event) { + payload, err := json.Marshal(event) + if err != nil { + log.Printf("mqtt v3 debug marshal failed err=%v", err) + return + } + + s.mu.RLock() + conns := make([]*websocket.Conn, 0, len(s.subscribers)) + for conn := range s.subscribers { + conns = append(conns, conn) + } + s.mu.RUnlock() + + for _, conn := range conns { + if err := conn.WriteMessage(websocket.TextMessage, payload); err != nil { + log.Printf("mqtt v3 debug websocket send failed err=%v", err) + s.RemoveSubscriber(conn) + } + } +} + +func decodeWearableHealthSamples(batch *whgwv3pb.WearableHealthTelemetryBatch, topic string, now int64) ([]DebugV3WearableSampleRecord, error) { + if batch.GetSampleEncoding() != wearableSampleEncodingCompactV1 { + return nil, fmt.Errorf("unsupported sample_encoding=%d", batch.GetSampleEncoding()) + } + + gatewayInfo := batch.GetGatewayInfo() + regionID := gatewayInfo.GetRegionId() + if regionID == 0 { + regionID = parseRegionFromTopic(topic) + } + gatewayMAC := formatMAC(gatewayInfo.GetGatewayMac()) + raw := batch.GetSamples() + records := make([]DebugV3WearableSampleRecord, 0, batch.GetSampleCount()) + for offset, sampleIndex := 0, 0; offset < len(raw); sampleIndex++ { + record, consumed, err := parseWearableHealthSample(raw[offset:], gatewayInfo, batch, topic, now, regionID, gatewayMAC, sampleIndex) + if err != nil { + return nil, fmt.Errorf("sample_index=%d offset=%d: %w", sampleIndex, offset, err) + } + offset += consumed + records = append(records, record) + } + return records, nil +} + +func parseWearableHealthSample(raw []byte, gatewayInfo *whgwv3pb.GatewayInfo, batch *whgwv3pb.WearableHealthTelemetryBatch, topic string, now int64, regionID uint32, gatewayMAC string, sampleIndex int) (DebugV3WearableSampleRecord, int, error) { + if len(raw) < 3 { + return DebugV3WearableSampleRecord{}, 0, fmt.Errorf("record too short") + } + + nodeID := raw[0] + flags := raw[1] + rssiSyncX2Neg := raw[2] + if (flags & wearableRecordReservedMask) != 0 { + return DebugV3WearableSampleRecord{}, 0, fmt.Errorf("reserved flags set: 0x%02x", flags) + } + + offset := 3 + timingErrorUs := int16(0) + hasTimingError := (flags & wearableRecordHasTimingError) != 0 + if hasTimingError { + if len(raw) < offset+2 { + return DebugV3WearableSampleRecord{}, 0, fmt.Errorf("timing error field truncated") + } + timingErrorUs = int16(binary.LittleEndian.Uint16(raw[offset : offset+2])) + offset += 2 + } + + hasHr := (flags & wearableUlHasHr) != 0 + hasStep := (flags & wearableUlHasStep) != 0 + hrStatus := byte(0) + hrValue := byte(0) + if hasHr { + if len(raw) < offset+2 { + return DebugV3WearableSampleRecord{}, 0, fmt.Errorf("hr block truncated") + } + hrStatus = raw[offset] + if (hrStatus & wearableHrReservedMask) != 0 { + return DebugV3WearableSampleRecord{}, 0, fmt.Errorf("reserved hr status bits set: 0x%02x", hrStatus) + } + hrValue = raw[offset+1] + offset += 2 + } + + stepValue := uint16(0) + if hasStep { + if len(raw) < offset+2 { + return DebugV3WearableSampleRecord{}, 0, fmt.Errorf("step block truncated") + } + stepValue = binary.LittleEndian.Uint16(raw[offset : offset+2]) + offset += 2 + } + + batteryQ4 := (flags >> wearableUlBatteryShift) & 0x0F + batteryPercent := uint32((uint16(batteryQ4)*100 + 7) / 15) + nodeID32 := uint32(nodeID) + + record := DebugV3WearableSampleRecord{ + Identifier: fmt.Sprintf("v3:wearable:%d:%s:%d:%d:%d", regionID, gatewayMAC, batch.GetFrameId(), nodeID32, sampleIndex), + Topic: topic, + ProtocolVersion: 3, + RegionID: regionID, + GatewayMAC: gatewayMAC, + GatewayIPv4Addr: formatIPv4(gatewayInfo.GetIpv4Addr()), + GatewayActiveUplink: int32(gatewayInfo.GetActiveUplink()), + GatewayCellularIMEI: gatewayInfo.GetCellularModem().GetImei(), + GatewayCellularRSSI: gatewayInfo.GetCellularModem().GetCsqRssi(), + GatewayCellularBER: gatewayInfo.GetCellularModem().GetCsqBer(), + ReportSeq: batch.GetReportSeq(), + FrameID: batch.GetFrameId(), + FrameUnixTimeUs: batch.GetFrameUnixTimeUs(), + RadioSubDevID: batch.GetRadioSubDevId(), + RfFrequencyHz: batch.GetRfFrequencyHz(), + SampleEncoding: batch.GetSampleEncoding(), + SampleCount: batch.GetSampleCount(), + SampleIndex: sampleIndex, + NodeID: nodeID32, + BeltAddr: fmt.Sprintf("%d-%d", regionID, nodeID32), + Flags: uint32(flags), + Battery: batteryPercent, + HasTimingError: hasTimingError, + TimingErrorUs: int32(timingErrorUs), + HasHeartRate: hasHr, + HeartRate: uint32(hrValue), + HrConfidence: int(hrStatus & wearableHrConfMask), + IsActive: (hrStatus & wearableHrActive) != 0, + IsOnSkin: (hrStatus & wearableHrOnSkin) != 0, + HasStepCount: hasStep, + StepCount: uint32(stepValue), + RssiSyncX2Neg: uint32(rssiSyncX2Neg), + SignalRSSINeg: wearableRssiToDBm(rssiSyncX2Neg), + ReceivedAt: now, + } + return record, offset, nil +} + +func wearableRssiToDBm(value uint8) float64 { + if value == 0 { + return 0 + } + return -float64(value) / 2 +} + +func buildGatewayStatusRecordV3(status *whgwv3pb.GatewayStatus, topic string, now int64) DebugV3GatewayStatusRecord { + gatewayInfo := status.GetInfo() + regionID := gatewayInfo.GetRegionId() + if regionID == 0 { + regionID = parseRegionFromTopic(topic) + } + gatewayMAC := formatMAC(gatewayInfo.GetGatewayMac()) + + return DebugV3GatewayStatusRecord{ + Identifier: fmt.Sprintf("v3:gateway:%d:%s:%d:%d:%d", regionID, gatewayMAC, status.GetStat().GetBootCount(), status.GetStat().GetUptimeMs(), status.GetStat().GetRxCount()), + Topic: topic, + ProtocolVersion: 3, + RegionID: regionID, + GatewayMAC: gatewayMAC, + GatewayIPv4Addr: formatIPv4(gatewayInfo.GetIpv4Addr()), + GatewayActiveUplink: int32(gatewayInfo.GetActiveUplink()), + GatewayCellularIMEI: gatewayInfo.GetCellularModem().GetImei(), + GatewayCellularRSSI: gatewayInfo.GetCellularModem().GetCsqRssi(), + GatewayCellularBER: gatewayInfo.GetCellularModem().GetCsqBer(), + BootCount: status.GetStat().GetBootCount(), + UptimeMs: status.GetStat().GetUptimeMs(), + DurationMsSinceLastPacket: status.GetStat().GetDurationMsSinceLastPacket(), + RxCount: status.GetStat().GetRxCount(), + BatteryVoltageMV: status.GetStat().GetBatteryInfo().GetVoltageMv(), + BatterySOCPercentage: status.GetStat().GetBatteryInfo().GetSocPercentage(), + ChargingRatePercentage: status.GetStat().GetBatteryInfo().GetChargingRatePercentage(), + ReceivedAt: now, + } +} + +func buildRadioFrameRecordV3(kind string, frame *whgwv3pb.RadioRxFrame, topic string, now int64) DebugV3RadioFrameRecord { + radioData := frame.GetRadioData() + hubInfo := radioData.GetHubInfo() + status := parsePacketStatusV3(radioData.GetPacketStatus()) + radio := parseRadioParametersV3(hubInfo.GetRadioParameters()) + gatewayMAC := parseGatewayMACFromTopic(topic) + + return DebugV3RadioFrameRecord{ + Identifier: fmt.Sprintf("v3:%s:%s:%d:%d", kind, gatewayMAC, hubInfo.GetSubDevId(), frame.GetRxSeq()), + Topic: topic, + ProtocolVersion: 3, + Kind: kind, + GatewayMAC: gatewayMAC, + HubBusID: hubInfo.GetBusId(), + HubSubDevID: hubInfo.GetSubDevId(), + PacketStatusKind: status.kind, + SignalRSSINeg: status.signalRSSINeg, + SNR: status.snr, + RawSignalRSSIX2Neg: status.rawSignalRSSIX2Neg, + RawSnrPktX4: status.rawSnrPktX4, + RawFskRssiSyncX2Neg: status.rawFskRssiSyncX2Neg, + RawFskRssiAvgX2Neg: status.rawFskRssiAvgX2Neg, + HubRadioMode: radio.mode, + HubRadioBW: radio.loraBw, + HubRadioSF: radio.loraSf, + HubRadioFrequencyMHz: chooseFrequencyMHz(radio), + HubGfskBitrateBps: radio.gfskBitrateBps, + HubGfskDeviationHz: radio.gfskDeviationHz, + HubGfskRxBandwidthHz: radio.gfskRxBandwidthHz, + HubGfskPayloadLength: radio.gfskPayloadLength, + DataHex: strings.ToUpper(hex.EncodeToString(radioData.GetData())), + DataLength: len(radioData.GetData()), + GatewayUptimeMs: frame.GetGatewayUptimeMs(), + RxSeq: frame.GetRxSeq(), + RxDoneHubUptimeUs: radioData.GetRxTiming().GetRxDoneHubUptimeUs(), + IrqToForwardUs: radioData.GetRxTiming().GetIrqToForwardUs(), + ReceivedAt: now, + } +} + +func parsePacketStatusV3(status *whgwv3pb.PacketStatus) packetStatusSnapshotV3 { + if status == nil { + return packetStatusSnapshotV3{} + } + if lora := status.GetLora(); lora != nil { + return packetStatusSnapshotV3{ + kind: "lora", + signalRSSINeg: -float64(lora.GetSignalRssiX2Neg()) / 2, + snr: float64(lora.GetSnrPktX4()) / 4, + rawSignalRSSIX2Neg: lora.GetSignalRssiX2Neg(), + rawSnrPktX4: lora.GetSnrPktX4(), + } + } + if fsk := status.GetFsk(); fsk != nil { + return packetStatusSnapshotV3{ + kind: "fsk", + signalRSSINeg: -float64(fsk.GetRssiSyncX2Neg()) / 2, + rawFskRssiSyncX2Neg: fsk.GetRssiSyncX2Neg(), + rawFskRssiAvgX2Neg: fsk.GetRssiAvgX2Neg(), + } + } + return packetStatusSnapshotV3{} +} + +func parseRadioParametersV3(params *whgwv3pb.RadioParameters) radioParametersSnapshotV3 { + if params == nil { + return radioParametersSnapshotV3{} + } + if lora := params.GetLora(); lora != nil { + return radioParametersSnapshotV3{ + mode: "lora", + loraBw: int32(lora.GetBw()), + loraSf: lora.GetSf(), + loraFrequencyMHz: float64(lora.GetFrequencyMhz()), + } + } + if gfsk := params.GetGfsk(); gfsk != nil { + return radioParametersSnapshotV3{ + mode: "gfsk", + gfskBitrateBps: gfsk.GetBitrateBps(), + gfskFrequencyMHz: float64(gfsk.GetFrequencyMhz()), + gfskDeviationHz: gfsk.GetFrequencyDeviationHz(), + gfskRxBandwidthHz: gfsk.GetRxBandwidthHz(), + gfskPayloadLength: gfsk.GetPayloadLength(), + } + } + return radioParametersSnapshotV3{} +} + +func chooseFrequencyMHz(radio radioParametersSnapshotV3) float64 { + if radio.mode == "gfsk" { + return radio.gfskFrequencyMHz + } + return radio.loraFrequencyMHz +} + +func parseGatewayMACFromTopic(topic string) string { + parts := strings.Split(topic, "/") + for i := 0; i < len(parts)-1; i++ { + if parts[i] == "gateway" { + return formatTopicGatewayMAC(parts[i+1]) + } + } + return "" +} + +func formatTopicGatewayMAC(value string) string { + trimmed := strings.TrimSpace(value) + if len(trimmed) != 12 { + return strings.ToUpper(trimmed) + } + chunks := make([]string, 0, 6) + for i := 0; i < len(trimmed); i += 2 { + chunks = append(chunks, strings.ToUpper(trimmed[i:i+2])) + } + return strings.Join(chunks, ":") +} + +func formatIPv4(value uint32) string { + if value == 0 { + return "" + } + return fmt.Sprintf("%d.%d.%d.%d", byte(value>>24), byte(value>>16), byte(value>>8), byte(value)) +} diff --git a/proto/v3/hr_packet_v3.pb.go b/proto/v3/hr_packet_v3.pb.go new file mode 100644 index 0000000..e701741 --- /dev/null +++ b/proto/v3/hr_packet_v3.pb.go @@ -0,0 +1,2120 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.6 +// protoc v5.28.3 +// source: hr_packet_v3.proto + +package whgwv3pb + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type HrConfidence int32 + +const ( + HrConfidence_ZERO HrConfidence = 0 + HrConfidence_LOW HrConfidence = 1 + HrConfidence_MEDIUM HrConfidence = 2 + HrConfidence_HIGH HrConfidence = 3 +) + +// Enum value maps for HrConfidence. +var ( + HrConfidence_name = map[int32]string{ + 0: "ZERO", + 1: "LOW", + 2: "MEDIUM", + 3: "HIGH", + } + HrConfidence_value = map[string]int32{ + "ZERO": 0, + "LOW": 1, + "MEDIUM": 2, + "HIGH": 3, + } +) + +func (x HrConfidence) Enum() *HrConfidence { + p := new(HrConfidence) + *p = x + return p +} + +func (x HrConfidence) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (HrConfidence) Descriptor() protoreflect.EnumDescriptor { + return file_hr_packet_v3_proto_enumTypes[0].Descriptor() +} + +func (HrConfidence) Type() protoreflect.EnumType { + return &file_hr_packet_v3_proto_enumTypes[0] +} + +func (x HrConfidence) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use HrConfidence.Descriptor instead. +func (HrConfidence) EnumDescriptor() ([]byte, []int) { + return file_hr_packet_v3_proto_rawDescGZIP(), []int{0} +} + +type LoRaBW int32 + +const ( + LoRaBW_BW_NONE LoRaBW = 0 + LoRaBW_BW_10_4 LoRaBW = 8 + LoRaBW_BW_15_6 LoRaBW = 1 + LoRaBW_BW_20_8 LoRaBW = 9 + LoRaBW_BW_31_25 LoRaBW = 2 + LoRaBW_BW_41_7 LoRaBW = 10 + LoRaBW_BW_62_5 LoRaBW = 3 + LoRaBW_BW_125_0 LoRaBW = 4 + LoRaBW_BW_250_0 LoRaBW = 5 + LoRaBW_BW_500_0 LoRaBW = 6 +) + +// Enum value maps for LoRaBW. +var ( + LoRaBW_name = map[int32]string{ + 0: "BW_NONE", + 8: "BW_10_4", + 1: "BW_15_6", + 9: "BW_20_8", + 2: "BW_31_25", + 10: "BW_41_7", + 3: "BW_62_5", + 4: "BW_125_0", + 5: "BW_250_0", + 6: "BW_500_0", + } + LoRaBW_value = map[string]int32{ + "BW_NONE": 0, + "BW_10_4": 8, + "BW_15_6": 1, + "BW_20_8": 9, + "BW_31_25": 2, + "BW_41_7": 10, + "BW_62_5": 3, + "BW_125_0": 4, + "BW_250_0": 5, + "BW_500_0": 6, + } +) + +func (x LoRaBW) Enum() *LoRaBW { + p := new(LoRaBW) + *p = x + return p +} + +func (x LoRaBW) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (LoRaBW) Descriptor() protoreflect.EnumDescriptor { + return file_hr_packet_v3_proto_enumTypes[1].Descriptor() +} + +func (LoRaBW) Type() protoreflect.EnumType { + return &file_hr_packet_v3_proto_enumTypes[1] +} + +func (x LoRaBW) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use LoRaBW.Descriptor instead. +func (LoRaBW) EnumDescriptor() ([]byte, []int) { + return file_hr_packet_v3_proto_rawDescGZIP(), []int{1} +} + +type NetworkUplinkKind int32 + +const ( + NetworkUplinkKind_NETWORK_UPLINK_UNKNOWN NetworkUplinkKind = 0 + NetworkUplinkKind_NETWORK_UPLINK_WIFI NetworkUplinkKind = 1 + NetworkUplinkKind_NETWORK_UPLINK_CELLULAR NetworkUplinkKind = 2 +) + +// Enum value maps for NetworkUplinkKind. +var ( + NetworkUplinkKind_name = map[int32]string{ + 0: "NETWORK_UPLINK_UNKNOWN", + 1: "NETWORK_UPLINK_WIFI", + 2: "NETWORK_UPLINK_CELLULAR", + } + NetworkUplinkKind_value = map[string]int32{ + "NETWORK_UPLINK_UNKNOWN": 0, + "NETWORK_UPLINK_WIFI": 1, + "NETWORK_UPLINK_CELLULAR": 2, + } +) + +func (x NetworkUplinkKind) Enum() *NetworkUplinkKind { + p := new(NetworkUplinkKind) + *p = x + return p +} + +func (x NetworkUplinkKind) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (NetworkUplinkKind) Descriptor() protoreflect.EnumDescriptor { + return file_hr_packet_v3_proto_enumTypes[2].Descriptor() +} + +func (NetworkUplinkKind) Type() protoreflect.EnumType { + return &file_hr_packet_v3_proto_enumTypes[2] +} + +func (x NetworkUplinkKind) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use NetworkUplinkKind.Descriptor instead. +func (NetworkUplinkKind) EnumDescriptor() ([]byte, []int) { + return file_hr_packet_v3_proto_rawDescGZIP(), []int{2} +} + +type StatusFlag struct { + state protoimpl.MessageState `protogen:"open.v1"` + HrConfidence HrConfidence `protobuf:"varint,1,opt,name=hr_confidence,json=hrConfidence,proto3,enum=whgw.gateway.v3.HrConfidence" json:"hr_confidence,omitempty"` + IsActive bool `protobuf:"varint,2,opt,name=is_active,json=isActive,proto3" json:"is_active,omitempty"` + IsOnSkin bool `protobuf:"varint,3,opt,name=is_on_skin,json=isOnSkin,proto3" json:"is_on_skin,omitempty"` + Battery uint32 `protobuf:"varint,4,opt,name=battery,proto3" json:"battery,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *StatusFlag) Reset() { + *x = StatusFlag{} + mi := &file_hr_packet_v3_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *StatusFlag) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StatusFlag) ProtoMessage() {} + +func (x *StatusFlag) ProtoReflect() protoreflect.Message { + mi := &file_hr_packet_v3_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StatusFlag.ProtoReflect.Descriptor instead. +func (*StatusFlag) Descriptor() ([]byte, []int) { + return file_hr_packet_v3_proto_rawDescGZIP(), []int{0} +} + +func (x *StatusFlag) GetHrConfidence() HrConfidence { + if x != nil { + return x.HrConfidence + } + return HrConfidence_ZERO +} + +func (x *StatusFlag) GetIsActive() bool { + if x != nil { + return x.IsActive + } + return false +} + +func (x *StatusFlag) GetIsOnSkin() bool { + if x != nil { + return x.IsOnSkin + } + return false +} + +func (x *StatusFlag) GetBattery() uint32 { + if x != nil { + return x.Battery + } + return 0 +} + +type HrPacket struct { + state protoimpl.MessageState `protogen:"open.v1"` + Status *StatusFlag `protobuf:"bytes,1,opt,name=status,proto3" json:"status,omitempty"` + Id uint32 `protobuf:"varint,2,opt,name=id,proto3" json:"id,omitempty"` + PacketNum uint32 `protobuf:"varint,3,opt,name=packet_num,json=packetNum,proto3" json:"packet_num,omitempty"` + Hr uint32 `protobuf:"varint,4,opt,name=hr,proto3" json:"hr,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *HrPacket) Reset() { + *x = HrPacket{} + mi := &file_hr_packet_v3_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *HrPacket) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*HrPacket) ProtoMessage() {} + +func (x *HrPacket) ProtoReflect() protoreflect.Message { + mi := &file_hr_packet_v3_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use HrPacket.ProtoReflect.Descriptor instead. +func (*HrPacket) Descriptor() ([]byte, []int) { + return file_hr_packet_v3_proto_rawDescGZIP(), []int{1} +} + +func (x *HrPacket) GetStatus() *StatusFlag { + if x != nil { + return x.Status + } + return nil +} + +func (x *HrPacket) GetId() uint32 { + if x != nil { + return x.Id + } + return 0 +} + +func (x *HrPacket) GetPacketNum() uint32 { + if x != nil { + return x.PacketNum + } + return 0 +} + +func (x *HrPacket) GetHr() uint32 { + if x != nil { + return x.Hr + } + return 0 +} + +type StepCountPacket struct { + state protoimpl.MessageState `protogen:"open.v1"` + Id uint32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` + PacketNum uint32 `protobuf:"varint,2,opt,name=packet_num,json=packetNum,proto3" json:"packet_num,omitempty"` + StepCount uint32 `protobuf:"varint,3,opt,name=step_count,json=stepCount,proto3" json:"step_count,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *StepCountPacket) Reset() { + *x = StepCountPacket{} + mi := &file_hr_packet_v3_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *StepCountPacket) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StepCountPacket) ProtoMessage() {} + +func (x *StepCountPacket) ProtoReflect() protoreflect.Message { + mi := &file_hr_packet_v3_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StepCountPacket.ProtoReflect.Descriptor instead. +func (*StepCountPacket) Descriptor() ([]byte, []int) { + return file_hr_packet_v3_proto_rawDescGZIP(), []int{2} +} + +func (x *StepCountPacket) GetId() uint32 { + if x != nil { + return x.Id + } + return 0 +} + +func (x *StepCountPacket) GetPacketNum() uint32 { + if x != nil { + return x.PacketNum + } + return 0 +} + +func (x *StepCountPacket) GetStepCount() uint32 { + if x != nil { + return x.StepCount + } + return 0 +} + +type WearableStatusFlag struct { + state protoimpl.MessageState `protogen:"open.v1"` + HrConfidence HrConfidence `protobuf:"varint,1,opt,name=hr_confidence,json=hrConfidence,proto3,enum=whgw.gateway.v3.HrConfidence" json:"hr_confidence,omitempty"` + IsActive bool `protobuf:"varint,2,opt,name=is_active,json=isActive,proto3" json:"is_active,omitempty"` + IsOnSkin bool `protobuf:"varint,3,opt,name=is_on_skin,json=isOnSkin,proto3" json:"is_on_skin,omitempty"` + Battery uint32 `protobuf:"varint,4,opt,name=battery,proto3" json:"battery,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *WearableStatusFlag) Reset() { + *x = WearableStatusFlag{} + mi := &file_hr_packet_v3_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *WearableStatusFlag) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*WearableStatusFlag) ProtoMessage() {} + +func (x *WearableStatusFlag) ProtoReflect() protoreflect.Message { + mi := &file_hr_packet_v3_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use WearableStatusFlag.ProtoReflect.Descriptor instead. +func (*WearableStatusFlag) Descriptor() ([]byte, []int) { + return file_hr_packet_v3_proto_rawDescGZIP(), []int{3} +} + +func (x *WearableStatusFlag) GetHrConfidence() HrConfidence { + if x != nil { + return x.HrConfidence + } + return HrConfidence_ZERO +} + +func (x *WearableStatusFlag) GetIsActive() bool { + if x != nil { + return x.IsActive + } + return false +} + +func (x *WearableStatusFlag) GetIsOnSkin() bool { + if x != nil { + return x.IsOnSkin + } + return false +} + +func (x *WearableStatusFlag) GetBattery() uint32 { + if x != nil { + return x.Battery + } + return 0 +} + +type LoRaParameters struct { + state protoimpl.MessageState `protogen:"open.v1"` + Bw LoRaBW `protobuf:"varint,1,opt,name=bw,proto3,enum=whgw.gateway.v3.LoRaBW" json:"bw,omitempty"` + Sf uint32 `protobuf:"varint,2,opt,name=sf,proto3" json:"sf,omitempty"` + FrequencyMhz float32 `protobuf:"fixed32,3,opt,name=frequency_mhz,json=frequencyMhz,proto3" json:"frequency_mhz,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *LoRaParameters) Reset() { + *x = LoRaParameters{} + mi := &file_hr_packet_v3_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *LoRaParameters) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LoRaParameters) ProtoMessage() {} + +func (x *LoRaParameters) ProtoReflect() protoreflect.Message { + mi := &file_hr_packet_v3_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use LoRaParameters.ProtoReflect.Descriptor instead. +func (*LoRaParameters) Descriptor() ([]byte, []int) { + return file_hr_packet_v3_proto_rawDescGZIP(), []int{4} +} + +func (x *LoRaParameters) GetBw() LoRaBW { + if x != nil { + return x.Bw + } + return LoRaBW_BW_NONE +} + +func (x *LoRaParameters) GetSf() uint32 { + if x != nil { + return x.Sf + } + return 0 +} + +func (x *LoRaParameters) GetFrequencyMhz() float32 { + if x != nil { + return x.FrequencyMhz + } + return 0 +} + +type GfskParameters struct { + state protoimpl.MessageState `protogen:"open.v1"` + BitrateBps uint32 `protobuf:"varint,1,opt,name=bitrate_bps,json=bitrateBps,proto3" json:"bitrate_bps,omitempty"` + FrequencyMhz float32 `protobuf:"fixed32,2,opt,name=frequency_mhz,json=frequencyMhz,proto3" json:"frequency_mhz,omitempty"` + FrequencyDeviationHz uint32 `protobuf:"varint,3,opt,name=frequency_deviation_hz,json=frequencyDeviationHz,proto3" json:"frequency_deviation_hz,omitempty"` + RxBandwidthHz uint32 `protobuf:"varint,4,opt,name=rx_bandwidth_hz,json=rxBandwidthHz,proto3" json:"rx_bandwidth_hz,omitempty"` + PayloadLength uint32 `protobuf:"varint,5,opt,name=payload_length,json=payloadLength,proto3" json:"payload_length,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GfskParameters) Reset() { + *x = GfskParameters{} + mi := &file_hr_packet_v3_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GfskParameters) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GfskParameters) ProtoMessage() {} + +func (x *GfskParameters) ProtoReflect() protoreflect.Message { + mi := &file_hr_packet_v3_proto_msgTypes[5] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GfskParameters.ProtoReflect.Descriptor instead. +func (*GfskParameters) Descriptor() ([]byte, []int) { + return file_hr_packet_v3_proto_rawDescGZIP(), []int{5} +} + +func (x *GfskParameters) GetBitrateBps() uint32 { + if x != nil { + return x.BitrateBps + } + return 0 +} + +func (x *GfskParameters) GetFrequencyMhz() float32 { + if x != nil { + return x.FrequencyMhz + } + return 0 +} + +func (x *GfskParameters) GetFrequencyDeviationHz() uint32 { + if x != nil { + return x.FrequencyDeviationHz + } + return 0 +} + +func (x *GfskParameters) GetRxBandwidthHz() uint32 { + if x != nil { + return x.RxBandwidthHz + } + return 0 +} + +func (x *GfskParameters) GetPayloadLength() uint32 { + if x != nil { + return x.PayloadLength + } + return 0 +} + +type RadioParameters struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Types that are valid to be assigned to Kind: + // + // *RadioParameters_Lora + // *RadioParameters_Gfsk + Kind isRadioParameters_Kind `protobuf_oneof:"kind"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *RadioParameters) Reset() { + *x = RadioParameters{} + mi := &file_hr_packet_v3_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *RadioParameters) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RadioParameters) ProtoMessage() {} + +func (x *RadioParameters) ProtoReflect() protoreflect.Message { + mi := &file_hr_packet_v3_proto_msgTypes[6] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RadioParameters.ProtoReflect.Descriptor instead. +func (*RadioParameters) Descriptor() ([]byte, []int) { + return file_hr_packet_v3_proto_rawDescGZIP(), []int{6} +} + +func (x *RadioParameters) GetKind() isRadioParameters_Kind { + if x != nil { + return x.Kind + } + return nil +} + +func (x *RadioParameters) GetLora() *LoRaParameters { + if x != nil { + if x, ok := x.Kind.(*RadioParameters_Lora); ok { + return x.Lora + } + } + return nil +} + +func (x *RadioParameters) GetGfsk() *GfskParameters { + if x != nil { + if x, ok := x.Kind.(*RadioParameters_Gfsk); ok { + return x.Gfsk + } + } + return nil +} + +type isRadioParameters_Kind interface { + isRadioParameters_Kind() +} + +type RadioParameters_Lora struct { + Lora *LoRaParameters `protobuf:"bytes,1,opt,name=lora,proto3,oneof"` +} + +type RadioParameters_Gfsk struct { + Gfsk *GfskParameters `protobuf:"bytes,2,opt,name=gfsk,proto3,oneof"` +} + +func (*RadioParameters_Lora) isRadioParameters_Kind() {} + +func (*RadioParameters_Gfsk) isRadioParameters_Kind() {} + +type LoRaPacketStatus struct { + state protoimpl.MessageState `protogen:"open.v1"` + SignalRssiX2Neg uint32 `protobuf:"varint,1,opt,name=signal_rssi_x2_neg,json=signalRssiX2Neg,proto3" json:"signal_rssi_x2_neg,omitempty"` + SnrPktX4 int32 `protobuf:"varint,2,opt,name=snr_pkt_x4,json=snrPktX4,proto3" json:"snr_pkt_x4,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *LoRaPacketStatus) Reset() { + *x = LoRaPacketStatus{} + mi := &file_hr_packet_v3_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *LoRaPacketStatus) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LoRaPacketStatus) ProtoMessage() {} + +func (x *LoRaPacketStatus) ProtoReflect() protoreflect.Message { + mi := &file_hr_packet_v3_proto_msgTypes[7] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use LoRaPacketStatus.ProtoReflect.Descriptor instead. +func (*LoRaPacketStatus) Descriptor() ([]byte, []int) { + return file_hr_packet_v3_proto_rawDescGZIP(), []int{7} +} + +func (x *LoRaPacketStatus) GetSignalRssiX2Neg() uint32 { + if x != nil { + return x.SignalRssiX2Neg + } + return 0 +} + +func (x *LoRaPacketStatus) GetSnrPktX4() int32 { + if x != nil { + return x.SnrPktX4 + } + return 0 +} + +type FskPacketStatus struct { + state protoimpl.MessageState `protogen:"open.v1"` + RssiSyncX2Neg uint32 `protobuf:"varint,1,opt,name=rssi_sync_x2_neg,json=rssiSyncX2Neg,proto3" json:"rssi_sync_x2_neg,omitempty"` + RssiAvgX2Neg uint32 `protobuf:"varint,2,opt,name=rssi_avg_x2_neg,json=rssiAvgX2Neg,proto3" json:"rssi_avg_x2_neg,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *FskPacketStatus) Reset() { + *x = FskPacketStatus{} + mi := &file_hr_packet_v3_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *FskPacketStatus) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FskPacketStatus) ProtoMessage() {} + +func (x *FskPacketStatus) ProtoReflect() protoreflect.Message { + mi := &file_hr_packet_v3_proto_msgTypes[8] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use FskPacketStatus.ProtoReflect.Descriptor instead. +func (*FskPacketStatus) Descriptor() ([]byte, []int) { + return file_hr_packet_v3_proto_rawDescGZIP(), []int{8} +} + +func (x *FskPacketStatus) GetRssiSyncX2Neg() uint32 { + if x != nil { + return x.RssiSyncX2Neg + } + return 0 +} + +func (x *FskPacketStatus) GetRssiAvgX2Neg() uint32 { + if x != nil { + return x.RssiAvgX2Neg + } + return 0 +} + +type PacketStatus struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Types that are valid to be assigned to Kind: + // + // *PacketStatus_Lora + // *PacketStatus_Fsk + Kind isPacketStatus_Kind `protobuf_oneof:"kind"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *PacketStatus) Reset() { + *x = PacketStatus{} + mi := &file_hr_packet_v3_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PacketStatus) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PacketStatus) ProtoMessage() {} + +func (x *PacketStatus) ProtoReflect() protoreflect.Message { + mi := &file_hr_packet_v3_proto_msgTypes[9] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PacketStatus.ProtoReflect.Descriptor instead. +func (*PacketStatus) Descriptor() ([]byte, []int) { + return file_hr_packet_v3_proto_rawDescGZIP(), []int{9} +} + +func (x *PacketStatus) GetKind() isPacketStatus_Kind { + if x != nil { + return x.Kind + } + return nil +} + +func (x *PacketStatus) GetLora() *LoRaPacketStatus { + if x != nil { + if x, ok := x.Kind.(*PacketStatus_Lora); ok { + return x.Lora + } + } + return nil +} + +func (x *PacketStatus) GetFsk() *FskPacketStatus { + if x != nil { + if x, ok := x.Kind.(*PacketStatus_Fsk); ok { + return x.Fsk + } + } + return nil +} + +type isPacketStatus_Kind interface { + isPacketStatus_Kind() +} + +type PacketStatus_Lora struct { + Lora *LoRaPacketStatus `protobuf:"bytes,1,opt,name=lora,proto3,oneof"` +} + +type PacketStatus_Fsk struct { + Fsk *FskPacketStatus `protobuf:"bytes,2,opt,name=fsk,proto3,oneof"` +} + +func (*PacketStatus_Lora) isPacketStatus_Kind() {} + +func (*PacketStatus_Fsk) isPacketStatus_Kind() {} + +type HubInfo struct { + state protoimpl.MessageState `protogen:"open.v1"` + BusId uint32 `protobuf:"varint,1,opt,name=bus_id,json=busId,proto3" json:"bus_id,omitempty"` + SubDevId uint32 `protobuf:"varint,2,opt,name=sub_dev_id,json=subDevId,proto3" json:"sub_dev_id,omitempty"` + RadioParameters *RadioParameters `protobuf:"bytes,3,opt,name=radio_parameters,json=radioParameters,proto3" json:"radio_parameters,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *HubInfo) Reset() { + *x = HubInfo{} + mi := &file_hr_packet_v3_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *HubInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*HubInfo) ProtoMessage() {} + +func (x *HubInfo) ProtoReflect() protoreflect.Message { + mi := &file_hr_packet_v3_proto_msgTypes[10] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use HubInfo.ProtoReflect.Descriptor instead. +func (*HubInfo) Descriptor() ([]byte, []int) { + return file_hr_packet_v3_proto_rawDescGZIP(), []int{10} +} + +func (x *HubInfo) GetBusId() uint32 { + if x != nil { + return x.BusId + } + return 0 +} + +func (x *HubInfo) GetSubDevId() uint32 { + if x != nil { + return x.SubDevId + } + return 0 +} + +func (x *HubInfo) GetRadioParameters() *RadioParameters { + if x != nil { + return x.RadioParameters + } + return nil +} + +type RadioData struct { + state protoimpl.MessageState `protogen:"open.v1"` + HubInfo *HubInfo `protobuf:"bytes,1,opt,name=hub_info,json=hubInfo,proto3" json:"hub_info,omitempty"` + PacketStatus *PacketStatus `protobuf:"bytes,2,opt,name=packet_status,json=packetStatus,proto3" json:"packet_status,omitempty"` + Data []byte `protobuf:"bytes,3,opt,name=data,proto3" json:"data,omitempty"` + RxTiming *RadioRxTiming `protobuf:"bytes,4,opt,name=rx_timing,json=rxTiming,proto3" json:"rx_timing,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *RadioData) Reset() { + *x = RadioData{} + mi := &file_hr_packet_v3_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *RadioData) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RadioData) ProtoMessage() {} + +func (x *RadioData) ProtoReflect() protoreflect.Message { + mi := &file_hr_packet_v3_proto_msgTypes[11] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RadioData.ProtoReflect.Descriptor instead. +func (*RadioData) Descriptor() ([]byte, []int) { + return file_hr_packet_v3_proto_rawDescGZIP(), []int{11} +} + +func (x *RadioData) GetHubInfo() *HubInfo { + if x != nil { + return x.HubInfo + } + return nil +} + +func (x *RadioData) GetPacketStatus() *PacketStatus { + if x != nil { + return x.PacketStatus + } + return nil +} + +func (x *RadioData) GetData() []byte { + if x != nil { + return x.Data + } + return nil +} + +func (x *RadioData) GetRxTiming() *RadioRxTiming { + if x != nil { + return x.RxTiming + } + return nil +} + +type RadioRxTiming struct { + state protoimpl.MessageState `protogen:"open.v1"` + RxDoneHubUptimeUs uint64 `protobuf:"varint,1,opt,name=rx_done_hub_uptime_us,json=rxDoneHubUptimeUs,proto3" json:"rx_done_hub_uptime_us,omitempty"` + IrqToForwardUs uint32 `protobuf:"varint,2,opt,name=irq_to_forward_us,json=irqToForwardUs,proto3" json:"irq_to_forward_us,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *RadioRxTiming) Reset() { + *x = RadioRxTiming{} + mi := &file_hr_packet_v3_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *RadioRxTiming) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RadioRxTiming) ProtoMessage() {} + +func (x *RadioRxTiming) ProtoReflect() protoreflect.Message { + mi := &file_hr_packet_v3_proto_msgTypes[12] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RadioRxTiming.ProtoReflect.Descriptor instead. +func (*RadioRxTiming) Descriptor() ([]byte, []int) { + return file_hr_packet_v3_proto_rawDescGZIP(), []int{12} +} + +func (x *RadioRxTiming) GetRxDoneHubUptimeUs() uint64 { + if x != nil { + return x.RxDoneHubUptimeUs + } + return 0 +} + +func (x *RadioRxTiming) GetIrqToForwardUs() uint32 { + if x != nil { + return x.IrqToForwardUs + } + return 0 +} + +type BatteryInfo struct { + state protoimpl.MessageState `protogen:"open.v1"` + VoltageMv uint32 `protobuf:"varint,1,opt,name=voltage_mv,json=voltageMv,proto3" json:"voltage_mv,omitempty"` + SocPercentage uint32 `protobuf:"varint,2,opt,name=soc_percentage,json=socPercentage,proto3" json:"soc_percentage,omitempty"` + ChargingRatePercentage int32 `protobuf:"zigzag32,3,opt,name=charging_rate_percentage,json=chargingRatePercentage,proto3" json:"charging_rate_percentage,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *BatteryInfo) Reset() { + *x = BatteryInfo{} + mi := &file_hr_packet_v3_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *BatteryInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BatteryInfo) ProtoMessage() {} + +func (x *BatteryInfo) ProtoReflect() protoreflect.Message { + mi := &file_hr_packet_v3_proto_msgTypes[13] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BatteryInfo.ProtoReflect.Descriptor instead. +func (*BatteryInfo) Descriptor() ([]byte, []int) { + return file_hr_packet_v3_proto_rawDescGZIP(), []int{13} +} + +func (x *BatteryInfo) GetVoltageMv() uint32 { + if x != nil { + return x.VoltageMv + } + return 0 +} + +func (x *BatteryInfo) GetSocPercentage() uint32 { + if x != nil { + return x.SocPercentage + } + return 0 +} + +func (x *BatteryInfo) GetChargingRatePercentage() int32 { + if x != nil { + return x.ChargingRatePercentage + } + return 0 +} + +type CellularModemInfo struct { + state protoimpl.MessageState `protogen:"open.v1"` + Imei string `protobuf:"bytes,1,opt,name=imei,proto3" json:"imei,omitempty"` + CsqRssi int32 `protobuf:"varint,2,opt,name=csq_rssi,json=csqRssi,proto3" json:"csq_rssi,omitempty"` + CsqBer int32 `protobuf:"varint,3,opt,name=csq_ber,json=csqBer,proto3" json:"csq_ber,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CellularModemInfo) Reset() { + *x = CellularModemInfo{} + mi := &file_hr_packet_v3_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CellularModemInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CellularModemInfo) ProtoMessage() {} + +func (x *CellularModemInfo) ProtoReflect() protoreflect.Message { + mi := &file_hr_packet_v3_proto_msgTypes[14] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CellularModemInfo.ProtoReflect.Descriptor instead. +func (*CellularModemInfo) Descriptor() ([]byte, []int) { + return file_hr_packet_v3_proto_rawDescGZIP(), []int{14} +} + +func (x *CellularModemInfo) GetImei() string { + if x != nil { + return x.Imei + } + return "" +} + +func (x *CellularModemInfo) GetCsqRssi() int32 { + if x != nil { + return x.CsqRssi + } + return 0 +} + +func (x *CellularModemInfo) GetCsqBer() int32 { + if x != nil { + return x.CsqBer + } + return 0 +} + +type GatewayInfo struct { + state protoimpl.MessageState `protogen:"open.v1"` + RegionId uint32 `protobuf:"varint,1,opt,name=region_id,json=regionId,proto3" json:"region_id,omitempty"` + GatewayMac []byte `protobuf:"bytes,2,opt,name=gateway_mac,json=gatewayMac,proto3" json:"gateway_mac,omitempty"` + ActiveUplink NetworkUplinkKind `protobuf:"varint,3,opt,name=active_uplink,json=activeUplink,proto3,enum=whgw.gateway.v3.NetworkUplinkKind" json:"active_uplink,omitempty"` + CellularModem *CellularModemInfo `protobuf:"bytes,4,opt,name=cellular_modem,json=cellularModem,proto3" json:"cellular_modem,omitempty"` + Ipv4Addr uint32 `protobuf:"varint,5,opt,name=ipv4_addr,json=ipv4Addr,proto3" json:"ipv4_addr,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GatewayInfo) Reset() { + *x = GatewayInfo{} + mi := &file_hr_packet_v3_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GatewayInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GatewayInfo) ProtoMessage() {} + +func (x *GatewayInfo) ProtoReflect() protoreflect.Message { + mi := &file_hr_packet_v3_proto_msgTypes[15] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GatewayInfo.ProtoReflect.Descriptor instead. +func (*GatewayInfo) Descriptor() ([]byte, []int) { + return file_hr_packet_v3_proto_rawDescGZIP(), []int{15} +} + +func (x *GatewayInfo) GetRegionId() uint32 { + if x != nil { + return x.RegionId + } + return 0 +} + +func (x *GatewayInfo) GetGatewayMac() []byte { + if x != nil { + return x.GatewayMac + } + return nil +} + +func (x *GatewayInfo) GetActiveUplink() NetworkUplinkKind { + if x != nil { + return x.ActiveUplink + } + return NetworkUplinkKind_NETWORK_UPLINK_UNKNOWN +} + +func (x *GatewayInfo) GetCellularModem() *CellularModemInfo { + if x != nil { + return x.CellularModem + } + return nil +} + +func (x *GatewayInfo) GetIpv4Addr() uint32 { + if x != nil { + return x.Ipv4Addr + } + return 0 +} + +type HrMeasurement struct { + state protoimpl.MessageState `protogen:"open.v1"` + HrPacket *HrPacket `protobuf:"bytes,1,opt,name=hr_packet,json=hrPacket,proto3" json:"hr_packet,omitempty"` + PacketStatus *PacketStatus `protobuf:"bytes,2,opt,name=packet_status,json=packetStatus,proto3" json:"packet_status,omitempty"` + GatewayInfo *GatewayInfo `protobuf:"bytes,3,opt,name=gateway_info,json=gatewayInfo,proto3" json:"gateway_info,omitempty"` + HubInfo *HubInfo `protobuf:"bytes,4,opt,name=hub_info,json=hubInfo,proto3" json:"hub_info,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *HrMeasurement) Reset() { + *x = HrMeasurement{} + mi := &file_hr_packet_v3_proto_msgTypes[16] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *HrMeasurement) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*HrMeasurement) ProtoMessage() {} + +func (x *HrMeasurement) ProtoReflect() protoreflect.Message { + mi := &file_hr_packet_v3_proto_msgTypes[16] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use HrMeasurement.ProtoReflect.Descriptor instead. +func (*HrMeasurement) Descriptor() ([]byte, []int) { + return file_hr_packet_v3_proto_rawDescGZIP(), []int{16} +} + +func (x *HrMeasurement) GetHrPacket() *HrPacket { + if x != nil { + return x.HrPacket + } + return nil +} + +func (x *HrMeasurement) GetPacketStatus() *PacketStatus { + if x != nil { + return x.PacketStatus + } + return nil +} + +func (x *HrMeasurement) GetGatewayInfo() *GatewayInfo { + if x != nil { + return x.GatewayInfo + } + return nil +} + +func (x *HrMeasurement) GetHubInfo() *HubInfo { + if x != nil { + return x.HubInfo + } + return nil +} + +type StepCountMeasurement struct { + state protoimpl.MessageState `protogen:"open.v1"` + StepCountPacket *StepCountPacket `protobuf:"bytes,1,opt,name=step_count_packet,json=stepCountPacket,proto3" json:"step_count_packet,omitempty"` + PacketStatus *PacketStatus `protobuf:"bytes,2,opt,name=packet_status,json=packetStatus,proto3" json:"packet_status,omitempty"` + GatewayInfo *GatewayInfo `protobuf:"bytes,3,opt,name=gateway_info,json=gatewayInfo,proto3" json:"gateway_info,omitempty"` + HubInfo *HubInfo `protobuf:"bytes,4,opt,name=hub_info,json=hubInfo,proto3" json:"hub_info,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *StepCountMeasurement) Reset() { + *x = StepCountMeasurement{} + mi := &file_hr_packet_v3_proto_msgTypes[17] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *StepCountMeasurement) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StepCountMeasurement) ProtoMessage() {} + +func (x *StepCountMeasurement) ProtoReflect() protoreflect.Message { + mi := &file_hr_packet_v3_proto_msgTypes[17] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StepCountMeasurement.ProtoReflect.Descriptor instead. +func (*StepCountMeasurement) Descriptor() ([]byte, []int) { + return file_hr_packet_v3_proto_rawDescGZIP(), []int{17} +} + +func (x *StepCountMeasurement) GetStepCountPacket() *StepCountPacket { + if x != nil { + return x.StepCountPacket + } + return nil +} + +func (x *StepCountMeasurement) GetPacketStatus() *PacketStatus { + if x != nil { + return x.PacketStatus + } + return nil +} + +func (x *StepCountMeasurement) GetGatewayInfo() *GatewayInfo { + if x != nil { + return x.GatewayInfo + } + return nil +} + +func (x *StepCountMeasurement) GetHubInfo() *HubInfo { + if x != nil { + return x.HubInfo + } + return nil +} + +type GatewayStatistic struct { + state protoimpl.MessageState `protogen:"open.v1"` + BootCount uint32 `protobuf:"varint,1,opt,name=boot_count,json=bootCount,proto3" json:"boot_count,omitempty"` + UptimeMs uint32 `protobuf:"varint,2,opt,name=uptime_ms,json=uptimeMs,proto3" json:"uptime_ms,omitempty"` + DurationMsSinceLastPacket uint32 `protobuf:"varint,3,opt,name=duration_ms_since_last_packet,json=durationMsSinceLastPacket,proto3" json:"duration_ms_since_last_packet,omitempty"` + RxCount uint32 `protobuf:"varint,4,opt,name=rx_count,json=rxCount,proto3" json:"rx_count,omitempty"` + BatteryInfo *BatteryInfo `protobuf:"bytes,5,opt,name=battery_info,json=batteryInfo,proto3" json:"battery_info,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GatewayStatistic) Reset() { + *x = GatewayStatistic{} + mi := &file_hr_packet_v3_proto_msgTypes[18] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GatewayStatistic) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GatewayStatistic) ProtoMessage() {} + +func (x *GatewayStatistic) ProtoReflect() protoreflect.Message { + mi := &file_hr_packet_v3_proto_msgTypes[18] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GatewayStatistic.ProtoReflect.Descriptor instead. +func (*GatewayStatistic) Descriptor() ([]byte, []int) { + return file_hr_packet_v3_proto_rawDescGZIP(), []int{18} +} + +func (x *GatewayStatistic) GetBootCount() uint32 { + if x != nil { + return x.BootCount + } + return 0 +} + +func (x *GatewayStatistic) GetUptimeMs() uint32 { + if x != nil { + return x.UptimeMs + } + return 0 +} + +func (x *GatewayStatistic) GetDurationMsSinceLastPacket() uint32 { + if x != nil { + return x.DurationMsSinceLastPacket + } + return 0 +} + +func (x *GatewayStatistic) GetRxCount() uint32 { + if x != nil { + return x.RxCount + } + return 0 +} + +func (x *GatewayStatistic) GetBatteryInfo() *BatteryInfo { + if x != nil { + return x.BatteryInfo + } + return nil +} + +type GatewayStatus struct { + state protoimpl.MessageState `protogen:"open.v1"` + Info *GatewayInfo `protobuf:"bytes,1,opt,name=info,proto3" json:"info,omitempty"` + Stat *GatewayStatistic `protobuf:"bytes,2,opt,name=stat,proto3" json:"stat,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GatewayStatus) Reset() { + *x = GatewayStatus{} + mi := &file_hr_packet_v3_proto_msgTypes[19] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GatewayStatus) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GatewayStatus) ProtoMessage() {} + +func (x *GatewayStatus) ProtoReflect() protoreflect.Message { + mi := &file_hr_packet_v3_proto_msgTypes[19] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GatewayStatus.ProtoReflect.Descriptor instead. +func (*GatewayStatus) Descriptor() ([]byte, []int) { + return file_hr_packet_v3_proto_rawDescGZIP(), []int{19} +} + +func (x *GatewayStatus) GetInfo() *GatewayInfo { + if x != nil { + return x.Info + } + return nil +} + +func (x *GatewayStatus) GetStat() *GatewayStatistic { + if x != nil { + return x.Stat + } + return nil +} + +type WearableHealthTelemetryBatch struct { + state protoimpl.MessageState `protogen:"open.v1"` + GatewayInfo *GatewayInfo `protobuf:"bytes,1,opt,name=gateway_info,json=gatewayInfo,proto3" json:"gateway_info,omitempty"` + ReportSeq uint32 `protobuf:"varint,2,opt,name=report_seq,json=reportSeq,proto3" json:"report_seq,omitempty"` + FrameId uint32 `protobuf:"varint,3,opt,name=frame_id,json=frameId,proto3" json:"frame_id,omitempty"` + FrameUnixTimeUs uint64 `protobuf:"varint,4,opt,name=frame_unix_time_us,json=frameUnixTimeUs,proto3" json:"frame_unix_time_us,omitempty"` + RadioSubDevId uint32 `protobuf:"varint,5,opt,name=radio_sub_dev_id,json=radioSubDevId,proto3" json:"radio_sub_dev_id,omitempty"` + RfFrequencyHz uint32 `protobuf:"varint,6,opt,name=rf_frequency_hz,json=rfFrequencyHz,proto3" json:"rf_frequency_hz,omitempty"` + SampleEncoding uint32 `protobuf:"varint,7,opt,name=sample_encoding,json=sampleEncoding,proto3" json:"sample_encoding,omitempty"` + SampleCount uint32 `protobuf:"varint,8,opt,name=sample_count,json=sampleCount,proto3" json:"sample_count,omitempty"` + Samples []byte `protobuf:"bytes,9,opt,name=samples,proto3" json:"samples,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *WearableHealthTelemetryBatch) Reset() { + *x = WearableHealthTelemetryBatch{} + mi := &file_hr_packet_v3_proto_msgTypes[20] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *WearableHealthTelemetryBatch) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*WearableHealthTelemetryBatch) ProtoMessage() {} + +func (x *WearableHealthTelemetryBatch) ProtoReflect() protoreflect.Message { + mi := &file_hr_packet_v3_proto_msgTypes[20] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use WearableHealthTelemetryBatch.ProtoReflect.Descriptor instead. +func (*WearableHealthTelemetryBatch) Descriptor() ([]byte, []int) { + return file_hr_packet_v3_proto_rawDescGZIP(), []int{20} +} + +func (x *WearableHealthTelemetryBatch) GetGatewayInfo() *GatewayInfo { + if x != nil { + return x.GatewayInfo + } + return nil +} + +func (x *WearableHealthTelemetryBatch) GetReportSeq() uint32 { + if x != nil { + return x.ReportSeq + } + return 0 +} + +func (x *WearableHealthTelemetryBatch) GetFrameId() uint32 { + if x != nil { + return x.FrameId + } + return 0 +} + +func (x *WearableHealthTelemetryBatch) GetFrameUnixTimeUs() uint64 { + if x != nil { + return x.FrameUnixTimeUs + } + return 0 +} + +func (x *WearableHealthTelemetryBatch) GetRadioSubDevId() uint32 { + if x != nil { + return x.RadioSubDevId + } + return 0 +} + +func (x *WearableHealthTelemetryBatch) GetRfFrequencyHz() uint32 { + if x != nil { + return x.RfFrequencyHz + } + return 0 +} + +func (x *WearableHealthTelemetryBatch) GetSampleEncoding() uint32 { + if x != nil { + return x.SampleEncoding + } + return 0 +} + +func (x *WearableHealthTelemetryBatch) GetSampleCount() uint32 { + if x != nil { + return x.SampleCount + } + return 0 +} + +func (x *WearableHealthTelemetryBatch) GetSamples() []byte { + if x != nil { + return x.Samples + } + return nil +} + +type RadioRxFrame struct { + state protoimpl.MessageState `protogen:"open.v1"` + RadioData *RadioData `protobuf:"bytes,1,opt,name=radio_data,json=radioData,proto3" json:"radio_data,omitempty"` + GatewayUptimeMs uint32 `protobuf:"varint,2,opt,name=gateway_uptime_ms,json=gatewayUptimeMs,proto3" json:"gateway_uptime_ms,omitempty"` + RxSeq uint32 `protobuf:"varint,3,opt,name=rx_seq,json=rxSeq,proto3" json:"rx_seq,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *RadioRxFrame) Reset() { + *x = RadioRxFrame{} + mi := &file_hr_packet_v3_proto_msgTypes[21] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *RadioRxFrame) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RadioRxFrame) ProtoMessage() {} + +func (x *RadioRxFrame) ProtoReflect() protoreflect.Message { + mi := &file_hr_packet_v3_proto_msgTypes[21] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RadioRxFrame.ProtoReflect.Descriptor instead. +func (*RadioRxFrame) Descriptor() ([]byte, []int) { + return file_hr_packet_v3_proto_rawDescGZIP(), []int{21} +} + +func (x *RadioRxFrame) GetRadioData() *RadioData { + if x != nil { + return x.RadioData + } + return nil +} + +func (x *RadioRxFrame) GetGatewayUptimeMs() uint32 { + if x != nil { + return x.GatewayUptimeMs + } + return 0 +} + +func (x *RadioRxFrame) GetRxSeq() uint32 { + if x != nil { + return x.RxSeq + } + return 0 +} + +type RadioNodeResponseTelemetry struct { + state protoimpl.MessageState `protogen:"open.v1"` + Frame *RadioRxFrame `protobuf:"bytes,1,opt,name=frame,proto3" json:"frame,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *RadioNodeResponseTelemetry) Reset() { + *x = RadioNodeResponseTelemetry{} + mi := &file_hr_packet_v3_proto_msgTypes[22] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *RadioNodeResponseTelemetry) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RadioNodeResponseTelemetry) ProtoMessage() {} + +func (x *RadioNodeResponseTelemetry) ProtoReflect() protoreflect.Message { + mi := &file_hr_packet_v3_proto_msgTypes[22] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RadioNodeResponseTelemetry.ProtoReflect.Descriptor instead. +func (*RadioNodeResponseTelemetry) Descriptor() ([]byte, []int) { + return file_hr_packet_v3_proto_rawDescGZIP(), []int{22} +} + +func (x *RadioNodeResponseTelemetry) GetFrame() *RadioRxFrame { + if x != nil { + return x.Frame + } + return nil +} + +type GatewayTelemetryMsg struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Types that are valid to be assigned to Choice: + // + // *GatewayTelemetryMsg_NtfHrMeasurement + // *GatewayTelemetryMsg_NtfGatewayStatus + // *GatewayTelemetryMsg_NtfStepCountMeasurement + // *GatewayTelemetryMsg_NtfRadioUnrecognizedFrame + // *GatewayTelemetryMsg_NtfRadioNodeGeneralRsp + Choice isGatewayTelemetryMsg_Choice `protobuf_oneof:"choice"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GatewayTelemetryMsg) Reset() { + *x = GatewayTelemetryMsg{} + mi := &file_hr_packet_v3_proto_msgTypes[23] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GatewayTelemetryMsg) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GatewayTelemetryMsg) ProtoMessage() {} + +func (x *GatewayTelemetryMsg) ProtoReflect() protoreflect.Message { + mi := &file_hr_packet_v3_proto_msgTypes[23] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GatewayTelemetryMsg.ProtoReflect.Descriptor instead. +func (*GatewayTelemetryMsg) Descriptor() ([]byte, []int) { + return file_hr_packet_v3_proto_rawDescGZIP(), []int{23} +} + +func (x *GatewayTelemetryMsg) GetChoice() isGatewayTelemetryMsg_Choice { + if x != nil { + return x.Choice + } + return nil +} + +func (x *GatewayTelemetryMsg) GetNtfHrMeasurement() *HrMeasurement { + if x != nil { + if x, ok := x.Choice.(*GatewayTelemetryMsg_NtfHrMeasurement); ok { + return x.NtfHrMeasurement + } + } + return nil +} + +func (x *GatewayTelemetryMsg) GetNtfGatewayStatus() *GatewayStatus { + if x != nil { + if x, ok := x.Choice.(*GatewayTelemetryMsg_NtfGatewayStatus); ok { + return x.NtfGatewayStatus + } + } + return nil +} + +func (x *GatewayTelemetryMsg) GetNtfStepCountMeasurement() *StepCountMeasurement { + if x != nil { + if x, ok := x.Choice.(*GatewayTelemetryMsg_NtfStepCountMeasurement); ok { + return x.NtfStepCountMeasurement + } + } + return nil +} + +func (x *GatewayTelemetryMsg) GetNtfRadioUnrecognizedFrame() *RadioRxFrame { + if x != nil { + if x, ok := x.Choice.(*GatewayTelemetryMsg_NtfRadioUnrecognizedFrame); ok { + return x.NtfRadioUnrecognizedFrame + } + } + return nil +} + +func (x *GatewayTelemetryMsg) GetNtfRadioNodeGeneralRsp() *RadioNodeResponseTelemetry { + if x != nil { + if x, ok := x.Choice.(*GatewayTelemetryMsg_NtfRadioNodeGeneralRsp); ok { + return x.NtfRadioNodeGeneralRsp + } + } + return nil +} + +type isGatewayTelemetryMsg_Choice interface { + isGatewayTelemetryMsg_Choice() +} + +type GatewayTelemetryMsg_NtfHrMeasurement struct { + NtfHrMeasurement *HrMeasurement `protobuf:"bytes,1,opt,name=ntf_hr_measurement,json=ntfHrMeasurement,proto3,oneof"` +} + +type GatewayTelemetryMsg_NtfGatewayStatus struct { + NtfGatewayStatus *GatewayStatus `protobuf:"bytes,2,opt,name=ntf_gateway_status,json=ntfGatewayStatus,proto3,oneof"` +} + +type GatewayTelemetryMsg_NtfStepCountMeasurement struct { + NtfStepCountMeasurement *StepCountMeasurement `protobuf:"bytes,3,opt,name=ntf_step_count_measurement,json=ntfStepCountMeasurement,proto3,oneof"` +} + +type GatewayTelemetryMsg_NtfRadioUnrecognizedFrame struct { + NtfRadioUnrecognizedFrame *RadioRxFrame `protobuf:"bytes,4,opt,name=ntf_radio_unrecognized_frame,json=ntfRadioUnrecognizedFrame,proto3,oneof"` +} + +type GatewayTelemetryMsg_NtfRadioNodeGeneralRsp struct { + NtfRadioNodeGeneralRsp *RadioNodeResponseTelemetry `protobuf:"bytes,7,opt,name=ntf_radio_node_general_rsp,json=ntfRadioNodeGeneralRsp,proto3,oneof"` +} + +func (*GatewayTelemetryMsg_NtfHrMeasurement) isGatewayTelemetryMsg_Choice() {} + +func (*GatewayTelemetryMsg_NtfGatewayStatus) isGatewayTelemetryMsg_Choice() {} + +func (*GatewayTelemetryMsg_NtfStepCountMeasurement) isGatewayTelemetryMsg_Choice() {} + +func (*GatewayTelemetryMsg_NtfRadioUnrecognizedFrame) isGatewayTelemetryMsg_Choice() {} + +func (*GatewayTelemetryMsg_NtfRadioNodeGeneralRsp) isGatewayTelemetryMsg_Choice() {} + +var File_hr_packet_v3_proto protoreflect.FileDescriptor + +const file_hr_packet_v3_proto_rawDesc = "" + + "\n" + + "\x12hr_packet_v3.proto\x12\x0fwhgw.gateway.v3\"\xa5\x01\n" + + "\n" + + "StatusFlag\x12B\n" + + "\rhr_confidence\x18\x01 \x01(\x0e2\x1d.whgw.gateway.v3.HrConfidenceR\fhrConfidence\x12\x1b\n" + + "\tis_active\x18\x02 \x01(\bR\bisActive\x12\x1c\n" + + "\n" + + "is_on_skin\x18\x03 \x01(\bR\bisOnSkin\x12\x18\n" + + "\abattery\x18\x04 \x01(\rR\abattery\"~\n" + + "\bHrPacket\x123\n" + + "\x06status\x18\x01 \x01(\v2\x1b.whgw.gateway.v3.StatusFlagR\x06status\x12\x0e\n" + + "\x02id\x18\x02 \x01(\rR\x02id\x12\x1d\n" + + "\n" + + "packet_num\x18\x03 \x01(\rR\tpacketNum\x12\x0e\n" + + "\x02hr\x18\x04 \x01(\rR\x02hr\"_\n" + + "\x0fStepCountPacket\x12\x0e\n" + + "\x02id\x18\x01 \x01(\rR\x02id\x12\x1d\n" + + "\n" + + "packet_num\x18\x02 \x01(\rR\tpacketNum\x12\x1d\n" + + "\n" + + "step_count\x18\x03 \x01(\rR\tstepCount\"\xad\x01\n" + + "\x12WearableStatusFlag\x12B\n" + + "\rhr_confidence\x18\x01 \x01(\x0e2\x1d.whgw.gateway.v3.HrConfidenceR\fhrConfidence\x12\x1b\n" + + "\tis_active\x18\x02 \x01(\bR\bisActive\x12\x1c\n" + + "\n" + + "is_on_skin\x18\x03 \x01(\bR\bisOnSkin\x12\x18\n" + + "\abattery\x18\x04 \x01(\rR\abattery\"n\n" + + "\x0eLoRaParameters\x12'\n" + + "\x02bw\x18\x01 \x01(\x0e2\x17.whgw.gateway.v3.LoRaBWR\x02bw\x12\x0e\n" + + "\x02sf\x18\x02 \x01(\rR\x02sf\x12#\n" + + "\rfrequency_mhz\x18\x03 \x01(\x02R\ffrequencyMhz\"\xdb\x01\n" + + "\x0eGfskParameters\x12\x1f\n" + + "\vbitrate_bps\x18\x01 \x01(\rR\n" + + "bitrateBps\x12#\n" + + "\rfrequency_mhz\x18\x02 \x01(\x02R\ffrequencyMhz\x124\n" + + "\x16frequency_deviation_hz\x18\x03 \x01(\rR\x14frequencyDeviationHz\x12&\n" + + "\x0frx_bandwidth_hz\x18\x04 \x01(\rR\rrxBandwidthHz\x12%\n" + + "\x0epayload_length\x18\x05 \x01(\rR\rpayloadLength\"\x87\x01\n" + + "\x0fRadioParameters\x125\n" + + "\x04lora\x18\x01 \x01(\v2\x1f.whgw.gateway.v3.LoRaParametersH\x00R\x04lora\x125\n" + + "\x04gfsk\x18\x02 \x01(\v2\x1f.whgw.gateway.v3.GfskParametersH\x00R\x04gfskB\x06\n" + + "\x04kind\"]\n" + + "\x10LoRaPacketStatus\x12+\n" + + "\x12signal_rssi_x2_neg\x18\x01 \x01(\rR\x0fsignalRssiX2Neg\x12\x1c\n" + + "\n" + + "snr_pkt_x4\x18\x02 \x01(\x05R\bsnrPktX4\"a\n" + + "\x0fFskPacketStatus\x12'\n" + + "\x10rssi_sync_x2_neg\x18\x01 \x01(\rR\rrssiSyncX2Neg\x12%\n" + + "\x0frssi_avg_x2_neg\x18\x02 \x01(\rR\frssiAvgX2Neg\"\x85\x01\n" + + "\fPacketStatus\x127\n" + + "\x04lora\x18\x01 \x01(\v2!.whgw.gateway.v3.LoRaPacketStatusH\x00R\x04lora\x124\n" + + "\x03fsk\x18\x02 \x01(\v2 .whgw.gateway.v3.FskPacketStatusH\x00R\x03fskB\x06\n" + + "\x04kind\"\x8b\x01\n" + + "\aHubInfo\x12\x15\n" + + "\x06bus_id\x18\x01 \x01(\rR\x05busId\x12\x1c\n" + + "\n" + + "sub_dev_id\x18\x02 \x01(\rR\bsubDevId\x12K\n" + + "\x10radio_parameters\x18\x03 \x01(\v2 .whgw.gateway.v3.RadioParametersR\x0fradioParameters\"\xd5\x01\n" + + "\tRadioData\x123\n" + + "\bhub_info\x18\x01 \x01(\v2\x18.whgw.gateway.v3.HubInfoR\ahubInfo\x12B\n" + + "\rpacket_status\x18\x02 \x01(\v2\x1d.whgw.gateway.v3.PacketStatusR\fpacketStatus\x12\x12\n" + + "\x04data\x18\x03 \x01(\fR\x04data\x12;\n" + + "\trx_timing\x18\x04 \x01(\v2\x1e.whgw.gateway.v3.RadioRxTimingR\brxTiming\"l\n" + + "\rRadioRxTiming\x120\n" + + "\x15rx_done_hub_uptime_us\x18\x01 \x01(\x04R\x11rxDoneHubUptimeUs\x12)\n" + + "\x11irq_to_forward_us\x18\x02 \x01(\rR\x0eirqToForwardUs\"\x8d\x01\n" + + "\vBatteryInfo\x12\x1d\n" + + "\n" + + "voltage_mv\x18\x01 \x01(\rR\tvoltageMv\x12%\n" + + "\x0esoc_percentage\x18\x02 \x01(\rR\rsocPercentage\x128\n" + + "\x18charging_rate_percentage\x18\x03 \x01(\x11R\x16chargingRatePercentage\"[\n" + + "\x11CellularModemInfo\x12\x12\n" + + "\x04imei\x18\x01 \x01(\tR\x04imei\x12\x19\n" + + "\bcsq_rssi\x18\x02 \x01(\x05R\acsqRssi\x12\x17\n" + + "\acsq_ber\x18\x03 \x01(\x05R\x06csqBer\"\xfc\x01\n" + + "\vGatewayInfo\x12\x1b\n" + + "\tregion_id\x18\x01 \x01(\rR\bregionId\x12\x1f\n" + + "\vgateway_mac\x18\x02 \x01(\fR\n" + + "gatewayMac\x12G\n" + + "\ractive_uplink\x18\x03 \x01(\x0e2\".whgw.gateway.v3.NetworkUplinkKindR\factiveUplink\x12I\n" + + "\x0ecellular_modem\x18\x04 \x01(\v2\".whgw.gateway.v3.CellularModemInfoR\rcellularModem\x12\x1b\n" + + "\tipv4_addr\x18\x05 \x01(\rR\bipv4Addr\"\x81\x02\n" + + "\rHrMeasurement\x126\n" + + "\thr_packet\x18\x01 \x01(\v2\x19.whgw.gateway.v3.HrPacketR\bhrPacket\x12B\n" + + "\rpacket_status\x18\x02 \x01(\v2\x1d.whgw.gateway.v3.PacketStatusR\fpacketStatus\x12?\n" + + "\fgateway_info\x18\x03 \x01(\v2\x1c.whgw.gateway.v3.GatewayInfoR\vgatewayInfo\x123\n" + + "\bhub_info\x18\x04 \x01(\v2\x18.whgw.gateway.v3.HubInfoR\ahubInfo\"\x9e\x02\n" + + "\x14StepCountMeasurement\x12L\n" + + "\x11step_count_packet\x18\x01 \x01(\v2 .whgw.gateway.v3.StepCountPacketR\x0fstepCountPacket\x12B\n" + + "\rpacket_status\x18\x02 \x01(\v2\x1d.whgw.gateway.v3.PacketStatusR\fpacketStatus\x12?\n" + + "\fgateway_info\x18\x03 \x01(\v2\x1c.whgw.gateway.v3.GatewayInfoR\vgatewayInfo\x123\n" + + "\bhub_info\x18\x04 \x01(\v2\x18.whgw.gateway.v3.HubInfoR\ahubInfo\"\xec\x01\n" + + "\x10GatewayStatistic\x12\x1d\n" + + "\n" + + "boot_count\x18\x01 \x01(\rR\tbootCount\x12\x1b\n" + + "\tuptime_ms\x18\x02 \x01(\rR\buptimeMs\x12@\n" + + "\x1dduration_ms_since_last_packet\x18\x03 \x01(\rR\x19durationMsSinceLastPacket\x12\x19\n" + + "\brx_count\x18\x04 \x01(\rR\arxCount\x12?\n" + + "\fbattery_info\x18\x05 \x01(\v2\x1c.whgw.gateway.v3.BatteryInfoR\vbatteryInfo\"x\n" + + "\rGatewayStatus\x120\n" + + "\x04info\x18\x01 \x01(\v2\x1c.whgw.gateway.v3.GatewayInfoR\x04info\x125\n" + + "\x04stat\x18\x02 \x01(\v2!.whgw.gateway.v3.GatewayStatisticR\x04stat\"\xfd\x02\n" + + "\x1cWearableHealthTelemetryBatch\x12?\n" + + "\fgateway_info\x18\x01 \x01(\v2\x1c.whgw.gateway.v3.GatewayInfoR\vgatewayInfo\x12\x1d\n" + + "\n" + + "report_seq\x18\x02 \x01(\rR\treportSeq\x12\x19\n" + + "\bframe_id\x18\x03 \x01(\rR\aframeId\x12+\n" + + "\x12frame_unix_time_us\x18\x04 \x01(\x04R\x0fframeUnixTimeUs\x12'\n" + + "\x10radio_sub_dev_id\x18\x05 \x01(\rR\rradioSubDevId\x12&\n" + + "\x0frf_frequency_hz\x18\x06 \x01(\rR\rrfFrequencyHz\x12'\n" + + "\x0fsample_encoding\x18\a \x01(\rR\x0esampleEncoding\x12!\n" + + "\fsample_count\x18\b \x01(\rR\vsampleCount\x12\x18\n" + + "\asamples\x18\t \x01(\fR\asamples\"\x8c\x01\n" + + "\fRadioRxFrame\x129\n" + + "\n" + + "radio_data\x18\x01 \x01(\v2\x1a.whgw.gateway.v3.RadioDataR\tradioData\x12*\n" + + "\x11gateway_uptime_ms\x18\x02 \x01(\rR\x0fgatewayUptimeMs\x12\x15\n" + + "\x06rx_seq\x18\x03 \x01(\rR\x05rxSeq\"Q\n" + + "\x1aRadioNodeResponseTelemetry\x123\n" + + "\x05frame\x18\x01 \x01(\v2\x1d.whgw.gateway.v3.RadioRxFrameR\x05frame\"\xf2\x03\n" + + "\x13GatewayTelemetryMsg\x12N\n" + + "\x12ntf_hr_measurement\x18\x01 \x01(\v2\x1e.whgw.gateway.v3.HrMeasurementH\x00R\x10ntfHrMeasurement\x12N\n" + + "\x12ntf_gateway_status\x18\x02 \x01(\v2\x1e.whgw.gateway.v3.GatewayStatusH\x00R\x10ntfGatewayStatus\x12d\n" + + "\x1antf_step_count_measurement\x18\x03 \x01(\v2%.whgw.gateway.v3.StepCountMeasurementH\x00R\x17ntfStepCountMeasurement\x12`\n" + + "\x1cntf_radio_unrecognized_frame\x18\x04 \x01(\v2\x1d.whgw.gateway.v3.RadioRxFrameH\x00R\x19ntfRadioUnrecognizedFrame\x12i\n" + + "\x1antf_radio_node_general_rsp\x18\a \x01(\v2+.whgw.gateway.v3.RadioNodeResponseTelemetryH\x00R\x16ntfRadioNodeGeneralRspB\b\n" + + "\x06choice*7\n" + + "\fHrConfidence\x12\b\n" + + "\x04ZERO\x10\x00\x12\a\n" + + "\x03LOW\x10\x01\x12\n" + + "\n" + + "\x06MEDIUM\x10\x02\x12\b\n" + + "\x04HIGH\x10\x03*\x8e\x01\n" + + "\x06LoRaBW\x12\v\n" + + "\aBW_NONE\x10\x00\x12\v\n" + + "\aBW_10_4\x10\b\x12\v\n" + + "\aBW_15_6\x10\x01\x12\v\n" + + "\aBW_20_8\x10\t\x12\f\n" + + "\bBW_31_25\x10\x02\x12\v\n" + + "\aBW_41_7\x10\n" + + "\x12\v\n" + + "\aBW_62_5\x10\x03\x12\f\n" + + "\bBW_125_0\x10\x04\x12\f\n" + + "\bBW_250_0\x10\x05\x12\f\n" + + "\bBW_500_0\x10\x06*e\n" + + "\x11NetworkUplinkKind\x12\x1a\n" + + "\x16NETWORK_UPLINK_UNKNOWN\x10\x00\x12\x17\n" + + "\x13NETWORK_UPLINK_WIFI\x10\x01\x12\x1b\n" + + "\x17NETWORK_UPLINK_CELLULAR\x10\x02B\x1fZ\x1dhr_receiver/proto/v3;whgwv3pbb\x06proto3" + +var ( + file_hr_packet_v3_proto_rawDescOnce sync.Once + file_hr_packet_v3_proto_rawDescData []byte +) + +func file_hr_packet_v3_proto_rawDescGZIP() []byte { + file_hr_packet_v3_proto_rawDescOnce.Do(func() { + file_hr_packet_v3_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_hr_packet_v3_proto_rawDesc), len(file_hr_packet_v3_proto_rawDesc))) + }) + return file_hr_packet_v3_proto_rawDescData +} + +var file_hr_packet_v3_proto_enumTypes = make([]protoimpl.EnumInfo, 3) +var file_hr_packet_v3_proto_msgTypes = make([]protoimpl.MessageInfo, 24) +var file_hr_packet_v3_proto_goTypes = []any{ + (HrConfidence)(0), // 0: whgw.gateway.v3.HrConfidence + (LoRaBW)(0), // 1: whgw.gateway.v3.LoRaBW + (NetworkUplinkKind)(0), // 2: whgw.gateway.v3.NetworkUplinkKind + (*StatusFlag)(nil), // 3: whgw.gateway.v3.StatusFlag + (*HrPacket)(nil), // 4: whgw.gateway.v3.HrPacket + (*StepCountPacket)(nil), // 5: whgw.gateway.v3.StepCountPacket + (*WearableStatusFlag)(nil), // 6: whgw.gateway.v3.WearableStatusFlag + (*LoRaParameters)(nil), // 7: whgw.gateway.v3.LoRaParameters + (*GfskParameters)(nil), // 8: whgw.gateway.v3.GfskParameters + (*RadioParameters)(nil), // 9: whgw.gateway.v3.RadioParameters + (*LoRaPacketStatus)(nil), // 10: whgw.gateway.v3.LoRaPacketStatus + (*FskPacketStatus)(nil), // 11: whgw.gateway.v3.FskPacketStatus + (*PacketStatus)(nil), // 12: whgw.gateway.v3.PacketStatus + (*HubInfo)(nil), // 13: whgw.gateway.v3.HubInfo + (*RadioData)(nil), // 14: whgw.gateway.v3.RadioData + (*RadioRxTiming)(nil), // 15: whgw.gateway.v3.RadioRxTiming + (*BatteryInfo)(nil), // 16: whgw.gateway.v3.BatteryInfo + (*CellularModemInfo)(nil), // 17: whgw.gateway.v3.CellularModemInfo + (*GatewayInfo)(nil), // 18: whgw.gateway.v3.GatewayInfo + (*HrMeasurement)(nil), // 19: whgw.gateway.v3.HrMeasurement + (*StepCountMeasurement)(nil), // 20: whgw.gateway.v3.StepCountMeasurement + (*GatewayStatistic)(nil), // 21: whgw.gateway.v3.GatewayStatistic + (*GatewayStatus)(nil), // 22: whgw.gateway.v3.GatewayStatus + (*WearableHealthTelemetryBatch)(nil), // 23: whgw.gateway.v3.WearableHealthTelemetryBatch + (*RadioRxFrame)(nil), // 24: whgw.gateway.v3.RadioRxFrame + (*RadioNodeResponseTelemetry)(nil), // 25: whgw.gateway.v3.RadioNodeResponseTelemetry + (*GatewayTelemetryMsg)(nil), // 26: whgw.gateway.v3.GatewayTelemetryMsg +} +var file_hr_packet_v3_proto_depIdxs = []int32{ + 0, // 0: whgw.gateway.v3.StatusFlag.hr_confidence:type_name -> whgw.gateway.v3.HrConfidence + 3, // 1: whgw.gateway.v3.HrPacket.status:type_name -> whgw.gateway.v3.StatusFlag + 0, // 2: whgw.gateway.v3.WearableStatusFlag.hr_confidence:type_name -> whgw.gateway.v3.HrConfidence + 1, // 3: whgw.gateway.v3.LoRaParameters.bw:type_name -> whgw.gateway.v3.LoRaBW + 7, // 4: whgw.gateway.v3.RadioParameters.lora:type_name -> whgw.gateway.v3.LoRaParameters + 8, // 5: whgw.gateway.v3.RadioParameters.gfsk:type_name -> whgw.gateway.v3.GfskParameters + 10, // 6: whgw.gateway.v3.PacketStatus.lora:type_name -> whgw.gateway.v3.LoRaPacketStatus + 11, // 7: whgw.gateway.v3.PacketStatus.fsk:type_name -> whgw.gateway.v3.FskPacketStatus + 9, // 8: whgw.gateway.v3.HubInfo.radio_parameters:type_name -> whgw.gateway.v3.RadioParameters + 13, // 9: whgw.gateway.v3.RadioData.hub_info:type_name -> whgw.gateway.v3.HubInfo + 12, // 10: whgw.gateway.v3.RadioData.packet_status:type_name -> whgw.gateway.v3.PacketStatus + 15, // 11: whgw.gateway.v3.RadioData.rx_timing:type_name -> whgw.gateway.v3.RadioRxTiming + 2, // 12: whgw.gateway.v3.GatewayInfo.active_uplink:type_name -> whgw.gateway.v3.NetworkUplinkKind + 17, // 13: whgw.gateway.v3.GatewayInfo.cellular_modem:type_name -> whgw.gateway.v3.CellularModemInfo + 4, // 14: whgw.gateway.v3.HrMeasurement.hr_packet:type_name -> whgw.gateway.v3.HrPacket + 12, // 15: whgw.gateway.v3.HrMeasurement.packet_status:type_name -> whgw.gateway.v3.PacketStatus + 18, // 16: whgw.gateway.v3.HrMeasurement.gateway_info:type_name -> whgw.gateway.v3.GatewayInfo + 13, // 17: whgw.gateway.v3.HrMeasurement.hub_info:type_name -> whgw.gateway.v3.HubInfo + 5, // 18: whgw.gateway.v3.StepCountMeasurement.step_count_packet:type_name -> whgw.gateway.v3.StepCountPacket + 12, // 19: whgw.gateway.v3.StepCountMeasurement.packet_status:type_name -> whgw.gateway.v3.PacketStatus + 18, // 20: whgw.gateway.v3.StepCountMeasurement.gateway_info:type_name -> whgw.gateway.v3.GatewayInfo + 13, // 21: whgw.gateway.v3.StepCountMeasurement.hub_info:type_name -> whgw.gateway.v3.HubInfo + 16, // 22: whgw.gateway.v3.GatewayStatistic.battery_info:type_name -> whgw.gateway.v3.BatteryInfo + 18, // 23: whgw.gateway.v3.GatewayStatus.info:type_name -> whgw.gateway.v3.GatewayInfo + 21, // 24: whgw.gateway.v3.GatewayStatus.stat:type_name -> whgw.gateway.v3.GatewayStatistic + 18, // 25: whgw.gateway.v3.WearableHealthTelemetryBatch.gateway_info:type_name -> whgw.gateway.v3.GatewayInfo + 14, // 26: whgw.gateway.v3.RadioRxFrame.radio_data:type_name -> whgw.gateway.v3.RadioData + 24, // 27: whgw.gateway.v3.RadioNodeResponseTelemetry.frame:type_name -> whgw.gateway.v3.RadioRxFrame + 19, // 28: whgw.gateway.v3.GatewayTelemetryMsg.ntf_hr_measurement:type_name -> whgw.gateway.v3.HrMeasurement + 22, // 29: whgw.gateway.v3.GatewayTelemetryMsg.ntf_gateway_status:type_name -> whgw.gateway.v3.GatewayStatus + 20, // 30: whgw.gateway.v3.GatewayTelemetryMsg.ntf_step_count_measurement:type_name -> whgw.gateway.v3.StepCountMeasurement + 24, // 31: whgw.gateway.v3.GatewayTelemetryMsg.ntf_radio_unrecognized_frame:type_name -> whgw.gateway.v3.RadioRxFrame + 25, // 32: whgw.gateway.v3.GatewayTelemetryMsg.ntf_radio_node_general_rsp:type_name -> whgw.gateway.v3.RadioNodeResponseTelemetry + 33, // [33:33] is the sub-list for method output_type + 33, // [33:33] is the sub-list for method input_type + 33, // [33:33] is the sub-list for extension type_name + 33, // [33:33] is the sub-list for extension extendee + 0, // [0:33] is the sub-list for field type_name +} + +func init() { file_hr_packet_v3_proto_init() } +func file_hr_packet_v3_proto_init() { + if File_hr_packet_v3_proto != nil { + return + } + file_hr_packet_v3_proto_msgTypes[6].OneofWrappers = []any{ + (*RadioParameters_Lora)(nil), + (*RadioParameters_Gfsk)(nil), + } + file_hr_packet_v3_proto_msgTypes[9].OneofWrappers = []any{ + (*PacketStatus_Lora)(nil), + (*PacketStatus_Fsk)(nil), + } + file_hr_packet_v3_proto_msgTypes[23].OneofWrappers = []any{ + (*GatewayTelemetryMsg_NtfHrMeasurement)(nil), + (*GatewayTelemetryMsg_NtfGatewayStatus)(nil), + (*GatewayTelemetryMsg_NtfStepCountMeasurement)(nil), + (*GatewayTelemetryMsg_NtfRadioUnrecognizedFrame)(nil), + (*GatewayTelemetryMsg_NtfRadioNodeGeneralRsp)(nil), + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_hr_packet_v3_proto_rawDesc), len(file_hr_packet_v3_proto_rawDesc)), + NumEnums: 3, + NumMessages: 24, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_hr_packet_v3_proto_goTypes, + DependencyIndexes: file_hr_packet_v3_proto_depIdxs, + EnumInfos: file_hr_packet_v3_proto_enumTypes, + MessageInfos: file_hr_packet_v3_proto_msgTypes, + }.Build() + File_hr_packet_v3_proto = out.File + file_hr_packet_v3_proto_goTypes = nil + file_hr_packet_v3_proto_depIdxs = nil +} diff --git a/proto/v3/hr_packet_v3.proto b/proto/v3/hr_packet_v3.proto new file mode 100644 index 0000000..6e407a5 --- /dev/null +++ b/proto/v3/hr_packet_v3.proto @@ -0,0 +1,193 @@ +syntax = "proto3"; + +package whgw.gateway.v3; + +option go_package = "hr_receiver/proto/v3;whgwv3pb"; + +enum HrConfidence { + ZERO = 0; + LOW = 1; + MEDIUM = 2; + HIGH = 3; +} + +enum LoRaBW { + BW_NONE = 0; + BW_10_4 = 0x08; + BW_15_6 = 0x01; + BW_20_8 = 0x09; + BW_31_25 = 0x02; + BW_41_7 = 0x0A; + BW_62_5 = 0x03; + BW_125_0 = 0x04; + BW_250_0 = 0x05; + BW_500_0 = 0x06; +} + +enum NetworkUplinkKind { + NETWORK_UPLINK_UNKNOWN = 0; + NETWORK_UPLINK_WIFI = 1; + NETWORK_UPLINK_CELLULAR = 2; +} + +message StatusFlag { + HrConfidence hr_confidence = 1; + bool is_active = 2; + bool is_on_skin = 3; + uint32 battery = 4; +} + +message HrPacket { + StatusFlag status = 1; + uint32 id = 2; + uint32 packet_num = 3; + uint32 hr = 4; +} + +message StepCountPacket { + uint32 id = 1; + uint32 packet_num = 2; + uint32 step_count = 3; +} + +message WearableStatusFlag { + HrConfidence hr_confidence = 1; + bool is_active = 2; + bool is_on_skin = 3; + uint32 battery = 4; +} + +message LoRaParameters { + LoRaBW bw = 1; + uint32 sf = 2; + float frequency_mhz = 3; +} + +message GfskParameters { + uint32 bitrate_bps = 1; + float frequency_mhz = 2; + uint32 frequency_deviation_hz = 3; + uint32 rx_bandwidth_hz = 4; + uint32 payload_length = 5; +} + +message RadioParameters { + oneof kind { + LoRaParameters lora = 1; + GfskParameters gfsk = 2; + } +} + +message LoRaPacketStatus { + uint32 signal_rssi_x2_neg = 1; + int32 snr_pkt_x4 = 2; +} + +message FskPacketStatus { + uint32 rssi_sync_x2_neg = 1; + uint32 rssi_avg_x2_neg = 2; +} + +message PacketStatus { + oneof kind { + LoRaPacketStatus lora = 1; + FskPacketStatus fsk = 2; + } +} + +message HubInfo { + uint32 bus_id = 1; + uint32 sub_dev_id = 2; + RadioParameters radio_parameters = 3; +} + +message RadioData { + HubInfo hub_info = 1; + PacketStatus packet_status = 2; + bytes data = 3; + RadioRxTiming rx_timing = 4; +} + +message RadioRxTiming { + uint64 rx_done_hub_uptime_us = 1; + uint32 irq_to_forward_us = 2; +} + +message BatteryInfo { + uint32 voltage_mv = 1; + uint32 soc_percentage = 2; + sint32 charging_rate_percentage = 3; +} + +message CellularModemInfo { + string imei = 1; + int32 csq_rssi = 2; + int32 csq_ber = 3; +} + +message GatewayInfo { + uint32 region_id = 1; + bytes gateway_mac = 2; + NetworkUplinkKind active_uplink = 3; + CellularModemInfo cellular_modem = 4; + uint32 ipv4_addr = 5; +} + +message HrMeasurement { + HrPacket hr_packet = 1; + PacketStatus packet_status = 2; + GatewayInfo gateway_info = 3; + HubInfo hub_info = 4; +} + +message StepCountMeasurement { + StepCountPacket step_count_packet = 1; + PacketStatus packet_status = 2; + GatewayInfo gateway_info = 3; + HubInfo hub_info = 4; +} + +message GatewayStatistic { + uint32 boot_count = 1; + uint32 uptime_ms = 2; + uint32 duration_ms_since_last_packet = 3; + uint32 rx_count = 4; + BatteryInfo battery_info = 5; +} + +message GatewayStatus { + GatewayInfo info = 1; + GatewayStatistic stat = 2; +} + +message WearableHealthTelemetryBatch { + GatewayInfo gateway_info = 1; + uint32 report_seq = 2; + uint32 frame_id = 3; + uint64 frame_unix_time_us = 4; + uint32 radio_sub_dev_id = 5; + uint32 rf_frequency_hz = 6; + uint32 sample_encoding = 7; + uint32 sample_count = 8; + bytes samples = 9; +} + +message RadioRxFrame { + RadioData radio_data = 1; + uint32 gateway_uptime_ms = 2; + uint32 rx_seq = 3; +} + +message RadioNodeResponseTelemetry { + RadioRxFrame frame = 1; +} + +message GatewayTelemetryMsg { + oneof choice { + HrMeasurement ntf_hr_measurement = 1; + GatewayStatus ntf_gateway_status = 2; + StepCountMeasurement ntf_step_count_measurement = 3; + RadioRxFrame ntf_radio_unrecognized_frame = 4; + RadioNodeResponseTelemetry ntf_radio_node_general_rsp = 7; + } +} diff --git a/routes/routes.go b/routes/routes.go index 341a30d..87c4e0c 100644 --- a/routes/routes.go +++ b/routes/routes.go @@ -156,6 +156,9 @@ func SetupRouter() *gin.Engine { admin.GET("/system-debug/mqtt/status", systemDebugController.MqttStatus) admin.POST("/system-debug/mqtt/start", systemDebugController.StartMqtt) admin.POST("/system-debug/mqtt/stop", systemDebugController.StopMqtt) + admin.GET("/system-debug/mqtt-v3/status", systemDebugController.MqttV3Status) + admin.POST("/system-debug/mqtt-v3/start", systemDebugController.StartMqttV3) + admin.POST("/system-debug/mqtt-v3/stop", systemDebugController.StopMqttV3) admin.GET("/system-debug/mqtt/replay/status", systemDebugController.MqttReplayStatus) admin.POST("/system-debug/mqtt/replay/start", systemDebugController.StartMqttReplay) admin.POST("/system-debug/mqtt/replay/stop", systemDebugController.StopMqttReplay) @@ -173,6 +176,7 @@ func SetupRouter() *gin.Engine { } v1.GET("/admin/system-debug/mqtt/ws", systemDebugController.MqttWebSocket) + v1.GET("/admin/system-debug/mqtt-v3/ws", systemDebugController.MqttV3WebSocket) v1.GET("/lesson-plans/share/:code/download", lessonPlanController.DownloadByShareCode) public := v1.Group("") {