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.
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):
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.
A fine timestamp (Fts element) could be added quite simply to the RadioMetaDataUpInfo structure as follows:
Func SetRadioMetaDataToProto() in the same file needs a little refactoring:
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):
This feature can be patched with the following commands:
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.