wayne roberts / sx128x

Dependents:   alarm_slave_extended_SX1280 alarm_master_extended_Vance_SX1280

Files at this revision

API Documentation at this revision

Comitter:
Wayne Roberts
Date:
Thu Jun 28 17:52:22 2018 -0700
Child:
1:70ef46fa6fc6
Commit message:
initial commit

Changed in this revision

sx1280.cpp Show annotated file Show diff for this revision Revisions of this file
sx12xx.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sx1280.cpp	Thu Jun 28 17:52:22 2018 -0700
@@ -0,0 +1,395 @@
+#include "sx12xx.h"
+
+Callback<void()> SX128x::diox_topHalf;    // low latency ISR context
+
+const float SX128x::timeOutStep[] = { 0.015625, 0.0625, 1, 4 };
+
+void SX128x::dioxisr()
+{
+    if (diox_topHalf)
+        diox_topHalf.call();
+}
+
+SX128x::SX128x(SPI& _spi, PinName _nss, PinName _busy, PinName _diox)
+    : spi(_spi), nss(_nss), busy(_busy), diox(_diox)
+{
+    nss = 1;
+
+    diox.rise(dioxisr);
+
+    if (busy) {
+        /*status_t status;
+        status.octet =*/ xfer(OPCODE_GET_STATUS, 0, 0, NULL);
+        while (busy)
+            ;
+    }
+
+    periodBase = 3;
+}
+
+uint8_t SX128x::xfer(uint8_t opcode, uint8_t wlen, uint8_t rlen, uint8_t* ptr)
+{
+    const uint8_t* stopPtr;
+    const uint8_t* wstop;
+    const uint8_t* rstop;
+    uint8_t nop = 0;
+    uint8_t ret;
+
+    if (opcode != OPCODE_GET_STATUS) {
+        if (sleeping) {
+            nss = 0;
+            while (busy)
+                ;
+            sleeping = false;
+        } else {
+            while (busy)
+                ;
+
+            nss = 0;
+        }
+    } else
+        nss = 0;
+
+    ret = spi.write(opcode);
+
+    wstop = ptr + wlen;
+    rstop = ptr + rlen;
+    if (rlen > wlen)
+        stopPtr = rstop;
+    else
+        stopPtr = wstop;
+
+    for (; ptr < stopPtr; ptr++) {
+        if (ptr < wstop && ptr < rstop)
+            *ptr = spi.write(*ptr);
+        else if (ptr < wstop)
+            spi.write(*ptr);
+        else
+            *ptr = spi.write(nop);    // n >= write length: send NOP
+    }
+
+    nss = 1;
+
+    if (opcode == OPCODE_SET_SLEEP)
+        sleeping = true;
+
+    return ret;
+}
+
+uint32_t SX128x::readReg(uint16_t addr, uint8_t len)
+{
+    uint32_t ret = 0;
+    unsigned i;
+
+    uint8_t buf[7];
+    buf[0] = addr >> 8;
+    buf[1] = (uint8_t)addr;
+    xfer(OPCODE_READ_REGISTER, 2, 3+len, buf);
+    for (i = 0; i < len; i++) {
+        ret <<= 8;
+        ret |= buf[i+3];
+    }
+    return ret;
+}
+
+void SX128x::start_tx(uint8_t pktLen, float timeout_ms)
+{
+    IrqFlags_t irqEnable;
+    uint8_t buf[8];
+
+    irqEnable.word = 0;
+    irqEnable.bits.TxDone = 1;
+    irqEnable.bits.RxTxTimeout = 1;
+
+    buf[0] = irqEnable.word >> 8;    // enable bits
+    buf[1] = irqEnable.word; // enable bits
+    buf[2] = irqEnable.word >> 8;     // dio1
+    buf[3] = irqEnable.word;  // dio1
+    buf[4] = 0; // dio2
+    buf[5] = 0; // dio2
+    buf[6] = 0; // dio3
+    buf[7] = 0; // dio3
+    xfer(OPCODE_SET_DIO_IRQ_PARAMS, 8, 0, buf);
+
+    {
+        uint8_t i;
+
+        while (busy)
+            ;
+
+        nss = 0;
+        spi.write(OPCODE_WRITE_BUFFER);
+        spi.write(0);   // offset
+        i = 0;
+        for (i = 0; i < pktLen; i++) {
+            spi.write(tx_buf[i]);
+        }
+        nss = 1;
+    }
+
+    buf[0] = 3;
+    if (timeout_ms > 0) {
+        unsigned t_o = timeout_ms / timeOutStep[periodBase];
+        buf[1] = t_o >> 8;
+        buf[2] = t_o;
+    } else {
+        /* no timeout */
+        buf[1] = 0;
+        buf[2] = 0;
+    }
+    xfer(OPCODE_SET_TX, 3, 0, buf);
+
+    chipMode = CHIPMODE_TX;
+    if (chipModeChange)
+        chipModeChange.call();
+}
+
+void SX128x::hw_reset(PinName pin)
+{
+    DigitalInOut nrst(pin);
+    nrst.output();
+    nrst = 0;
+    wait_us(100);
+    nrst = 1;
+    nrst.mode(PullUp);
+    nrst.input();
+
+    while (busy)
+        ;
+}
+
+uint64_t SX128x::getSyncAddr(uint8_t num)
+{
+    uint64_t ret;
+    unsigned regAdr = REG_ADDR_PKT_SYNC_ADRS_1 + ((num-1) * 5);
+    ret = readReg(regAdr, 1);
+    ret <<= 32;
+    ret |= readReg(regAdr+1, 4);
+    return ret;
+}
+
+void SX128x::setSyncAddr(uint8_t num, uint64_t sa)
+{
+    unsigned regAdr = REG_ADDR_PKT_SYNC_ADRS_1 + ((num-1) * 5);
+    writeReg(regAdr+1, sa & 0xffffffff, 4);
+    sa >>= 32;
+    writeReg(regAdr, sa & 0xff, 1);
+}
+
+void SX128x::set_tx_dbm(int8_t dbm)
+{
+    uint8_t buf[2];
+
+    buf[0] = dbm;
+    buf[1] = RADIO_RAMP_20_US;
+    xfer(OPCODE_SET_TX_PARAMS, 2, 0, buf);
+}
+
+void SX128x::setMHz(float MHz)
+{
+    unsigned frf = MHz / PLL_STEP_MHZ;
+    uint8_t buf[3];
+
+    buf[0] = frf >> 16;
+    buf[1] = frf >> 8;
+    buf[2] = frf;
+    xfer(OPCODE_SET_RF_FREQUENCY, 3, 0, buf);
+}
+
+float SX128x::getMHz()
+{
+    uint32_t frf = readReg(REG_ADDR_RFFREQ, 3);
+    return frf * PLL_STEP_MHZ;
+}
+
+void SX128x::setStandby(stby_t stby)
+{
+    uint8_t octet = stby;
+    xfer(OPCODE_SET_STANDBY, 1, 0, &octet);
+
+    chipMode = CHIPMODE_NONE;
+    if (chipModeChange)
+        chipModeChange.call();
+}
+
+void SX128x::setFS()
+{
+    xfer(OPCODE_SET_FS, 0, 0, NULL);
+
+    chipMode = CHIPMODE_NONE;
+    if (chipModeChange)
+        chipModeChange.call();
+}
+
+void SX128x::setSleep(bool warmStart)
+{
+    sleepConfig_t sc;
+
+    sc.octet = 0;
+    sc.retentionBits.dataRAM         = warmStart;
+    sc.retentionBits.dataBuffer      = warmStart;
+    sc.retentionBits.instructionRAM  = warmStart;
+    xfer(OPCODE_SET_SLEEP, 1, 0, &sc.octet);
+
+    chipMode = CHIPMODE_NONE;
+    if (chipModeChange)
+        chipModeChange.call();
+}
+
+uint8_t SX128x::getPacketType()
+{
+    uint8_t buf[2];
+
+    xfer(OPCODE_GET_PACKET_TYPE, 0, 2, buf);
+
+    return buf[1];
+}
+
+void SX128x::setPacketType(uint8_t type)
+{
+    xfer(OPCODE_SET_PACKET_TYPE, 1, 0, &type);
+}
+
+void SX128x::setBufferBase(uint8_t txAddr, uint8_t rxAddr)
+{
+    uint8_t buf[2];
+
+    buf[0] = txAddr; // TX base address
+    buf[1] = rxAddr; // RX base address
+    xfer(OPCODE_SET_BUFFER_BASE_ADDR, 2, 0, buf);
+}
+
+void SX128x::setRegulator(uint8_t rmp)
+{
+    xfer(OPCODE_SET_REGULATOR_MODE, 1, 0, &rmp);
+}
+
+void SX128x::start_rx(float timeout_ms)
+{
+    IrqFlags_t irqEnable;
+    uint8_t buf[8];
+    unsigned t_o;
+
+    irqEnable.word = 0;
+    irqEnable.bits.RxDone = 1;
+    irqEnable.bits.RxTxTimeout = 1;
+
+    buf[0] = irqEnable.word >> 8;    // enable bits
+    buf[1] = irqEnable.word; // enable bits
+    buf[2] = irqEnable.word >> 8;     // dio1
+    buf[3] = irqEnable.word;  // dio1
+    buf[4] = 0; // dio2
+    buf[5] = 0; // dio2
+    buf[6] = 0; // dio3
+    buf[7] = 0; // dio3
+    xfer(OPCODE_SET_DIO_IRQ_PARAMS, 8, 0, buf);
+
+    buf[0] = periodBase;
+    if (timeout_ms > 0) {
+        t_o = timeout_ms / timeOutStep[periodBase];
+        buf[1] = t_o >> 8;
+        buf[2] = t_o;
+    } else {
+        /* receive packets forever */
+        buf[1] = 0xff;
+        buf[2] = 0xff;
+    }
+    xfer(OPCODE_SET_RX, 3, 0, buf);
+
+    chipMode = CHIPMODE_RX;
+    if (chipModeChange) {
+        chipModeChange.call();
+    }
+}
+
+void SX128x::service()
+{
+    IrqFlags_t irqFlags, clearIrqFlags;
+    uint8_t buf[6];
+    pktStatus_t pktStatus;
+
+    if (busy) {
+        return;
+    }
+
+    while (diox) {
+        xfer(OPCODE_GET_IRQ_STATUS, 0, 3, buf);
+        irqFlags.word = buf[1] << 8;
+        irqFlags.word |= buf[2];
+        clearIrqFlags.word = 0;
+        if (irqFlags.bits.TxDone) {
+            if (txDone)
+                txDone.call();
+            clearIrqFlags.bits.TxDone = 1;
+            chipMode = CHIPMODE_NONE;
+            if (chipModeChange)
+                chipModeChange.call();
+        }
+        if (irqFlags.bits.RxDone) {
+            if (rxDone) {
+                uint8_t len;
+                xfer(OPCODE_GET_RX_BUFFER_STATUS, 0, 3, buf);
+                if (buf[1] == 0)
+                    len = readReg(REG_ADDR_LORA_TX_PAYLOAD_LENGTH, 1);  // lora implicit
+                else
+                    len = buf[1];
+
+                ReadBuffer(len, buf[2]);
+                xfer(OPCODE_GET_PACKET_STATUS, 0, 6, pktStatus.buf);
+                rxDone(len, &pktStatus);
+            }
+            clearIrqFlags.bits.RxDone = 1;
+        }
+        if (irqFlags.bits.RxTxTimeout) {
+            if (chipMode != CHIPMODE_NONE) {
+                if (timeout)
+                    timeout(chipMode == CHIPMODE_TX);
+            }
+            chipMode = CHIPMODE_NONE;
+            if (chipModeChange)
+                chipModeChange.call();
+            clearIrqFlags.bits.RxTxTimeout = 1;
+        }
+
+        if (clearIrqFlags.word != 0) {
+            buf[0] = clearIrqFlags.word >> 8;
+            buf[1] = (uint8_t)clearIrqFlags.word;
+            xfer(OPCODE_CLEAR_IRQ_STATUS, 2, 0, buf);
+        }
+
+    } // ...while (diox)
+
+} // ..service()
+
+void SX128x::writeReg(uint16_t addr, uint32_t data, uint8_t len)
+{
+    uint8_t buf[6];
+    uint8_t n;
+    buf[0] = addr >> 8;
+    buf[1] = (uint8_t)addr;
+    for (n = len; n > 0; n--) {
+        buf[n+1] = (uint8_t)data;
+        data >>= 8;
+    }
+    xfer(OPCODE_WRITE_REGISTER, 2+len, 2+len, buf);
+}
+
+void SX128x::ReadBuffer(uint8_t size, uint8_t offset)
+{
+    unsigned i;
+    while (busy)
+        ;
+
+    nss = 0;
+
+    spi.write(OPCODE_READ_BUFFER);
+    spi.write(offset);
+    spi.write(0);   // NOP
+    i = 0;
+    for (i = 0; i < size; i++) {
+        rx_buf[i] = spi.write(0);
+    }
+
+    nss = 1;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sx12xx.h	Thu Jun 28 17:52:22 2018 -0700
@@ -0,0 +1,651 @@
+#include "mbed.h"
+#ifndef SX128x_H
+#define SX128x_H
+
+/***************************************************************/
+#define OPCODE_GET_PACKET_TYPE          0x03
+#define OPCODE_CLEAR_DEVICE_ERRORS      0x07
+#define OPCODE_GET_IRQ_STATUS           0x15
+#define OPCODE_GET_RX_BUFFER_STATUS     0x17
+#define OPCODE_WRITE_REGISTER           0x18
+#define OPCODE_READ_REGISTER            0x19
+#define OPCODE_WRITE_BUFFER             0x1a
+#define OPCODE_READ_BUFFER              0x1b
+#define OPCODE_GET_PACKET_STATUS        0x1d
+#define OPCODE_GET_RSSIINST             0x1f
+#define OPCODE_SET_STANDBY              0x80
+#define OPCODE_SET_RX                   0x82
+#define OPCODE_SET_TX                   0x83
+#define OPCODE_SET_SLEEP                0x84
+#define OPCODE_SET_RF_FREQUENCY         0x86
+#define OPCODE_SET_CAD_PARAM            0x88
+#define OPCODE_CALIBRATE                0x89
+#define OPCODE_SET_PACKET_TYPE          0x8a
+#define OPCODE_SET_MODULATION_PARAMS    0x8b
+#define OPCODE_SET_PACKET_PARAMS        0x8c
+#define OPCODE_SET_DIO_IRQ_PARAMS       0x8d
+#define OPCODE_SET_TX_PARAMS            0x8e
+#define OPCODE_SET_BUFFER_BASE_ADDR     0x8f
+#define OPCODE_SET_PA_CONFIG            0x95
+#define OPCODE_SET_REGULATOR_MODE       0x96
+#define OPCODE_CLEAR_IRQ_STATUS         0x97
+#define OPCODE_SET_LORA_SYMBOL_TIMEOUT  0xa0
+#define OPCODE_GET_STATUS               0xc0
+#define OPCODE_SET_FS                   0xc1
+#define OPCODE_SET_CAD                  0xc5
+#define OPCODE_SET_TX_CARRIER           0xd1
+#define OPCODE_SET_TX_PREAMBLE          0xd2
+/***************************************************************/
+#define REG_ADDR_AFIRQ                    0x053 // 7bit
+#define REG_ADDR_RXBW                     0x881 // 7bit
+#define REG_ADDR_GFSK_DEMODSTATUS         0x8cb // 5bit
+#define REG_ADDR_LORA_TX_PAYLOAD_LENGTH   0x901 // 8bit
+#define REG_ADDR_LORA_PKTPAR0             0x902 // 8bit
+#define REG_ADDR_LORA_PKTPAR1             0x902 // 8bit
+#define REG_ADDR_LORA_LRCTL               0x904 // 8bit
+#define REG_ADDR_LORA_IRQMASK             0x90f // 24bit
+#define REG_ADDR_LORA_PREAMBLE            0x93f // 8bit
+#define REG_ADDR_LORA_MODEMSTAT           0x95c // 8bit
+
+#define REG_ADDR_FSK_CFG                  0x9a0 // 8bit
+#define REG_ADDR_FSK_MODDFH               0x9a1 // 8bit
+#define REG_ADDR_FSK_MODDFL               0x9a2 // 8bit
+#define REG_ADDR_RFFREQ                   0x9a3 // 24bit
+
+#define REG_ADDR_PKTCTRL0                 0x9c0 // 8bit
+#define REG_ADDR_PKTCTRL1                 0x9c1 // 8bit
+#define REG_ADDR_PKT_TX_HEADER            0x9c2 // 8bit
+#define REG_ADDR_PAYLOAD_LEN              0x9c3 // 8bit
+#define REG_ADDR_PKT_BITSTREAM_CTRL       0x9c4 // 8bit
+#define REG_ADDR_FLORA_PREAMBLE_HI        0x9ca // 8bit   contains data rate
+#define REG_ADDR_PKT_SYNC_ADRS_CTRL       0x9cd // 8bit
+#define REG_ADDR_PKT_SYNC_ADRS_1          0x9ce // 40bit / 5bytes
+#define REG_ADDR_PKT_SYNC_ADRS_2          0x9d2 // 40bit / 5bytes
+#define REG_ADDR_PKT_SYNC_ADRS_3          0x9d8 // 40bit / 5bytes
+
+#define REG_ADDR_FLRC_SYNCWORDCTRL       0x98b // 5bit
+#define REG_ADDR_FLRC_IRQSTATUS          0x990 // 3bit
+
+#define REG_ADDR_PA_PWR_CTRL              0xa53 // 8bit
+/***************************************************************/
+#define PLL_STEP_HZ        198.364257812       // 52MHz / 2^18
+#define PLL_STEP_MHZ       0.000198364257812   // 52 / 2^18
+
+#define RX_CONTINUOUS_TIMEOUT   0xffff  // receive forever
+#define RX_SINGLE_TIMEOUT       0x0000  // receive until packet received
+
+#define PACKET_TYPE_GFSK     0
+#define PACKET_TYPE_LORA     1
+#define PACKET_TYPE_RANGING  2
+#define PACKET_TYPE_FLRC     3
+#define PACKET_TYPE_BLE      4
+
+
+#define RADIO_PACKET_FIXED_LENGTH           0x00
+#define RADIO_PACKET_VARIABLE_LENGTH        0x20
+
+// birate & bandwidth modParam1:
+#define GFSK_BLE_BR_2_000_BW_2_4    0x04 // Mbps:2      bw:2.4MHz        0000 0100
+#define GFSK_BLE_BR_1_600_BW_2_4    0x28 // Mbps:1.6    bw:2.4MHz        0010 1000
+#define GFSK_BLE_BR_1_000_BW_2_4    0x4C // Mbps:1      bw:2.4MHz        0100 1100
+#define GFSK_BLE_BR_1_000_BW_1_2    0x45 // Mbps:1      bw:1.2MHz        0100 0101
+#define GFSK_BLE_BR_0_800_BW_2_4    0x70 // Mbps:0.8    bw:2.4MHz        0111 0000
+#define GFSK_BLE_BR_0_800_BW_1_2    0x69 // Mbps:0.8    bw:1.2MHz        0110 1001
+#define GFSK_BLE_BR_0_500_BW_1_2    0x8D // Mbps:0.5    bw:1.2MHz        1000 1101
+#define GFSK_BLE_BR_0_500_BW_0_6    0x86 // Mbps:0.5    bw:0.6MHz        1000 0110
+#define GFSK_BLE_BR_0_400_BW_1_2    0xB1 // Mbps:0.4    bw:1.2MHz        1011 0001
+#define GFSK_BLE_BR_0_400_BW_0_6    0xAA // Mbps:0.4    bw:0.6MHz        1010 1010
+#define GFSK_BLE_BR_0_250_BW_0_6    0xCE // Mbps:0.25   bw:0.6MHz        1100 1110
+#define GFSK_BLE_BR_0_250_BW_0_3    0xC7 // Mbps:0.25   bw:0.3MHz        1100 0111
+#define GFSK_BLE_BR_0_125_BW_0_3    0xEF // Mbps:0.125  bw:0.3MHz        1110 1111
+
+// modulationIndex modParam2
+#define MOD_IND_0_35   0x00 // 0.35
+#define MOD_IND_0_5    0x01 // 0.5
+#define MOD_IND_0_75   0x02 // 0.75
+#define MOD_IND_1_00   0x03 // 1
+#define MOD_IND_1_25   0x04 // 1.25
+#define MOD_IND_1_50   0x05 // 1.5
+#define MOD_IND_1_75   0x06 // 1.75
+#define MOD_IND_2_00   0x07 // 2
+#define MOD_IND_2_25   0x08 // 2.25
+#define MOD_IND_2_50   0x09 // 2.5
+#define MOD_IND_2_75   0x0A // 2.75
+#define MOD_IND_3_00   0x0B // 3
+#define MOD_IND_3_25   0x0C // 3.25
+#define MOD_IND_3_50   0x0D // 3.5
+#define MOD_IND_3_75   0x0E // 3.75
+#define MOD_IND_4_00   0x0F // 4
+
+// modulationShaping modParam3:
+#define BT_OFF    0x00 // No filtering
+#define BT_1_0    0x10 // BT1
+#define BT_0_5    0x20 // BT0.5
+
+// packetParam6: 
+#define RADIO_CRC_OFF        0x00 // CRC off
+#define RADIO_CRC_1_BYTES    0x10 // CRC field used 1 byte
+#define RADIO_CRC_2_BYTES    0x20 // CRC field uses 2 bytes
+#define RADIO_CRC_3_BYTES    0x30 // ??? CRC field uses 3 bytes FLRC ????
+
+// GFSK packetParam7:
+#define WHITENING_ENABLE    0x00
+#define WHITENING_DISABLE   0x08
+
+// LoRa spreadingFactor modParam1:
+#define LORA_SF_5    0x50
+#define LORA_SF_6    0x60
+#define LORA_SF_7    0x70
+#define LORA_SF_8    0x80
+#define LORA_SF_9    0x90
+#define LORA_SF_10   0xA0
+#define LORA_SF_11   0xB0
+#define LORA_SF_12   0xC0
+
+// LoRa modParam2
+#define LORA_BW_1600    0x0A // 1625.0KHz
+#define LORA_BW_800     0x18 // 812.5KHz
+#define LORA_BW_400     0x26 // 406.25KHz
+#define LORA_BW_200     0x34 // 203.125KHz
+
+// LoRa modParam3
+#define LORA_CR_4_5      0x01 // 4/5
+#define LORA_CR_4_6      0x02 // 4/6
+#define LORA_CR_4_7      0x03 // 4/7
+#define LORA_CR_4_8      0x04 // 4/8
+#define LORA_CR_LI_4_5   0x05 // 4/5*
+#define LORA_CR_LI_4_6   0x06 // 4/6*
+#define LORA_CR_LI_4_7   0x07 // 4/8*
+
+// LoRa packetParam2:
+#define EXPLICIT_HEADER   0x00  // var length
+#define IMPLICIT_HEADER   0x80  // fixed Length
+
+// LoRa packetParam4:
+#define LORA_CRC_ENABLE    0x20
+#define LORA_CRC_DISABLE   0x00
+
+// LoRa packetParam5
+#define LORA_IQ_STD        0x40 // IQ as defined
+#define LORA_IQ_INVERTED   0x00 // IQ swapped
+
+// transmitter power ramping
+#define RADIO_RAMP_02_US   0x00 // 2 microseconds
+#define RADIO_RAMP_04_US   0x20 // 4 microseconds
+#define RADIO_RAMP_06_US   0x40 // 6 microseconds
+#define RADIO_RAMP_08_US   0x60 // 8 microseconds
+#define RADIO_RAMP_10_US   0x80 // 10 microseconds
+#define RADIO_RAMP_12_US   0xA0 // 12 microseconds
+#define RADIO_RAMP_16_US   0xC0 // 16 microseconds
+#define RADIO_RAMP_20_US   0xE0 // 20 microseconds
+
+// BLE packetParam1 
+#define BLE_PAYLOAD_LENGTH_MAX_31_BYTES    0x00 // maxlen:31    Bluetooth® 4.1 and above
+#define BLE_PAYLOAD_LENGTH_MAX_37_BYTES    0x20 // maxlen:37    Bluetooth® 4.1 and above
+#define BLE_TX_TEST_MODE                   0x40 // maxlen:63    Bluetooth® 4.1 and above
+#define BLE_PAYLOAD_LENGTH_MAX_255_BYTES   0x80 // maxlen:255   Bluetooth® 4.2 and above
+
+// BLE packetParam2
+#define BLE_CRC_OFF     0x00 // No CRC No
+#define BLE_CRC_3B      0x10 // CRC field used 3bytes Yes
+
+// BLE packetParam3     ignored in BLE_TX_TEST_MODE 
+#define BLE_PRBS_9          0x00// P7(x) = x9+ x5+ 1   PRBS9 sequence ‘1111111110000011110 1....’ (in transmission order)
+#define BLE_EYELONG_1_0     0x04 // Repeated ‘11110000’ (in transmission order) sequence
+#define BLE_EYESHORT_1_0   0x08 // Repeated ‘10101010’ (in transmission order) sequence
+#define BLE_PRBS_15         0x0C // Pseudo Random Binary Sequence based on 15th degree polynomial P15(x) = x15+ x14+ x13 + x12+ x2+ x + 1
+#define BLE_ALL_1          0x10 // Repeated ‘11111111’ (in transmission order) sequence
+#define BLE_ALL_0          0x14 // Repeated ‘11111111’ (in transmission order) sequence
+#define BLE_EYELONG_0_1    0x18 // Repeated ‘00001111’ (in transmission order) sequence
+#define BLE_EYESHORT_0_1   0x1C // Repeated ‘01010101’ (in transmission order) sequence
+
+// packetParam1 
+#define PREAMBLE_LENGTH_4_BITS      0x00 // 4bits
+#define PREAMBLE_LENGTH_8_BITS      0x10 // 8bits
+#define PREAMBLE_LENGTH_12_BITS     0x20 // 12bits
+#define PREAMBLE_LENGTH_16_BITS     0x30 // 16bits
+#define PREAMBLE_LENGTH_20_BITS     0x40 // 20bits
+#define PREAMBLE_LENGTH_24_BITS     0x50 // 24bits
+#define PREAMBLE_LENGTH_28_BITS     0x60 // 28bits
+#define PREAMBLE_LENGTH_32_BITS     0x70 // 32bits
+
+// FLRC pktParam2
+#define FLRC_SYNC_NOSYNC          0x00  // 21 bits preamble
+#define FLRC_SYNC_WORD_LEN_P32S   0x04  // 21 bits preamble + 32bit syncword
+
+// FLRC modParam1
+#define FLRC_BR_1_300_BW_1_2        0x45 // 1.3Mb/s      1.2MHz
+#define FLRC_BR_1_000_BW_1_2        0x69 // 1.04Mb/s     1.2MHz
+#define FLRC_BR_0_650_BW_0_6        0x86 // 0.65Mb/s     0.6MHz
+#define FLRC_BR_0_520_BW_0_6        0xAA // 0.52Mb/s     0.6MHz
+#define FLRC_BR_0_325_BW_0_3        0xC7 // 0.325Mb/s    0.3MHz
+#define FLRC_BR_0_260_BW_0_3        0xEB // 0.26Mb/s     0.3MHz
+
+// FLRC modParam2
+#define FLRC_CR_1_2     0x00
+#define FLRC_CR_3_4     0x02
+#define FLRC_CR_1_0     0x04
+
+typedef enum {
+    STDBY_RC = 0,  // Device running on RC 13MHz, set STDBY_RC mode
+    STDBY_XOSC     // Device running on XTAL 52MHz, set STDBY_XOSC mode
+} stby_t;
+
+typedef union {
+    struct {
+        uint8_t PreambleLength;   // param1
+        uint8_t HeaderType;       // param2
+        uint8_t PayloadLength;    // param3
+        uint8_t crc;              // param4
+        uint8_t InvertIQ;         // param5
+        uint8_t unused[2];
+    } lora;
+    struct {
+        uint8_t PreambleLength; // param1
+        uint8_t SyncWordLength; // param2      bytes
+        uint8_t SyncWordMatch;  // param3
+        uint8_t HeaderType;     // param4
+        uint8_t PayloadLength;  // param5
+        uint8_t CRCLength;      // param6
+        uint8_t Whitening;      // param7
+    } gfskFLRC;
+    struct {
+        uint8_t ConnectionState; // param1
+        uint8_t CrcLength;       // param2
+        uint8_t BleTestPayload;  // param3
+        uint8_t Whitening;       // param4
+        uint8_t unused[3];
+    } ble;
+    uint8_t buf[7];
+} PacketParams_t;
+
+//TODO -- uint8_t LowDatarateOptimize; // param4
+typedef union {
+    struct {
+        uint8_t spreadingFactor; // param1
+        uint8_t bandwidth; // param2
+        uint8_t codingRate; // param3
+    } lora;
+    struct {
+        uint8_t bitrateBandwidth;  // param1
+        uint8_t ModulationIndex;  // param1
+        uint8_t ModulationShaping;  // param3
+    } gfskBle;
+    struct {
+        uint8_t bitrateBandwidth;  // param1
+        uint8_t CodingRate;  // param1
+        uint8_t ModulationShaping;  // param3
+    } flrc;
+    uint8_t buf[3];
+} ModulationParams_t;
+
+typedef union {
+    struct {    // 
+        uint16_t TxDone           : 1;    // 0
+        uint16_t RxDone           : 1;    // 1
+        uint16_t SyncWordValid: 1;    // 2
+        uint16_t SyncWordError: 1;    // 3
+        uint16_t HeaderValid: 1;    // 4
+        uint16_t HeaderError: 1;    // 5
+        uint16_t CrcError: 1;    // 6
+        uint16_t RangingSlaveResponseDone: 1;    // 7
+        uint16_t RangingSlaveRequestDiscard: 1;    // 8
+        uint16_t RangingMasterResultValid: 1;    // 9
+        uint16_t RangingMasterTimeout: 1;    // 10
+        uint16_t RangingMasterRequestValid: 1;    // 11
+        uint16_t CadDone: 1;    // 12
+        uint16_t CadDetected: 1;    // 13
+        uint16_t RxTxTimeout: 1;    // 14
+        uint16_t PreambleDetected: 1;    // 15
+    } bits;
+    uint16_t word;
+} IrqFlags_t;
+
+typedef union {
+    struct {    // 
+        uint8_t busy       : 1;    // 0
+        uint8_t reserved   : 1;    // 1
+        uint8_t cmdStatus  : 3;    // 2,3,4
+        uint8_t chipMode   : 3;    // 5,6,7
+    } bits;
+    uint8_t octet;
+} status_t;
+
+typedef enum {
+    CHIPMODE_NONE = 0,
+    CHIPMODE_RX,
+    CHIPMODE_TX
+} chipMode_e;
+
+typedef union {
+    struct {
+        uint8_t dataRAM         : 1;    // 0
+        uint8_t dataBuffer      : 1;    // 1
+        uint8_t instructionRAM  : 1;    // 2
+    } retentionBits;
+    uint8_t octet;
+} sleepConfig_t;
+
+
+typedef union {
+    struct {
+        status_t status;
+        uint8_t rfu;
+        uint8_t rssiSync;
+        struct {
+            uint8_t pktCtrlBusy    : 1;    // 0
+            uint8_t packetReceived : 1;    // 1
+            uint8_t headerReceived : 1;    // 2
+            uint8_t AbortErr       : 1;    // 3
+            uint8_t CrcError       : 1;    // 4
+            uint8_t LengthError    : 1;    // 5
+            uint8_t SyncError      : 1;    // 6
+            uint8_t reserved       : 1;    // 7
+        } errors;
+        struct {
+            uint8_t pktSent : 1;    // 0
+            uint8_t res41   : 4;    // 1,2,3,4
+            uint8_t rxNoAck : 1;    // 5
+            uint8_t res67   : 1;    // 6,7
+        } pkt_status;
+        struct {
+            uint8_t syncAddrsCode : 3;    // 0,1,2
+            uint8_t reserved      : 5;    // 3,4,5,6,7
+        } sync;
+    } ble_gfsk_flrc;
+    struct {
+        status_t status;
+        uint8_t rssiSync;
+        uint8_t snr;
+        uint8_t reserved[4];
+    } lora;
+    uint8_t buf[6];
+} pktStatus_t;
+
+/**********************************************************/
+
+typedef union {
+    struct {
+        uint8_t irq0     : 2; // 0,1
+        uint8_t irq1     : 2; // 2,3
+        uint8_t alt_func : 4; // 4,5,6,7
+    } bits;
+    uint8_t octet;
+} RegAfIrq_t; // 0x053
+
+typedef union {
+    struct {
+        uint8_t dig_fe_en : 1; // 0
+        uint8_t zero_if   : 1; // 1
+        uint8_t if_sel    : 1; // 2
+        uint8_t lora_mode : 1; // 3
+        uint8_t res       : 4; // 4,5,6,7
+    } bits;
+    uint8_t octet;
+} RegCfg_t; // 0x880
+
+typedef union {
+    struct {
+        uint8_t bw            : 3; // 0,1,2
+        uint8_t res3          : 1; // 3
+        uint8_t interp_factor : 1; // 4,5,6
+        uint8_t res7          : 1; // 7
+    } bits;
+    uint8_t octet;
+} RegRxBw_t; // 0x881
+
+typedef union {
+    struct {
+        uint8_t DccBw                : 2; // 0,1
+        uint8_t DccInit              : 1; // 2
+        uint8_t IgnoreAutoDccRestart : 1; // 3
+        uint8_t DccForce             : 1; // 4
+        uint8_t DccBypass            : 1; // 5
+        uint8_t DccFreeze            : 1; // 6
+        uint8_t res7                 : 1; // 7
+    } bits;
+    uint8_t octet;
+} RegDcc_t; // 0x882
+
+typedef union {
+    struct {
+        uint8_t SyncAdrsIrqStatus : 1; // 0
+        uint8_t PreambleIrqStatus : 1; // 1
+        uint8_t dtb_pa2sel_sel    : 2; // 2,3
+        uint8_t db_out_sel        : 1; // 4
+        uint8_t reserved          : 3; // 5,6,7
+    } bits;
+    uint8_t octet;
+} GfskDemodStatus_t; // 0x8cb
+
+typedef union {
+    struct {
+        uint8_t cont_rx : 1; // 0
+        uint8_t modem_bw : 3; // 1,2,3
+        uint8_t modem_sf : 4; // 4,5,6,7
+    } bits;
+    uint8_t octet;
+} LoRaPktPar0_t; // 0x902
+
+typedef union {
+    struct {
+        uint8_t coding_rate     : 3; // 0,1,2
+        uint8_t ppm_offset      : 2; // 3,4
+        uint8_t tx_mode         : 1; // 5
+        uint8_t rxinvert_iq     : 1; // 6
+        uint8_t implicit_header : 1; // 7
+    } bits;
+    uint8_t octet;
+} LoRaPktPar1_t; // 0x903
+
+typedef union {
+    struct {
+        uint8_t cadrxtx             : 2; // 0,1
+        uint8_t sd_en               : 1; // 2
+        uint8_t modem_en            : 1; // 3
+        uint8_t lora_register_clear : 1; // 4
+        uint8_t crc_en              : 1; // 5
+        uint8_t fine_sync_en        : 1; // 6
+        uint8_t sd_force_tx_mode    : 1; // 7
+    } bits;
+    uint8_t octet;
+} LoRaLrCtl_t; // 0x904
+
+typedef union {
+    struct {
+        uint8_t preamble_symb1_nb : 4; // 0,1,2,3
+        uint8_t preamble_symb_nb_exp : 4; // 4,5,6,7
+    } bits;
+    uint8_t octet;
+} LoRaPreambleReg_t; // 0x93f
+
+typedef union {
+    struct {
+        uint8_t rx_state      : 4; // 0,1,2,3
+        uint8_t tx_state      : 3; // 4,5,6
+        uint8_t tx_ranging_on : 1; // 7
+    } bits;
+    uint8_t octet;
+} LoRaModemStat_t; // 0x95c
+
+typedef union {
+    struct {
+        uint8_t mod_on   : 1; // 0
+        uint8_t sd_on    : 1; // 1
+        uint8_t mod_mode : 1; // 2        0=gfsk  1=flora
+        uint8_t tx_mode  : 1; // 3
+        uint8_t gf_bt    : 2; // 4,5      0=noFilter  1=BT1.0  2=BT0.5   3=BT0.3
+        uint8_t rxtxn    : 1; // 6        0=tx   1=rx
+        uint8_t cal_en   : 1; // 7
+    } bits;
+    uint8_t octet;
+} FskCfg_t; // 0x9a0
+
+typedef union {
+    struct {
+        uint8_t freqDev      : 5; // 0,1,2,3,4
+        uint8_t sd_in_lsb    : 1; // 5
+        uint8_t disable_dclk : 1; // 7
+    } bits;
+    uint8_t octet;
+} FskModDfH_t; // 0x9a1
+
+typedef union {
+    struct {
+        uint8_t pkt_ctrl_on          : 1; // 0
+        uint8_t pkt_start_p          : 1; // 1    0=idle   1=busy
+        uint8_t pkt_abort_p          : 1; // 2
+        uint8_t pkt_software_clear_p : 1; // 3    software reset pulse
+        uint8_t pkt_rx_ntx           : 1; // 4    0=tx   1=rx
+        uint8_t pkt_len_format       : 1; // 5    0=fixed   1=dynamic
+        uint8_t pkt_protocol         : 2; // 6,7  1=flora  2=ble  3=generic
+    } bits;
+    uint8_t octet;
+} PktCtrl0_t; // 0x9c0
+
+typedef union {
+    struct {
+        uint8_t infinite_preamble : 1; // 0
+        uint8_t sync_adrs_len     : 3; // 1,2,3   bytes = sync_adrs_len + 1
+        uint8_t preamble_len      : 3; // 4,5,6   bits = (preamble_len*4) + 4
+        uint8_t preamble_det_on   : 1; // 7
+    } gfsk;
+    struct {
+        uint8_t reserved         : 1; // 0
+        uint8_t sync_adrs_len    : 2; // 1,2     0=preamble only   1=preamble+16bitSync    2=preamble+32bitSync
+        uint8_t reserved3        : 1; // 3
+        uint8_t agc_preamble_len : 3; // 4,5,6
+        uint8_t reserved7        : 1; // 7
+    } flrc;
+    uint8_t octet;
+} PktCtrl1_t; // 0x9c1
+
+typedef union {
+    struct {
+        uint8_t payload_len_N : 1; // 0
+        uint8_t tx_reserved : 4; // 1,2,3,4
+        uint8_t tx_no_ack : 1; // 5
+        uint8_t tx_pkt_type : 2; // 6,7   defines packet type field in header
+    } bits;
+    struct {
+        uint8_t infinite_rxtx  : 1; // 0
+        uint8_t tx_payload_src : 1; // 1        0=fifo   1=prbs
+        uint8_t tx_type        : 3; // 2,3,4       payload for BLE tx test
+        uint8_t cs_type        : 3; // 5,6,7       connection state
+    } ble;
+    uint8_t octet;
+} PktTxHeader_t; // 0x9c2
+
+typedef union {
+    struct {
+        uint8_t crc_in_fifo       : 1; // 0     1=received CRC written to FIFO at end
+        uint8_t flora_coding_rate : 2; // 1,2
+        uint8_t whit_disable      : 1; // 3
+        uint8_t crc_mode          : 2; // 4,5   0=nocrc   1=1byteCRC  2=2byteCRC  3=reserved
+        uint8_t rssi_mode         : 2; // 6,7   enables rssi read mode of received packets 0=none  1=syncReg  2=avgReg  3=bothRegs
+    } bits;
+    uint8_t octet;
+} PktBitStreamCtrl_t; // 0x9c4
+
+typedef union {
+    struct {
+        uint8_t flora_preamble_20_16 : 5; // 0,1,2,3,4
+        uint8_t data_rate            : 3; // 5,6,7
+    } bits;
+    uint8_t octet;
+} FloraPreambleHi_t; // 0x9ca
+
+typedef union {
+    struct {
+        uint8_t sync_adrs_bit_detections : 2; // 0,1   last bits matching   0=none   1=2bits   2=4bits   3=8bits
+        uint8_t reserved                 : 2; // 2,3
+        uint8_t sync_addr_mask           : 3; // 4,5,6
+        uint8_t cont_rx                  : 1; // 7
+    } ble;
+    struct {
+        uint8_t sync_adrs_errors         : 4; // 0,12,3   how many bit errors are tolerated in sync word
+        uint8_t sync_addr_mask           : 3; // 4,5,6
+        uint8_t cont_rx                  : 1; // 7
+    } gfskflrc;
+    uint8_t octet;
+} PktSyncAdrs_t; // 0x9cd
+
+typedef union {
+    struct {
+        uint8_t tolerated_errors : 4; // 0,1,2,3    for sync word
+        uint8_t valid_status     : 1; // 4         0x98c-98f is valid
+        uint8_t reserved         : 3; // 5,6,7
+    } bits;
+    uint8_t octet;
+} FlrcSyncWordCtrl_t; // 0x98b 
+
+typedef union {
+    struct {
+        uint8_t sync_word_irq : 1; // 0
+        uint8_t preamble_irq  : 1; // 1
+        uint8_t stop_radio    : 1; // 3
+        uint8_t reserved      : 1; // 4,5,6,7
+    } bits;
+    uint8_t octet;
+} FlrcIrqStatus_t; // 0x990 
+
+typedef union {
+    struct {
+        uint8_t tx_pwr    : 5; // 0,1,2,3,4
+        uint8_t ramp_time : 3; // 5,6,7
+    } bits;
+    uint8_t octet;
+} PaPwrCtrl_t; // 0xa53 
+
+class SX128x {
+    public:
+        SX128x(SPI&, PinName nss, PinName busy, PinName diox);
+
+        static Callback<void()> diox_topHalf;    // low latency ISR context
+        Callback<void()> txDone; // user context
+        void (*rxDone)(uint8_t size, const pktStatus_t*); // user context
+        Callback<void()> chipModeChange; // read chipMode_e chipMode
+        void (*timeout)(bool tx); // user context
+
+        //! RF transmit packet buffer
+        uint8_t tx_buf[256];    // lora fifo size
+        
+        //! RF receive packet buffer
+        uint8_t rx_buf[256];    // lora fifo size
+
+        void service(void);
+        uint8_t xfer(uint8_t opcode, uint8_t writeLen, uint8_t readLen, uint8_t* buf);
+        void start_tx(uint8_t pktLen, float timeout_ms);  // tx_buf must be filled prior to calling
+        void start_rx(float timeout_ms);   // timeout given in milliseconds, -1 = forever
+        void hw_reset(PinName nrst);
+        void set_tx_dbm(int8_t dbm);
+        void setMHz(float);
+        float getMHz(void);
+        void setStandby(stby_t);
+        void setSleep(bool warmStart);
+        void setFS(void);
+        void writeReg(uint16_t addr, uint32_t data, uint8_t len);
+        uint32_t readReg(uint16_t addr, uint8_t len);
+        void setPacketType(uint8_t);
+        uint8_t getPacketType(void);
+        void ReadBuffer(uint8_t size, uint8_t offset);
+        uint64_t getSyncAddr(uint8_t num);
+        void setSyncAddr(uint8_t num, uint64_t sa);
+        void setRegulator(uint8_t);
+        void setBufferBase(uint8_t txAddr, uint8_t rxAddr);
+
+        chipMode_e chipMode;
+        uint8_t periodBase;
+        static const float timeOutStep[4];
+
+    private:
+        SPI& spi;
+        DigitalOut nss;
+        DigitalIn busy;
+        InterruptIn diox;
+        static void dioxisr(void);
+        bool sleeping;
+};
+
+#endif /* SX126x_H */
+