Example #1
0
void spirit1_write(ot_u8 addr, ot_u8 data) {
    ot_u8 cmd[3];
    cmd[0]  = 0;
    cmd[1]  = addr;
    cmd[2]  = data;
    spirit1_spibus_io(3, 0, cmd);
}
Example #2
0
ot_u8 spirit1_read(ot_u8 addr) {
    ot_u8 cmd[2];
    cmd[0]  = 1;
    cmd[1]  = addr;
    spirit1_spibus_io(2, 1, cmd);
    return spirit1.busrx[0];
}
Example #3
0
void spirit1_burstread(ot_u8 start_addr, ot_u8 length, ot_u8* data) {
    ot_u8 cmd[2];
    cmd[0]  = 1;
    cmd[1]  = start_addr;
    spirit1_spibus_io(2, length, (ot_u8*)cmd);
    memcpy(data, spirit1.busrx, length);
}
Example #4
0
void spirit1_set_txpwr(ot_u8* pwr_code) {
/// Sets the tx output power.
/// "pwr_code" is a value, 0-127, that is: eirp_code/2 - 40 = TX dBm
/// i.e. eirp_code=0 => -40 dBm, eirp_code=80 => 0 dBm, etc
    static const ot_u8 pa_lut[84] = {
          87, 0x57, 0x56, 0x55, 0x54, 0x53, 0x53, 0x52, 0x52, 0x50,     //-30 to -25.5
        0x4F, 0x4E, 0x4D, 0x4C, 0x4B, 0x4B, 0x4A, 0x49, 0x48, 0x47,     //-25 to -20.5
        0x46, 0x45, 0x44, 0x43, 0x42, 0x41, 0x40, 0x3F, 0x3E, 0x3C,     //-20 to -15.5
        0x3B, 0x3A, 0x39, 0x38, 0x37, 0x36, 0x34, 0x33, 0x32, 0x31,     //-15 to -10.5
        0x30, 0x2F, 0x2D, 0x2C, 0x2B, 0x2A, 0x29, 0x27,   42, 0x25,     //-10 to -5.5
        0x24, 0x23, 0x22, 0x20, 0x1F, 0x1E, 0x1D, 0x1C, 0x1B, 0x19,     //-5 to -0.5
          30, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0F,     // 0 to 4.5
        0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08, 0x07, 0x06, 0x05,     // 5 to 9.5
        0x04, 0x03,    1, 0x01                                          // 10 to 11.5
    };

    ot_u8   pa_table[10];
    ot_u8*  cursor;
    ot_int  step;
    ot_int  eirp_val;

    ///@todo autoscaling algorithm, and refresh value in *pwr_code
    // Autoscaling: Try to make RSSI at receiver be -90 < RX_RSSI < -80
    // The simple algorithm uses the last_rssi and last_linkloss values
    //if (*pwr_code & 0x80) {
    //}
    //else {
    //}

    // Not autoscaling: extract TX power directly from pwr_code
    eirp_val = *pwr_code;

    // Offset SPIRIT1 PA CFG to match DASH7 PA CFG, plus antenna losses
    // SPIRIT1: 0 --> -30 dBm, 83 --> 11.5 dBm, half-dBm steps
    // DASH7: 0 --> -40 dBm, 127 --> 23.5 dBm, half-dBm steps
    eirp_val += (-10*2) + (RF_HDB_ATTEN);

    // Adjust base power code in case it is out-of-range:
    // SPIRIT1 PA starts at -30, DASH7 pwr_code starts at -40.
    if (eirp_val < 0)       eirp_val = 0;
    else if (eirp_val > 83) eirp_val = 83;

    // Build PA RAMP using 8 steps of variable size.
    pa_table[0] = 0;
    pa_table[1] = RFREG(PAPOWER8);
    cursor      = &pa_table[2];
    step        = eirp_val >> 3;
    do {
        *cursor++   = pa_lut[eirp_val];
        eirp_val   -= step;
    } while (cursor != &pa_table[9]);


    // Write new PA Table to device
    spirit1_spibus_io(10, 0, pa_table);
}
Example #5
0
void em2_encode_data() {
    ot_int  fill;
    ot_int  load;
    ot_u8   save[2];
    ot_u8*  cmd;

    // Loop unrolling for FIFO loading
    load = (rfctl.txlimit - spirit1_txbytes());

    while (1) {
        fill = (load < em2.bytes) ? load : em2.bytes;
        if (fill <= 0) break;

        if (fill > 24) fill = 24;
        load       -= fill;
        em2.bytes  -= fill;

        if (txq.options.ubyte[UPPER] != 0) {
            crc_calc_nstream(fill);
#           if (M2_FEATURE(RSCODE))
            if (em2.lctl & 0x40) {
                em2_rs_encode(fill);
            }
#           endif
        }

        cmd     = txq.getcursor;
        save[0] = *(--cmd);
        *cmd    = 0xff;
        save[1] = *(--cmd);
        *cmd    = 0x00;

        txq.getcursor += fill;
        spirit1_spibus_io(fill+2, 0, cmd);
        *cmd++  = save[1];
        *cmd    = save[0];
    }

    /// dummy SPI access to complete fill
    //spirit1_read(RFREG(IRQ_STATUS0));
    *(ot_u16*)save  = PLATFORM_ENDIAN16_C(0x8000);
    spirit1_spibus_io(2, 0, save);
}
Example #6
0
void spirit1_wfe_aes() {
    // Kill any interrupts and activate the WFE event source (always pin 2)
    EXTI->IMR  &= (RFI_SOURCE2 | RFI_SOURCE1 | RFI_SOURCE0);
    EXTI->EMR  |= RFI_SOURCE2;

    // read-out all IRQ_STATUS bits to clear
    {   ot_u8 cmd[2];
        cmd[0]  = 1;
        cmd[1]  = RFREG(IRQ_STATUS3);
        spirit1_spibus_io(2, 4, (ot_u8*)cmd);
    }

    // write AES to IRQ MASK
    spirit1_write(0x40, RFREG(IRQ_MASK3));
}
Example #7
0
void em2_decode_data() {
    static const ot_u8 cmd[] = { 0x01, 0xFF };
    ot_u16 grab;

em2_decode_data_TOP:

    grab = spirit1_rxbytes();
    if (grab != 0) {
        if (grab > 24)  grab = 24;

        spirit1_spibus_io(2, grab, (ot_u8*)cmd);
        q_writestring(&rxq, spirit1.busrx, grab);

        if (em2.state == 0) {
            ot_int ext_bytes;
            em2.state--;
            em2.bytes       = 1 + (ot_int)rxq.front[0];
            rxq.front[1]   &= ~0x20;                    // always clear this bit
            em2.lctl        = rxq.front[1];
            em2.crc5        = em2_check_crc5();
            if (em2.crc5 != 0) {
                return;
            }

            ext_bytes = 0;
            if (em2.lctl & 0x40) {
                ext_bytes = em2_rs_init_decode(&rxq);
            }
            crc_init_stream(False, em2.bytes-ext_bytes, rxq.getcursor);
        }

        crc_calc_nstream(grab);

        ///@todo we can optimize this also by waiting until crc is done,
        ///      and then verifying that it is not accurate.  but we need
        ///      better speed profiling before doing that.
#       if (M2_FEATURE(RSCODE))
        if (em2.lctl & 0x40) {
            em2_rs_decode(grab);
        }
#       endif

        em2.bytes -= grab;
        if (em2.bytes > 0) {
            goto em2_decode_data_TOP;
        }
    }
}
Example #8
0
OT_WEAK void rm2_enter_channel(ot_u8 old_chan_id, ot_u8 old_tx_eirp) {
    static const ot_u8 dr_matrix[32] = { 
        0, RFREG(MOD1), DRF_MOD1_SS, DRF_MOD0_SS, DRF_FDEV0, DRF_CHFLT_SS, 0, 0, 
        0, RFREG(MOD1), DRF_MOD1_LS, DRF_MOD0_LS, DRF_FDEV0, DRF_CHFLT_LS, 0, 0, 
        0, RFREG(MOD1), DRF_MOD1_HS, DRF_MOD0_HS, DRF_FDEV0, DRF_CHFLT_HS, 0, 0,    /// @todo change HS to MS (mid speed)
        0, RFREG(MOD1), DRF_MOD1_HS, DRF_MOD0_HS, DRF_FDEV0, DRF_CHFLT_HS, 0, 0,
    };    
    ot_u8   fc_i;

    /// Flag PA table reprogram (done before TX): only flag if power is different
    if (old_tx_eirp != phymac[0].tx_eirp) {
        rfctl.flags |= RADIO_FLAG_SETPWR;
    }

    /// Configure data rate: only change registers if required
    if ((old_chan_id ^ phymac[0].channel) & 0x30) {
        ot_u8 offset;
        offset = (phymac[0].channel & 0x30) >> 1;
        spirit1_spibus_io(6, 0, (ot_u8*)&dr_matrix[offset]);
    }
Example #9
0
void spirit1_load_defaults() {
/// The data ordering is: WRITE LENGTH, WRITE HEADER (0), START ADDR, VALUES
/// Ignore registers that are set later, are unused, or use the hardware default values.
    static const ot_u8 spirit1_defaults[] = {
        15, 0,  0x01,   DRF_ANA_FUNC_CONF0,
                        RFGPO(READY), RFGPO(GND), RFGPO(GND), RFGPO(GND),
                        DRF_MCU_CK_CONF,
                        DRF_IF_OFFSET_ANA, DRF_SYNT3, DRF_SYNT2, DRF_SYNT1,
                        DRF_SYNT0, DRF_CHSPACE, DRF_IF_OFFSET_DIG,
        3,  0,  0xB4,   DRF_XO_RCO_TEST,
        4,  0,  0x9E,   DRF_SYNTH_CONFIG1, DRF_SYNTH_CONFIG0,
        3,  0,  0x18,   DRF_PAPOWER0,
        6,  0,  0x1C,   DRF_FDEV0, DRF_CHFLT_LS, DRF_AFC2, DRF_AFC1,
        7,  0,  0x23,   DRF_CLOCKREC, DRF_AGCCTRL2, DRF_AGCCTRL1, DRF_AGCCTRL0, DRF_ANT_SELECT_CONF,
        3,  0,  0x3A,   DRF_QI,
        3,  0,  0x41,   DRF_FIFO_CONFIG0,
        4,  0,  0x4F,   DRF_PCKT_FLT_OPTIONS, DRF_PROTOCOL2,
      //3,  0,  0x93,   RFINT_TX_FIFO_ERROR,
        6,  0,  0xA3,   DRF_DEM_ORDER, DRF_PM_CONFIG2, DRF_PM_CONFIG1, DRF_PM_CONFIG0,
        0   //Terminating 0
    };

    ot_u8* cursor;
    cursor = (ot_u8*)spirit1_defaults;

    while (*cursor != 0) {
        ot_u8 cmd_len   = *cursor++;
        ot_u8* cmd      = cursor;
        cursor         += cmd_len;
        spirit1_spibus_io(cmd_len, 0, cmd);
    }

    // Early debugging test to make sure data was written (look at first write block)
    //{
    //    volatile ot_u8 test;
    //    ot_u8 i;
    //    for (i=0x01; i<=0x0D; ++i) {
    //        test = spirit1_read(i);
    //    }
    //}
}
Example #10
0
ot_u16 spirit1_mcstate() {
    static const ot_u8 cmd[2] = { 1, RFREG(MC_STATE1) };
    spirit1_spibus_io(2, 2, (ot_u8*)cmd);
    return (ot_u16)*((ot_u16*)spirit1.busrx);
}
Example #11
0
void spirit1_burstwrite(ot_u8 start_addr, ot_u8 length, ot_u8* cmd_data) {
    cmd_data[0] = 0;
    cmd_data[1] = start_addr;
    spirit1_spibus_io((2+length), 0, cmd_data);
}
Example #12
0
void spirit1_strobe(ot_u8 strobe) {
    ot_u8 cmd[2];
    cmd[0]  = 0x80;
    cmd[1]  = strobe;
    spirit1_spibus_io(2, 0, cmd);
}
Example #13
0
inline void spirit1_iocfg_tx()  {
    spirit1_int_clearall();
    spirit1_spibus_io(5, 0, (ot_u8*)gpio_tx);
}