Description
- 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.