Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Chirpstack-consertratord-sx1302 backend - Fine Timestamp is missing from uplink event? #65

Closed
LouneCode opened this issue Jun 11, 2023 · 3 comments

Comments

@LouneCode
Copy link
Contributor

  • [ x] I have searched the issues of this repository and believe that this is not a duplicate.

Summary

I have investigated the consentratord backend code and found that the Fine timestamp information basis on PPS signal missing from current implementation?

Consertratord-sx1302 implementation has been build on Semtechs's HAL library (libloragw). Sx1302_hal library includes code for Fine timestamp implementation (for hardware with PPS signal). It seems that the Fine Timestamp solution can be added to consertratord-sx1302 backend quite easily.

Similar cases can be found from following issues:

 

What is the use-case?

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

Implementation description - Solution proposal

Add Fine Timestamp information to the up-event of the concentratord-sx1302 backend.

 

1) consertratord.toml

consertratord.toml file found in the same folder where chirpstack-concentratord-sx1302 executable is. Following lines to be added into consertratord.toml configuration file for enabling Fine Timestamp functionality:

  • model_flags=["USB","GNSS"]
  • [gateway.fine_timestamp]
  • enable=true
  • mode="ALL_SF"

 

# LoRa gateway configuration.
[gateway]

  # Antenna gain (dB).
  antenna_gain=0

  # Public LoRaWAN network.
  lorawan_public=true

  # Gateway vendor / model.
  #
  # This configures various vendor and model specific settings like the min / max
  # frequency and TX gain table.
  #model="rak_2287_eu868"
  model="semtech_sx1302css868gw1_eu868"

  # Gateway vendor / model flags.
  #
  # Flag can be used to configure additional vendor / model features. The
  # following flags can be used:
  #
  #   Global flags:
  #     GNSS - Enable GNSS / GPS support
  #     USB  - Use USB for concentrator communication (default is SPI)
  model_flags=["USB","GNSS"]

  # Time fallback.
  #
  # In case the gateway does not have a GNSS module or is unable to aquire a
  # GNSS fix, use the system-time for setting the 'time' field on RX.
  time_fallback_enabled=true

  #Fine Timestamp
  #mode: HIGH_CAPACITY or ALL_SF
  [gateway.fine_timestamp]
    enable=true
    mode="ALL_SF"

 

2) chirpstack-concentratord-sx1302/src/handler/uplink.rs

Added frame.ftime and frame.ftime_received fields and needed formating to info!() macro.

                    info!(
                        "Frame received, uplink_id: {}, count_us: {}, freq: {}, bw: {}, mod: {:?}, dr: {:?} fts: {:0>9}, fts_recv: {} ",
                        rx_info.uplink_id,
                        frame.count_us,
                        frame.freq_hz,
                        frame.bandwidth,
                        frame.modulation,
                        frame.datarate,
                        frame.ftime,
                        frame.ftime_received
                    );

Now consertratord-sx1302 log shows Fine Timestamp information "...fts: 143869299, fts_recv: true". The Fts field is a nano secons since last trailing edge of the PPS signal of the GPS module. This nano second information is need for aproximation of the geolocation.

2023-06-11T19:13:54.123Z INFO  [libconcentratord::events] Publishing stats event, rx_received: 3, rx_received_ok: 1, tx_received: 0, tx_emitted: 0
2023-06-11T19:14:13.171Z INFO  [chirpstack_concentratord_sx1302::handler::uplink] Frame received, uplink_id: 1604220501, count_us: 3057298334, freq: 867300000, bw: 125000, mod: LoRa, dr: SF7 fts: 108051544, fts_recv: true
2023-06-11T19:14:24.124Z INFO  [libconcentratord::events] Publishing stats event, rx_received: 3, rx_received_ok: 1, tx_received: 0, tx_emitted: 0
2023-06-11T19:14:43.209Z INFO  [chirpstack_concentratord_sx1302::handler::uplink] Frame received, uplink_id: 2494718995, count_us: 3087334149, freq: 868100000, bw: 125000, mod: LoRa, dr: SF7 fts: 143869299, fts_recv: true
2023-06-11T19:14:54.130Z INFO  [libconcentratord::events] Publishing stats event, rx_received: 1, rx_received_ok: 1, tx_received: 0, tx_emitted: 0
2

 

