diff --git a/lora.go b/lora.go index 000f7dd..a361346 100644 --- a/lora.go +++ b/lora.go @@ -22,9 +22,9 @@ type Config struct { // Must be set when working with implicit headers. MaxImplicitPayloadLength uint8 CodingRate CodingRate - SpreadFactor SpreadFactor // this should probably be called "SpreadingFactor" to be consistent with LoRa terminology - SyncWord uint16 // for new chips sync word is full 16 bits - TxPower int8 // Tx Power in dBm. + SpreadingFactor SpreadingFactor + SyncWord uint16 // for new chips sync word is full 16 bits + TxPower int8 // Tx Power in dBm. CRC bool // Low data rate optimisation flag. The use of this flag is mandated when // the symbol duration exceeds 16ms. Increases reliability at high spreading factors. @@ -34,9 +34,9 @@ type Config struct { } // SymbolPeriod returns the time it takes to transmit a single symbol given the -// current configuration parameters. It depends on Spread factor and Bandwidth. +// current configuration parameters. It depends on Spreading factor and Bandwidth. func (cfg *Config) SymbolPeriod() time.Duration { - T_s := time.Second * time.Duration(cfg.SpreadFactor.ChipsPerSymbol()) / + T_s := time.Second * time.Duration(cfg.SpreadingFactor.ChipsPerSymbol()) / time.Duration(cfg.Bandwidth.Hertz()) return T_s } @@ -47,7 +47,7 @@ func (cfg *Config) SymbolPeriod() time.Duration { // - CRC presence (presence == longer) // - Header type (explicit == longer) // - Coding rate (proportional) -// - Spread factor (inversely proportional) +// - Spreading factor (inversely proportional) // - Preamble length (proportional) // - Low data rate optimisation (presence == longer) func (cfg *Config) TimeOnAir(payloadLength int) time.Duration { @@ -58,10 +58,10 @@ func (cfg *Config) TimeOnAir(payloadLength int) time.Duration { ih := int64(cfg.HeaderType) ldr := int64(b2u8(cfg.LDRO)) cr := int64(cfg.CodingRate) - spread := int64(cfg.SpreadFactor) + sf := int64(cfg.SpreadingFactor) // Page 31 SX1276IMLTRT SEMTECH | Alldatasheet. - Npayload := 8*int64(payloadLength) - 4*spread + 28 + 16*crc - 20*ih - div := 4 * (spread - 2*ldr) + Npayload := 8*int64(payloadLength) - 4*sf + 28 + 16*crc - 20*ih + div := 4 * (sf - 2*ldr) // Apply Ceil and max with minimal branching. if Npayload < 0 || div <= 0 { Npayload = 0 @@ -77,7 +77,7 @@ func (cfg *Config) TimeOnAir(payloadLength int) time.Duration { // time calculated. Npayload += 8 + int64(cfg.PreambleLength) + 5 // Calculate LoRa Transmission Parameter Relationship page 28. - chipsPerSymbol := cfg.SpreadFactor.ChipsPerSymbol() // chips per symbol. + chipsPerSymbol := cfg.SpreadingFactor.ChipsPerSymbol() // chips per symbol. return time.Second * time.Duration(Npayload*int64(chipsPerSymbol)) / time.Duration(cfg.Bandwidth.Hertz()) } @@ -110,15 +110,15 @@ const ( CR4_8 CodingRate = 4 ) -// SpreadFactor defines the number of chips per symbol. Higher spread factors +// SpreadingFactor defines the number of chips per symbol. Higher spreading factors // imply longer transmission times but more robust communications. -// The number of chips per symbol is 2^SF, so a spread factor of 8 takes twice -// as long to transmit a symbol as a spread factor of 7. -type SpreadFactor uint8 +// The number of chips per symbol is 2^SF, so a spreading factor of 8 takes twice +// as long to transmit a symbol as a spreading factor of 7. +type SpreadingFactor uint8 -// Common spread factors. Decide the number of chips per symbol. +// Common spreading factors. Decide the number of chips per symbol. const ( - SF5 SpreadFactor = iota + 5 + SF5 SpreadingFactor = iota + 5 SF6 SF7 SF8 @@ -130,9 +130,9 @@ const ( // ChipsPerSymbol returns the number of chips in a symbol. A chip is a subdivision // of a symbol in the frequency domain rather than the time domain, which is why -// the units of this value is Hz, not Duration. A chip tells tells where to start +// the units of this value is Hz, not Duration. A chip tells where to start // the frequency sweep for a symbol. -func (sf SpreadFactor) ChipsPerSymbol() int64 { +func (sf SpreadingFactor) ChipsPerSymbol() int64 { return 1 << sf } diff --git a/lora_test.go b/lora_test.go index 2d3161a..e4cf46e 100644 --- a/lora_test.go +++ b/lora_test.go @@ -22,13 +22,13 @@ func TestTimeOnAir(t *testing.T) { { desc: "LoRaWAN 240bytes", // https://www.thethingsnetwork.org/airtime-calculator cfg: lora.Config{ - Bandwidth: lora.BW125k, - Frequency: 915e6, - SpreadFactor: lora.SF7, - HeaderType: lora.HeaderExplicit, - CodingRate: loraWANCodeRate, - CRC: true, - PreambleLength: loraWANPreambleLength, + Bandwidth: lora.BW125k, + Frequency: 915e6, + SpreadingFactor: lora.SF7, + HeaderType: lora.HeaderExplicit, + CodingRate: loraWANCodeRate, + CRC: true, + PreambleLength: loraWANPreambleLength, }, plen: 240, expected: 394.5e3 * time.Microsecond, @@ -36,13 +36,13 @@ func TestTimeOnAir(t *testing.T) { { desc: "LoRaWAN 5byte BW=500kHz", // https://www.thethingsnetwork.org/airtime-calculator cfg: lora.Config{ - Bandwidth: lora.BW500k, - Frequency: 915e6, - SpreadFactor: lora.SF7, - HeaderType: lora.HeaderExplicit, - CodingRate: loraWANCodeRate, - CRC: true, - PreambleLength: loraWANPreambleLength, + Bandwidth: lora.BW500k, + Frequency: 915e6, + SpreadingFactor: lora.SF7, + HeaderType: lora.HeaderExplicit, + CodingRate: loraWANCodeRate, + CRC: true, + PreambleLength: loraWANPreambleLength, }, plen: 10, expected: 15.4e3 * time.Microsecond, diff --git a/sx127x/sx127x.go b/sx127x/sx127x.go index 7fb934b..fc12716 100644 --- a/sx127x/sx127x.go +++ b/sx127x/sx127x.go @@ -81,7 +81,7 @@ type DeviceLoRa struct { func DefaultConfig(freq lora.Frequency) lora.Config { return lora.Config{ Frequency: freq, - SpreadFactor: lora.SF7, + SpreadingFactor: lora.SF7, Bandwidth: lora.BW125k, CodingRate: lora.CR4_5, PreambleLength: 8, @@ -103,7 +103,7 @@ func NewLoRa(bus SPI, cs, reset PinOutput) *DeviceLoRa { } var ( - errBadSpread = errors.New("bad spread factor") + errBadSpreadingFactor = errors.New("bad spreading factor") errSF6Implicit = errors.New("SF6 can only be used with implicit header type") // Page 30: Implicit Header Mode. errPreambleTooShort = errors.New("preamble length too short") ErrNotDetected = errors.New("sx127x not detected") @@ -116,6 +116,7 @@ var ( ErrCRC = errors.New("crc error") ErrRxTimeout = errors.New("rx timeout") errImplicitPacketTooLarge = errors.New("packet length exceeds MaxImplicitPayloadLength") + errSyncWordTooLarge = errors.New("sync word too long") ) func (d *DeviceLoRa) InitLoRaMode() (err error) { @@ -139,9 +140,9 @@ func (d *DeviceLoRa) InitLoRaMode() (err error) { func (d *DeviceLoRa) Configure(cfg lora.Config) (err error) { switch { - case cfg.SpreadFactor < lora.SF6 || cfg.SpreadFactor > lora.SF12: - err = errBadSpread - case cfg.SpreadFactor == lora.SF6 && cfg.HeaderType != lora.HeaderImplicit: + case cfg.SpreadingFactor < lora.SF6 || cfg.SpreadingFactor > lora.SF12: + err = errBadSpreadingFactor + case cfg.SpreadingFactor == lora.SF6 && cfg.HeaderType != lora.HeaderImplicit: err = errSF6Implicit case cfg.PreambleLength < 6: err = errPreambleTooShort @@ -156,6 +157,8 @@ func (d *DeviceLoRa) Configure(cfg lora.Config) (err error) { err = errors.New("MaxImplicitPayloadLength parameter must be set when working with implicit headers") case cfg.TxPower > 20 || cfg.TxPower < -4: err = errors.New("tx power not in operating range -4..20") + case cfg.SyncWord > 0xff: + err = errSyncWordTooLarge } if err != nil { return err @@ -189,7 +192,7 @@ func (d *DeviceLoRa) Configure(cfg lora.Config) (err error) { return err } // TODO(soypat): Use default OCP? - err = d.setSyncWord(cfg.SyncWord) + err = d.setSyncWord(uint8(cfg.SyncWord)) if err != nil { return err } @@ -197,7 +200,7 @@ func (d *DeviceLoRa) Configure(cfg lora.Config) (err error) { if err != nil { return err } - err = d.setSpreadFactorConsistent(cfg.SpreadFactor) + err = d.setSpreadingFactorConsistent(cfg.SpreadingFactor) if err != nil { return err } @@ -706,7 +709,7 @@ func (d *DeviceLoRa) ReadConfig() (cfg lora.Config, err error) { cfg.CodingRate = lora.CodingRate(cfg1>>1) & 0b111 cfg.HeaderType = lora.HeaderType(cfg1 & 1) cfg2 := buf[1] - cfg.SpreadFactor = lora.SpreadFactor(cfg1 >> 4) + cfg.SpreadingFactor = lora.SpreadingFactor(cfg1 >> 4) cfg.CRC = cfg2&0x4 != 0 // continuousMode = cfg2&0x8 != 0 cfg.PreambleLength = binary.BigEndian.Uint16(buf[3:]) @@ -715,7 +718,7 @@ func (d *DeviceLoRa) ReadConfig() (cfg lora.Config, err error) { if err != nil { return cfg, err } - cfg.SyncWord = sync + cfg.SyncWord = uint16(sync) // Read Frequency. err = d.read(regFRF_MSB, buf[:3]) if err != nil { @@ -864,9 +867,9 @@ func (d *DeviceLoRa) setFrequency(freq lora.Frequency) error { return d.Write8(regFRF_LSB, freqReg[2]) // Write LSB last! } -// setSpreadFactorConsistent sets the spreading factor and closely related parameters +// setSpreadingFactorConsistent sets the spreading factor and closely related parameters // including Low Data Rate Optimization, DetectionOptimize, and DetectionThreshold. -func (d *DeviceLoRa) setSpreadFactorConsistent(sf lora.SpreadFactor) (err error) { +func (d *DeviceLoRa) setSpreadingFactorConsistent(sf lora.SpreadingFactor) (err error) { err = d.setSpreadingFactor(sf) if err != nil { return err @@ -889,9 +892,9 @@ func (d *DeviceLoRa) setSpreadFactorConsistent(sf lora.SpreadFactor) (err error) // It does not set parameters closely associated with the spreading factor such as // the Low Data Optimization, the Detection threshold, Detection Optimize and the // Symbol Timeout. -func (d *DeviceLoRa) setSpreadingFactor(sf lora.SpreadFactor) error { +func (d *DeviceLoRa) setSpreadingFactor(sf lora.SpreadingFactor) error { if sf < 6 || sf > 12 { - return errBadSpread + return errBadSpreadingFactor } const sfMask = 0b111 << 4 return d.writeMasked8(regMODEM_CONFIG_2, sfMask, uint8(sf)<<4) diff --git a/sx128x/sx128x.go b/sx128x/sx128x.go index b692574..c5fb913 100644 --- a/sx128x/sx128x.go +++ b/sx128x/sx128x.go @@ -31,7 +31,7 @@ type DeviceLoRa struct { func DefaultConfig(freq lora.Frequency) lora.Config { return lora.Config{ Frequency: freq, - SpreadFactor: lora.SF9, + SpreadingFactor: lora.SF9, Bandwidth: lora.BW1625k, CodingRate: lora.CR4_5, PreambleLength: 12, @@ -90,13 +90,13 @@ func (d *DeviceLoRa) Configure(config lora.Config) error { if err != nil { return err } - err = d.setModulationParamsLoRa(config.SpreadFactor, config.Bandwidth, config.CodingRate) + err = d.setModulationParamsLoRa(config.SpreadingFactor, config.Bandwidth, config.CodingRate) if err != nil { return err } // special register setting depending on spreading factor chosen - switch config.SpreadFactor { + switch config.SpreadingFactor { case lora.SF5, lora.SF6: d.writeRegister(regSpreadingFactorAdditionalConfiguration, []byte{0x1E}) case lora.SF7, lora.SF8: @@ -418,7 +418,7 @@ func (d *DeviceLoRa) setBufferBaseAddress(txBase uint8, rxBase uint8) error { return err } -func (d *DeviceLoRa) setModulationParamsLoRa(spreadingFactor lora.SpreadFactor, bandwidth lora.Frequency, codingRate lora.CodingRate) error { +func (d *DeviceLoRa) setModulationParamsLoRa(spreadingFactor lora.SpreadingFactor, bandwidth lora.Frequency, codingRate lora.CodingRate) error { err := d.waitWhileBusy(time.Second) if err != nil { return err