2 This project is free software: you can redistribute it and/or modify
3 it under the terms of the GNU General Public License as published by
4 the Free Software Foundation, either version 3 of the License, or
5 (at your option) any later version.
7 Multiprotocol is distributed in the hope that it will be useful,
8 but WITHOUT ANY WARRANTY; without even the implied warranty of
9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 GNU General Public License for more details.
12 You should have received a copy of the GNU General Public License
13 along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
16 #if defined(MLINK_CYRF6936_INO)
18 #include "iface_cyrf6936.h"
20 //#define MLINK_FORCE_ID
21 #define MLINK_BIND_COUNT 696 // around 20s
22 #define MLINK_NUM_FREQ 78
23 #define MLINK_BIND_CHANNEL 0x01
24 #define MLINK_PACKET_SIZE 8
39 uint8_t MLINK_Data_Code[16], MLINK_CRC_Init, MLINK_Unk_6_2;
41 const uint8_t PROGMEM MLINK_init_vals[][2] = {
43 { CYRF_01_TX_LENGTH, 0x08 }, // Length of packet
44 { CYRF_02_TX_CTRL, 0x40 }, // Clear TX Buffer
45 { CYRF_03_TX_CFG, 0x3C }, //0x3E in normal mode, 0x3C in bind mode: SDR 64 chip codes (=8 bytes data code used)
46 { CYRF_05_RX_CTRL, 0x00 },
47 { CYRF_06_RX_CFG, 0x93 }, // AGC enabled, overwrite enable, valid flag enable
48 { CYRF_0B_PWR_CTRL, 0x00 },
49 //{ CYRF_0C_XTAL_CTRL, 0x00 }, // Set to GPIO on reset
50 //{ CYRF_0D_IO_CFG, 0x00 }, // Set to GPIO on reset
51 //{ CYRF_0E_GPIO_CTRL, 0x00 }, // Set by the CYRF_SetTxRxMode function
52 { CYRF_0F_XACT_CFG, 0x04 }, // end state idle
53 { CYRF_10_FRAMING_CFG, 0x00 }, // SOP disabled
54 { CYRF_11_DATA32_THOLD, 0x05 }, // not used???
55 { CYRF_12_DATA64_THOLD, 0x0F }, // 64 Chip Data PN Code Correlator Threshold
56 { CYRF_14_EOP_CTRL, 0x05 }, // 5 consecutive noncorrelations symbol for EOP
57 { CYRF_15_CRC_SEED_LSB, 0x00 }, // not used???
58 { CYRF_16_CRC_SEED_MSB, 0x00 }, // not used???
59 { CYRF_1B_TX_OFFSET_LSB,0x00 },
60 { CYRF_1C_TX_OFFSET_MSB,0x00 },
61 { CYRF_1D_MODE_OVERRIDE,0x00 },
62 { CYRF_1E_RX_OVERRIDE, 0x14 }, // RX CRC16 is disabled and Force Receive Data Rate
63 { CYRF_1F_TX_OVERRIDE, 0x04 }, // TX CRC16 is disabled
64 { CYRF_26_XTAL_CFG, 0x08 },
65 { CYRF_29_RX_ABORT, 0x00 },
66 { CYRF_32_AUTO_CAL_TIME,0x3C },
67 { CYRF_35_AUTOCAL_OFFSET,0x14 },
68 { CYRF_39_ANALOG_CTRL, 0x03 }, // Receive invert and all slow
71 static void __attribute__((unused)) MLINK_cyrf_config()
73 for(uint8_t i = 0; i < sizeof(MLINK_init_vals) / 2; i++)
74 CYRF_WriteRegister(pgm_read_byte_near(&MLINK_init_vals[i][0]), pgm_read_byte_near(&MLINK_init_vals[i][1]));
75 CYRF_WritePreamble(0x333304);
76 CYRF_SetTxRxMode(TX_EN);
79 static void __attribute__((unused)) MLINK_send_bind_packet()
81 uint8_t p_c=packet_count>>1;
83 memset(packet, p_c<0x16?0x00:0xFF, MLINK_PACKET_SIZE-1);
84 packet[0]=0x0F; // bind
89 packet[2]=0x40; //unknown but seems constant
90 packet[4]=0x01; //unknown but seems constant
91 packet[5]=0x03; //unknown but seems constant
92 packet[6]=0xE3; //unknown but seems constant
95 packet[6]=MLINK_CRC_Init; //CRC init value
98 packet[2]=MLINK_Unk_6_2; //unknown and different
99 //Start of hopping frequencies
100 for(uint8_t i=0;i<4;i++)
101 packet[i+3]=hopping_frequency[i];
104 packet[6]=0x51; //unknown but seems constant
107 packet[2]=0x51; //unknown but seems constant
108 packet[3]=0xEC; //unknown but seems constant
109 packet[4]=0x05; //unknown but seems constant
113 memset(&packet[2],0x00,5);
116 if(p_c>=0x01 && p_c<=0x04)
118 uint8_t p_c_5=(p_c-1)*5;
119 for(uint8_t i=0;i<5;i++)
121 packet[i+2]=MLINK_Data_Code[i+p_c_5];
124 if(p_c>=0x07 && p_c<=0x15)
125 {//Hopping frequencies
126 uint8_t p_c_5=5*(p_c-6)-1;
127 for(uint8_t i=0;i<5;i++)
128 if(i+p_c_5<MLINK_NUM_FREQ)
129 packet[i+2]=hopping_frequency[i+p_c_5];
135 memset(&packet[2], 0x00, MLINK_PACKET_SIZE-3);
139 crc8=0xFF; // Init = 0xFF
140 for(uint8_t i=0;i<MLINK_PACKET_SIZE-1;i++)
141 crc8_update(bit_reverse(packet[i]));
142 packet[7] = bit_reverse(crc8); // CRC reflected out
146 debug("P(%02d):",p_c);
147 for(uint8_t i=0;i<8;i++)
148 debug(" %02X",packet[i]);
153 CYRF_WriteDataPacketLen(packet, MLINK_PACKET_SIZE);
156 static void __attribute__((unused)) MLINK_send_data_packet()
158 static uint8_t tog=0;
161 #ifdef FAILSAFE_ENABLE
163 if(IS_FAILSAFE_VALUES_on && phase==MLINK_SEND1)
165 fs=10; // Original radio is sending 70 packets
181 default: //MLINK_SEND1:
186 //Pack 6 channels per packet
187 for(uint8_t i=0;i<6;i++)
189 uint8_t val=start<16 ? convert_channel_16b_nolimit(start,426 >> 4,3448 >> 4,true) : 0x00;
190 start--; // switch to next channel
197 if(hopping_frequency_no==0)
199 //Channels to be sent
200 if(phase==MLINK_SEND1 || ((hopping_frequency_no%5==0) && (phase==MLINK_SEND2)))
202 if((hopping_frequency_no&1)==0)
203 packet[0] = 0x09; //10,8,6
205 packet[0] = 0x01; //11,9,7
208 if(phase==MLINK_SEND2)
211 packet[0] = 0x02; //x,15,13
213 packet[0] = 0x0A; //x,14,12
217 {//phase==MLINK_SEND3
218 if((hopping_frequency_no&1)==0)
219 packet[0] = 0x88; //4,2,0
221 packet[0] = 0x80; //5,3,1
225 start=4+6*(packet[0]&3);
226 if((packet[0]&0x08)==0)
229 //Channels 426..1937..3448
230 for(uint8_t i=0;i<3;i++)
232 uint16_t val=start<16 ? convert_channel_16b_nolimit(start,426,3448,false) : 0x0000;
233 start-=2; // switch to next channel
234 packet[i*2+1]=val>>8;
240 crc8=bit_reverse(hopping_frequency_no + MLINK_CRC_Init); // Init = relected freq index + offset
241 for(uint8_t i=0;i<MLINK_PACKET_SIZE-1;i++)
242 crc8_update(bit_reverse(packet[i]));
243 packet[7] = bit_reverse(crc8); // CRC reflected out
246 CYRF_WriteDataPacketLen(packet, MLINK_PACKET_SIZE);
250 debug("P(%02d):",hopping_frequency_no);
251 for(uint8_t i=0;i<8;i++)
252 debug(" %02X",packet[i]);
257 #ifdef MLINK_HUB_TELEMETRY
258 static void __attribute__((unused)) MLINK_Send_Telemetry()
259 { // not sure how MLINK telemetry works, the 2 RXs I have are sending something completly different...
260 telemetry_counter += 2; // TX LQI counter
263 if(packet_in[0]==0x13)
264 { // RX-9-DR : 13 1A C8 00 01 64 00
266 for(uint8_t i=1; i<5; i+=3)
267 {//2 sensors per packet
269 switch(packet_in[i]&0x0F)
272 if((packet_in[i]&0xF0) == 0x00)
273 v_lipo1 = packet_in[i+1]; // Rx_Batt*20
275 v_lipo2 = packet_in[i+1];
290 RX_RSSI=RX_LQI=packet_in[i+1]>>1;
293 #if defined HUB_TELEMETRY
296 uint16_t val=((packet_in[i+2]&0x80)<<8)|((packet_in[i+2]&0x7F)<<7)|(packet_in[i+1]>>1); //remove the alarm LSB bit, move the sign bit to MSB
297 frsky_send_user_frame(id, val, val>>8);
303 if(packet_in[0]==0x03)
304 { // RX-5 : 03 15 23 00 00 01 02
305 //Incoming packet values
306 RX_RSSI = packet_in[2]<<1; // Looks to be the RX RSSI value
307 RX_LQI = packet_in[5]; // Looks to be connection lost
313 TX_RSSI = CYRF_ReadRegister(CYRF_13_RSSI)&0x1F;
319 telemetry_counter = 100;
324 #ifdef MLINK_FW_TELEMETRY
325 static void __attribute__((unused)) MLINK_Send_Telemetry()
327 telemetry_counter += 2; // TX LQI counter
331 TX_RSSI = CYRF_ReadRegister(CYRF_13_RSSI)&0x1F;
337 telemetry_counter = 100;
342 uint16_t MLINK_callback()
351 status=CYRF_ReadRegister(CYRF_05_RX_CTRL);
352 if( (status&0x80) == 0 )
354 len=CYRF_ReadRegister(CYRF_09_RX_COUNT);
355 debugln("L=%02X",len)
358 CYRF_ReadDataPacketLen(packet, len*2);
360 for(uint8_t i=0;i<8;i++)
361 debug(" %02X",packet[i*2]);
364 crc8=0xFF; // Init = 0xFF
365 for(uint8_t i=0;i<MLINK_PACKET_SIZE-1;i++)
366 crc8_update(bit_reverse(packet[i<<1]));
367 if(packet[14] == bit_reverse(crc8))
371 packet_count=3; // Start sending bind payload
372 else if(packet_count > 0x19*2)
374 if(packet[0] == 0x8F)
376 else if(packet[0] == 0x9F)
377 packet_count=0x80; // End bind
379 packet_count=0; // Restart bind...
386 CYRF_WriteRegister(CYRF_29_RX_ABORT, 0x20); // Enable RX abort
387 CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x24); // Force end state
388 CYRF_WriteRegister(CYRF_29_RX_ABORT, 0x00); // Disable RX abort
389 phase=MLINK_BIND_TX; // Retry sending bind packet
390 CYRF_SetTxRxMode(TX_EN); // Transmit mode
394 if(--bind_counter==0 || packet_count>=0x1B*2)
395 { // Switch to normal mode
397 phase=MLINK_PREP_DATA;
400 MLINK_send_bind_packet();
401 if(packet_count == 0 || packet_count > 0x19*2)
403 phase++; // MLINK_BIND_PREP_RX
404 return 4700; // Original is 4900
410 case MLINK_BIND_PREP_RX:
412 while ((uint16_t)((uint16_t)micros()-(uint16_t)start) < 200) // Wait max 200µs for TX to finish
413 if((CYRF_ReadRegister(CYRF_02_TX_CTRL) & 0x80) == 0x00)
414 break; // Packet transmission complete
415 CYRF_SetTxRxMode(RX_EN); // Receive mode
416 CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x82); // Prepare to receive
417 phase++; //MLINK_BIND_RX
418 if(packet_count > 0x19*2)
419 return 28712; // Give more time to the RX to confirm that the bind is ok...
423 case MLINK_PREP_DATA:
424 CYRF_ConfigDataCode(MLINK_Data_Code);
425 MLINK_CRC_Init += 0xED;
426 hopping_frequency_no = 0x00;
427 CYRF_ConfigRFChannel(hopping_frequency[hopping_frequency_no]);
429 #if defined(MLINK_HUB_TELEMETRY) || defined(MLINK_FW_TELEMETRY)
437 MLINK_send_data_packet();
441 MLINK_send_data_packet();
443 if(hopping_frequency_no%5==0)
447 MLINK_send_data_packet();
451 //Switch to next channel
452 hopping_frequency_no++;
453 if(hopping_frequency_no>=MLINK_NUM_FREQ)
454 hopping_frequency_no=0;
455 CYRF_ConfigRFChannel(hopping_frequency[hopping_frequency_no]);
458 if(hopping_frequency_no%5==0)
460 CYRF_SetTxRxMode(RX_EN); // Receive mode
461 CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x82); // Prepare to receive
463 return 8038+2434+410-1000;
470 #if defined(MLINK_HUB_TELEMETRY) || defined(MLINK_FW_TELEMETRY)
476 TX_LQI=telemetry_counter;
477 if(telemetry_counter==0)
479 telemetry_counter = 0;
482 status=CYRF_ReadRegister(CYRF_05_RX_CTRL);
483 debug("T(%02X):",status);
484 if( (status&0x80) == 0 )
486 len=CYRF_ReadRegister(CYRF_09_RX_COUNT);
488 if( len && len <= MLINK_PACKET_SIZE )
490 CYRF_ReadDataPacketLen(packet_in, len*2);
491 #if defined(MLINK_HUB_TELEMETRY) || defined(MLINK_FW_TELEMETRY)
492 if(len==MLINK_PACKET_SIZE)
494 for(uint8_t i=0;i<8;i++)
496 crc8=bit_reverse(MLINK_CRC_Init);
497 for(uint8_t i=0;i<MLINK_PACKET_SIZE-1;i++)
499 packet_in[i]=packet_in[i<<1];
500 crc8_update(bit_reverse(packet_in[i]));
501 debug(" %02X",packet_in[i]);
503 if(packet_in[14] == bit_reverse(crc8)) // Packet CRC is ok
504 MLINK_Send_Telemetry();
512 CYRF_WriteRegister(CYRF_29_RX_ABORT, 0x20); // Enable RX abort
513 CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x24); // Force end state
514 CYRF_WriteRegister(CYRF_29_RX_ABORT, 0x00); // Disable RX abort
515 CYRF_SetTxRxMode(TX_EN); // Transmit mode
522 static void __attribute__((unused)) MLINK_shuffle_freqs(uint32_t seed, uint8_t *hop)
526 for(uint8_t i=0; i < MLINK_NUM_FREQ/2; i++)
528 uint8_t r = random(0xfefefefe) % (MLINK_NUM_FREQ/2);
529 uint8_t tmp = hop[r];
539 //Init ID and RF freqs
540 for(uint8_t i=0; i < MLINK_NUM_FREQ/2; i++)
542 hopping_frequency[i ] = (i<<1) + 3;
543 hopping_frequency[i+MLINK_NUM_FREQ/2] = (i<<1) + 3;
546 memcpy(MLINK_Data_Code ,rx_tx_addr,4);
547 MLINK_shuffle_freqs(MProtocol_id, hopping_frequency);
550 MProtocol_id ^= 0x6FBE3201;
551 set_rx_tx_addr(MProtocol_id);
552 memcpy(MLINK_Data_Code+4,rx_tx_addr,4);
553 MLINK_shuffle_freqs(MProtocol_id, &hopping_frequency[MLINK_NUM_FREQ/2]);
556 MLINK_CRC_Init = rx_tx_addr[3]; //value sent during bind then used to init the CRC
557 MLINK_Unk_6_2 = 0x3A; //unknown value sent during bind but doesn't seem to matter
559 #ifdef MLINK_FORCE_ID
563 memcpy(MLINK_Data_Code,"\x4C\x97\x9D\xBF\xB8\x3D\xB5\xBE",8);
564 memcpy(hopping_frequency,"\x0D\x41\x09\x43\x17\x2D\x05\x31\x13\x3B\x1B\x3D\x0B\x41\x11\x45\x09\x2B\x17\x4D\x19\x3F\x03\x3F\x0F\x37\x1F\x47\x1B\x49\x07\x35\x27\x2F\x15\x33\x23\x39\x1F\x33\x19\x45\x0D\x2D\x11\x35\x0B\x47\x25\x3D\x21\x37\x1D\x3B\x05\x2F\x21\x39\x23\x4B\x03\x31\x25\x29\x07\x4F\x1D\x4B\x15\x4D\x13\x4F\x0F\x49\x29\x2B\x27\x43",MLINK_NUM_FREQ);
565 MLINK_Unk_6_2 = 0x3A; //unknown value sent during bind but doesn't seem to matter
566 MLINK_CRC_Init = 0x07; //value sent during bind then used to init the CRC
571 memcpy(MLINK_Data_Code,"\xC0\x90\x8F\xBB\x7C\x8E\x2B\x8E",8);
572 memcpy(hopping_frequency,"\x05\x41\x27\x4B\x17\x33\x11\x39\x0F\x3F\x05\x2F\x13\x2D\x25\x31\x1F\x2D\x25\x35\x03\x41\x1B\x43\x09\x3D\x1F\x29\x1D\x35\x0D\x3B\x19\x49\x23\x3B\x17\x47\x1D\x2B\x13\x37\x0B\x31\x23\x33\x29\x3F\x07\x37\x07\x43\x11\x2B\x1B\x39\x0B\x4B\x03\x4F\x21\x47\x0F\x4D\x15\x45\x21\x4F\x09\x3D\x19\x2F\x15\x45\x0D\x49\x27\x4D",MLINK_NUM_FREQ);
573 MLINK_Unk_6_2 = 0x02; //unknown value but doesn't seem to matter
574 MLINK_CRC_Init = 0x3E; //value sent during bind then used to init the CRC
577 //MLINK_Unk_6_2 = 0x7e; //unknown value but doesn't seem to matter
578 //MLINK_CRC_Init = 0xA2; //value sent during bind then used to init the CRC
581 for(uint8_t i=0;i<8;i++)
582 MLINK_Data_Code[i+8]=MLINK_Data_Code[7-i];
585 for(uint8_t i=0;i<16;i++)
586 debug(" %02X", MLINK_Data_Code[i]);
589 debugln("CRC init: %02X", MLINK_CRC_Init)
592 for(uint8_t i=0;i<MLINK_NUM_FREQ;i++)
593 debug(" %02X", hopping_frequency[i]);
596 if(IS_BIND_IN_PROGRESS)
599 bind_counter = MLINK_BIND_COUNT;
600 CYRF_ConfigDataCode((uint8_t*)"\x6F\xBE\x32\x01\xDB\xF1\x2B\x01\xE3\x5C\xFA\x02\x97\x93\xF9\x02"); //Bind data code
601 CYRF_ConfigRFChannel(MLINK_BIND_CHANNEL);
602 phase = MLINK_BIND_TX;
605 phase = MLINK_PREP_DATA;