3) chirpstack-concentratord-sx1302/src/wrapper/mod.rs

pub fn uplink_to_proto() returns Resultgw::UplinkFrame. fine_time_since_gps_epoch structe is added to gw::UplinkFrame. packet.ftime field holds precise receiving time information if Fine Timestamp property is enabled on consertratord-sx1302.

            fine_time_since_gps_epoch: match packet.ftime_received {
                true => Some(prost_types::Duration {
                            seconds: 0i64,
                            nanos: packet.ftime as i32
                        }),
                false => None
            },

And here is whole changed uplink_to_proto() function.


pub fn uplink_to_proto(
    gateway_id: &[u8],
    packet: &hal::RxPacket,
    time_fallback: bool,
) -> Result<gw::UplinkFrame> {
    let mut rng = rand::thread_rng();
    let uplink_id: u32 = rng.gen();

    Ok(gw::UplinkFrame {
        phy_payload: packet.payload[..packet.size as usize].to_vec(),
        tx_info: Some(gw::UplinkTxInfo {
            frequency: packet.freq_hz,
            modulation: Some(gw::Modulation {
                parameters: match packet.modulation {
                    hal::Modulation::LoRa => {
                        Some(gw::modulation::Parameters::Lora(gw::LoraModulationInfo {
                            bandwidth: packet.bandwidth,
                            spreading_factor: match packet.datarate {
                                hal::DataRate::SF5 => 5,
                                hal::DataRate::SF6 => 6,
                                hal::DataRate::SF7 => 7,
                                hal::DataRate::SF8 => 8,
                                hal::DataRate::SF9 => 9,
                                hal::DataRate::SF10 => 10,
                                hal::DataRate::SF11 => 11,
                                hal::DataRate::SF12 => 12,
                                _ => return Err(anyhow!("unexpected spreading-factor")),
                            },
                            code_rate: match packet.coderate {
                                hal::CodeRate::LoRa4_5 => gw::CodeRate::Cr45,
                                hal::CodeRate::LoRa4_6 => gw::CodeRate::Cr46,
                                hal::CodeRate::LoRa4_7 => gw::CodeRate::Cr47,
                                hal::CodeRate::LoRa4_8 => gw::CodeRate::Cr48,
                                hal::CodeRate::Undefined => gw::CodeRate::CrUndefined,
                            }
                            .into(),
                            ..Default::default()
                        }))
                    }
                    hal::Modulation::FSK => {
                        Some(gw::modulation::Parameters::Fsk(gw::FskModulationInfo {
                            datarate: match packet.datarate {
                                hal::DataRate::FSK(v) => v * 1000,
                                _ => return Err(anyhow!("unexpected datarate")),
                            },
                            ..Default::default()
                        }))
                    }
                    hal::Modulation::Undefined => None,
                },
            }),
        }),
        rx_info: Some(gw::UplinkRxInfo {
            uplink_id,
            context: packet.count_us.to_be_bytes().to_vec(),
            gateway_id: hex::encode(gateway_id),
            rssi: packet.rssis as i32,
            snr: packet.snr,
            channel: packet.if_chain as u32,
            rf_chain: packet.rf_chain as u32,
            time: match gps::cnt2time(packet.count_us) {
                Ok(v) => {
                    let v = v.duration_since(UNIX_EPOCH).unwrap();
                    Some(prost_types::Timestamp {
                        seconds: v.as_secs() as i64,
                        nanos: v.subsec_nanos() as i32,
                    })
                }
                Err(err) => {
                    debug!(
                        "Could not get GPS time, uplink_id: {}, error: {}",
                        uplink_id, err
                    );

                    if time_fallback {
                        Some(prost_types::Timestamp::from(SystemTime::now()))
                    } else {
                        None
                    }
                }
            },
            time_since_gps_epoch: match gps::cnt2epoch(packet.count_us) {
                Ok(v) => Some(prost_types::Duration {
                    seconds: v.as_secs() as i64,
                    nanos: v.subsec_nanos() as i32,
                }),
                Err(err) => {
                    debug!(
                        "Could not get GPS epoch, uplink_id: {}, error: {}",
                        uplink_id, err
                    );
                    None
                }
            },           
            fine_time_since_gps_epoch: match packet.ftime_received {
                true => Some(prost_types::Duration {
                            seconds: 0i64,
                            nanos: packet.ftime as i32
                        }),
                false => None
            },
            crc_status: match packet.status {
                hal::CRC::CRCOk => gw::CrcStatus::CrcOk,
                hal::CRC::BadCRC => gw::CrcStatus::BadCrc,
                hal::CRC::NoCRC | hal::CRC::Undefined => gw::CrcStatus::NoCrc,
            }
            .into(),
            ..Default::default()
        }),
        ..Default::default()
    })
}

 

