mirror of
https://github.com/kidoman/embd
synced 2024-12-22 12:50:19 +01:00
Back out addition of rfm69 radio support 'cause it's not ready
This commit is contained in:
parent
eac7d5af1b
commit
acf38b972d
@ -1 +0,0 @@
|
|||||||
package radio
|
|
@ -1,8 +0,0 @@
|
|||||||
RFM69 Driver Info
|
|
||||||
=================
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Interesting links
|
|
||||||
-----------------
|
|
||||||
- Info about listen mode with low duty cycle: https://lowpowerlab.com/forum/low-power-techniques/ultra-low-power-listening-mode-for-battery-nodes/
|
|
@ -1,68 +0,0 @@
|
|||||||
// Copyright 2016 by Thorsten von Eicken, see LICENSE file
|
|
||||||
|
|
||||||
package rfm69
|
|
||||||
|
|
||||||
const (
|
|
||||||
REG_FIFO = 0x00
|
|
||||||
REG_OPMODE = 0x01
|
|
||||||
REG_FRFMSB = 0x07
|
|
||||||
REG_PALEVEL = 0x11
|
|
||||||
REG_LNAVALUE = 0x18
|
|
||||||
REG_AFCMSB = 0x1F
|
|
||||||
REG_AFCLSB = 0x20
|
|
||||||
REG_FEIMSB = 0x21
|
|
||||||
REG_FEILSB = 0x22
|
|
||||||
REG_RSSIVALUE = 0x24
|
|
||||||
REG_IRQFLAGS1 = 0x27
|
|
||||||
REG_IRQFLAGS2 = 0x28
|
|
||||||
REG_SYNCVALUE1 = 0x2F
|
|
||||||
REG_SYNCVALUE2 = 0x30
|
|
||||||
REG_NODEADDR = 0x39
|
|
||||||
REG_BCASTADDR = 0x3A
|
|
||||||
REG_FIFOTHRESH = 0x3C
|
|
||||||
REG_PKTCONFIG2 = 0x3D
|
|
||||||
REG_AESKEYMSB = 0x3E
|
|
||||||
|
|
||||||
MODE_SLEEP = 0 << 2
|
|
||||||
MODE_STANDBY = 1 << 2
|
|
||||||
MODE_TRANSMIT = 3 << 2
|
|
||||||
MODE_RECEIVE = 4 << 2
|
|
||||||
|
|
||||||
START_TX = 0xC2
|
|
||||||
STOP_TX = 0x42
|
|
||||||
|
|
||||||
RCCALSTART = 0x80
|
|
||||||
IRQ1_MODEREADY = 1 << 7
|
|
||||||
IRQ1_RXREADY = 1 << 6
|
|
||||||
IRQ1_SYNADDRMATCH = 1 << 0
|
|
||||||
|
|
||||||
IRQ2_FIFONOTEMPTY = 1 << 6
|
|
||||||
IRQ2_PACKETSENT = 1 << 3
|
|
||||||
IRQ2_PAYLOADREADY = 1 << 2
|
|
||||||
)
|
|
||||||
|
|
||||||
// register values to initialize the chip, this array has pairs of <address, data>
|
|
||||||
var configRegs = []byte{
|
|
||||||
// POR value is better for first rf_sleep 0x01, 0x00, // OpMode = sleep
|
|
||||||
0x02, 0x00, // DataModul = packet mode, fsk
|
|
||||||
0x03, 0x02, // BitRateMsb, data rate = 49,261 khz
|
|
||||||
0x04, 0x8A, // BitRateLsb, divider = 32 MHz / 650
|
|
||||||
0x05, 0x02, // FdevMsb = 45 KHz
|
|
||||||
0x06, 0xE1, // FdevLsb = 45 KHz
|
|
||||||
0x0B, 0x20, // Low M
|
|
||||||
0x19, 0x4A, // RxBw 100 KHz
|
|
||||||
0x1A, 0x42, // AfcBw 125 KHz
|
|
||||||
0x1E, 0x0C, // AfcAutoclearOn, AfcAutoOn
|
|
||||||
//0x25, 0x40, //0x80, // DioMapping1 = SyncAddress (Rx)
|
|
||||||
0x26, 0x07, // disable clkout
|
|
||||||
0x29, 0xA0, // RssiThresh -80 dB
|
|
||||||
0x2D, 0x05, // PreambleSize = 5
|
|
||||||
0x2E, 0x88, // SyncConfig = sync on, sync size = 2
|
|
||||||
0x2F, 0x2D, // SyncValue1 = 0x2D
|
|
||||||
0x37, 0xD0, // PacketConfig1 = fixed, white, no filtering
|
|
||||||
0x38, 0x42, // PayloadLength = 0, unlimited
|
|
||||||
0x3C, 0x8F, // FifoTresh, not empty, level 15
|
|
||||||
0x3D, 0x12, // 0x10, // PacketConfig2, interpkt = 1, autorxrestart off
|
|
||||||
0x6F, 0x20, // TestDagc ...
|
|
||||||
0x71, 0x02, // RegTestAfc
|
|
||||||
}
|
|
@ -1,257 +0,0 @@
|
|||||||
// Copyright 2016 by Thorsten von Eicken, see LICENSE file
|
|
||||||
|
|
||||||
// The RFM69 package interfaces with a HopeRF RFM69 radio connected to an SPI bus. In addition,
|
|
||||||
// an interrupt capable GPIO pin may be used to avoid having to poll the radio.
|
|
||||||
package rfm69
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"log"
|
|
||||||
|
|
||||||
"github.com/kidoman/embd"
|
|
||||||
)
|
|
||||||
|
|
||||||
// rfm69 represents a HopeRF RFM69 radio
|
|
||||||
type rfm69 struct {
|
|
||||||
// configuration
|
|
||||||
spi embd.SPIBus // bus where the radio is connected
|
|
||||||
intrPin embd.InterruptPin // interrupt pin for RX and TX interrupts
|
|
||||||
id byte // my RF ID/address
|
|
||||||
group byte // RF address of group
|
|
||||||
freq int // center frequency
|
|
||||||
parity byte // ???
|
|
||||||
// state
|
|
||||||
mode byte // current operation mode
|
|
||||||
// info about current RX packet
|
|
||||||
rxInfo *RxInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
type Packet struct {
|
|
||||||
Length uint8 // number of message bytes plus 1 for the address byte
|
|
||||||
Address uint8 // destination address
|
|
||||||
Message []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
type RxInfo struct {
|
|
||||||
rssi int // rssi value for current packet
|
|
||||||
lna int // low noise amp gain for current packet
|
|
||||||
fei int // frequency error for current packet
|
|
||||||
afc int // frequency correction applied for current packet
|
|
||||||
}
|
|
||||||
|
|
||||||
// New creates a connection to an rfm69 radio connected to the provided SPI bus and interrupt pin.
|
|
||||||
// the bufCount determines how many transmit buffers are allocated to allow for the queueing of
|
|
||||||
// transmit packets.
|
|
||||||
// For the RFM69 the SPI bus must be set to 10Mhz and mode 0.
|
|
||||||
func New(bus embd.SPIBus, intr embd.InterruptPin, id, group byte, freq int) *rfm69 {
|
|
||||||
// bit 7 = b7^b5^b3^b1; bit 6 = b6^b4^b2^b0
|
|
||||||
parity := group ^ (group << 4)
|
|
||||||
parity = (parity ^ (parity << 2)) & 0xc0
|
|
||||||
return &rfm69{spi: bus, intrPin: intr, id: id, group: group, freq: freq, parity: parity,
|
|
||||||
mode: 255}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rf *rfm69) writeReg(addr, data byte) error {
|
|
||||||
buf := []byte{addr | 0x80, data}
|
|
||||||
return rf.spi.TransferAndReceiveData(buf)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rf *rfm69) readReg(addr byte) (byte, error) {
|
|
||||||
buf := []byte{addr & 0x7f, 0}
|
|
||||||
err := rf.spi.TransferAndReceiveData(buf)
|
|
||||||
return buf[1], err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rf *rfm69) Init() error {
|
|
||||||
// try to establish communication with the rfm69
|
|
||||||
sync := func(pattern byte) error {
|
|
||||||
n := 10
|
|
||||||
for {
|
|
||||||
rf.writeReg(REG_SYNCVALUE1, pattern)
|
|
||||||
v, err := rf.readReg(REG_SYNCVALUE1)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if v == pattern {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if n == 0 {
|
|
||||||
return fmt.Errorf("Cannot sync with rfm69 chip")
|
|
||||||
}
|
|
||||||
n--
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err := sync(0xaa); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := sync(0x55); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// write the configuration into the registers
|
|
||||||
for i := 0; i < len(configRegs)-1; i += 2 {
|
|
||||||
if err := rf.writeReg(configRegs[i], configRegs[i+1]); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rf.setFrequency(rf.freq)
|
|
||||||
rf.writeReg(REG_SYNCVALUE2, rf.group)
|
|
||||||
|
|
||||||
if gpio, ok := rf.intrPin.(embd.DigitalPin); ok {
|
|
||||||
log.Printf("Set intr direction")
|
|
||||||
gpio.SetDirection(embd.In)
|
|
||||||
}
|
|
||||||
if err := rf.intrPin.Watch(embd.EdgeRising, rf.intrHandler); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rf *rfm69) setFrequency(freq int) {
|
|
||||||
// accept any frequency scale as input, including KHz and MHz
|
|
||||||
// multiply by 10 until freq >= 100 MHz
|
|
||||||
for freq > 0 && freq < 100000000 {
|
|
||||||
freq = freq * 10
|
|
||||||
}
|
|
||||||
|
|
||||||
// Frequency steps are in units of (32,000,000 >> 19) = 61.03515625 Hz
|
|
||||||
// use multiples of 64 to avoid multi-precision arithmetic, i.e. 3906.25 Hz
|
|
||||||
// due to this, the lower 6 bits of the calculated factor will always be 0
|
|
||||||
// this is still 4 ppm, i.e. well below the radio's 32 MHz crystal accuracy
|
|
||||||
// 868.0 MHz = 0xD90000, 868.3 MHz = 0xD91300, 915.0 MHz = 0xE4C000
|
|
||||||
frf := (freq << 2) / (32000000 >> 11)
|
|
||||||
rf.writeReg(REG_FRFMSB, byte(frf>>10))
|
|
||||||
rf.writeReg(REG_FRFMSB+1, byte(frf>>2))
|
|
||||||
rf.writeReg(REG_FRFMSB+2, byte(frf<<6))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rf *rfm69) setMode(mode byte) error {
|
|
||||||
reg, err := rf.readReg(REG_OPMODE)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
reg = (reg & 0xE3) | mode
|
|
||||||
err = rf.writeReg(REG_OPMODE, reg)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
for {
|
|
||||||
val, err := rf.readReg(REG_IRQFLAGS1)
|
|
||||||
if err != nil {
|
|
||||||
rf.mode = 255
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if val&IRQ1_MODEREADY != 0 {
|
|
||||||
rf.mode = mode
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rf *rfm69) Send(header byte, message []byte) error {
|
|
||||||
if len(message) > 62 {
|
|
||||||
return fmt.Errorf("message too long")
|
|
||||||
}
|
|
||||||
rf.setMode(MODE_SLEEP)
|
|
||||||
|
|
||||||
buf := make([]byte, len(message)+4)
|
|
||||||
buf[0] = REG_FIFO | 0x80
|
|
||||||
buf[1] = byte(len(message) + 2)
|
|
||||||
buf[2] = (header & 0x3f) | rf.parity
|
|
||||||
buf[3] = (header & 0xC0) | rf.id
|
|
||||||
copy(buf[4:], message)
|
|
||||||
err := rf.spi.TransferAndReceiveData(buf)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
rf.setMode(MODE_TRANSMIT)
|
|
||||||
for {
|
|
||||||
val, err := rf.readReg(REG_IRQFLAGS2)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if val&IRQ2_PACKETSENT != 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rf.setMode(MODE_STANDBY)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rf *rfm69) readInfo() *RxInfo {
|
|
||||||
// collect rxinfo, start with rssi
|
|
||||||
rxInfo := &RxInfo{}
|
|
||||||
rssi, _ := rf.readReg(REG_RSSIVALUE)
|
|
||||||
rxInfo.rssi = 0 - int(rssi)/2
|
|
||||||
// low noise amp gain
|
|
||||||
lna, _ := rf.readReg(REG_LNAVALUE)
|
|
||||||
rxInfo.lna = int((lna >> 3) & 0x7)
|
|
||||||
// auto freq correction applied, caution: signed value
|
|
||||||
buf := []byte{REG_AFCMSB, 0, 0}
|
|
||||||
rf.spi.TransferAndReceiveData(buf)
|
|
||||||
rxInfo.afc = int(int8(buf[1]))<<8 | int(buf[2])
|
|
||||||
// freq error detected, caution: signed value
|
|
||||||
buf = []byte{REG_FEIMSB, 0, 0}
|
|
||||||
rf.spi.TransferAndReceiveData(buf)
|
|
||||||
rxInfo.fei = int(int8(buf[1]))<<8 | int(buf[2])
|
|
||||||
return rxInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rf *rfm69) Receive() (header byte, message []byte, info *RxInfo, err error) {
|
|
||||||
// if we're not in receive mode, then switch, this also flushes the FIFO
|
|
||||||
if rf.mode != MODE_RECEIVE {
|
|
||||||
rf.setMode(MODE_RECEIVE)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// if we don't have rxinfo check whether we have RX_READY, which means that we've
|
|
||||||
// started receiving a packet so we can collect info
|
|
||||||
if rf.rxInfo == nil {
|
|
||||||
irq1, err := rf.readReg(REG_IRQFLAGS1)
|
|
||||||
if err != nil {
|
|
||||||
return 0, nil, nil, err
|
|
||||||
}
|
|
||||||
if irq1&IRQ1_RXREADY != 0 {
|
|
||||||
rf.rxInfo = rf.readInfo()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// see whether we have a full packet
|
|
||||||
irq2, err := rf.readReg(REG_IRQFLAGS2)
|
|
||||||
if err != nil {
|
|
||||||
return 0, nil, nil, err
|
|
||||||
}
|
|
||||||
if irq2&IRQ2_PAYLOADREADY == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
i2 := rf.readInfo()
|
|
||||||
if rf.rxInfo != nil && i2 != nil &&
|
|
||||||
(rf.rxInfo.rssi != i2.rssi || rf.rxInfo.lna != i2.lna ||
|
|
||||||
rf.rxInfo.afc != i2.afc || rf.rxInfo.fei != i2.fei) {
|
|
||||||
fmt.Printf("\nrxInfo mismatch: %+v vs %+v\n", *rf.rxInfo, *i2)
|
|
||||||
}
|
|
||||||
// got packet, read it by fetching the entire FIFO, should be faster than first
|
|
||||||
// looking at the length
|
|
||||||
buf := make([]byte, 67)
|
|
||||||
buf[0] = REG_FIFO
|
|
||||||
err = rf.spi.TransferAndReceiveData(buf)
|
|
||||||
if err != nil {
|
|
||||||
return 0, nil, nil, err
|
|
||||||
}
|
|
||||||
// return the packet
|
|
||||||
info = rf.rxInfo
|
|
||||||
rf.rxInfo = nil
|
|
||||||
l := buf[1]
|
|
||||||
if l > 66 {
|
|
||||||
l = 66 // or error?
|
|
||||||
}
|
|
||||||
header = buf[2]
|
|
||||||
message = buf[3 : 2+l]
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rf *rfm69) intrHandler(pin embd.DigitalPin) {
|
|
||||||
log.Printf("Interrupt called!")
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user