460 lines
11 KiB
Arduino
Raw Normal View History

2015-12-30 01:41:12 +01:00
/*
This project 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
(at your option) any later version.
Multiprotocol 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 Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
*/
#if defined(DEVO_CYRF6936_INO)
#include "iface_cyrf6936.h"
//For Debug
//#define NO_SCRAMBLE
2016-08-25 13:42:21 +02:00
#define DEVO_PKTS_PER_CHANNEL 4
#define DEVO_BIND_COUNT 0x1388
#define DEVO_NUM_WAIT_LOOPS (100 / 5) //each loop is ~5us. Do not wait more than 100us
enum {
2015-12-30 01:41:12 +01:00
DEVO_BIND,
DEVO_BIND_SENDCH,
DEVO_BOUND,
DEVO_BOUND_1,
DEVO_BOUND_2,
DEVO_BOUND_3,
DEVO_BOUND_4,
DEVO_BOUND_5,
DEVO_BOUND_6,
DEVO_BOUND_7,
DEVO_BOUND_8,
DEVO_BOUND_9,
DEVO_BOUND_10,
};
2016-08-25 13:42:21 +02:00
static void __attribute__((unused)) DEVO_scramble_pkt()
2015-12-30 01:41:12 +01:00
{
#ifdef NO_SCRAMBLE
return;
#else
2016-08-25 13:42:21 +02:00
for(uint8_t i = 0; i < 15; i++)
2015-12-30 01:41:12 +01:00
packet[i + 1] ^= cyrfmfg_id[i % 4];
#endif
}
2016-08-25 13:42:21 +02:00
static void __attribute__((unused)) DEVO_add_pkt_suffix()
2015-12-30 01:41:12 +01:00
{
2016-08-25 13:42:21 +02:00
uint8_t bind_state;
2016-08-26 18:33:05 +02:00
#ifdef ENABLE_PPM
if(mode_select && option==0 && IS_BIND_DONE) //PPM mode and option not already set and bind is finished
2016-08-26 18:33:05 +02:00
{
BIND_SET_INPUT;
BIND_SET_PULLUP; // set pullup
if(IS_BIND_BUTTON_on)
{
eeprom_write_byte((EE_ADDR)(MODELMODE_EEPROM_OFFSET+RX_num),0x01); // Set fixed id mode for the current model
2016-08-26 18:33:05 +02:00
option=1;
}
BIND_SET_OUTPUT;
}
#endif //ENABLE_PPM
if(prev_option!=option && IS_BIND_DONE)
2016-08-25 14:48:48 +02:00
{
MProtocol_id = RX_num + MProtocol_id_master;
bind_counter=DEVO_BIND_COUNT;
}
if (option)
2015-12-30 01:41:12 +01:00
{
2016-08-25 13:42:21 +02:00
if (bind_counter > 0)
bind_state = 0xc0;
else
bind_state = 0x80;
}
2015-12-30 01:41:12 +01:00
else
2016-08-25 13:42:21 +02:00
bind_state = 0x00;
packet[10] = bind_state | (DEVO_PKTS_PER_CHANNEL - packet_count - 1);
2015-12-30 01:41:12 +01:00
packet[11] = *(hopping_frequency_ptr + 1);
packet[12] = *(hopping_frequency_ptr + 2);
2016-08-25 14:48:48 +02:00
packet[13] = MProtocol_id & 0xff;
packet[14] = (MProtocol_id >> 8) & 0xff;
packet[15] = (MProtocol_id >> 16) & 0xff;
2015-12-30 01:41:12 +01:00
}
2016-08-25 13:42:21 +02:00
static void __attribute__((unused)) DEVO_build_beacon_pkt(uint8_t upper)
2015-12-30 01:41:12 +01:00
{
2019-06-23 17:13:30 +02:00
packet[0] = (num_ch << 4) | 0x07;
uint8_t max = 8, offset = 0, enable = 0;
2015-12-30 01:41:12 +01:00
if (upper)
{
packet[0] += 1;
max = 4;
offset = 8;
2015-12-30 01:41:12 +01:00
}
for(uint8_t i = 0; i < max; i++)
{
#ifdef FAILSAFE_ENABLE
uint16_t failsafe=Failsafe_data[CH_EATR[i+offset]];
2019-06-23 17:13:30 +02:00
if(i + offset < num_ch && failsafe!=FAILSAFE_CHANNEL_HOLD && IS_FAILSAFE_VALUES_on)
{
enable |= 0x80 >> i;
packet[i+1] = ((failsafe*25)>>8)-100;
}
else
#else
(void)offset;
#endif
packet[i+1] = 0;
}
packet[9] = enable;
2016-08-25 13:42:21 +02:00
DEVO_add_pkt_suffix();
2015-12-30 01:41:12 +01:00
}
2016-08-25 13:42:21 +02:00
static void __attribute__((unused)) DEVO_build_bind_pkt()
2015-12-30 01:41:12 +01:00
{
2019-06-23 17:13:30 +02:00
packet[0] = (num_ch << 4) | 0x0a;
2016-08-25 13:42:21 +02:00
packet[1] = bind_counter & 0xff;
packet[2] = (bind_counter >> 8);
packet[3] = *hopping_frequency_ptr;
packet[4] = *(hopping_frequency_ptr + 1);
packet[5] = *(hopping_frequency_ptr + 2);
packet[6] = cyrfmfg_id[0];
packet[7] = cyrfmfg_id[1];
packet[8] = cyrfmfg_id[2];
packet[9] = cyrfmfg_id[3];
DEVO_add_pkt_suffix();
2015-12-30 01:41:12 +01:00
//The fixed-id portion is scrambled in the bind packet
//I assume it is ignored
2016-08-25 13:42:21 +02:00
packet[13] ^= cyrfmfg_id[0];
packet[14] ^= cyrfmfg_id[1];
packet[15] ^= cyrfmfg_id[2];
2015-12-30 01:41:12 +01:00
}
2016-08-25 13:42:21 +02:00
static void __attribute__((unused)) DEVO_build_data_pkt()
2015-12-30 01:41:12 +01:00
{
2016-08-25 13:42:21 +02:00
static uint8_t ch_idx=0;
2019-06-23 17:13:30 +02:00
packet[0] = (num_ch << 4) | (0x0b + ch_idx);
2015-12-30 01:41:12 +01:00
uint8_t sign = 0x0b;
2016-08-25 13:42:21 +02:00
for (uint8_t i = 0; i < 4; i++)
2015-12-30 01:41:12 +01:00
{
int16_t value=convert_channel_16b_nolimit(CH_EATR[ch_idx * 4 + i],-1600,1600,false);//range -1600..+1600
2015-12-30 01:41:12 +01:00
if(value < 0)
{
value = -value;
sign |= 1 << (7 - i);
}
packet[2 * i + 1] = value & 0xff;
packet[2 * i + 2] = (value >> 8) & 0xff;
}
packet[9] = sign;
2016-08-25 13:42:21 +02:00
ch_idx++;
2019-06-23 17:13:30 +02:00
if (ch_idx * 4 >= num_ch)
2015-12-30 01:41:12 +01:00
ch_idx = 0;
2016-08-25 13:42:21 +02:00
DEVO_add_pkt_suffix();
2015-12-30 01:41:12 +01:00
}
#if defined DEVO_HUB_TELEMETRY
2020-05-09 16:11:10 +02:00
static void __attribute__((unused)) DEVO_parse_telemetry_packet()
{
DEVO_scramble_pkt(); //This will unscramble the packet
debugln("RX");
if ((((uint32_t)packet[15] << 16) | ((uint32_t)packet[14] << 8) | packet[13]) != (MProtocol_id & 0x00ffffff))
return; // ID does not match
//RSSI
TX_RSSI = CYRF_ReadRegister(CYRF_13_RSSI) & 0x1F;
TX_RSSI = (TX_RSSI << 1) + TX_RSSI;
RX_RSSI = TX_RSSI;
telemetry_link = 1;
//TODO: FW telemetry https://github.com/DeviationTX/deviation/blob/5efb6a28bea697af9a61b5a0ed2528cc8d203f90/src/protocol/devo_cyrf6936.c#L232
debug("P[0]=%02X",packet[0]);
if (packet[0] == 0x30) // Volt packet
{
v_lipo1 = packet[1] << 1;
v_lipo2 = packet[3] << 1;
}
}
#endif
2020-05-09 16:11:10 +02:00
2016-08-25 13:42:21 +02:00
static void __attribute__((unused)) DEVO_cyrf_set_bound_sop_code()
2015-12-30 01:41:12 +01:00
{
/* crc == 0 isn't allowed, so use 1 if the math results in 0 */
uint8_t crc = (cyrfmfg_id[0] + (cyrfmfg_id[1] >> 6) + cyrfmfg_id[2]);
if(! crc)
crc = 1;
uint8_t sopidx = (0xff &((cyrfmfg_id[0] << 2) + cyrfmfg_id[1] + cyrfmfg_id[2])) % 10;
CYRF_SetTxRxMode(TX_EN);
CYRF_ConfigCRCSeed((crc << 8) + crc);
2016-09-04 16:47:34 +02:00
CYRF_PROGMEM_ConfigSOPCode(DEVO_j6pro_sopcodes[sopidx]);
2015-12-30 01:41:12 +01:00
CYRF_SetPower(0x08);
}
2016-08-25 13:42:21 +02:00
const uint8_t PROGMEM DEVO_init_vals[][2] = {
{ CYRF_1D_MODE_OVERRIDE, 0x38 },
{ CYRF_03_TX_CFG, 0x08 },
{ CYRF_06_RX_CFG, 0x4A },
{ CYRF_0B_PWR_CTRL, 0x00 },
{ CYRF_10_FRAMING_CFG, 0xA4 },
{ CYRF_11_DATA32_THOLD, 0x05 },
{ CYRF_12_DATA64_THOLD, 0x0E },
{ CYRF_1B_TX_OFFSET_LSB, 0x55 },
{ CYRF_1C_TX_OFFSET_MSB, 0x05 },
{ CYRF_32_AUTO_CAL_TIME, 0x3C },
{ CYRF_35_AUTOCAL_OFFSET, 0x14 },
{ CYRF_39_ANALOG_CTRL, 0x01 },
{ CYRF_1E_RX_OVERRIDE, 0x10 },
{ CYRF_1F_TX_OVERRIDE, 0x00 },
{ CYRF_01_TX_LENGTH, 0x10 },
{ CYRF_0F_XACT_CFG, 0x10 },
{ CYRF_27_CLK_OVERRIDE, 0x02 },
{ CYRF_28_CLK_EN, 0x02 },
{ CYRF_0F_XACT_CFG, 0x28 }
2016-08-15 11:52:43 +02:00
};
2016-08-25 13:42:21 +02:00
static void __attribute__((unused)) DEVO_cyrf_init()
2015-12-30 01:41:12 +01:00
{
/* Initialise CYRF chip */
2016-08-25 13:42:21 +02:00
for(uint8_t i = 0; i < sizeof(DEVO_init_vals) / 2; i++)
CYRF_WriteRegister(pgm_read_byte( &DEVO_init_vals[i][0]), pgm_read_byte( &DEVO_init_vals[i][1]) );
2015-12-30 01:41:12 +01:00
}
2016-08-25 13:42:21 +02:00
static void __attribute__((unused)) DEVO_set_radio_channels()
2015-12-30 01:41:12 +01:00
{
CYRF_FindBestChannels(hopping_frequency, 3, 4, 4, 80);
hopping_frequency[3] = hopping_frequency[0];
hopping_frequency[4] = hopping_frequency[1];
}
static void __attribute__((unused)) DEVO_BuildPacket()
2015-12-30 01:41:12 +01:00
{
2016-08-25 13:42:21 +02:00
static uint8_t failsafe_pkt=0;
2015-12-30 01:41:12 +01:00
switch(phase)
{
case DEVO_BIND:
2016-08-25 13:42:21 +02:00
if(bind_counter)
2015-12-30 01:41:12 +01:00
bind_counter--;
2016-08-25 13:42:21 +02:00
DEVO_build_bind_pkt();
2015-12-30 01:41:12 +01:00
phase = DEVO_BIND_SENDCH;
break;
case DEVO_BIND_SENDCH:
2016-08-25 13:42:21 +02:00
if(bind_counter)
2015-12-30 01:41:12 +01:00
bind_counter--;
2016-08-25 13:42:21 +02:00
DEVO_build_data_pkt();
DEVO_scramble_pkt();
2015-12-30 01:41:12 +01:00
if (bind_counter == 0)
{
phase = DEVO_BOUND;
BIND_DONE;
}
else
phase = DEVO_BIND;
break;
case DEVO_BOUND:
case DEVO_BOUND_1:
case DEVO_BOUND_2:
case DEVO_BOUND_3:
case DEVO_BOUND_4:
case DEVO_BOUND_5:
case DEVO_BOUND_6:
case DEVO_BOUND_7:
case DEVO_BOUND_8:
case DEVO_BOUND_9:
2016-08-25 13:42:21 +02:00
DEVO_build_data_pkt();
DEVO_scramble_pkt();
2015-12-30 01:41:12 +01:00
phase++;
2016-08-25 13:42:21 +02:00
if (bind_counter)
2015-12-30 01:41:12 +01:00
{
bind_counter--;
if (bind_counter == 0)
BIND_DONE;
}
break;
case DEVO_BOUND_10:
2019-06-23 17:13:30 +02:00
DEVO_build_beacon_pkt(num_ch > 8 ? failsafe_pkt : 0);
2015-12-30 01:41:12 +01:00
failsafe_pkt = failsafe_pkt ? 0 : 1;
2016-08-25 13:42:21 +02:00
DEVO_scramble_pkt();
2015-12-30 01:41:12 +01:00
phase = DEVO_BOUND_1;
break;
}
2016-08-25 13:42:21 +02:00
packet_count++;
if(packet_count == DEVO_PKTS_PER_CHANNEL)
packet_count = 0;
2015-12-30 01:41:12 +01:00
}
uint16_t devo_callback()
{
2016-08-25 13:42:21 +02:00
static uint8_t txState=0;
2020-05-09 16:11:10 +02:00
#if defined DEVO_HUB_TELEMETRY
2020-05-09 16:11:10 +02:00
int delay;
if (txState == 0)
{
#ifdef MULTI_SYNC
telemetry_set_input_sync(2400);
#endif
DEVO_BuildPacket();
CYRF_WriteDataPacket(packet);
txState = 1;
return 900;
}
if (txState == 1)
{
int i = 0;
uint8_t reg;
while (! ((reg = CYRF_ReadRegister(CYRF_04_TX_IRQ_STATUS)) & 0x02))
{
if (++i >= DEVO_NUM_WAIT_LOOPS)
break;
}
if (((reg & 0x22) == 0x20) || (CYRF_ReadRegister(CYRF_02_TX_CTRL) & 0x80))
{
CYRF_Reset();
DEVO_cyrf_init();
DEVO_cyrf_set_bound_sop_code();
CYRF_ConfigRFChannel(*hopping_frequency_ptr);
//printf("Rst CYRF\n");
delay = 1500;
txState = 15;
}
else
{
if (phase == DEVO_BOUND)
{
/* exit binding state */
phase = DEVO_BOUND_3;
DEVO_cyrf_set_bound_sop_code();
}
if((packet_count != 0) && (bind_counter == 0))
{
CYRF_SetTxRxMode(RX_EN); //Receive mode
CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x87); //0x80??? //Prepare to receive
txState = 2;
return 1300;
}
}
if(packet_count == 0)
{
CYRF_SetPower(0x08); //Keep tx power updated
hopping_frequency_ptr = hopping_frequency_ptr == &hopping_frequency[2] ? hopping_frequency : hopping_frequency_ptr + 1;
CYRF_ConfigRFChannel(*hopping_frequency_ptr);
}
delay = 1500;
}
if(txState == 2)
{
uint8_t rx_state = CYRF_ReadRegister(CYRF_07_RX_IRQ_STATUS);
if((rx_state & 0x03) == 0x02)
{ // RXC=1, RXE=0 then 2nd check is required (debouncing)
rx_state |= CYRF_ReadRegister(CYRF_07_RX_IRQ_STATUS);
}
if((rx_state & 0x07) == 0x02)
{ // good data (complete with no errors)
CYRF_WriteRegister(CYRF_07_RX_IRQ_STATUS, 0x80); // need to set RXOW before data read
CYRF_ReadDataPacketLen(packet, CYRF_ReadRegister(CYRF_09_RX_COUNT));
DEVO_parse_telemetry_packet();
}
CYRF_SetTxRxMode(TX_EN); //Write mode
delay = 200;
}
txState = 0;
return delay;
#else
2015-12-30 01:41:12 +01:00
if (txState == 0)
{
2019-11-11 19:15:39 +01:00
#ifdef MULTI_SYNC
telemetry_set_input_sync(2400);
#endif
2015-12-30 01:41:12 +01:00
txState = 1;
DEVO_BuildPacket();
CYRF_WriteDataPacket(packet);
return 1200;
}
txState = 0;
uint8_t i = 0;
while (! (CYRF_ReadRegister(CYRF_04_TX_IRQ_STATUS) & 0x02))
2016-08-25 13:42:21 +02:00
if(++i > DEVO_NUM_WAIT_LOOPS)
2015-12-30 01:41:12 +01:00
return 1200;
if (phase == DEVO_BOUND)
{
/* exit binding state */
phase = DEVO_BOUND_3;
2016-08-25 13:42:21 +02:00
DEVO_cyrf_set_bound_sop_code();
2015-12-30 01:41:12 +01:00
}
2016-08-25 13:42:21 +02:00
if(packet_count == 0)
2015-12-30 01:41:12 +01:00
{
2016-08-25 13:42:21 +02:00
CYRF_SetPower(0x08); //Keep tx power updated
2015-12-30 01:41:12 +01:00
hopping_frequency_ptr = hopping_frequency_ptr == &hopping_frequency[2] ? hopping_frequency : hopping_frequency_ptr + 1;
CYRF_ConfigRFChannel(*hopping_frequency_ptr);
}
return 1200;
2020-05-09 16:11:10 +02:00
#endif
2015-12-30 01:41:12 +01:00
}
uint16_t DevoInit()
{
2019-06-23 17:13:30 +02:00
switch(sub_protocol)
{
case 1:
num_ch=10;
break;
case 2:
num_ch=12;
break;
case 3:
num_ch=6;
break;
case 4:
num_ch=7;
break;
default:
num_ch=8;
break;
}
2016-08-25 13:42:21 +02:00
DEVO_cyrf_init();
2015-12-30 01:41:12 +01:00
CYRF_GetMfgData(cyrfmfg_id);
CYRF_SetTxRxMode(TX_EN);
CYRF_ConfigCRCSeed(0x0000);
2016-09-04 16:47:34 +02:00
CYRF_PROGMEM_ConfigSOPCode(DEVO_j6pro_sopcodes[0]);
2016-08-25 13:42:21 +02:00
DEVO_set_radio_channels();
2015-12-30 01:41:12 +01:00
hopping_frequency_ptr = hopping_frequency;
CYRF_ConfigRFChannel(*hopping_frequency_ptr);
2016-08-25 13:42:21 +02:00
packet_count = 0;
2016-08-25 14:48:48 +02:00
prev_option=option;
2016-08-25 13:42:21 +02:00
if(option==0)
{
MProtocol_id = ((uint32_t)(hopping_frequency[0] ^ cyrfmfg_id[0] ^ cyrfmfg_id[3]) << 16)
| ((uint32_t)(hopping_frequency[1] ^ cyrfmfg_id[1] ^ cyrfmfg_id[4]) << 8)
| ((uint32_t)(hopping_frequency[2] ^ cyrfmfg_id[2] ^ cyrfmfg_id[5]) << 0);
2016-08-25 14:48:48 +02:00
MProtocol_id %= 1000000;
2015-12-30 01:41:12 +01:00
bind_counter = DEVO_BIND_COUNT;
phase = DEVO_BIND;
2016-08-25 13:42:21 +02:00
BIND_IN_PROGRESS;
2015-12-30 01:41:12 +01:00
}
else
{
phase = DEVO_BOUND_1;
bind_counter = 0;
2016-08-25 13:42:21 +02:00
DEVO_cyrf_set_bound_sop_code();
2015-12-30 01:41:12 +01:00
}
return 2400;
}
#endif