I wrote a simple Rust zeromq client program for printing up-events of the consertratord-sx1302 backend. Now Fine Timestamp information found in fine_time_since_gps_epoch: Some(Duration { seconds: 0, nanos: 48290698 }) Structure as follows. In this example second part is allway zere. Only nano second part matters for the geolocation calculations.


Topic: up
phy_payload: [64, 97, 158, 199, 1, 128, 245, 148, 3, 132, 29, 75, 233, 12, 129, 60, 199, 85, 34, 198, 216, 151, 189]
phy_payload: UplinkRxInfo { gateway_id: "0016c001ff1f11ddd", uplink_id: 1836980030, time: Some(Timestamp { seconds: 1686508758, nanos: 116930490 }), time_since_gps_epoch: None, fine_time_since_gps_epoch: Some(Duration { seconds: 0, nanos: 48290698 }), rssi: -99, snr: 12.25, channel: 3, rf_chain: 0, board: 0, antenna: 0, location: None, context: [57, 90, 153, 82], metadata: {}, crc_status: CrcOk }
Topic: up
phy_payload: [64, 97, 158, 199, 1, 128, 246, 148, 3, 86, 239, 135, 219, 156, 240, 225, 92, 184, 205, 19, 254, 61, 94]
phy_payload: UplinkRxInfo { gateway_id: "0016c001ff1f1ddd", uplink_id: 2518488021, time: Some(Timestamp { seconds: 1686508788, nanos: 161273198 }), time_since_gps_epoch: None, fine_time_since_gps_epoch: Some(Duration { seconds: 0, nanos: 91829739 }), rssi: -42, snr: 11.25, channel: 1, rf_chain: 1, board: 0, antenna: 0, location: None, context: [59, 37, 6, 226], metadata: {}, crc_status: CrcOk }
Topic: up
phy_payload: [64, 97, 158, 199, 1, 128, 247, 148, 3, 167, 7, 251, 70, 240, 160, 220, 53, 167, 110, 184, 203, 240, 19]
phy_payload: UplinkRxInfo { gateway_id: "0016c001ff1f1ddd", uplink_id: 1110056337, time: Some(Timestamp { seconds: 1686508818, nanos: 194757382 }), time_since_gps_epoch: None, fine_time_since_gps_epoch: Some(Duration { seconds: 0, nanos: 134425134 }), rssi: -42, snr: 9.5, channel: 2, rf_chain: 1, board: 0, antenna: 0, location: None, context: [60, 239, 112, 194], metadata: {}, crc_status: CrcOk }

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

Yes ! can. I have a smoke tested this solution proposal and it seems to work . But first let's wait for the review and comments of the idea....

@brocaar
Copy link
Collaborator

brocaar commented Jun 12, 2023

Hi @LouneCode please do create a pull-request for this 👍

I think we can use the seconds part of the time_since_gps_epoch for the fine_time_since_gps_epoch + the packet.ftime as nanos, then we have the full duration since GPS epoch.

@brocaar brocaar closed this as completed Jun 12, 2023
@brocaar brocaar reopened this Jun 12, 2023
@LouneCode
Copy link
Contributor Author

OK, I'll try make a pull-request with the suggested improvements.

@brocaar
Copy link
Collaborator

brocaar commented Jun 12, 2023

Thanks! :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants