rename spreadfactor and cleanup type change in sx127x

This commit is contained in:
Joel Wetzell
2026-05-13 08:52:30 -05:00
parent 2ce3e57401
commit aeff7af92a
4 changed files with 52 additions and 49 deletions
+16 -16
View File
@@ -22,7 +22,7 @@ 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
SpreadingFactor SpreadingFactor
SyncWord uint16 // for new chips sync word is full 16 bits
TxPower int8 // Tx Power in dBm.
CRC bool
@@ -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
}
+2 -2
View File
@@ -24,7 +24,7 @@ func TestTimeOnAir(t *testing.T) {
cfg: lora.Config{
Bandwidth: lora.BW125k,
Frequency: 915e6,
SpreadFactor: lora.SF7,
SpreadingFactor: lora.SF7,
HeaderType: lora.HeaderExplicit,
CodingRate: loraWANCodeRate,
CRC: true,
@@ -38,7 +38,7 @@ func TestTimeOnAir(t *testing.T) {
cfg: lora.Config{
Bandwidth: lora.BW500k,
Frequency: 915e6,
SpreadFactor: lora.SF7,
SpreadingFactor: lora.SF7,
HeaderType: lora.HeaderExplicit,
CodingRate: loraWANCodeRate,
CRC: true,
+16 -13
View File
@@ -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)
+4 -4
View File
@@ -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