Skip to content

Basic Station backend: FineTimeSinceGpsEpoch missing from uplink event? #228

Open
@LouneCode

Description

@LouneCode
  • I have searched the issues of this repository and believe that this is not a duplicate.

Summary

Hi all,

It looks like the ChirpStack Gateway Bridge with Basic Station backend don't support fine timestamps? Actually the websocket message of the Basic Station backend has a “fts” tag for fine timestamps, but this feature is missing from the ChirpStack Gateway bridge?

 

Basic Station backend websocket message (SX1303, SX1302):

2022-12-19 17:20:14.797 [AIO:XDEB] [3|WS] > {"msgtype":"updf","MHdr":64, ---> "fts":-1 <--- ,"rssi":-45,"snr":13.75,"rxtime":1671470414.687880516}}

What is the use-case?

A Fine timestamp is used to get the TDoA geolocation of the transmitter (sensor).

Implementation description

ChirpStack Gateway Bridge

The RadioMetaDataUpInfo structure in radio_meta_data.go implements which elements of a websocket message to parse.

// RadioMetaDataUpInfo contains the radio meta-data uplink info.
type RadioMetaDataUpInfo struct {
	RxTime  float64 `json:"rxtime"`
	RCtx    uint64  `json:"rctx"`
	XTime   uint64  `json:"xtime"`
	GPSTime int64   `json:"gpstime"`
	RSSI    float32 `json:"rssi"`
	SNR     float32 `json:"snr"`
}

A fine timestamp (Fts element) could be added quite simply to the RadioMetaDataUpInfo structure as follows:

// RadioMetaDataUpInfo contains the radio meta-data uplink info.
type RadioMetaDataUpInfo struct {
	RxTime  float64 `json:"rxtime"`
	RCtx    uint64  `json:"rctx"`
	XTime   uint64  `json:"xtime"`
	GPSTime int64   `json:"gpstime"`
	Fts     *int64  `json:"fts,omitempty"`
	RSSI    float32 `json:"rssi"`
	SNR     float32 `json:"snr"`
}

Func SetRadioMetaDataToProto() in the same file needs a little refactoring:

// SetRadioMetaDataToProto sets the given parameters to the given protobuf struct.
func SetRadioMetaDataToProto(loraBand band.Band, gatewayID lorawan.EUI64, rmd RadioMetaData, pb *gw.UplinkFrame) error {
	//
	// TxInfo
	//
	dr, err := loraBand.GetDataRate(rmd.DR)
	if err != nil {
		return errors.Wrap(err, "get data-rate error")
	}

	pb.TxInfo = &gw.UplinkTxInfo{
		Frequency: rmd.Frequency,
	}

	switch dr.Modulation {
	case band.LoRaModulation:
		pb.TxInfo.Modulation = &gw.Modulation{
			Parameters: &gw.Modulation_Lora{
				Lora: &gw.LoraModulationInfo{
					Bandwidth:             uint32(dr.Bandwidth) * 1000,
					SpreadingFactor:       uint32(dr.SpreadFactor),
					CodeRate:              gw.CodeRate_CR_4_5,
					PolarizationInversion: false,
				},
			},
		}
	case band.FSKModulation:
		pb.TxInfo.Modulation = &gw.Modulation{
			Parameters: &gw.Modulation_Fsk{
				Fsk: &gw.FskModulationInfo{
					Datarate: uint32(dr.BitRate),
				},
			},
		}
	}

	//
	// RxInfo
	//
	pb.RxInfo = &gw.UplinkRxInfo{
		GatewayId: gatewayID.String(),
		Rssi:      int32(rmd.UpInfo.RSSI),
		Snr:       float32(rmd.UpInfo.SNR),
	}

	if rxTime := rmd.UpInfo.RxTime; rxTime != 0 {
		sec, nsec := math.Modf(rmd.UpInfo.RxTime)
		if sec != 0 {
			val := time.Unix(int64(sec), int64(nsec))
			pb.RxInfo.Time = timestamppb.New(val)
		}
	}

	if gpsTime := rmd.UpInfo.GPSTime; gpsTime != 0 {
		gpsTimeDur := time.Duration(gpsTime) * time.Microsecond
		gpsTimeTime := time.Time(gps.NewTimeFromTimeSinceGPSEpoch(gpsTimeDur))

		pb.RxInfo.TimeSinceGpsEpoch = durationpb.New(gpsTimeDur)
		pb.RxInfo.Time = timestamppb.New(gpsTimeTime)
	}

	if fts := rmd.UpInfo.Fts; fts != nil {
		if *fts > -1 {

			ftsTimeDur := time.Duration(*fts) * time.Nanosecond

			if gpsTime := rmd.UpInfo.GPSTime; gpsTime != 0 {
				gpsTimeDur := time.Duration(gpsTime) * time.Microsecond
				// take the seconds from the gps time
				gpsTimeDur = gpsTimeDur - (gpsTimeDur % time.Second)
				// add the nanos from the fine-timestamp
				ftsTimeDur = gpsTimeDur + ftsTimeDur
			}

			pb.RxInfo.FineTimeSinceGpsEpoch = durationpb.New(ftsTimeDur)
		}
	}

After these small changes, the fine timestamp information exist in the uplink event as follows (if you are using the GLS Basic Station instead of Basic Station backend):

"rxInfo": [
    {
        "gatewayId": "0016c001ffxxxxxx",
        "uplinkId": 3232276575,
        "time": "2022-12-26T12:01:47.709920+00:00",
        "timeSinceGpsEpoch": "1356091325.709920s",
        "fineTimeSinceGpsEpoch": "1356091325.263021396s",
        "rssi": -45,
        "snr": 14.25,
        "location": {
            "latitude": 62.1979847889177,
            "longitude": 21.123254060745244
        },
        "context": "AAAAAAAAAAAAMgABVWHvOA==",
        "metadata": {
            "region_common_name": "EU868",
            "region_name": "eu868"
        }
    },

This feature can be patched with the following commands:

$ git clone https://github.com/chirpstack/chirpstack-gateway-bridge.git chirpstack-gateway-bridge
$ cd chirpstack-gateway-bridge
$ curl https://raw.githubusercontent.com/LouneCode/GLS-chripstack-gateway-bridge/main/builder/GLS_CSGB_v4.0.8.1.patch | git apply

# Sanity check:
$ cat ./internal/backend/basicstation/structs/radio_meta_data.go

 

More information about this idea can be found at:

 

Can you implement this by yourself and make a pull request?

See the implementation proposal above.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions