Ejemplo n.º 1
0
static inline int _get_iid(netdev2_t *netdev, eui64_t *value, size_t max_len)
{
    if (max_len < sizeof(eui64_t)) {
        return -EOVERFLOW;
    }

    uint8_t *eui64 = (uint8_t*) value;
#ifdef CPUID_ID_LEN
    int n = (CPUID_ID_LEN < sizeof(eui64_t))
        ? CPUID_ID_LEN
        : sizeof(eui64_t);

    char cpuid[CPUID_ID_LEN];
    cpuid_get(cpuid);

    memcpy(eui64 + 8 - n, cpuid, n);

#else
    for (int i = 0; i < 8; i++) {
        eui64[i] = i;
    }
#endif

    /* make sure we mark the address as non-multicast and not globally unique */
    eui64[0] &= ~(0x01);
    eui64[0] |= 0x02;

    return sizeof(eui64_t);
}
Ejemplo n.º 2
0
int main(void)
{
    gnrc_netreg_entry_t ne;

    uint8_t cpuid[CPUID_LEN];
    cpuid_get(cpuid);
    conn_test_id = djb2_hash(cpuid, CPUID_LEN);
    random_init(conn_test_id);

    ne.pid = thread_create(_stack, sizeof(_stack), THREAD_PRIORITY_MAIN - 1,
                             THREAD_CREATE_STACKTEST, _listener, NULL,
                             "listener");

    ne.demux_ctx = GNRC_NETREG_DEMUX_CTX_ALL;
    gnrc_netreg_register(GNRC_NETTYPE_UNDEF, &ne);

    puts("Connectivity Test program!");
    printf("MY ID: %08lX\n", (unsigned long) conn_test_id);
    unsigned res = CONN_TEST_CHAN;
    if (gnrc_netapi_set(CONN_TEST_NETIF, NETOPT_CHANNEL, 0, (uint16_t *)&res, sizeof(uint16_t)) < 0) {
        puts("main: error setting channel");
    }

    unsigned int addr_len = 8;
    if (gnrc_netapi_set(CONN_TEST_NETIF, NETOPT_SRC_LEN, 0, (uint16_t *)&addr_len, sizeof(uint16_t)) < 0) {
        printf("main: error setting addressing mode\n");
    }
    xtimer_set_msg(&ct_timer, (SEC_IN_USEC * 3) + (random_uint32() & 0x001FFFFF), &ct_m, ne.pid);

    char line_buf[SHELL_DEFAULT_BUFSIZE];
    shell_run(shell_commands, line_buf, SHELL_DEFAULT_BUFSIZE);
    return 0;
}
Ejemplo n.º 3
0
static int nrfmin_init(netdev_t *dev)
{
    uint8_t cpuid[CPUID_LEN];

    /* check given device descriptor */
    assert(dev);

    /* initialize our own address from the CPU ID */
    my_addr = 0;
    cpuid_get(cpuid);
    for (int i = 0; i < CPUID_LEN; i++) {
        my_addr ^= cpuid[i] << (8 * (i & 0x01));
    }

    /* power on the NRFs radio */
    NRF_RADIO->POWER = 1;
    /* load driver specific configuration */
    NRF_RADIO->MODE = CONF_MODE;
    /* configure variable parameters to default values */
    NRF_RADIO->TXPOWER = NRFMIN_TXPOWER_DEFAULT;
    NRF_RADIO->FREQUENCY = NRFMIN_CHAN_DEFAULT;
    /* pre-configure radio addresses */
    NRF_RADIO->PREFIX0 = CONF_ADDR_PREFIX0;
    NRF_RADIO->BASE0   = (CONF_ADDR_BASE | my_addr);
    NRF_RADIO->BASE1   = CONF_ADDR_BCAST;
    /* always send from logical address 0 */
    NRF_RADIO->TXADDRESS = 0x00UL;
    /* and listen to logical addresses 0 and 1 */
    NRF_RADIO->RXADDRESSES = 0x03UL;
    /* configure data fields and packet length whitening and endianess */
    NRF_RADIO->PCNF0 = ((CONF_S1 << RADIO_PCNF0_S1LEN_Pos) |
                        (CONF_S0 << RADIO_PCNF0_S0LEN_Pos) |
                        (CONF_LEN << RADIO_PCNF0_LFLEN_Pos));
    NRF_RADIO->PCNF1 = ((CONF_WHITENING << RADIO_PCNF1_WHITEEN_Pos) |
                        (CONF_ENDIAN << RADIO_PCNF1_ENDIAN_Pos) |
                        (CONF_BASE_ADDR_LEN << RADIO_PCNF1_BALEN_Pos) |
                        (CONF_STATLEN << RADIO_PCNF1_STATLEN_Pos) |
                        (NRFMIN_PKT_MAX << RADIO_PCNF1_MAXLEN_Pos));
    /* configure the CRC unit, we skip the address field as this seems to lead
     * to wrong checksum calculation on nRF52 devices in some cases */
    NRF_RADIO->CRCCNF = CONF_CRC_LEN | RADIO_CRCCNF_SKIPADDR_Msk;
    NRF_RADIO->CRCPOLY = CONF_CRC_POLY;
    NRF_RADIO->CRCINIT = CONF_CRC_INIT;
    /* set shortcuts for more efficient transfer */
    NRF_RADIO->SHORTS = RADIO_SHORTS_READY_START_Msk;
    /* enable interrupts */
    NVIC_EnableIRQ(RADIO_IRQn);
    /* enable END interrupt */
    NRF_RADIO->EVENTS_END = 0;
    NRF_RADIO->INTENSET = RADIO_INTENSET_END_Msk;
    /* put device in receive mode */
    target_state = STATE_RX;
    goto_target_state();

    DEBUG("[nrfmin] initialization successful\n");

    return 0;
}
Ejemplo n.º 4
0
int cc430radio_setup(cc430radio_t *dev, const cc430radio_params_t *params)
{
    DEBUG("%s:%s:%u\n", RIOT_FILE_RELATIVE, __func__, __LINE__);

#ifdef MODULE_CC430RADIO_HOOKS
    cc430radio_hooks_init();
#endif

    dev->params = *params;

    /* Configure chip-select */
    //gpio_init(dev->params.cs, GPIO_DIR_OUT, GPIO_NOPULL);
    //gpio_set(dev->params.cs);

    /* Configure GDO1 */
    //gpio_init(dev->params.gdo1, GPIO_DIR_IN, GPIO_NOPULL);

    /* Configure SPI */
    //spi_acquire(dev->params.spi);
    //spi_init_master(dev->params.spi, SPI_CONF_FIRST_RISING, SPI_SPEED_5MHZ);
    //spi_release(dev->params.spi);

#ifndef CC430RADIO_DONT_RESET
    /* reset device*/
    _power_up_reset(dev);
#endif

    /* set default state */
    dev->radio_state = RADIO_IDLE;

    /* Write configuration to configuration registers */
    cc430radio_writeburst_reg(dev, 0x00, cc430radio_default_conf, cc430radio_default_conf_size);

    /* Write PATABLE (power settings) */
    cc430radio_writeburst_reg(dev, CC430RADIO_PATABLE, CC430RADIO_DEFAULT_PATABLE, 8);

    /* set base frequency */
    cc430radio_set_base_freq_raw(dev, CC430RADIO_DEFAULT_FREQ);

    /* Set default channel number */
    cc430radio_set_channel(dev, CC430RADIO_DEFAULT_CHANNEL);

    /* set default node id */
#ifdef CPUID_ID_LEN
    if (CPUID_ID_LEN>0) {
        char cpuid[CPUID_ID_LEN];
        cpuid_get(cpuid);
        cc430radio_set_address(dev, (uint8_t) cpuid[CPUID_ID_LEN-1]);
    }
#endif

    LOG_INFO("cc430radio: initialized with address=%u and channel=%i\n",
            (unsigned)dev->radio_address,
            dev->radio_channel);

    return 0;
}
Ejemplo n.º 5
0
int main(void)
{
    uint8_t id[CPUID_ID_LEN];

    cpuid_get(id);

    for (unsigned int i = 0; i < CPUID_ID_LEN; i++) {
        printf("0x%02x ", id[i]);
    }

    printf("\n");

    return 0;
}
Ejemplo n.º 6
0
int
sol_platform_impl_get_machine_id(char id[SOL_STATIC_ARRAY_SIZE(33)])
{
#ifdef CPUID_ID_LEN
    char cpuid[CPUID_ID_LEN];

    /* Assume, for now, the the cpuid we get is a valid UUID */
    cpuid_get(cpuid);
    serial_to_string(cpuid, CPUID_ID_LEN, id);

    return 0;
#else
    return -ENOSYS;
#endif
}
Ejemplo n.º 7
0
int
sol_platform_impl_get_serial_number(char **number)
{
#ifdef CPUID_ID_LEN
    char cpuid[CPUID_ID_LEN];

    if (!number)
        return -EINVAL;

    *number = malloc(CPUID_ID_LEN * 2 + 1);
    SOL_NULL_CHECK(*number, -ENOMEM);

    cpuid_get(cpuid);
    serial_to_string(cpuid, CPUID_ID_LEN, *number);

    return 0;
#else
    return -ENOSYS;
#endif
}
Ejemplo n.º 8
0
void ng_at86rf2xx_reset(ng_at86rf2xx_t *dev)
{
#if CPUID_ID_LEN
    uint8_t cpuid[CPUID_ID_LEN];
    eui64_t addr_long;
#endif

    /* trigger hardware reset */
    gpio_clear(dev->reset_pin);
    hwtimer_wait(HWTIMER_TICKS(RESET_DELAY));
    gpio_set(dev->reset_pin);
    /* reset options and sequence number */
    dev->seq_nr = 0;
    dev->options = 0;
    /* set short and long address */
#if CPUID_ID_LEN
    cpuid_get(cpuid);

#if CPUID_ID_LEN < 8
    /* in case CPUID_ID_LEN < 8, fill missing bytes with zeros */
    for (int i = CPUID_ID_LEN; i < 8; i++) {
        cpuid[i] = 0;
    }
#else
    for (int i = 8; i < CPUID_ID_LEN; i++) {
        cpuid[i & 0x07] ^= cpuid[i];
    }
#endif
    /* make sure we mark the address as non-multicast and not globally unique */
    cpuid[0] &= ~(0x01);
    cpuid[0] |= 0x02;
    /* copy and set long address */
    memcpy(&addr_long, cpuid, 8);
    ng_at86rf2xx_set_addr_long(dev, NTOHLL(addr_long.uint64.u64));
    ng_at86rf2xx_set_addr_short(dev, NTOHS(addr_long.uint16[0].u16));
#else
    ng_at86rf2xx_set_addr_long(dev, NG_AT86RF2XX_DEFAULT_ADDR_LONG);
    ng_at86rf2xx_set_addr_short(dev, NG_AT86RF2XX_DEFAULT_ADDR_SHORT);
#endif
    /* set default PAN id */
    ng_at86rf2xx_set_pan(dev, NG_AT86RF2XX_DEFAULT_PANID);
    /* set default channel */
    ng_at86rf2xx_set_chan(dev, NG_AT86RF2XX_DEFAULT_CHANNEL);
    /* set default TX power */
    ng_at86rf2xx_set_txpower(dev, NG_AT86RF2XX_DEFAULT_TXPOWER);
    /* set default options */
    ng_at86rf2xx_set_option(dev, NG_AT86RF2XX_OPT_AUTOACK, true);
    ng_at86rf2xx_set_option(dev, NG_AT86RF2XX_OPT_CSMA, true);
    ng_at86rf2xx_set_option(dev, NG_AT86RF2XX_OPT_TELL_RX_START, false);
    ng_at86rf2xx_set_option(dev, NG_AT86RF2XX_OPT_TELL_RX_END, true);
    /* set default protocol */
#ifdef MODULE_NG_SIXLOWPAN
    dev->proto = NG_NETTYPE_SIXLOWPAN;
#else
    dev->proto = NG_NETTYPE_UNDEF;
#endif
    /* enable safe mode (protect RX FIFO until reading data starts) */
    ng_at86rf2xx_reg_write(dev, NG_AT86RF2XX_REG__TRX_CTRL_2,
                          NG_AT86RF2XX_TRX_CTRL_2_MASK__RX_SAFE_MODE);
#ifdef MODULE_NG_AT86RF212B
    ng_at86rf2xx_set_freq(dev,NG_AT86RF2XX_FREQ_915MHZ);
#endif

    /* don't populate masked interrupt flags to IRQ_STATUS register */
    uint8_t tmp = ng_at86rf2xx_reg_read(dev, NG_AT86RF2XX_REG__TRX_CTRL_1);
    tmp &= ~(NG_AT86RF2XX_TRX_CTRL_1_MASK__IRQ_MASK_MODE);
    ng_at86rf2xx_reg_write(dev, NG_AT86RF2XX_REG__TRX_CTRL_1, tmp);

    /* enable interrupts */
    ng_at86rf2xx_reg_write(dev, NG_AT86RF2XX_REG__IRQ_MASK,
                          NG_AT86RF2XX_IRQ_STATUS_MASK__TRX_END);
    /* clear interrupt flags */
    ng_at86rf2xx_reg_read(dev, NG_AT86RF2XX_REG__IRQ_STATUS);

    /* go into RX state */
    ng_at86rf2xx_set_state(dev, NG_AT86RF2XX_STATE_RX_AACK_ON);

    DEBUG("ng_at86rf2xx_reset(): reset complete.\n");
}
Ejemplo n.º 9
0
static int nd_init(netdev2_t *netdev)
{
    enc28j60_t *dev = (enc28j60_t *)netdev;
    int res;
    uint8_t tmp;

    /* get exclusive access of the device */
    mutex_lock(&dev->devlock);

    /* setup the low-level interfaces */
    gpio_init(dev->reset_pin, GPIO_OUT);
    gpio_clear(dev->reset_pin);     /* this puts the device into reset state */
    gpio_init(dev->cs_pin, GPIO_OUT);
    gpio_set(dev->cs_pin);
    gpio_init_int(dev->int_pin, GPIO_IN, GPIO_FALLING, on_int, (void *)dev);
    res = spi_init_master(dev->spi, SPI_CONF_FIRST_RISING, SPI_SPEED);
    if (res < 0) {
        DEBUG("[enc28j60] init: error initializing SPI bus [%i]\n", res);
        return -1;
    }

    /* wait at least 1ms and then release device from reset state */
    xtimer_usleep(DELAY_RESET);
    gpio_set(dev->reset_pin);

    /* wait for oscillator to be stable before proceeding */
    res = 0;
    do {
        tmp = cmd_rcr(dev, REG_ESTAT, -1);
        if (res++ >= STARTUP_TIMEOUT) {
            DEBUG("[enc28j60] init: error waiting for stable clock, SPI ok?\n");
            return -1;
        }
    } while (!(tmp & ESTAT_CLKRDY));

    /* disable clock output to save a little power */
    cmd_wcr(dev, REG_B3_ECOCON, 3, 0x00);

    /* BUFFER configuration */
    /* configure the RX buffer */
    cmd_w_addr(dev, ADDR_RX_START, BUF_RX_START);
    cmd_w_addr(dev, ADDR_RX_END, BUF_RX_END);
    cmd_w_addr(dev, ADDR_RX_READ, BUF_RX_START);
    /* configure the TX buffer */
    cmd_w_addr(dev, ADDR_TX_START, BUF_TX_START);
    cmd_w_addr(dev, ADDR_TX_END, BUF_TX_END);

    /* FILTER configuration */
    /* setup receive filters - we accept everything per default */
    cmd_wcr(dev, REG_B1_ERXFCON, 1, 0);

    /* MAC configuration */
    /* enable RX through filter and enable sending of RX and TX pause frames */
    tmp = (MACON1_TXPAUS | MACON1_RXPAUS | MACON1_MARXEN);
    cmd_wcr(dev, REG_B2_MACON1, 2, tmp);
    /* enable full duplex mode, padding to min 60 byte + CRC for all frames and
     * CRC creation for all packets before transmission */
    tmp = (MACON3_FULDPX | MACON3_PADCFG0 | MACON3_TXCRCEN | MACON3_FRMLNEN);
    cmd_wcr(dev, REG_B2_MACON3, 2, tmp);
    /* defer TX infinitely if medium is busy for IEEE 802.3 compliance */
    tmp = (MACON4_DEFER);
    cmd_wcr(dev, REG_B2_MACON4, 2, tmp);
    /* set back-to-back inter-packet gap -> 0x15 for full duplex */
    cmd_wcr(dev, REG_B2_MABBIPG, 2, MABBIPG_FD);
    /* set non-back-to-back inter packet gap -> 0x12 is default */
    cmd_wcr(dev, REG_B2_MAIPGL, 2, MAIPGL_FD);
    /* set default MAC address */
#if CPUID_LEN
    uint8_t macbuf[CPUID_LEN];
    cpuid_get(&macbuf);     /* we get the full ID but use only parts of it */
    macbuf[0] |= 0x02;      /* locally administered address */
    macbuf[0] &= ~0x01;     /* unicast address */
#else
    uint8_t macbuf[] = ENC28J60_FALLBACK_MAC;
#endif
    mac_set(dev, macbuf);

    /* PHY configuration */
    cmd_w_phy(dev, REG_PHY_PHCON1, PHCON1_PDPXMD);
    cmd_w_phy(dev, REG_PHY_PHIE, PHIE_PLNKIE | PHIE_PGEIE);

    /* Finishing touches */
    /* enable hardware flow control */
    cmd_wcr(dev, REG_B3_EFLOCON, 3, EFLOCON_FULDPXS | EFLOCON_FCEN1);
    /* enable auto-inc of read and write pointers for the RBM/WBM commands */
    cmd_bfs(dev, REG_ECON2, -1, ECON2_AUTOINC);
    /* enable receive, link and tx interrupts */
    cmd_bfc(dev, REG_EIR, -1, (EIR_LINKIF | EIR_PKTIF | EIR_RXERIF | EIR_TXIF |
                               EIR_TXERIF));
    cmd_bfs(dev, REG_EIE, -1, (EIE_INTIE | EIE_LINKIE | EIE_PKTIE | EIE_RXERIE |
                               EIE_TXIE | EIE_TXERIE));
    /* allow receiving bytes from now on */
    cmd_bfs(dev, REG_ECON1, -1, ECON1_RXEN);

#ifdef MODULE_NETSTATS_L2
    memset(&netdev->stats, 0, sizeof(netstats_t));
#endif
    mutex_unlock(&dev->devlock);
    return 0;
}
Ejemplo n.º 10
0
void at86rf2xx_reset(at86rf2xx_t *dev)
{
#if CPUID_LEN
    uint8_t cpuid[CPUID_LEN];
    eui64_t addr_long;
#endif

    at86rf2xx_hardware_reset(dev);

    /* Reset state machine to ensure a known state */
    at86rf2xx_reset_state_machine(dev);

    /* reset options and sequence number */
    dev->seq_nr = 0;
    dev->options = 0;
    /* set short and long address */
#if CPUID_LEN
    cpuid_get(cpuid);

#if CPUID_LEN < 8
    /* in case CPUID_LEN < 8, fill missing bytes with zeros */
    for (int i = CPUID_LEN; i < 8; i++) {
        cpuid[i] = 0;
    }
#else
    for (int i = 8; i < CPUID_LEN; i++) {
        cpuid[i & 0x07] ^= cpuid[i];
    }
#endif
    /* make sure we mark the address as non-multicast and not globally unique */
    cpuid[0] &= ~(0x01);
    cpuid[0] |= 0x02;
    /* copy and set long address */
    memcpy(&addr_long, cpuid, 8);
    at86rf2xx_set_addr_long(dev, NTOHLL(addr_long.uint64.u64));
    at86rf2xx_set_addr_short(dev, NTOHS(addr_long.uint16[0].u16));
#else
    at86rf2xx_set_addr_long(dev, AT86RF2XX_DEFAULT_ADDR_LONG);
    at86rf2xx_set_addr_short(dev, AT86RF2XX_DEFAULT_ADDR_SHORT);
#endif
    /* set default PAN id */
    at86rf2xx_set_pan(dev, AT86RF2XX_DEFAULT_PANID);
    /* set default channel */
    at86rf2xx_set_chan(dev, AT86RF2XX_DEFAULT_CHANNEL);
    /* set default TX power */
    at86rf2xx_set_txpower(dev, AT86RF2XX_DEFAULT_TXPOWER);
    /* set default options */
    at86rf2xx_set_option(dev, AT86RF2XX_OPT_AUTOACK, true);
    at86rf2xx_set_option(dev, AT86RF2XX_OPT_CSMA, true);
    at86rf2xx_set_option(dev, AT86RF2XX_OPT_TELL_RX_START, false);
    at86rf2xx_set_option(dev, AT86RF2XX_OPT_TELL_RX_END, true);
    /* set default protocol */
#ifdef MODULE_GNRC_SIXLOWPAN
    dev->proto = GNRC_NETTYPE_SIXLOWPAN;
#else
    dev->proto = GNRC_NETTYPE_UNDEF;
#endif
    /* enable safe mode (protect RX FIFO until reading data starts) */
    at86rf2xx_reg_write(dev, AT86RF2XX_REG__TRX_CTRL_2,
                        AT86RF2XX_TRX_CTRL_2_MASK__RX_SAFE_MODE);
#ifdef MODULE_AT86RF212B
    at86rf2xx_set_page(dev, 0);
#endif

    /* don't populate masked interrupt flags to IRQ_STATUS register */
    uint8_t tmp = at86rf2xx_reg_read(dev, AT86RF2XX_REG__TRX_CTRL_1);
    tmp &= ~(AT86RF2XX_TRX_CTRL_1_MASK__IRQ_MASK_MODE);
    at86rf2xx_reg_write(dev, AT86RF2XX_REG__TRX_CTRL_1, tmp);

    /* disable clock output to save power */
    tmp = at86rf2xx_reg_read(dev, AT86RF2XX_REG__TRX_CTRL_0);
    tmp &= ~(AT86RF2XX_TRX_CTRL_0_MASK__CLKM_CTRL);
    tmp &= ~(AT86RF2XX_TRX_CTRL_0_MASK__CLKM_SHA_SEL);
    tmp |= (AT86RF2XX_TRX_CTRL_0_CLKM_CTRL__OFF);
    at86rf2xx_reg_write(dev, AT86RF2XX_REG__TRX_CTRL_0, tmp);

    /* enable interrupts */
    at86rf2xx_reg_write(dev, AT86RF2XX_REG__IRQ_MASK,
                        AT86RF2XX_IRQ_STATUS_MASK__TRX_END);
    /* clear interrupt flags */
    at86rf2xx_reg_read(dev, AT86RF2XX_REG__IRQ_STATUS);

    /* go into RX state */
    at86rf2xx_set_state(dev, AT86RF2XX_STATE_RX_AACK_ON);

    DEBUG("at86rf2xx_reset(): reset complete.\n");
}
Ejemplo n.º 11
0
/*
 * Public interface functions
 */
