/* * * mur.sat * * Somewhen in the year 20xx, mur.at will have a nano satellite launched * into a low earth orbit (310 km above the surface of our planet). The * satellite itself is a TubeSat personal satellite kit, developed and * launched by interorbital systems. mur.sat is a joint venture of mur.at, * ESC im Labor and realraum. * * Please visit the project hompage at sat.mur.at for further information. * * * Copyright (C) 2012 Bernhard Tittelbach * 2015 Christian Pointner * * This file is part of mur.sat. * * mur.sat is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * mur.sat is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with mur.sat. If not, see . * */ #include #include #include #include "c1101lib.h" #include "hhd70.h" #include "util.h" /**** Helper Functions ****/ #define SPIC1101_MAX_WAIT 21 /* ###### ###### LUFA Library Copyright (C) Dean Camera, 2012. dean [at] fourwalledcubicle [dot] com www.lufa-lib.org */ //#include #include /* Global I/O Buffers: */ //static RingBuffer_t SPItoUSB_Buffer; //static uint8_t SPItoUSB_Buffer_Data[8]; int16_t c1101_spi_write_byte_ok_get_status(char data) { //~ uint8_t debug_sb[6]; char sb; unsigned int attempts = 0; do { sb = hhd70_spi_exchange_byte(data); //Note: content of returned StatusByte is actually context depenedant on sent command // i.e. we won't get Fifo Byte count or overflow status on normal command and so on // e.g. we only get TX Fifo Free Byte count while writing to TX Fifo // thus it makes sense to only check for CHIP_RDY here //~ ((uint8_t*)"spi byte exchanged ",255); //~ debug_sprint_int16hex(debug_sb, sb); //~ (debug_sb,255); if (attempts++ > SPIC1101_MAX_WAIT) return -1; } while ( SPIC1101_SB_CHIP_NOT_RDY(sb) ); return sb; } int16_t c1101_spi_strobe_command(char address) { char rbyte; if (address < 0x30) return -1; hhd70_spi_cs_enable(); hhd70_c1101_wait_chip_rdy(); //POST DEBUG: don't return anything rbyte = c1101_spi_write_byte_ok_get_status(address); if (rbyte < 0) return -1; hhd70_spi_cs_disable(); return rbyte; } // note addresses range from 0x00 to 0x2F for normal registers and 0xF0 to 0xFD for special status registers int16_t c1101_spi_read_register(char address) { char rbyte; if (address < 0x30) address |= 0x80; else address |= 0xC0; hhd70_spi_cs_enable(); hhd70_c1101_wait_chip_rdy(); if (c1101_spi_write_byte_ok_get_status(address) < 0) return -1; rbyte = hhd70_spi_read_byte(); hhd70_spi_cs_disable(); return rbyte; } // note addresses range from 0x00 to 0x2F for normal registers int16_t c1101_spi_write_register(char address, char byte) { hhd70_spi_cs_enable(); hhd70_c1101_wait_chip_rdy(); if (c1101_spi_write_byte_ok_get_status(address & 0x3F) < 0) return -1; _delay_ms(2); if (c1101_spi_write_byte_ok_get_status(byte) < 0) return -1; hhd70_spi_cs_disable(); return 1; } void c1101_spi_dump_registers_to_usb(void) { int c = 0; char debug_sb[6]; hhd70_spi_cs_enable(); hhd70_c1101_wait_chip_rdy(); if (c1101_spi_write_byte_ok_get_status(0xC0) < 0) return; printf("dump all 46 registers:\r\n"); for (c=0; c<47; c++) { debug_sprint_int16hex(debug_sb, hhd70_spi_read_byte()); printf("%s", debug_sb); printf("\r\n"); } hhd70_spi_cs_disable(); } int c1101_spi_read_rxfifo(int leave_num_bytes, char *buffer, int maxlen) { int num_read = 0; uint8_t num_available = 0; hhd70_spi_cs_enable(); hhd70_c1101_wait_chip_rdy(); if (c1101_spi_write_byte_ok_get_status(SPIC1101_ADDR_RXBYTES) < 0) return -1; num_available = hhd70_spi_read_byte(); if (num_available == 0) return 0; if (c1101_spi_write_byte_ok_get_status(SPIC1101_ADDR_FIFO_READ_BURST) < 0) return -1; while (maxlen-- > 0 && num_available - num_read > leave_num_bytes) { buffer[num_read++] = hhd70_spi_read_byte(); } hhd70_spi_cs_disable(); return num_read; } //note: currently this function reads at most 15 bytes int c1101_spi_read_rxfifo_max15(int leave_num_bytes, char *buffer, int maxlen) { int16_t sb; int num_read = 0; hhd70_spi_cs_enable(); hhd70_c1101_wait_chip_rdy(); sb = c1101_spi_write_byte_ok_get_status(SPIC1101_ADDR_FIFO_READ_BURST); if (sb < 0) return -1; //note if SPIC1101_SB_FIFO_BYTES_AVAILABLE(sb) == 15 then 15 or more bytes are available while (maxlen-- > 0 && SPIC1101_SB_FIFO_BYTES_AVAILABLE(sb) - num_read > leave_num_bytes) { //hope this works !! buffer[num_read++] = hhd70_spi_read_byte(); } hhd70_spi_cs_disable(); return num_read; } //note: always check if num_written returned == len given int c1101_spi_write_txfifo(char *buffer, int len) { char sb; int num_written = 0; hhd70_spi_cs_enable(); hhd70_c1101_wait_chip_rdy(); sb = c1101_spi_write_byte_ok_get_status(SPIC1101_ADDR_FIFO_WRITE_BURST); if (sb < 0) return -1; while (len-- > 0 && SPIC1101_SB_FIFO_BYTES_AVAILABLE(sb) > 2) { sb = c1101_spi_write_byte_ok_get_status(buffer[num_written++]); } hhd70_spi_cs_disable(); return num_written; } //patable muste be char array of length 8 int c1101_spi_write_patable(uint8_t const patable[]) { int16_t sb; int8_t len = 8; hhd70_spi_cs_enable(); hhd70_c1101_wait_chip_rdy(); sb = c1101_spi_write_byte_ok_get_status(SPIC1101_ADDR_PATABLE_WRITE_BURST); if (sb < 0) return -1; while (len-- > 0) { sb = c1101_spi_write_byte_ok_get_status(*patable); patable++; } hhd70_spi_cs_disable(); return sb; } static uint8_t const pa_table_values_[] = { 0x00, 0x30, 0x20, 0x10, 0x01, 0x02, 0x11, 0x03, 0x12, 0x04, 0x05, 0x13, 0x06, 0x07, 0x21, 0x14, 0x08, 0x09, 0x0A, 0x15, 0x0B, 0x31, 0x16, 0x0C, 0x0D, 0x0E, 0x17, 0x0F, 0x22, 0x18, 0x19, 0x1A, 0x1B, 0x32, 0x23, 0x1C, 0x6F, 0x1D, 0x1E, 0x1F, 0x24, 0x33, 0x25, 0x34, 0x26, 0x6E, 0x27, 0x35, 0x28, 0x6D, 0x6C, 0x29, 0x36, 0x6B, 0x2A, 0x6A, 0x37, 0x69, 0x2B, 0x68, 0x38, 0x2C, 0x8F, 0x67, 0x2D, 0x57, 0x39, 0x66, 0x2E, 0x56, 0x3A, 0x2F, 0x65, 0x55, 0x3B, 0x64, 0x54, 0x3C, 0x63, 0x3D, 0x53, 0x3E, 0x62, 0x3F, 0x52, 0x40, 0x61, 0x51, 0x60, 0x50, 0x8E, 0x8D, 0x8C, 0xCF, 0x8B, 0x8A, 0x89, 0x88, 0x87, 0x86, 0x85, 0xCE, 0x84, 0x83, 0xCD, 0x82, 0xCC, 0x81, 0xCB, 0x80, 0xCA, 0xC9, 0xC8, 0xC7, 0xC6, 0xC5, 0xC4, 0xC3, 0xC2, 0xC1, 0xC0 }; #define PA_TABLE_VALUES_MAX ((sizeof(pa_table_values_)/sizeof(uint8_t))-1) static uint8_t ook_power_ = 83; // ==> 3F /**** External Functions ****/ uint16_t c1101_setFSKDeviationFromCarrier(int8_t m, int8_t e) { c1101_spi_write_register(SPIC1101_ADDR_DEVIATN, (m & 0x7) | ((e & 0x7) << 4)); return (1983u * (8u+((uint32_t)m)) * (1u << ((uint32_t)e))) / 100; //return +- deviation in 10Hz Steps } void c1101_init(void) { //reset C1101 c1101_spi_strobe_command(SPIC1101_ADDR_SRES); _delay_ms(100); //flush FIFOs c1101_spi_strobe_command(SPIC1101_ADDR_SFRX); c1101_spi_strobe_command(SPIC1101_ADDR_SFTX); //dump pre-init default values to usb c1101_spi_dump_registers_to_usb(); //enable analog temperature sensor on GDO0 c1101_spi_write_register(SPIC1101_ADDR_IOCFG0, 0x80); //enable RX FIFO interrupt (i.e. GPO2 pulls high if >= FIFOTHR bytes are in RX FIFO) c1101_spi_write_register(SPIC1101_ADDR_IOCFG2, 0x41 ); //0x40, 0x42, 0x44, 0x47 // FIFOTHR RX FIFO and TX FIFO Thresholds // pull GPO high (interrupt) if more than 12 bytes in rx buffer (or less than 53 in tx) //c1101_spi_write_register(SPIC1101_ADDR_FIFOTHR, 2); //assert at 12 bytes in RX Fifo and 53 in TX Fifo c1101_spi_write_register(SPIC1101_ADDR_FIFOTHR, 0); //assert at 4 bytes in RX Fifo and 61 in TX Fifo // PKTCTRL0 Packet Automation Control //c1101_spi_write_register(SPIC1101_ADDR_PKTCTRL0, 0b0000000010); //crc disabled; use FIFOs; infinite packet length mode c1101_spi_write_register(SPIC1101_ADDR_PKTCTRL0, 0b0000000001); //crc disabled; use FIFOs; variable packet length mode (first TX FIFO byte must be length) //c1101_spi_write_register(SPIC1101_ADDR_PKTCTRL0, 0b0000000101); //crc enabled; use FIFOs; variable packet length mode (first TX FIFO byte must be length) c1101_spi_write_register(SPIC1101_ADDR_PKTCTRL1, 0x00); //no address check, no append rssi and crc_ok to packet // FSCTRL1 Frequency Synthesizer Control c1101_spi_write_register(SPIC1101_ADDR_FSCTRL1, 0x06); // FREQn Frequency Control Words c1101_spi_write_register(SPIC1101_ADDR_FREQ2, 0x10); //should be 435.125 mhz c1101_spi_write_register(SPIC1101_ADDR_FREQ1, 0xBF); c1101_spi_write_register(SPIC1101_ADDR_FREQ0, 0xEF); c1101_spi_write_register(SPIC1101_ADDR_FSCTRL0, 0); //frequency offset // MDMCFGn Modem Configuration c1101_spi_write_register(SPIC1101_ADDR_MDMCFG4, 0xF8); c1101_spi_write_register(SPIC1101_ADDR_MDMCFG3, 0x83); c1101_spi_write_register(SPIC1101_ADDR_MDMCFG2, 0x12); //gfsk, 15/16 sync word c1101_spi_write_register(SPIC1101_ADDR_MDMCFG1, 0x00); //Sync Word c1101_spi_write_register(SPIC1101_ADDR_SYNC1, 0x21); c1101_spi_write_register(SPIC1101_ADDR_SYNC0, 0x42); // DEVIATN Modem Deviation Setting c1101_spi_write_register(SPIC1101_ADDR_DEVIATN, 0x11); //0x11 equals deviation of 3.5kHz; 0x27 equals deviation of 11.9kHz // MCSM0 Main Radio Control State Machine Configuration c1101_spi_write_register(SPIC1101_ADDR_MCSM0, 0x18); c1101_spi_write_register(SPIC1101_ADDR_MCSM1, 0b00111100); // State RX after recieving packet-> stay in RX; State TX after sending packet -> IDLE // FOCCFG Frequency Offset Compensation Configuration c1101_spi_write_register(SPIC1101_ADDR_FOCCFG, 0x16); // WORCTRL Wake On Radio Control c1101_spi_write_register(SPIC1101_ADDR_WORCTRL, 0xFB); // FSCALn Frequency Synthesizer Calibration c1101_spi_write_register(SPIC1101_ADDR_FSCAL3, 0xE9); c1101_spi_write_register(SPIC1101_ADDR_FSCAL2, 0x2A); c1101_spi_write_register(SPIC1101_ADDR_FSCAL1, 0x00); c1101_spi_write_register(SPIC1101_ADDR_FSCAL0, 0x1F); //FREN0 TX Power: c1101_spi_write_register(SPIC1101_ADDR_FREND0, 0x10); //should be set using RF-Studio !!, for now, only use PA-Table Entry[0] no power ramping !! (FIXME: but should maybe be used) c1101_spi_write_register(SPIC1101_ADDR_PATABLE_WRITE, 0xC0); //write PATABLE[0] only, rest needs to be written in Burst-Mode ! set to max power 10dBm // note: for now: assume f_xosc to be 26 Mhz // for ~433.125 Mhz -> freq = 1091741, freq_offset = 0 //c1101_setFrequency(1091741,0,15); //AFU Satellite Band: 435.000 - 438.000 kHz //AFU Salellite Band Max Bandwith: 20 kHz hhd70_config_GDO0_OOK_output(false); } //Note for comparision: void c1101_init_w_rfstudiosettings1(void) { // Sync word qualifier mode = 30/32 sync word bits detected // CRC autoflush = false // Channel spacing = 199.951172 // Data format = Normal mode // Data rate = 9.59587 // RX filter BW = 58.035714 // PA ramping = true // Preamble count = 4 // Address config = No address check // Whitening = false // Carrier frequency = 435.124695 // Device address = 0 // TX power = 10 // Manchester enable = false // CRC enable = true // Deviation = 11.901855 // Modulation format = GFSK // Base frequency = 435.124695 // Modulated = true // Channel number = 0 // PA table uint8_t const pa_table[8] = {0x00,0x12,0x0e,0x34,0x60,0xc5,0xc1,0xc0}; // // Rf settings for CC1101 // //reset C1101 c1101_spi_strobe_command(SPIC1101_ADDR_SRES); _delay_ms(100); //flush FIFOs c1101_spi_strobe_command(SPIC1101_ADDR_SFRX); c1101_spi_strobe_command(SPIC1101_ADDR_SFTX); //enable analog temperature sensor on GDO0 c1101_spi_write_register(SPIC1101_ADDR_IOCFG0, 0x80); //enable RX FIFO interrupt (i.e. GPO2 pulls high if >= FIFOTHR bytes are in RX FIFO) c1101_spi_write_register(SPIC1101_ADDR_IOCFG2, 0x41 ); //0x40, 0x42, 0x44, 0x47 //Values from SmartRFStudio: c1101_spi_write_patable(pa_table); hhd70_config_GDO0_OOK_output(false); } void c1101_init_ook_beacon(void) { // Sync word qualifier mode = No preamble/sync // CRC autoflush = false // Channel spacing = 49.987793 // Data format = Synchronous serial mode // Data rate = 1.00112 // RX filter BW = 58.035714 // PA ramping = true // Preamble count = 2 // Address config = No address check // Whitening = false // Carrier frequency = 437.524902 MHz // Device address = 0 // TX power = 10 // Manchester enable = false // CRC enable = false // Deviation = 2.975464 // Modulation format = ASK/OOK // Base frequency = 437.524902 MHz // Channel number = 0 // PA table by TI //reset C1101 c1101_spi_strobe_command(SPIC1101_ADDR_SRES); _delay_ms(100); //flush FIFOs c1101_spi_strobe_command(SPIC1101_ADDR_SFRX); c1101_spi_strobe_command(SPIC1101_ADDR_SFTX); // // Rf settings for CC1101 // c1101_spi_write_register(SPIC1101_ADDR_IOCFG0, 0x00); //enable RX FIFO interrupt (i.e. GPO2 pulls high if >= FIFOTHR bytes are in RX FIFO) c1101_spi_write_register(SPIC1101_ADDR_IOCFG2, 0x41 ); //0x40, 0x42, 0x44, 0x47 // pull GPO high (interrupt) if more than 12 bytes in rx buffer (or less than 53 in tx) //c1101_spi_write_register(SPIC1101_ADDR_FIFOTHR,0x47); //RX FIFO and TX FIFO Thresholds c1101_spi_write_register(SPIC1101_ADDR_FIFOTHR, 0); //assert at 4 bytes in RX Fifo and 61 in TX Fifo //c1101_spi_write_register(SPIC1101_ADDR_PKTCTRL0,0x12);//Packet Automation Control //c1101_spi_write_register(SPIC1101_ADDR_PKTCTRL0, 0b0000000001); //crc disabled; use FIFOs; variable packet length mode (first TX FIFO byte must be length) c1101_spi_write_register(SPIC1101_ADDR_PKTCTRL0, 0b0000110001); //crc disabled; asynchronous serial input on GDO0 c1101_spi_write_register(SPIC1101_ADDR_FSCTRL1,0x06); //Frequency Synthesizer Control c1101_spi_write_register(SPIC1101_ADDR_FREQ2,0x10); //Frequency Control Word, High Byte c1101_spi_write_register(SPIC1101_ADDR_FREQ1,0xD3); //Frequency Control Word, Middle Byte c1101_spi_write_register(SPIC1101_ADDR_FREQ0,0xF0); //Frequency Control Word, Low Byte c1101_spi_write_register(SPIC1101_ADDR_MDMCFG4,0xF5); //Modem Configuration c1101_spi_write_register(SPIC1101_ADDR_MDMCFG3,0x43); //Modem Configuration c1101_spi_write_register(SPIC1101_ADDR_MDMCFG2,0x30); //Modem Configuration c1101_spi_write_register(SPIC1101_ADDR_MDMCFG1,0x00); //Modem Configuration c1101_spi_write_register(SPIC1101_ADDR_DEVIATN,0x07); //Modem Deviation Setting c1101_spi_write_register(SPIC1101_ADDR_MCSM0,0x18); //Main Radio Control State Machine Configuration c1101_spi_write_register(SPIC1101_ADDR_FOCCFG,0x16); //Frequency Offset Compensation Configuration c1101_spi_write_register(SPIC1101_ADDR_WORCTRL,0xFB); //Wake On Radio Control c1101_spi_write_register(SPIC1101_ADDR_FREND0,0x11); //Front End TX Configuration // PA_POWER[2:0] = 1 c1101_spi_write_register(SPIC1101_ADDR_FSCAL3,0xE9); //Frequency Synthesizer Calibration c1101_spi_write_register(SPIC1101_ADDR_FSCAL2,0x2A); //Frequency Synthesizer Calibration c1101_spi_write_register(SPIC1101_ADDR_FSCAL1,0x00); //Frequency Synthesizer Calibration c1101_spi_write_register(SPIC1101_ADDR_FSCAL0,0x1F); //Frequency Synthesizer Calibration c1101_ook_power_set(ook_power_); hhd70_config_GDO0_OOK_output(true); } uint8_t c1101_ook_power_get() { return ook_power_; } uint8_t c1101_ook_power_get_raw() { return pa_table_values_[ook_power_]; } void c1101_ook_power_set(uint8_t power) { uint8_t val = pa_table_values_[(power <= PA_TABLE_VALUES_MAX) ? power : PA_TABLE_VALUES_MAX]; uint8_t const pa_table[8] = {0x00, val ,0x00,0x00,0x00,0x00,0x00,0x00}; c1101_spi_write_patable(pa_table); } void c1101_ook_power_inc() { ook_power_ = (ook_power_ < PA_TABLE_VALUES_MAX) ? ook_power_ + 1 : PA_TABLE_VALUES_MAX; uint8_t const pa_table[8] = {0x00, pa_table_values_[ook_power_] ,0x00,0x00,0x00,0x00,0x00,0x00}; c1101_spi_write_patable(pa_table); } void c1101_ook_power_dec() { ook_power_ = (ook_power_ > 0) ? ook_power_ - 1 : 0; uint8_t const pa_table[8] = {0x00, pa_table_values_[ook_power_] ,0x00,0x00,0x00,0x00,0x00,0x00}; c1101_spi_write_patable(pa_table); } // see Datasheet Chapter 14.1 Frequency Offset Compensation // freq_offset: desired frequency offset [Hz] *2^14 / f_XTAL //f_XTAL = 26Mhz void c1101_permanently_save_current_rx_tx_freqoffset_auto_compensation() { int16_t freq_offset; freq_offset = c1101_spi_read_register(SPIC1101_ADDR_FREQUEST); if (freq_offset >= 0) { c1101_spi_write_register(SPIC1101_ADDR_FSCTRL0, (uint8_t) freq_offset); } } // WARNING: All content of the PATABLE except for the first byte (index 0) is lost when entering the SLEEP state. char c1101_putToSleep(void) { return c1101_spi_strobe_command(SPIC1101_ADDR_SPWD); } uint16_t c1101_measureTemp(void) { uint16_t temp; char ptest_value=0x7F; ptest_value = c1101_spi_read_register(SPIC1101_ADDR_PTEST); c1101_spi_write_register(SPIC1101_ADDR_PTEST, 0xBF); _delay_ms(5); temp = adc_read(ADCMUX_INTERNALTEMP); c1101_spi_write_register(SPIC1101_ADDR_PTEST, ptest_value); return temp; } void c1101_handleMARCStatusByte(char sb) { //on RXFifo Overflow, Flush RX Fifo if (sb == 0x11) { c1101_spi_strobe_command(SPIC1101_ADDR_SFRX); printf("RX fifo flushed\r\n"); } //on TXFifo Overflow, Flush TX Fifo else if (sb == 0x16) { c1101_spi_strobe_command(SPIC1101_ADDR_SFTX); printf("TX fifo flushed\r\n"); } } void c1101_handleStatusByte(char sb) { //on RXFifo Overflow, Flush RX Fifo if (SPIC1101_SB_RXFIFO_OVERFLOW(sb)) { c1101_spi_strobe_command(SPIC1101_ADDR_SFRX); printf("RX fifo flushed\r\n"); } //on TXFifo Overflow, Flush TX Fifo if (SPIC1101_SB_TXFIFO_OVERFLOW(sb)) { c1101_spi_strobe_command(SPIC1101_ADDR_SFTX); printf("TX fifo flushed\r\n"); } } char c1101_getStatus(void) { char sb=0; hhd70_spi_cs_enable(); hhd70_c1101_wait_chip_rdy(); sb = c1101_spi_write_byte_ok_get_status(SPIC1101_ADDR_SNOP); hhd70_spi_cs_disable(); c1101_handleStatusByte(sb); return sb; } char c1101_getMARCState(void) { char sb=0; sb = c1101_spi_read_register(SPIC1101_ADDR_MARCSTATE); sb &= 0x1F; //debug start /* char debug_sb[6]; */ /* printf("c1101 MARCState:\r\n"); */ /* debug_sprint_int16hex(debug_sb, sb); */ /* printf("%s", debug_sb); */ /* printf("\r\n"); */ //debug end return sb; } uint8_t c1101_getNumBytesInTXFifo(void) { return c1101_spi_read_register(SPIC1101_ADDR_TXBYTES); } //true if IDLE state reached before timeout [ms] bool c1101_waitUntilIDLEState(uint16_t timeout_ms) { uint8_t sb; for (uint16_t c = 0; c < timeout_ms; c++) { sb = c1101_getStatus(); if (SPIC1101_SB_IDLE(sb)) return true; _delay_ms(1); } return false; } //wait until C1101 left TX State bool c1101_waitUntilTXFinished(uint16_t timeout_ms) { uint8_t c1101_state; for (uint16_t c = 0; c < timeout_ms; c++) { c1101_state = c1101_getMARCState(); c1101_handleMARCStatusByte(c1101_state); _delay_ms(1); if (! (c1101_state == 19 || c1101_state == 20)) return true; } return false; } //wait until in IDLE or RX State: bool c1101_waitUntilIDLEorRXState(uint16_t timeout_ms) { uint8_t c1101_state; for (uint16_t c = 0; c < timeout_ms; c++) { c1101_state = c1101_getMARCState(); c1101_handleMARCStatusByte(c1101_state); _delay_ms(1); if (c1101_state == 1 || (c1101_state >= 13 && c1101_state <= 15)) return true; } return false; } bool c1101_writeFrequencyRegisters(uint32_t freq) { if (! c1101_waitUntilIDLEState(2000)) //wait 2sec max return false; //programm frequency c1101_spi_write_register(SPIC1101_ADDR_FREQ0, freq & 0xFF); c1101_spi_write_register(SPIC1101_ADDR_FREQ1, (freq >> 8) & 0xFF); c1101_spi_write_register(SPIC1101_ADDR_FREQ2, (freq >> 16) & 0x3F); //set channel 0 c1101_spi_write_register(SPIC1101_ADDR_CHANNR, 0); return true; } uint32_t c1101_readFrequencyRegisters(void) { uint32_t freq = 0; freq = ((uint8_t) c1101_spi_read_register(SPIC1101_ADDR_FREQ2)) & 0x3F; freq = freq << 8; freq |= ((uint8_t) c1101_spi_read_register(SPIC1101_ADDR_FREQ1)); freq = freq << 8; freq |= ((uint8_t) c1101_spi_read_register(SPIC1101_ADDR_FREQ0)); return freq; } //f_XOSC = 26Mhz // freq: desired_carrier_freq [Hz] *2^16 / f_XOSC bool c1101_setFrequency(uint32_t freq_hz) { uint32_t freq = (uint32_t)((float)freq_hz / C1101_FREQ_TO_HZ); if ( freq <= 0x3FFFFF) return c1101_writeFrequencyRegisters(freq); else return false; } //f_XOSC = 26Mhz // freq: desired_carrier_freq [Hz] *2^16 / f_XOSC bool c1101_changeFrequencyByRelativeValue(int32_t freq_change_hz) { int32_t freq_change = (int32_t)((float)freq_change_hz / C1101_FREQ_TO_HZ); int32_t freq = (int32_t) c1101_readFrequencyRegisters(); freq += freq_change; if ( freq >= 0 && freq <= 0x3FFFFF ) return c1101_writeFrequencyRegisters((uint32_t) freq); else return false; } uint32_t c1101_getCurrentCarrierFrequencyHz(void) { return (uint32_t)((float)c1101_readFrequencyRegisters() * C1101_FREQ_TO_HZ); } // if_freq: desired intermidiate rx frequency [Hz] *2^10 / f_XOSC bool c1101_setIFFrequency(uint32_t freq_hz) { uint8_t if_freq = freq_hz / 25391; //make sure we are in idle mode if (! c1101_waitUntilIDLEState(2000)) //wait 2sec max return false; c1101_spi_write_register(SPIC1101_ADDR_FSCTRL1, if_freq & 0x1F); return true; } bool c1101_transmitData(char *buffer, uint8_t len) { //~ uint8_t debug_sb[6]; uint8_t num_written = 0; bool success = true; //~ uint8_t mcsm1 = c1101_spi_read_register(SPIC1101_ADDR_MCSM1); //~ //configure state machine to automatically go to IDLE, once packet was transmitted //~ mcsm1 = (mcsm1 & 0b11111100) | 0b00; //~ c1101_spi_write_register(SPIC1101_ADDR_MCSM1, 0x18); //~ c1101_spi_write_register(SPIC1101_ADDR_PKTCTRL0, 0b0000000001); //crc disabled; use FIFOs; variable packet length mode (first TX FIFO byte must be length) // flush TX FIFO c1101_spi_strobe_command(SPIC1101_ADDR_SFTX); //~ //fill buffer //~ num_written = c1101_spi_write_txfifo(buffer, len); //~ buffer += num_written; //~ len -= num_written; //~ ((uint8_t*)"TX num written",255); //~ debug_sprint_int16hex(debug_sb, num_written); //~ (debug_sb,255); //~ ((uint8_t*)"TX len",255); //~ debug_sprint_int16hex(debug_sb, len); //~ (debug_sb,255); //~ c1101_getStatus(); //~ ((uint8_t*)"TX bytes",255); //~ debug_sprint_int16hex(debug_sb, c1101_getNumBytesInTXFifo()); //~ (debug_sb,255); //start transmitting //num_written = c1101_spi_strobe_command(SPIC1101_ADDR_STX); //~ num_written = hhd70_spi_exchange_byte(SPIC1101_ADDR_STX); //~ ((uint8_t*)"Strobe STX",255); //~ debug_sprint_int16hex(debug_sb, num_written); //~ (debug_sb,255); //enable Power Amplifier hhd70_palna_txmode(); //should actually be done by c1101 itself, by connecting PTT function of GPO0 pin to LNA/PA toggle //keep buffer filled do { c1101_getStatus(); num_written = c1101_spi_write_txfifo(buffer, len ); buffer += num_written; len -= num_written; //wait until in IDLE or RX State: if (! c1101_waitUntilIDLEorRXState(10000)) //wait for max 10s { success = false; goto c1101_transmitData_cleanup; } //from state IDLE or RX go to TX num_written = c1101_spi_strobe_command(SPIC1101_ADDR_STX); //~ ((uint8_t*)"TX2 num written",255); //~ debug_sprint_int16hex(debug_sb, num_written); //~ (debug_sb,255); //~ ((uint8_t*)"TX2 len",255); //~ debug_sprint_int16hex(debug_sb, len); //~ (debug_sb,255); //~ ((uint8_t*)"TX2 bytes",255); //~ debug_sprint_int16hex(debug_sb, c1101_getNumBytesInTXFifo()); //~ (debug_sb,255); } while (len > 0); //wait until TX finished if (!c1101_waitUntilTXFinished(10000)) //wait 10s max, then just shut down PA { success = false; goto c1101_transmitData_cleanup; } c1101_transmitData_cleanup: //disable Power Amplifier //FIXME, instead use PTT function of GPO0 -> interrupt handler -> toggle rx/tx hhd70_palna_rxmode(); return success; } void c1101_transmitData_infPktMode(char *buffer, uint8_t len) { //in infinite Packet Mode, prepend length to buffer: char *new_buffer = malloc(len+1); new_buffer[0] = len; memcpy(new_buffer+1, buffer, len); //variable packet length: write length of packet to TX FIFO: c1101_transmitData(new_buffer, len+1); free(new_buffer); } void c1101_recieveData(void) { uint8_t const max_len=255; char recv_data[256]; uint8_t num_recv = 0; uint8_t num_recv_total = 0; uint8_t num_leave_in_fifo = 1; do { num_recv = c1101_spi_read_rxfifo( num_leave_in_fifo, recv_data+num_recv_total, max_len - num_recv_total); num_recv_total += num_recv; //variable packet length: //don't read last byte in fifo unless packet has finished receiving num_leave_in_fifo = (recv_data[0] - num_recv_total < 64)? 0 : 1; } while (num_recv > 0); recv_data[num_recv_total]=0; printf("RX: Data Recieved: "); printf("%s", recv_data); printf("\r\n"); c1101_getStatus(); // get status and handle possiblble RX Fifo Overflow } //max returned: 64 bytes int c1101_readRXFifo(char *buffer) { //check RXBYTES.NUM_RXBYTES // never read more bytes than avaiblabe or we will read garbage //note: if RX transmission fills fifo buffer at exact same time as last RX Fifo Bit is read via SPI, Fifo Pointer will not be properly updated // and last read byte will be duplicated. // thus: don't last avialable FIFO Bytes unless we can be sure that it will be the last byte of a packet and we can be sure that a following duplicated byte is actually an Fifo duplication and not an actually recieved byte ! return 0; }