static bool getBind1(uint8_t *packet)
{
    // len|bind |tx
    // id|03|01|idx|h0|h1|h2|h3|h4|00|00|00|00|00|00|00|00|00|00|00|00|00|00|00|CHK1|CHK2|RSSI|LQI/CRC|
    // Start by getting bind packet 0 and the txid
    if (cc2500getGdo()) {
        uint8_t ccLen = cc2500ReadReg(CC2500_3B_RXBYTES | CC2500_READ_BURST) & 0x7F;
        if (ccLen) {
            cc2500ReadFifo(packet, ccLen);
            if (packet[ccLen - 1] & 0x80) {
                if (packet[2] == 0x01) {
                    if (packet[5] == 0x00) {
                        rxCc2500SpiConfigMutable()->bindTxId[0] = packet[3];
                        rxCc2500SpiConfigMutable()->bindTxId[1] = packet[4];
                        for (uint8_t n = 0; n < 5; n++) {
                            rxCc2500SpiConfigMutable()->bindHopData[packet[5] + n] =
                                packet[6 + n];
                        }

                        rxCc2500SpiConfigMutable()->rxNum = packet[12];

                        return true;
                    }
                }
            }
        }
    }

    return false;
}
static bool tuneRx(uint8_t *packet)
{
    if (bindOffset >= 126) {
        bindOffset = -126;
    }
    if ((millis() - timeTunedMs) > 50) {
        timeTunedMs = millis();
        bindOffset += 5;
        cc2500WriteReg(CC2500_0C_FSCTRL0, (uint8_t)bindOffset);
    }
    if (cc2500getGdo()) {
        uint8_t ccLen = cc2500ReadReg(CC2500_3B_RXBYTES | CC2500_READ_BURST) & 0x7F;
        if (ccLen) {
            cc2500ReadFifo(packet, ccLen);
            if (packet[ccLen - 1] & 0x80) {
                if (packet[2] == 0x01) {
                    uint8_t Lqi = packet[ccLen - 1] & 0x7F;
                    // higher lqi represent better link quality
                    if (Lqi > 50) {
                        rxCc2500SpiConfigMutable()->bindOffset = bindOffset;
                        return true;
                    }
                }
            }
        }
    }

    return false;
}
static bool getBind2(uint8_t *packet)
{
    if (bindIdx <= 120) {
        if (cc2500getGdo()) {
            uint8_t ccLen = cc2500ReadReg(CC2500_3B_RXBYTES | CC2500_READ_BURST) & 0x7F;
            if (ccLen) {
                cc2500ReadFifo(packet, ccLen);
                if (packet[ccLen - 1] & 0x80) {
                    if (packet[2] == 0x01) {
                        if ((packet[3] == rxCc2500SpiConfig()->bindTxId[0]) &&
                            (packet[4] == rxCc2500SpiConfig()->bindTxId[1])) {
                            if (packet[5] == bindIdx) {
#if defined(DJTS)
                                if (packet[5] == 0x2D) {
                                    for (uint8_t i = 0; i < 2; i++) {
                                        rxCc2500SpiConfigMutable()->bindHopData[packet[5] + i] = packet[6 + i];
                                    }
                                    listLength = 47;

                                    return true;
                                }
#endif

                                for (uint8_t n = 0; n < 5; n++) {
                                    if (packet[6 + n] == packet[ccLen - 3] || (packet[6 + n] == 0)) {
                                        if (bindIdx >= 0x2D) {
                                            listLength = packet[5] + n;

                                            return true;
                                        }
                                    }

                                    rxCc2500SpiConfigMutable()->bindHopData[packet[5] + n] = packet[6 + n];
                                }

                                bindIdx = bindIdx + 5;

                                return false;
                            }
                        }
                    }
                }
            }
        }

        return false;
    } else {
        return true;
    }
}
rx_spi_received_e frSkyDHandlePacket(uint8_t * const packet, uint8_t * const protocolState)
{
    static timeUs_t lastPacketReceivedTime = 0;
    static timeUs_t telemetryTimeUs;

    rx_spi_received_e ret = RX_SPI_RECEIVED_NONE;

    const timeUs_t currentPacketReceivedTime = micros();

    switch (*protocolState) {
    case STATE_STARTING:
        listLength = 47;
        initialiseData(0);
        *protocolState = STATE_UPDATE;
        nextChannel(1);
        cc2500Strobe(CC2500_SRX);

        break;
    case STATE_UPDATE:
        lastPacketReceivedTime = currentPacketReceivedTime;
        *protocolState = STATE_DATA;

        if (rxSpiCheckBindRequested(false)) {
            lastPacketReceivedTime = 0;
            timeoutUs = 50;
            missingPackets = 0;

            *protocolState = STATE_INIT;

            break;
        }
        FALLTHROUGH; //!!TODO -check this fall through is correct
    // here FS code could be
    case STATE_DATA:
        if (cc2500getGdo()) {
            uint8_t ccLen = cc2500ReadReg(CC2500_3B_RXBYTES | CC2500_READ_BURST) & 0x7F;
            if (ccLen >= 20) {
                cc2500ReadFifo(packet, 20);
                if (packet[19] & 0x80) {
                    missingPackets = 0;
                    timeoutUs = 1;
                    if (packet[0] == 0x11) {
                        if ((packet[1] == rxFrSkySpiConfig()->bindTxId[0]) &&
                            (packet[2] == rxFrSkySpiConfig()->bindTxId[1])) {
                            rxSpiLedOn();
                            nextChannel(1);
                            cc2500setRssiDbm(packet[18]);
#if defined(USE_RX_FRSKY_SPI_TELEMETRY)
                            if ((packet[3] % 4) == 2) {
                                telemetryTimeUs = micros();
                                buildTelemetryFrame(packet);
                                *protocolState = STATE_TELEMETRY;
                            } else
#endif
                            {
                                cc2500Strobe(CC2500_SRX);
                                *protocolState = STATE_UPDATE;
                            }
                            ret = RX_SPI_RECEIVED_DATA;
                            lastPacketReceivedTime = currentPacketReceivedTime;
                        }
                    }
                }
            }
        }

        if (cmpTimeUs(currentPacketReceivedTime, lastPacketReceivedTime) > (timeoutUs * SYNC_DELAY_MAX)) {
#if defined(USE_RX_CC2500_SPI_PA_LNA)
            cc2500TxDisable();
#endif
            if (timeoutUs == 1) {
#if defined(USE_RX_CC2500_SPI_PA_LNA) && defined(USE_RX_CC2500_SPI_DIVERSITY) // SE4311 chip
                if (missingPackets >= 2) {
                    cc2500switchAntennae();
                }
#endif

                if (missingPackets > MAX_MISSING_PKT) {
                    timeoutUs = 50;

                    setRssiDirect(0, RSSI_SOURCE_RX_PROTOCOL);
                }

                missingPackets++;
                nextChannel(1);
            } else {
                rxSpiLedToggle();

                setRssi(0, RSSI_SOURCE_RX_PROTOCOL);
                nextChannel(13);
            }

            cc2500Strobe(CC2500_SRX);
            *protocolState = STATE_UPDATE;
        }
        break;
#if defined(USE_RX_FRSKY_SPI_TELEMETRY)
    case STATE_TELEMETRY:
        if (cmpTimeUs(micros(), telemetryTimeUs) >= 1380) {
            cc2500Strobe(CC2500_SIDLE);
            cc2500SetPower(6);
            cc2500Strobe(CC2500_SFRX);
#if defined(USE_RX_CC2500_SPI_PA_LNA)
            cc2500TxEnable();
#endif
            cc2500Strobe(CC2500_SIDLE);
            cc2500WriteFifo(frame, frame[0] + 1);
            *protocolState = STATE_DATA;
            ret = RX_SPI_RECEIVED_DATA;
            lastPacketReceivedTime = currentPacketReceivedTime;
        }

        break;

#endif
    }

    return ret;
}
static void initialise() {
    cc2500Reset();
    cc2500WriteReg(CC2500_02_IOCFG0,   0x01);
    cc2500WriteReg(CC2500_18_MCSM0,    0x18);
    cc2500WriteReg(CC2500_07_PKTCTRL1, 0x04);
    cc2500WriteReg(CC2500_3E_PATABLE,  0xFF);
    cc2500WriteReg(CC2500_0C_FSCTRL0,  0x00);
    cc2500WriteReg(CC2500_0D_FREQ2,    0x5C);
    cc2500WriteReg(CC2500_13_MDMCFG1,  0x23);
    cc2500WriteReg(CC2500_14_MDMCFG0,  0x7A);
    cc2500WriteReg(CC2500_19_FOCCFG,   0x16);
    cc2500WriteReg(CC2500_1A_BSCFG,    0x6C);
    cc2500WriteReg(CC2500_1B_AGCCTRL2, 0x03);
    cc2500WriteReg(CC2500_1C_AGCCTRL1, 0x40);
    cc2500WriteReg(CC2500_1D_AGCCTRL0, 0x91);
    cc2500WriteReg(CC2500_21_FREND1,   0x56);
    cc2500WriteReg(CC2500_22_FREND0,   0x10);
    cc2500WriteReg(CC2500_23_FSCAL3,   0xA9);
    cc2500WriteReg(CC2500_24_FSCAL2,   0x0A);
    cc2500WriteReg(CC2500_25_FSCAL1,   0x00);
    cc2500WriteReg(CC2500_26_FSCAL0,   0x11);
    cc2500WriteReg(CC2500_29_FSTEST,   0x59);
    cc2500WriteReg(CC2500_2C_TEST2,    0x88);
    cc2500WriteReg(CC2500_2D_TEST1,    0x31);
    cc2500WriteReg(CC2500_2E_TEST0,    0x0B);
    cc2500WriteReg(CC2500_03_FIFOTHR,  0x07);
    cc2500WriteReg(CC2500_09_ADDR,     0x00);

    switch (spiProtocol) {
    case RX_SPI_FRSKY_D:
        cc2500WriteReg(CC2500_17_MCSM1,    0x0C);
        cc2500WriteReg(CC2500_0E_FREQ1,    0x76);
        cc2500WriteReg(CC2500_0F_FREQ0,    0x27);
        cc2500WriteReg(CC2500_06_PKTLEN,   0x19);
        cc2500WriteReg(CC2500_08_PKTCTRL0, 0x05);
        cc2500WriteReg(CC2500_0B_FSCTRL1,  0x08);
        cc2500WriteReg(CC2500_10_MDMCFG4,  0xAA);
        cc2500WriteReg(CC2500_11_MDMCFG3,  0x39);
        cc2500WriteReg(CC2500_12_MDMCFG2,  0x11);
        cc2500WriteReg(CC2500_15_DEVIATN,  0x42);

        break;
    case RX_SPI_FRSKY_X:
        cc2500WriteReg(CC2500_17_MCSM1,    0x0C);
        cc2500WriteReg(CC2500_0E_FREQ1,    0x76);
        cc2500WriteReg(CC2500_0F_FREQ0,    0x27);
        cc2500WriteReg(CC2500_06_PKTLEN,   0x1E);
        cc2500WriteReg(CC2500_08_PKTCTRL0, 0x01);
        cc2500WriteReg(CC2500_0B_FSCTRL1,  0x0A);
        cc2500WriteReg(CC2500_10_MDMCFG4,  0x7B);
        cc2500WriteReg(CC2500_11_MDMCFG3,  0x61);
        cc2500WriteReg(CC2500_12_MDMCFG2,  0x13);
        cc2500WriteReg(CC2500_15_DEVIATN,  0x51);

        break;
    case RX_SPI_FRSKY_X_LBT:
        cc2500WriteReg(CC2500_17_MCSM1,    0x0E);
        cc2500WriteReg(CC2500_0E_FREQ1,    0x80);
        cc2500WriteReg(CC2500_0F_FREQ0,    0x00);
        cc2500WriteReg(CC2500_06_PKTLEN,   0x23);
        cc2500WriteReg(CC2500_08_PKTCTRL0, 0x01);
        cc2500WriteReg(CC2500_0B_FSCTRL1,  0x08);
        cc2500WriteReg(CC2500_10_MDMCFG4,  0x7B);
        cc2500WriteReg(CC2500_11_MDMCFG3,  0xF8);
        cc2500WriteReg(CC2500_12_MDMCFG2,  0x03);
        cc2500WriteReg(CC2500_15_DEVIATN,  0x53);

        break;
    default:

        break;
    }

    for(unsigned c = 0;c < 0xFF; c++)
    { //calibrate all channels
        cc2500Strobe(CC2500_SIDLE);
        cc2500WriteReg(CC2500_0A_CHANNR, c);
        cc2500Strobe(CC2500_SCAL);
        delayMicroseconds(900); //
        calData[c][0] = cc2500ReadReg(CC2500_23_FSCAL3);
        calData[c][1] = cc2500ReadReg(CC2500_24_FSCAL2);
        calData[c][2] = cc2500ReadReg(CC2500_25_FSCAL1);
    }
}