/*---------------------------------------------------------------------------*/ static int prepare(const void *payload, unsigned short payload_len) { uint8_t i; PRINTF("RF: Prepare 0x%02x bytes\n", payload_len + CHECKSUM_LEN); /* * When we transmit in very quick bursts, make sure previous transmission * is not still in progress before re-writing to the TX FIFO */ while(REG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_TX_ACTIVE); if((rf_flags & RX_ACTIVE) == 0) { on(); } CC2538_RF_CSP_ISFLUSHTX(); PRINTF("RF: data = "); /* Send the phy length byte first */ REG(RFCORE_SFR_RFDATA) = payload_len + CHECKSUM_LEN; if(CC2538_RF_CONF_TX_USE_DMA) { PRINTF("<uDMA payload>"); /* Set the transfer source's end address */ udma_set_channel_src(CC2538_RF_CONF_TX_DMA_CHAN, (uint32_t)(payload) + payload_len - 1); /* Configure the control word */ udma_set_channel_control_word(CC2538_RF_CONF_TX_DMA_CHAN, UDMA_TX_FLAGS | udma_xfer_size(payload_len)); /* Enabled the RF TX uDMA channel */ udma_channel_enable(CC2538_RF_CONF_TX_DMA_CHAN); /* Trigger the uDMA transfer */ udma_channel_sw_request(CC2538_RF_CONF_TX_DMA_CHAN); /* * No need to wait for this to end. Even if transmit() gets called * immediately, the uDMA controller will stream the frame to the TX FIFO * faster than transmit() can empty it */ } else { for(i = 0; i < payload_len; i++) { REG(RFCORE_SFR_RFDATA) = ((unsigned char *)(payload))[i]; PRINTF("%02x", ((unsigned char *)(payload))[i]); } } PRINTF("\n"); return 0; }
/*---------------------------------------------------------------------------*/ static int read(void *buf, unsigned short bufsize) { uint8_t i; uint8_t len; uint8_t crc_corr; int8_t rssi; PRINTF("RF: Read\n"); if((REG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_FIFOP) == 0) { return 0; } /* Check the length */ len = REG(RFCORE_SFR_RFDATA); /* Check for validity */ if(len > CC2538_RF_MAX_PACKET_LEN) { /* Oops, we must be out of sync. */ PRINTF("RF: bad sync\n"); RIMESTATS_ADD(badsynch); CC2538_RF_CSP_ISFLUSHRX(); return 0; } if(len <= CC2538_RF_MIN_PACKET_LEN) { PRINTF("RF: too short\n"); RIMESTATS_ADD(tooshort); CC2538_RF_CSP_ISFLUSHRX(); return 0; } if(len - CHECKSUM_LEN > bufsize) { PRINTF("RF: too long\n"); RIMESTATS_ADD(toolong); CC2538_RF_CSP_ISFLUSHRX(); return 0; } /* If we reach here, chances are the FIFO is holding a valid frame */ PRINTF("RF: read (0x%02x bytes) = ", len); len -= CHECKSUM_LEN; /* Don't bother with uDMA for short frames (e.g. ACKs) */ if(CC2538_RF_CONF_RX_USE_DMA && len > UDMA_RX_SIZE_THRESHOLD) { PRINTF("<uDMA payload>"); /* Set the transfer destination's end address */ udma_set_channel_dst(CC2538_RF_CONF_RX_DMA_CHAN, (uint32_t)(buf) + len - 1); /* Configure the control word */ udma_set_channel_control_word(CC2538_RF_CONF_RX_DMA_CHAN, UDMA_RX_FLAGS | udma_xfer_size(len)); /* Enabled the RF RX uDMA channel */ udma_channel_enable(CC2538_RF_CONF_RX_DMA_CHAN); /* Trigger the uDMA transfer */ udma_channel_sw_request(CC2538_RF_CONF_RX_DMA_CHAN); /* Wait for the transfer to complete. */ while(udma_channel_get_mode(CC2538_RF_CONF_RX_DMA_CHAN)); } else { for(i = 0; i < len; ++i) { ((unsigned char *)(buf))[i] = REG(RFCORE_SFR_RFDATA); PRINTF("%02x", ((unsigned char *)(buf))[i]); } } /* Read the RSSI and CRC/Corr bytes */ rssi = ((int8_t)REG(RFCORE_SFR_RFDATA)) - RSSI_OFFSET; crc_corr = REG(RFCORE_SFR_RFDATA); PRINTF("%02x%02x\n", (uint8_t)rssi, crc_corr); /* MS bit CRC OK/Not OK, 7 LS Bits, Correlation value */ if(crc_corr & CRC_BIT_MASK) { packetbuf_set_attr(PACKETBUF_ATTR_RSSI, rssi); packetbuf_set_attr(PACKETBUF_ATTR_LINK_QUALITY, crc_corr & LQI_BIT_MASK); RIMESTATS_ADD(llrx); } else { RIMESTATS_ADD(badcrc); PRINTF("RF: Bad CRC\n"); CC2538_RF_CSP_ISFLUSHRX(); return 0; } #if CC2538_RF_CONF_SNIFFER write_byte(magic[0]); write_byte(magic[1]); write_byte(magic[2]); write_byte(magic[3]); write_byte(len + 2); for(i = 0; i < len; ++i) { write_byte(((unsigned char *)(buf))[i]); } write_byte(rssi); write_byte(crc_corr); flush(); #endif /* If FIFOP==1 and FIFO==0 then we had a FIFO overflow at some point. */ if(REG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_FIFOP) { if(REG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_FIFO) { process_poll(&cc2538_rf_process); } else { CC2538_RF_CSP_ISFLUSHRX(); } } return (len); }
PROCESS_THREAD(spiProcess, ev, data) { PROCESS_BEGIN(); uint8_t spi_data_fifo[SPIFIFOSIZE]; uint8_t packetLen; spi_packet_t spi_rx_pkt; uint8_t* dma_src_end_addr; static uint8_t spi_data_ptr = 0; uint8_t proc_idx; while (1){ PROCESS_YIELD(); switch (spiState){ case SPI_RESET: spi_cs_int = 0; spi_rxfifo_halffull = 0; spiInUse = 0; spi_data_ptr = 0; spix_interrupt_enable(SPIDEV, SSI_IM_RXIM_M); spiState = SPI_WAIT; process_poll(&mainProcess); #ifdef LED_DEBUG leds_off(LEDS_RED); leds_on(LEDS_GREEN); leds_on(LEDS_BLUE); #endif break; /* Wait SPI from Edison*/ case SPI_WAIT: #ifdef LED_DEBUG leds_on(LEDS_BLUE); #endif if (spi_rxfifo_halffull==1){ spi_rxfifo_halffull = 0; spi_data_ptr += spix_get_data(SPIDEV, spi_data_fifo+spi_data_ptr); spix_interrupt_enable(SPIDEV, SSI_IM_RXIM_M); spiInUse = 1; } if (spi_cs_int==1){ spi_data_ptr += spix_get_data(SPIDEV, spi_data_fifo+spi_data_ptr); spi_cs_int = 0; spiInUse = 1; proc_idx = 0; while (proc_idx < spi_data_ptr){ proc_idx += spi_packet_parse(&spi_rx_pkt, spi_data_fifo+proc_idx); switch (spi_rx_pkt.cmd){ // write length and data into tx fifo case SPI_MASTER_REQ_DATA: packetLen = triumviRXPackets[triumviFullIDX].length; spix_put_data_single(SPIDEV, packetLen); dma_src_end_addr = triumviRXPackets[triumviFullIDX].payload + packetLen - 1; udma_set_channel_src(CC2538_SPI0_TX_DMA_CHAN, (uint32_t)(dma_src_end_addr)); udma_set_channel_control_word(CC2538_SPI0_TX_DMA_CHAN, (SPI0TX_DMA_FLAG | udma_xfer_size(packetLen))); udma_channel_enable(CC2538_SPI0_TX_DMA_CHAN); GPIO_CLR_PIN(TRIUMVI_DATA_READY_PORT_BASE, TRIUMVI_DATA_READY_MASK); break; // do nothing... case SPI_MASTER_DUMMY: break; // spi transmission is completed, advances pointer case SPI_MASTER_GET_DATA: if ((triumviAvailIDX!=triumviFullIDX) || (triumviRXBufFull==1)){ triumviRXBufFull = 0; if (triumviFullIDX == TRIUMVI_PACKET_BUF_LEN-1) triumviFullIDX = 0; else triumviFullIDX += 1; #ifndef LED_DEBUG leds_off(LEDS_GREEN); #endif } resetCnt = 0; spiInUse = 0; break; case SPI_MASTER_RADIO_ON: NETSTACK_RADIO.on(); spiInUse = 0; break; case SPI_MASTER_RADIO_OFF: NETSTACK_RADIO.off(); spiInUse = 0; break; default: spiInUse = 0; break; } } spi_data_ptr = 0; #ifndef LED_DEBUG leds_off(LEDS_BLUE); #else leds_on(LEDS_RED); leds_off(LEDS_GREEN); leds_on(LEDS_BLUE); #endif } process_poll(&mainProcess); break; default: break; } } PROCESS_END(); }