int nrfmin_init(ng_netdev_t *dev)
{
    uint8_t cpuid[CPUID_ID_LEN];
    uint8_t tmp;
    int i;

    /* check given device descriptor */
    if (dev == NULL) {
        return -ENODEV;
    }
    /* set initial values */
    dev->driver = &nrfmin_driver;
    dev->event_cb = NULL;
    dev->mac_pid = KERNEL_PID_UNDEF;
    /* keep a pointer for future reference */
    _netdev = dev;

    /* power on the NRFs radio */
    NRF_RADIO->POWER = 1;
    /* load driver specific configuration */
    NRF_RADIO->MODE = CONF_MODE;
    /* configure variable parameters to default values */
    NRF_RADIO->TXPOWER = NRFMIN_DEFAULT_TXPOWER;
    NRF_RADIO->FREQUENCY = NRFMIN_DEFAULT_CHANNEL;
    /* get default address from CPU ID */
    cpuid_get(cpuid);
    tmp = 0;
    for (i = 0; i < (CPUID_ID_LEN / 2); i++) {
        tmp ^= cpuid[i];
    }
    _addr = ((uint16_t)tmp) << 8;
    tmp = 0;
    for (; i < CPUID_ID_LEN; i++) {
        tmp ^= cpuid[i];
    }
    _addr |= tmp;
    /* pre-configure radio addresses */
    NRF_RADIO->PREFIX0 = CONF_ADDR_PREFIX0;
    NRF_RADIO->BASE0   = (NRFMIN_DEFAULT_PAN << 16) | _addr;
    NRF_RADIO->BASE1   = (NRFMIN_DEFAULT_PAN << 16) | CONF_ADDR_BCAST;
    NRF_RADIO->TXADDRESS = 0x00UL;      /* always send from address 0 */
    NRF_RADIO->RXADDRESSES = 0x03UL;    /* listen to addresses 0 and 1 */
    /* configure data fields and packet length whitening and endianess */
    NRF_RADIO->PCNF0 = (CONF_S1 << RADIO_PCNF0_S1LEN_Pos) |
                       (CONF_S0 << RADIO_PCNF0_S0LEN_Pos) |
                       (CONF_LEN << RADIO_PCNF0_LFLEN_Pos);
    NRF_RADIO->PCNF1 = (CONF_WHITENING << RADIO_PCNF1_WHITEEN_Pos) |
                       (CONF_ENDIAN << RADIO_PCNF1_ENDIAN_Pos) |
                       (CONF_BASE_ADDR_LEN << RADIO_PCNF1_BALEN_Pos) |
                       (CONF_STATLEN << RADIO_PCNF1_STATLEN_Pos) |
                       (CONF_PAYLOAD_LEN << RADIO_PCNF1_MAXLEN_Pos);
    /* configure CRC unit */
    NRF_RADIO->CRCCNF = CONF_CRC_LEN;
    NRF_RADIO->CRCPOLY = CONF_CRC_POLY;
    NRF_RADIO->CRCINIT = CONF_CRC_INIT;
    /* set shortcuts for more efficient transfer */
    NRF_RADIO->SHORTS = (1 << RADIO_SHORTS_READY_START_Pos);
    /* enable interrupts */
    NVIC_SetPriority(RADIO_IRQn, RADIO_IRQ_PRIO);
    NVIC_EnableIRQ(RADIO_IRQn);
    /* enable END interrupt */
    NRF_RADIO->EVENTS_END = 0;
    NRF_RADIO->INTENSET = (1 << RADIO_INTENSET_END_Pos);
    /* put device in receive mode */
    _switch_to_rx();
    return 0;
}