Documentation ¶
Overview ¶
The SX1231 package interfaces with a HopeRF RFM69 radio connected to an SPI bus.
The RFM69 modules use a Semtech SX1231 or SX1231H radio chip and this package should work fine with other radio modules using the same chip. The only real difference will be the power output section where different modules use different output stage configurations.
The driver is fully interrupt driven and requires that the radio's DIO0 pin be connected to an interrupt capable GPIO pin. The transmit and receive interface uses a pair of tx and rx channels, each having a small amount of buffering.
In general, other than a few user errors (such as passing too large a packet to Send) there should be no errors during the radio's operation unless there is a hardware failure. For this reason radio interface errors are treated as fatal: if such an error occurs the rx channel is closed and the error is recorded in the Radio struct where it can be retrieved using the Error function. The object will be unusable for further operation and the client code will have to create and initialize a fresh object which will re-establish communication with the radio chip.
This driver does not do a number of things that other sx1231 drivers tend to do with the goal of leaving these tasks to higher-level drivers. This driver does not use the address filtering capability: it recevies all packets because that's simpler and the few extra interrupts should not matter to a system that can run Golang. It also accepts packets that have a CRC error and simply flags the error. It does not constrain the sync bytes, the frequency, or the data rates.
The main limitations of this driver are that it operates the sx1231 in FSK variable-length packet mode and limits the packet size to the 66 bytes that fit into the FIFO, meaning that the payloads pushed into the TX channel must be 65 bytes or less, leaving one byte for the required packet length.
The methods on the Radio object are not concurrency safe. Since they all deal with configuration this should not pose difficulties. The Error function may be called from multiple goroutines and obviously the TX and RX channels work well with concurrency.
Index ¶
- Constants
- Variables
- func JLDecode(grp byte, payload []byte) (src, dst byte, ack bool, outPayload []byte, err error)
- func JLEncode(grp, src, dst byte, ack bool, payload []byte) []byte
- func JeeLabsSync(grp byte) []byte
- func MakeJLAck(grp byte, payload []byte) []byte
- type LogPrintf
- type Radio
- type RadioOpts
- type Rate
- type RxPacket
- type Temporary
Constants ¶
const ( REG_FIFO = 0x00 REG_OPMODE = 0x01 REG_DATAMODUL = 0x02 REG_BITRATEMSB = 0x03 REG_FDEVMSB = 0x05 REG_FRFMSB = 0x07 REG_AFCCTRL = 0x0B REG_VERSION = 0x10 REG_PALEVEL = 0x11 REG_LNAVALUE = 0x18 REG_RXBW = 0x19 REG_AFCBW = 0x1A REG_AFCFEI = 0x1E REG_AFCMSB = 0x1F REG_AFCLSB = 0x20 REG_FEIMSB = 0x21 REG_FEILSB = 0x22 REG_RSSICONFIG = 0x23 REG_RSSIVALUE = 0x24 REG_DIOMAPPING1 = 0x25 REG_IRQFLAGS1 = 0x27 REG_IRQFLAGS2 = 0x28 REG_RSSITHRES = 0x29 REG_SYNCCONFIG = 0x2E REG_SYNCVALUE1 = 0x2F REG_SYNCVALUE2 = 0x30 REG_NODEADDR = 0x39 REG_BCASTADDR = 0x3A REG_FIFOTHRESH = 0x3C REG_PKTCONFIG2 = 0x3D REG_AESKEYMSB = 0x3E REG_TESTPA1 = 0x5A REG_TESTPA2 = 0x5C REG_TESTAFC = 0x71 MODE_SLEEP = 0 << 2 MODE_STANDBY = 1 << 2 MODE_FS = 2 << 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_PLLLOCK = 1 << 4 IRQ1_RSSI = 1 << 3 IRQ1_TIMEOUT = 1 << 2 IRQ1_SYNCMATCH = 1 << 0 IRQ2_FIFONOTEMPTY = 1 << 6 IRQ2_PACKETSENT = 1 << 3 IRQ2_PAYLOADREADY = 1 << 2 IRQ2_CRCOK = 1 << 1 DIO_MAPPING = 0x31 DIO_RSSI = 0xC0 DIO_SYNC = 0x80 DIO_PAYREADY = 0x40 DIO_PKTSENT = 0x00 )
Variables ¶
var Rates = map[uint32]Rate{
49230: {45000, 0, 0x4A, 0x42},
49231: {180000, 0, 0x49, 0x49},
49232: {45000, 0, 0x52, 0x4A},
49233: {51660, 0, 0x52, 0x4A},
50000: {90000, 0, 0x42, 0x42},
}
Rates is the table of supported bit rates and their corresponding register settings. The map key is the bit rate in bits per second. In order to operate at a new bit rate the table can be extended by the client.
Functions ¶
func JLDecode ¶
JLDecode decodes a JeeLabs packet. See JLEncode for a description of the packet format. The outPayload it returns has the src/dst stripped.
func JLEncode ¶
JLEncode encodes a JeeLabs packet.
Jeelabs native rfm69 packet format ¶
From the radio's perspective, a packet has 5 preamble bytes, 2 sync bytes, a length byte, a dest address byte, up to 64 payload bytes, and 2-byte CRC. The length counts the payload plus the dest address.
The JeeLabs format defines the 5-byte preamble (the radio allows many options) and the 2 sync bytes. The first sync byte is 0x2d, the second is the group ID (network number). The JeeLabs format also uses the first payload byte as a source address. This means that the application payload can hold up to 63 bytes. Finally, in newer JeeLabs usage the first payload byte (after the src address) is a packet type format byte.
The destination address byte is calculated as the 6-bit destination node ID and two sync parity bits at the top. Bit 7 (MSB) is calculated as the group's b7^b5^b3^b1 and bit 6 as the group's b6^b4^b2^b0.
The source address byte is calculated as the 6-bit source node ID and two control bits. Bit 7 is an ACK request bit and bit 6 is unassigned.
A packet with destination ID 0 is a broadcast packet, a node ID of 62 is used for anonymouns tx-only nodes, and a node ID of 63 is used on the receiving end to denote a node that receives all packets regardless of destination (promiscuous mode).
func JeeLabsSync ¶
JeeLabsSync returns a byte array of sync bytes given the group number.
Types ¶
type LogPrintf ¶
type LogPrintf func(format string, v ...interface{})
LogPrintf is a function used by the driver to print logging info.
type Radio ¶
type Radio struct { // state sync.Mutex // guard concurrent access to the radio // contains filtered or unexported fields }
Radio represents a Semtech SX1231 radio as used in HopeRF's RFM69 modules.
func New ¶
New initializes an sx1231 Radio given an spi.Conn and an interrupt pin, and places the radio in receive mode.
The SPI bus must be set to 10Mhz max and mode 0.
The RF sync bytes used are specified using the sync array, the frequency is specified in Hz, Khz, or Mhz, and the data bitrate is specified in bits per second and must match one of the rates in the Rates table.
To transmit, push packet payloads into the returned txChan. Received packets will be sent on the returned rxChan, which has a small amount of buffering. The rxChan will be closed if a persistent error occurs when communicating with the device, use the Error() function to retrieve the error.
func (*Radio) SetFrequency ¶
SetFrequency changes the center frequency at which the radio transmits and receives. The frequency can be specified at any scale (hz, khz, mhz). The frequency value is not checked and invalid values will simply cause the radio not to work particularly well.
func (*Radio) SetPower ¶
SetPower configures the radio for the specified output power (TODO: should be in dBm).
type RadioOpts ¶
type RadioOpts struct { Sync []byte // RF sync bytes Freq uint32 // frequency in Hz, Khz, or Mhz Rate uint32 // data bitrate in bits per second, must exist in Rates table PABoost bool // true: use PA1+PA2, false: use PA0 Logger LogPrintf // function to use for logging }
RadioOpts contains options used when initilizing a Radio.
type Rate ¶
type Rate struct { Fdev int // TX frequency deviation in Hz Shaping byte // 0:none, 1:gaussian BT=1, 2:gaussian BT=0.5, 3:gaussian BT=0.3 RxBw byte // value for rxBw register (0x19) AfcBw byte // value for afcBw register (0x1A) }
Rate describes the SX1231 configuration to achieve a specific bit rate.
The datasheet is somewhat confused and confusing about what Fdev and RxBw really mean. Fdev is defined as the deviation between the center freq and the modulated freq, while conventionally the frequency deviation fdev is the difference between the 0 and 1 freq's, thus the conventional fdev is Fdev*2.
Similarly the RxBw is specified as the single-sided bandwidth while conventionally the signal or channel bandwidths are defined using the total bandwidths.
Given that the sx1231 is a zero-if receiver it is recommended to configure a modulation index greater than 1.2, e.g. best approx 2. Modulation index is defined as fdev/bit-rate. This means that Fdev should be approx equal to bps. [Martyn, or are you targeting a modulation index of 4?]
The signal bandwidth (20dB roll-off) can be approximated by fdev + bit-rate. Since RxBw is specified as the single-sided bandwidth it needs to be at least (fdev+bit-rate)/2. Or, in sx1231 config terms, Fdev + bitrate/2. If AFC is used, in order to accommodate a crystal offset between Tx and Rx of Fdelta the AFC bandwidth should be approx fdev + bit-rate + 2*Fdelta.
type RxPacket ¶
type RxPacket struct { Payload []byte // payload, from address to last data byte, excluding length & crc Rssi int // rssi value for current packet Snr int // rssi - noise floor for current packet Fei int // frequency error for current packet At time.Time // time of rx interrupt }
RxPacket is a received packet with stats.