Refactoring
This commit is contained in:
parent
654112c45c
commit
4a9335b6d0
2 changed files with 116 additions and 150 deletions
81
device.go
81
device.go
|
@ -8,6 +8,11 @@ import (
|
|||
"github.com/fulr/spidev"
|
||||
)
|
||||
|
||||
const (
|
||||
spiPath = "/dev/spidev0.0"
|
||||
irqPin = gpio.GPIO25
|
||||
)
|
||||
|
||||
// Device RFM69 Device
|
||||
type Device struct {
|
||||
SpiDevice *spidev.SPIDevice
|
||||
|
@ -36,21 +41,41 @@ type Data struct {
|
|||
}
|
||||
|
||||
// NewDevice creates a new device
|
||||
func NewDevice(spi *spidev.SPIDevice, gpio gpio.Pin, nodeID, networkID byte, isRfm69HW bool) (*Device, error) {
|
||||
func NewDevice(nodeID, networkID byte, isRfm69HW bool) (*Device, error) {
|
||||
pin, err := gpio.OpenPin(irqPin, gpio.ModeInput)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
spi, err := spidev.NewSPIDevice(spiPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ret := &Device{
|
||||
SpiDevice: spi,
|
||||
gpio: gpio,
|
||||
gpio: pin,
|
||||
network: networkID,
|
||||
address: nodeID,
|
||||
isRFM69HW: isRfm69HW,
|
||||
powerLevel: 31,
|
||||
}
|
||||
|
||||
err := ret.setup()
|
||||
err = ret.setup()
|
||||
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// Close cleans up
|
||||
func (r *Device) Close() error {
|
||||
err := r.gpio.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.SpiDevice.Close()
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *Device) writeReg(addr, data byte) error {
|
||||
tx := make([]byte, 2)
|
||||
tx[0] = addr | 0x80
|
||||
|
@ -82,11 +107,9 @@ func (r *Device) setup() error {
|
|||
/* 0x04 */ {REG_BITRATELSB, RF_BITRATELSB_55555},
|
||||
/* 0x05 */ {REG_FDEVMSB, RF_FDEVMSB_50000}, // default: 5KHz, (FDEV + BitRate / 2 <= 500KHz)
|
||||
/* 0x06 */ {REG_FDEVLSB, RF_FDEVLSB_50000},
|
||||
|
||||
/* 0x07 */ {REG_FRFMSB, RF_FRFMSB_868},
|
||||
/* 0x08 */ {REG_FRFMID, RF_FRFMID_868},
|
||||
/* 0x09 */ {REG_FRFLSB, RF_FRFLSB_868},
|
||||
|
||||
// looks like PA1 and PA2 are not implemented on RFM69W, hence the max output power is 13dBm
|
||||
// +17dBm and +20dBm are possible on RFM69HW
|
||||
// +13dBm formula: Pout = -18 + OutputPower (with PA0 or PA1**)
|
||||
|
@ -94,7 +117,6 @@ func (r *Device) setup() error {
|
|||
// +20dBm formula: Pout = -11 + OutputPower (with PA1 and PA2)** and high power PA settings (section 3.3.7 in datasheet)
|
||||
///* 0x11 */ { REG_PALEVEL, RF_PALEVEL_PA0_ON | RF_PALEVEL_PA1_OFF | RF_PALEVEL_PA2_OFF | RF_PALEVEL_OUTPUTPOWER_11111},
|
||||
///* 0x13 */ { REG_OCP, RF_OCP_ON | RF_OCP_TRIM_95 }, // over current protection (default is 95mA)
|
||||
|
||||
// RXBW defaults are { REG_RXBW, RF_RXBW_DCCFREQ_010 | RF_RXBW_MANT_24 | RF_RXBW_EXP_5} (RxBw: 10.4KHz)
|
||||
/* 0x19 */ {REG_RXBW, RF_RXBW_DCCFREQ_010 | RF_RXBW_MANT_16 | RF_RXBW_EXP_2}, // (BitRate < 2 * RxBw)
|
||||
//for BR-19200: /* 0x19 */ { REG_RXBW, RF_RXBW_DCCFREQ_010 | RF_RXBW_MANT_24 | RF_RXBW_EXP_3 },
|
||||
|
@ -114,48 +136,37 @@ func (r *Device) setup() error {
|
|||
//for BR-19200: /* 0x3D */ { REG_PACKETCONFIG2, RF_PACKET2_RXRESTARTDELAY_NONE | RF_PACKET2_AUTORXRESTART_ON | RF_PACKET2_AES_OFF }, // RXRESTARTDELAY must match transmitter PA ramp-down time (bitrate dependent)
|
||||
/* 0x6F */ {REG_TESTDAGC, RF_DAGC_IMPROVED_LOWBETA0}, // run DAGC continuously in RX mode for Fading Margin Improvement, recommended default for AfcLowBetaOn=0
|
||||
}
|
||||
|
||||
for data, err := r.readReg(REG_SYNCVALUE1); err == nil && data != 0xAA; data, err = r.readReg(REG_SYNCVALUE1) {
|
||||
err := r.writeReg(REG_SYNCVALUE1, 0xAA)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
for data, err := r.readReg(REG_SYNCVALUE1); err == nil && data != 0x55; data, err = r.readReg(REG_SYNCVALUE1) {
|
||||
r.writeReg(REG_SYNCVALUE1, 0x55)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
for _, c := range config {
|
||||
err := r.writeReg(c[0], c[1])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Encryption is persistent between resets and can trip you up during debugging.
|
||||
// Disable it during initialization so we always start from a known state.
|
||||
err := r.Encrypt([]byte{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// called regardless if it's a RFM69W or RFM69HW
|
||||
err = r.setHighPower(r.isRFM69HW)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = r.SetMode(RF_OPMODE_STANDBY)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = r.waitForMode()
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -192,53 +203,54 @@ func (r *Device) SetMode(newMode byte) error {
|
|||
if newMode == r.mode {
|
||||
return nil
|
||||
}
|
||||
|
||||
err := r.readWriteReg(REG_OPMODE, 0xE3, newMode)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if r.isRFM69HW && (newMode == RF_OPMODE_RECEIVER || newMode == RF_OPMODE_TRANSMITTER) {
|
||||
err := r.setHighPowerRegs(newMode == RF_OPMODE_TRANSMITTER)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// we are using packet mode, so this check is not really needed
|
||||
// but waiting for mode ready is necessary when going from sleep because the FIFO may not be immediately available from previous mode
|
||||
if r.mode == RF_OPMODE_SLEEP {
|
||||
err = r.waitForMode()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
r.mode = newMode
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetModeAndWait sets the mode and waits for it
|
||||
func (r *Device) SetModeAndWait(newMode byte) error {
|
||||
err := r.SetMode(RF_OPMODE_STANDBY)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = r.waitForMode()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Device) setHighPower(turnOn bool) error {
|
||||
r.isRFM69HW = turnOn
|
||||
|
||||
ocp := byte(RF_OCP_ON)
|
||||
if r.isRFM69HW {
|
||||
ocp = RF_OCP_OFF
|
||||
}
|
||||
|
||||
err := r.writeReg(REG_OCP, ocp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if r.isRFM69HW { // turning ON
|
||||
// enable P1 & P2 amplifier stages
|
||||
if r.isRFM69HW {
|
||||
err = r.readWriteReg(REG_PALEVEL, 0x1F, RF_PALEVEL_PA1_ON|RF_PALEVEL_PA2_ON)
|
||||
} else {
|
||||
// enable P0 only
|
||||
err = r.readWriteReg(REG_PALEVEL, 0, RF_PALEVEL_PA0_ON|RF_PALEVEL_PA1_OFF|RF_PALEVEL_PA2_OFF|r.powerLevel)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -341,16 +353,13 @@ func (r *Device) writeFifo(data *Data) error {
|
|||
tx[1] = byte(buffersize + 3)
|
||||
tx[2] = data.ToAddress
|
||||
tx[3] = r.address
|
||||
|
||||
if data.RequestAck {
|
||||
tx[4] = 0x40
|
||||
}
|
||||
if data.SendAck {
|
||||
tx[4] = 0x80
|
||||
}
|
||||
|
||||
copy(tx[5:], data.Data[:buffersize])
|
||||
|
||||
_, err := r.SpiDevice.Xfer(tx)
|
||||
return err
|
||||
}
|
||||
|
@ -358,34 +367,28 @@ func (r *Device) writeFifo(data *Data) error {
|
|||
func (r *Device) readFifo() (Data, error) {
|
||||
var err error
|
||||
data := Data{}
|
||||
|
||||
data.Rssi, err = r.readRSSI(false)
|
||||
if err != nil {
|
||||
return data, err
|
||||
}
|
||||
|
||||
tx := new([67]byte)
|
||||
tx[0] = REG_FIFO & 0x7f
|
||||
rx, err := r.SpiDevice.Xfer(tx[:3])
|
||||
if err != nil {
|
||||
return data, err
|
||||
}
|
||||
|
||||
data.ToAddress = rx[2]
|
||||
length := rx[1] - 3
|
||||
if length > 66 {
|
||||
length = 66
|
||||
}
|
||||
|
||||
rx, err = r.SpiDevice.Xfer(tx[:length+3])
|
||||
if err != nil {
|
||||
return data, err
|
||||
}
|
||||
|
||||
data.FromAddress = rx[1]
|
||||
data.SendAck = bool(rx[2]&0x80 > 0)
|
||||
data.RequestAck = bool(rx[2]&0x40 > 0)
|
||||
data.Data = rx[3:]
|
||||
|
||||
return data, nil
|
||||
}
|
||||
|
|
185
handler.go
185
handler.go
|
@ -7,122 +7,85 @@ import (
|
|||
)
|
||||
|
||||
// Loop is the main receive and transmit handling loop
|
||||
func (r *Device) Loop() (chan Data, chan Data, chan int) {
|
||||
func (r *Device) Loop() (chan Data, chan int) {
|
||||
quit := make(chan int)
|
||||
txChan := make(chan Data, 5)
|
||||
rxChan := make(chan Data, 5)
|
||||
ch := make(chan Data, 5)
|
||||
go r.loopInternal(ch, quit)
|
||||
return ch, quit
|
||||
}
|
||||
|
||||
go func() {
|
||||
irq := make(chan int)
|
||||
func (r *Device) loopInternal(ch chan Data, quit chan int) {
|
||||
irq := make(chan int)
|
||||
r.gpio.BeginWatch(gpio.EdgeRising, func() {
|
||||
irq <- 1
|
||||
})
|
||||
defer r.gpio.EndWatch()
|
||||
|
||||
r.gpio.BeginWatch(gpio.EdgeRising, func() {
|
||||
irq <- 1
|
||||
})
|
||||
err := r.SetMode(RF_OPMODE_RECEIVER)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
return
|
||||
}
|
||||
defer r.SetMode(RF_OPMODE_STANDBY)
|
||||
|
||||
err := r.SetMode(RF_OPMODE_RECEIVER)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
return
|
||||
}
|
||||
defer r.SetMode(RF_OPMODE_STANDBY)
|
||||
|
||||
for {
|
||||
select {
|
||||
case dataToTransmit := <-txChan:
|
||||
// TODO: can send?
|
||||
r.readWriteReg(REG_PACKETCONFIG2, 0xFB, RF_PACKET2_RXRESTART) // avoid RX deadlocks
|
||||
|
||||
err = r.SetMode(RF_OPMODE_STANDBY)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
err = r.waitForMode()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
err = r.writeReg(REG_DIOMAPPING1, RF_DIOMAPPING1_DIO0_00)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
err = r.writeFifo(&dataToTransmit)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
log.Print("transmit", dataToTransmit)
|
||||
|
||||
err = r.SetMode(RF_OPMODE_TRANSMITTER)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
<-irq
|
||||
log.Print("transmit done")
|
||||
|
||||
err = r.SetMode(RF_OPMODE_STANDBY)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
err = r.waitForMode()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
err = r.writeReg(REG_DIOMAPPING1, RF_DIOMAPPING1_DIO0_01)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
err = r.SetMode(RF_OPMODE_RECEIVER)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
case <-irq:
|
||||
if r.mode != RF_OPMODE_RECEIVER {
|
||||
continue
|
||||
}
|
||||
|
||||
flags, err := r.readReg(REG_IRQFLAGS2)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if flags&RF_IRQFLAGS2_PAYLOADREADY == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
data, err := r.readFifo()
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
return
|
||||
}
|
||||
|
||||
log.Print("receive", data)
|
||||
|
||||
if data.ToAddress != 255 && data.RequestAck {
|
||||
resp := Data{
|
||||
FromAddress: r.address,
|
||||
ToAddress: data.FromAddress,
|
||||
SendAck: true,
|
||||
}
|
||||
txChan <- resp
|
||||
}
|
||||
|
||||
rxChan <- data
|
||||
|
||||
err = r.SetMode(RF_OPMODE_RECEIVER)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
case <-quit:
|
||||
quit <- 1
|
||||
for {
|
||||
select {
|
||||
case dataToTransmit := <-ch:
|
||||
// TODO: can send?
|
||||
r.readWriteReg(REG_PACKETCONFIG2, 0xFB, RF_PACKET2_RXRESTART) // avoid RX deadlocks
|
||||
err = r.SetModeAndWait(RF_OPMODE_STANDBY)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
err = r.writeReg(REG_DIOMAPPING1, RF_DIOMAPPING1_DIO0_00)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
err = r.writeFifo(&dataToTransmit)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
err = r.SetMode(RF_OPMODE_TRANSMITTER)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
<-irq
|
||||
err = r.SetModeAndWait(RF_OPMODE_STANDBY)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
err = r.writeReg(REG_DIOMAPPING1, RF_DIOMAPPING1_DIO0_01)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
err = r.SetMode(RF_OPMODE_RECEIVER)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
case <-irq:
|
||||
if r.mode != RF_OPMODE_RECEIVER {
|
||||
continue
|
||||
}
|
||||
flags, err := r.readReg(REG_IRQFLAGS2)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if flags&RF_IRQFLAGS2_PAYLOADREADY == 0 {
|
||||
continue
|
||||
}
|
||||
data, err := r.readFifo()
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
return
|
||||
}
|
||||
ch <- data
|
||||
err = r.SetMode(RF_OPMODE_RECEIVER)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
case <-quit:
|
||||
quit <- 1
|
||||
return
|
||||
}
|
||||
}()
|
||||
|
||||
return rxChan, txChan, quit
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue