static void CORONA_rf_init() { CC2500_Strobe(CC2500_SIDLE); for (u8 i = 0; i <= 0x2E; ++i) CC2500_WriteReg(i, CORONA_init_values[i]); CC2500_Strobe(CC2500_SCAL); // just duplicating stock tx CC2500_ReadReg(CC2500_25_FSCAL1); // just duplicating stock tx if (Model.proto_opts[PROTO_OPTS_FORMAT] == FORMAT_V2) { CC2500_WriteReg(CC2500_0A_CHANNR, CORONA_BIND_CHANNEL_V2); CC2500_WriteReg(CC2500_0E_FREQ1, 0x80); CC2500_WriteReg(CC2500_0F_FREQ0, 0x00); CC2500_WriteReg(CC2500_15_DEVIATN, 0x50); CC2500_WriteReg(CC2500_17_MCSM1, 0x00); CC2500_WriteReg(CC2500_1B_AGCCTRL2, 0x67); CC2500_WriteReg(CC2500_1C_AGCCTRL1, 0xFB); CC2500_WriteReg(CC2500_1D_AGCCTRL0, 0xDC); } else if (Model.proto_opts[PROTO_OPTS_FORMAT] == FORMAT_FDV3) { // Flydream receiver captures have deviation 50, tx captures show 47 CC2500_WriteReg(CC2500_15_DEVIATN, 0x50); } CC2500_WriteReg(CC2500_0C_FSCTRL0, Model.proto_opts[PROTO_OPTS_FREQFINE]); CC2500_SetTxRxMode(TX_EN); CC2500_SetPower(0); // min power for binding, set in build_packet for normal operation }
uint8_t frsky_d8_rx_getpkt(void) { uint8_t ret = 0; if (HAL_GPIO_ReadPin(CC2500_GD0_GPIO, CC2500_GD0_PIN) == GPIO_PIN_SET) { // note: can't read this while the packet is still being received. // HAL_Delay(1); // but this is just silly. CC2500_Strobe(CC2500_STROBE_SIDLE); volatile uint8_t rx_packet_length = CC2500_ReadReg(CC2500_REG_RXBYTES | CC2500_READ_BURST); if ((rx_packet_length > 7) && (rx_packet_length < D8_MAX_PACKET_SIZE)) // TODO: fix this to detect pktlen from bindmode { CC2500_ReadRXData(rxmsg.packet, rx_packet_length); if ((rxmsg.d8_rx_packet_data.header_bindcode == m_config.frsky_d8_bind_info.bind_id) && (rxmsg.d8_rx_packet_data.len == 0x11)) /* So, there's two bytes in the packet header that indicate something. * 0x0100 - North American launch day taranis A * - DJT jr module * 0x0300 - XJT jr module * There are others out there which are unknown, so this check is removed for now. * Also, there's a CRC or something at the end. But it isn't. 0xA0 bits will always match it. */ ret = rx_packet_length; } CC2500_Strobe(CC2500_STROBE_SFRX); } return ret; }
int CC2500_Reset() { CC2500_Strobe(CC2500_SRES); usleep(1000); CC2500_SetTxRxMode(TXRX_OFF); return CC2500_ReadReg(CC2500_0E_FREQ1) == 0xC4; }
void frsky_d8_rx_loop(void) { // TODO: disable LNA on high power rxing // TODO: rssi injection (and settings) //36ms loop. rx 3 times every 9ms. then ~2ms, then tx a packet (~6ms?). then wait for next packet, continue cycle. static uint8_t frsky_state = FRSKY_RX1; // can be derived from counter static uint8_t hopchan = 0; // can be derived from counter static uint8_t rx_state = STATE_WILL_RX; static uint8_t fail_state = STATE_SEARCH; static uint32_t lastPktTime = 0; // time last packet was received, used mainly for failasfe. static uint32_t nextPktTime = 200; // time of next expected incoming packet. default: approx. 200ms startup time, to not f**k shit up, this is still hacky and shitty tho static uint32_t lastHopTime = 0; // time of last hop, normally every 9ms, in searchmode every 45ms. telem txing places this in the middle of its packet frame for simplicity static uint32_t txStartTime = 0; // time when the tx packet should start, usually 2ms after an RX3 was received. static uint8_t gotFirstPkt = 0; static uint32_t failsafeBtnTime = 0; static uint8_t failsafeBtnSettingStatus = 0; uint32_t time = HAL_GetTick(); uint8_t freqoff_est; if (m_config.frsky_d8_bind_info.bind_type == BIND_TYPE_NONE) { /* do nothing if not bound. */ return; } switch (rx_state) { case STATE_WILL_RX: frsky_rx_enable(hopchan); rx_state = STATE_RXING; break; /* end STATE_WILL_RX */ case STATE_RXING: if (frsky_d8_rx_getpkt() != 0) { rx_state = STATE_RXD; break; } switch (fail_state) { case STATE_RUNNING: /* If we expected a packet and didn't get it, take action after a timeout. */ if (time > (nextPktTime + 2)) { /* Here we 'emulate' a packet RXing in order to prepare for the next action. */ /* lastHopTime is updated to the time the packet should have been received, which is the current nextPktTime. */ /* nextPktTime is updated to reflect the next anticipated packet, in 9 or 18ms. */ /* lastPktTime is untouched, as no real RXing was done. */ hopchan = (hopchan + 1) % D8_NUM_HOP_CHANNELS; frsky_state = (frsky_state + 1) % NUM_FRSKY_STATES; frsky_rx_toggle_ant(); lastHopTime = nextPktTime; if (frsky_state == FRSKY_TX_TELEM) { nextPktTime = nextPktTime + 18; rx_state = STATE_PREPARE_TX; } else { nextPktTime = nextPktTime + 9; rx_state = STATE_WILL_RX; } } /* if it has been a long time since the last valid packet, go to a different hop sequence in an attempt to find the tx's hop phase. */ /* TODO: make this timeout configurable, maybe */ if (time > (lastPktTime + 1000)) fail_state = STATE_SEARCH; break; /* end STATE_RUNNING */ case STATE_SEARCH: HAL_GPIO_WritePin(LED_RED_GPIO, LED_RED_PIN, LED_RED_STATE_ON); if (gotFirstPkt > 1) HAL_GPIO_WritePin(LED_GREEN_GPIO, LED_GREEN_PIN, LED_GREEN_STATE_OFF); /* hop every 45ms while looking for packets */ if (time > (lastHopTime + 45)) { hopchan = (hopchan + 1) % D8_NUM_HOP_CHANNELS; /* TODO: allow TXing while in failsafe. maybe? */ frsky_state = FRSKY_RX1; lastHopTime = HAL_GetTick(); frsky_rx_toggle_ant(); rx_state = STATE_WILL_RX; } break; /* end STATE_SEARCH */ } break; /* end STATE_RXING */ case STATE_RXD: /* lastPktTime and lastHopTime are both updated with the current time. */ /* nextPktTime is updated to reflect the next anticipated packet, in 9 or 18ms. */ lastPktTime = time; lastHopTime = time; hopchan = (rxmsg.packet[3] + 1) % D8_NUM_HOP_CHANNELS; frsky_state = (rxmsg.packet[3] + 1) % NUM_FRSKY_STATES; // sets up the next state fail_state = STATE_RUNNING; failsafeStatus = 0; HAL_GPIO_WritePin(LED_RED_GPIO, LED_RED_PIN, LED_RED_STATE_OFF); HAL_GPIO_WritePin(LED_GREEN_GPIO, LED_GREEN_PIN, LED_GREEN_STATE_ON); frsky_rx_toggle_ant(); frsky_rx_process_channels(); /* Read and process rssi. Do this after channels! */ rssi = CC2500_ReadReg(CC2500_REG_RSSI); // rssidbm = frsky_getrssidbm(rssi); if(rssichan != -1) { /* turn 0-255 into 988-2012 */ channelValues[rssichan] = ((uint16_t)rssi * 4) + 988; // TODO: fix ranges } /* read frequency drift estimation and write this value back to the cc2500 offset register. */ freqoff_est = CC2500_ReadReg(CC2500_REG_FREQEST); CC2500_WriteReg(CC2500_REG_FSCTRL0, freqoff_est); /* nextPktTime is the expected time of the next incoming packet * it is either 9ms or 18ms depending on if there is telem txing this cycle. */ if (frsky_state == FRSKY_TX_TELEM) { nextPktTime = lastPktTime + 18; rx_state = STATE_PREPARE_TX; } else { nextPktTime = lastPktTime + 9; rx_state = STATE_WILL_RX; } if (gotFirstPkt == 0) gotFirstPkt = 1; break; /* end STATE_RXD */ case STATE_PREPARE_TX: frsky2way_d8_build_telem_packet(); frsky_set_hopchan(hopchan); txStartTime = lastHopTime + 2; // set up time to activate txing. lastHopTime = lastHopTime + 9; // not actually lasthoptime, but keeps 9ms interval for simplicity. rx_state = STATE_WILL_TX; break; /* end STATE_PREPARE_TX */ case STATE_WILL_TX: /* TODO: disable-able telem txing in config. why? cuz. */ if (time > txStartTime) { CC2500_WriteTXData(txmsg.packet, txmsg.packet[0]+1); rx_state = STATE_TXING; } break; /* end STATE_WILL_TX */ case STATE_TXING: if (time > (txStartTime + 8)) // need to give enough time to tx entire packet. rx_state = STATE_TXD; break; /* end STATE_TXING */ case STATE_TXD: hopchan = (hopchan + 1) % D8_NUM_HOP_CHANNELS; frsky_state = FRSKY_RX1; rx_state = STATE_WILL_RX; break; /* end STATE_TXD */ default: rx_state = STATE_SEARCH; break; } /* end rx_state switch statement */ /* stuff to do once after first packet RXd, is there anything? TODO: */ if (gotFirstPkt == 1) { gotFirstPkt = 2; } /* detect and handle failsafe condition */ if ((gotFirstPkt >= 1) & ((time - lastPktTime) > m_config.failsafeDelay) & (failsafeStatus == 0)) { failsafeStatus = 1; uint8_t failtype; if (m_config.failsafeType == FAILSAFE_AUTODETECT) { if (m_config.failsafeValues[0] == 0) // failsafe values have not been set. failtype = FAILSAFE_STOPOUTPUT; else failtype = FAILSAFE_SAVEDVALUES; } else { failtype = m_config.failsafeType; } switch (failtype) { default: case FAILSAFE_STOPOUTPUT: output_handle_functions.outputStop(); break; case FAILSAFE_SAVEDVALUES: for (uint8_t i = 0; i < MAX_CHANNEL_OUTPUTS; i++) { channelValues[i] = m_config.failsafeValues[i]; } if(rssichan != -1) { channelValues[rssichan] = 988; // TODO: fix ranges } output_handle_functions.outputUpdate(); break; } } /* failsafe button handler */ /* we have a packet, we're not in failsafe, and we haven't already set failsafes this btnpress. */ if ((gotFirstPkt >= 1) & (failsafeStatus == 0) & (failsafeBtnSettingStatus == 0)) { if ((HAL_GPIO_ReadPin(BIND_FAIL_BUTTON_GPIO, BIND_FAIL_BUTTON_PIN) == GPIO_PIN_RESET) & (failsafeBtnTime == 0)) // pin is NO and pulled high { failsafeBtnTime = time; } else if ((HAL_GPIO_ReadPin(BIND_FAIL_BUTTON_GPIO, BIND_FAIL_BUTTON_PIN) == GPIO_PIN_RESET) & ((time - failsafeBtnTime) > 2000)) { HAL_GPIO_WritePin(LED_RED_GPIO, LED_RED_PIN, LED_RED_STATE_ON); failsafeBtnSettingStatus = 1; for (uint8_t i = 0; i < MAX_CHANNEL_OUTPUTS; i++) { m_config.failsafeValues[i] = channelValues[i]; } eeprom_write(); HAL_Delay(1000); HAL_GPIO_WritePin(LED_RED_GPIO, LED_RED_PIN, LED_RED_STATE_OFF); } } /* Reset failsafe button timer if button is released */ if (HAL_GPIO_ReadPin(BIND_FAIL_BUTTON_GPIO, BIND_FAIL_BUTTON_PIN) == GPIO_PIN_SET) { failsafeBtnTime = 0; failsafeBtnSettingStatus = 0; } }