mirror of
https://github.com/soypat/lora.git
synced 2026-08-19 20:13:55 +00:00
add more functionality
This commit is contained in:
@@ -40,7 +40,9 @@ func main() {
|
|||||||
panic(err.Error())
|
panic(err.Error())
|
||||||
}
|
}
|
||||||
dev := sx127x.NewLoRa(SX127X_SPI, SX127X_PIN_CS.Set, SX127X_PIN_RST.Set)
|
dev := sx127x.NewLoRa(SX127X_SPI, SX127X_PIN_CS.Set, SX127X_PIN_RST.Set)
|
||||||
err = dev.Configure(sx127x.DefaultConfig(lora.Freq433_0M))
|
cfg := sx127x.DefaultConfig(lora.Freq433_0M)
|
||||||
|
cfg.TxPower = 0 // Minimum power.
|
||||||
|
err = dev.Configure(cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err.Error())
|
panic(err.Error())
|
||||||
}
|
}
|
||||||
@@ -57,5 +59,9 @@ func main() {
|
|||||||
print(".")
|
print(".")
|
||||||
}
|
}
|
||||||
time.Sleep(2 * time.Second)
|
time.Sleep(2 * time.Second)
|
||||||
|
// err = dev.Configure(cfg)
|
||||||
|
// if err != nil {
|
||||||
|
// println("got error configuring:", err.Error())
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-5
@@ -124,11 +124,12 @@ const (
|
|||||||
irqCDDETD_MASK uint8 = 0x01
|
irqCDDETD_MASK uint8 = 0x01
|
||||||
|
|
||||||
// DIO function mappings D0D1D2D3
|
// DIO function mappings D0D1D2D3
|
||||||
mapDIO0_LORA_RXDONE uint8 = 0x00 // 00------
|
|
||||||
mapDIO0_LORA_TXDONE uint8 = 0x40 // 01------
|
mapDIO0_RXDONE uint8 = 0x00 // 00------ LoRa
|
||||||
mapDIO1_LORA_RXTOUT uint8 = 0x00 // --00----
|
mapDIO0_TXDONE uint8 = 0x40 // 01------ LoRa
|
||||||
mapDIO1_LORA_NOP uint8 = 0x30 // --11----
|
mapDIO1_RXTOUT uint8 = 0x00 // --00---- LoRa
|
||||||
mapDIO2_LORA_NOP uint8 = 0xC0 // ----11--
|
mapDIO1_NOP uint8 = 0x30 // --11---- LoRa
|
||||||
|
mapDIO2_NOP uint8 = 0xC0 // ----11-- LoRa
|
||||||
|
|
||||||
// SX127X_PAYLOAD_LENGTH uint8 = 0x40
|
// SX127X_PAYLOAD_LENGTH uint8 = 0x40
|
||||||
|
|
||||||
|
|||||||
+77
-18
@@ -84,12 +84,12 @@ func DefaultConfig(freq lora.Frequency) lora.Config {
|
|||||||
SpreadFactor: lora.SF7,
|
SpreadFactor: lora.SF7,
|
||||||
Bandwidth: 125 * lora.KiloHertz,
|
Bandwidth: 125 * lora.KiloHertz,
|
||||||
CodingRate: lora.CR4_5,
|
CodingRate: lora.CR4_5,
|
||||||
PreambleLength: 12,
|
PreambleLength: 8,
|
||||||
HeaderType: lora.HeaderExplicit,
|
HeaderType: lora.HeaderExplicit,
|
||||||
MaxImplicitPayloadLength: 0, // No need to be set when working with explicit headers.
|
MaxImplicitPayloadLength: 0, // No need to be set when working with explicit headers.
|
||||||
CRC: true,
|
CRC: true,
|
||||||
SyncWord: publicSyncword,
|
SyncWord: publicSyncword,
|
||||||
TxPower: 0, // Low power by default.
|
TxPower: 2, // Low power by default.
|
||||||
LDRO: false,
|
LDRO: false,
|
||||||
IQInversion: false,
|
IQInversion: false,
|
||||||
}
|
}
|
||||||
@@ -150,6 +150,7 @@ func (d *DeviceLoRa) Configure(cfg lora.Config) (err error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
time.Sleep(15 * time.Millisecond) // Wait for sleep to take effect.
|
||||||
err = d.setFrequency(cfg.Frequency)
|
err = d.setFrequency(cfg.Frequency)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -170,10 +171,11 @@ func (d *DeviceLoRa) Configure(cfg lora.Config) (err error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = d.setTxPower(cfg.TxPower)
|
err = d.setTxPower(cfg.TxPower, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
// TODO(soypat): Use default OCP?
|
||||||
err = d.setSyncWord(cfg.SyncWord)
|
err = d.setSyncWord(cfg.SyncWord)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -330,6 +332,10 @@ func (d *DeviceLoRa) Tx(packet []byte) (err error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
err = d.SetIRQTxDoneOnDIO0()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
d.write8(regFIFO_TX_BASE_ADDR, 0)
|
d.write8(regFIFO_TX_BASE_ADDR, 0)
|
||||||
d.write8(regFIFO_ADDR_PTR, 0)
|
d.write8(regFIFO_ADDR_PTR, 0)
|
||||||
for i := 0; i < len(packet); i++ {
|
for i := 0; i < len(packet); i++ {
|
||||||
@@ -364,6 +370,36 @@ func (d *DeviceLoRa) Tx(packet []byte) (err error) {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetRxDoneOnDIO0 sets the TxDone interrupt on the DIO0 pin of the device.
|
||||||
|
func (d *DeviceLoRa) SetIRQTxDoneOnDIO0() (err error) {
|
||||||
|
// set the IRQ mapping DIO0=TxDone DIO1=NOP DIO2=NOP.
|
||||||
|
err = d.write8(regDIO_MAPPING_1, mapDIO0_TXDONE)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = d.clearIRQ(0xff) // Clear all radio IRQ Flags to avoid instant interrupt raise.
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// Unmask TxDone interrupt.
|
||||||
|
return d.writeMasked8(regIRQ_FLAGS_MASK, irqTXDONE_MASK, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetRxDoneOnDIO0 sets the RxDone interrupt on the DIO0 pin of the device.
|
||||||
|
func (d *DeviceLoRa) SetIRQRxDoneOnDIO0() (err error) {
|
||||||
|
// set the IRQ mapping DIO0=TxDone DIO1=NOP DIO2=NOP.
|
||||||
|
err = d.write8(regDIO_MAPPING_1, mapDIO0_RXDONE)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = d.clearIRQ(0xff) // Clear all radio IRQ Flags to avoid instant interrupt raise.
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// Unmask RxDone interrupt.
|
||||||
|
return d.writeMasked8(regIRQ_FLAGS_MASK, irqRXDONE_MASK, 0)
|
||||||
|
}
|
||||||
|
|
||||||
// RxSingle receives a single packet over LoRa network and blocks until packet is
|
// RxSingle receives a single packet over LoRa network and blocks until packet is
|
||||||
// received or timeout occurs. Timeout is controlled by value set in [SetSymbolTimeout].
|
// received or timeout occurs. Timeout is controlled by value set in [SetSymbolTimeout].
|
||||||
func (d *DeviceLoRa) RxSingle(dst []byte) (uint8, error) {
|
func (d *DeviceLoRa) RxSingle(dst []byte) (uint8, error) {
|
||||||
@@ -701,15 +737,21 @@ func (d *DeviceLoRa) enableTxContinuousMode(enable bool) error {
|
|||||||
return d.writeMasked8(regMODEM_CONFIG_2, 1<<3, b2u8(enable)<<3)
|
return d.writeMasked8(regMODEM_CONFIG_2, 1<<3, b2u8(enable)<<3)
|
||||||
}
|
}
|
||||||
|
|
||||||
// PA_HF and PA_LF are high efficiency amplifiers capable of yielding RF power programmable in 1 dB steps from -4 to
|
// setTxPower sets the transmit power of the device in dBm.
|
||||||
// +14dBm directly into a 50 ohm load with low current consumption. PA_LF covers the lower bands (up to 525 MHz), whilst
|
// The useRFO parameter selects between the PA_BOOST and RFO pin. Usually PA_BOOST is used.
|
||||||
// PA_HF will cover the upper bands (from 779 MHz). The output power is sensitive to the power supply voltage, and typically
|
//
|
||||||
// their performance is expressed at 3.3V.
|
// # It is important to set Over Current Protection (OCP) when using high power to prevent device damage.
|
||||||
|
func (d *DeviceLoRa) setTxPower(txPow int8, useRFO bool) error {
|
||||||
|
if useRFO {
|
||||||
|
return d.setRFOTxPower(txPow)
|
||||||
|
}
|
||||||
|
return d.setPABoostTxPower(txPow)
|
||||||
|
}
|
||||||
|
|
||||||
// setTxPower sets the transmit power without using te PA_BOOST.
|
// setRFOTxPower sets the transmit power without using te PA_BOOST.
|
||||||
func (d *DeviceLoRa) setTxPower(txPow int8) error {
|
func (d *DeviceLoRa) setRFOTxPower(txPow int8) error {
|
||||||
if txPow >= 16 {
|
if txPow < -4 || txPow >= 16 {
|
||||||
return errors.New("requested tx power exceeds capabilities without PA_BOOST")
|
return errors.New("RFO tx power out of range -4..15")
|
||||||
}
|
}
|
||||||
MaxPower, OutputPower := rfoPowReg(txPow)
|
MaxPower, OutputPower := rfoPowReg(txPow)
|
||||||
// This unsets PaSelect bit which switches mode of operation to RFO pin (limited to 14dBm power).
|
// This unsets PaSelect bit which switches mode of operation to RFO pin (limited to 14dBm power).
|
||||||
@@ -717,9 +759,25 @@ func (d *DeviceLoRa) setTxPower(txPow int8) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// Set to minimal current.
|
return nil
|
||||||
return d.setOCP(45)
|
}
|
||||||
// return d.write8(regOCP, 0) // TODO: Disable OCP?
|
|
||||||
|
func (d *DeviceLoRa) setPABoostTxPower(txPow int8) error {
|
||||||
|
if txPow < 2 || txPow > 23 {
|
||||||
|
return errors.New("PA_BOOST tx power out of range 2..23")
|
||||||
|
}
|
||||||
|
const PASelect = 0x80
|
||||||
|
const MaxPower = 0b111 << 4
|
||||||
|
// It's possible to add 3dBm by setting regPADAC.
|
||||||
|
// if txPow > 20 {
|
||||||
|
// txPow -= 3
|
||||||
|
// d.write8(regPA_DAC, 0x07) // Enable PA_DAC
|
||||||
|
// } else {
|
||||||
|
// d.write8(regPA_DAC, 0x04) // Disable PA_DAC
|
||||||
|
// }
|
||||||
|
outputPower := paBoostPowReg(txPow)
|
||||||
|
|
||||||
|
return d.write8(regPA_CONFIG, PASelect|MaxPower|outputPower)
|
||||||
}
|
}
|
||||||
|
|
||||||
func rfoPowReg(txPow int8) (MaxPower, OutputPower uint8) {
|
func rfoPowReg(txPow int8) (MaxPower, OutputPower uint8) {
|
||||||
@@ -728,7 +786,7 @@ func rfoPowReg(txPow int8) (MaxPower, OutputPower uint8) {
|
|||||||
// Pout = Pmax - (15 - OutputPower) => OutputPower = 15 - (Pmax - Pout)
|
// Pout = Pmax - (15 - OutputPower) => OutputPower = 15 - (Pmax - Pout)
|
||||||
// Where Pmax=10.8+0.6*MaxPower [dBm]
|
// Where Pmax=10.8+0.6*MaxPower [dBm]
|
||||||
// To solve this combined equation we set MaxPower depending on txPow
|
// To solve this combined equation we set MaxPower depending on txPow
|
||||||
// and solve from there on. The result is error margin +/- 0.3dBm. See tests.
|
// and solve from there on. The result has an error margin of +/- 0.3dBm. See tests.
|
||||||
switch {
|
switch {
|
||||||
case txPow < 2:
|
case txPow < 2:
|
||||||
MaxPower = 0b000
|
MaxPower = 0b000
|
||||||
@@ -749,9 +807,9 @@ func paBoostPowReg(txPow int8) (OutputPower uint8) {
|
|||||||
return OutputPower
|
return OutputPower
|
||||||
}
|
}
|
||||||
|
|
||||||
// setOCP defines Overload Current Protection configuration. It receives
|
// SetOCP defines Overload Current Protection configuration. It receives
|
||||||
// the max current (Imax) in milliamperes.
|
// the max current (Imax) in milliamperes.
|
||||||
func (d *DeviceLoRa) setOCP(mA uint8) error {
|
func (d *DeviceLoRa) SetOCP(mA uint8) error {
|
||||||
const ocpEnabledMask = 1 << 5
|
const ocpEnabledMask = 1 << 5
|
||||||
return d.write8(regOCP, ocpEnabledMask|(0x1F&ocpTrim(mA)))
|
return d.write8(regOCP, ocpEnabledMask|(0x1F&ocpTrim(mA)))
|
||||||
}
|
}
|
||||||
@@ -905,7 +963,7 @@ func (d *DeviceLoRa) write8(addr, value byte) error {
|
|||||||
d.csEnable(true)
|
d.csEnable(true)
|
||||||
err := d.bus.Tx(writeBuf, readBuf)
|
err := d.bus.Tx(writeBuf, readBuf)
|
||||||
d.csEnable(false)
|
d.csEnable(false)
|
||||||
if debugBufSize > 0 {
|
if debugBufSize > 0 && addr != regFIFO {
|
||||||
d.debugWrite[addr] = value
|
d.debugWrite[addr] = value
|
||||||
d.debugMask[addr] = 0xFF
|
d.debugMask[addr] = 0xFF
|
||||||
d.read8(addr) // refresh address value.
|
d.read8(addr) // refresh address value.
|
||||||
@@ -917,6 +975,7 @@ func (d *DeviceLoRa) csEnable(b bool) {
|
|||||||
d.cs(!b)
|
d.cs(!b)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//go:inline
|
||||||
func b2u8(b bool) uint8 {
|
func b2u8(b bool) uint8 {
|
||||||
if b {
|
if b {
|
||||||
return 1
|
return 1
|
||||||
|
|||||||
Reference in New Issue
Block a user