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/>.
15 // compatible with MT99xx, Eachine H7, Yi Zhan i6S and LS114/124
16 // Last sync with Goebish mt99xx_nrf24l01.c dated 2016-01-29
18 #if defined(MT99XX_CCNRF_INO)
20 #include "iface_xn297.h"
22 #define MT99XX_BIND_COUNT 928
23 #define MT99XX_PACKET_PERIOD_FY805 2460
24 #define MT99XX_PACKET_PERIOD_MT 2625
25 #define MT99XX_PACKET_PERIOD_YZ 3125
26 #define MT99XX_PACKET_PERIOD_A180 3400 // timing changes between the packets 2 x 27220 then 1x 26080, it seems that it is only on the first RF channel which jitters by 1.14ms but hard to pinpoint with XN297dump
27 #define MT99XX_PACKET_PERIOD_DRAGON 1038 // there is a pause of 2x1038 between two packets, no idea why and how since it is not even stable on a same dump...
28 #define MT99XX_PACKET_PERIOD_DRAGON_TELEM 10265 // long pause to receive the telemetry packets, 3 are sent by the RX one after the other
29 #define MT99XX_PACKET_PERIOD_F949G 3450
30 #define MT99XX_PACKET_PERIOD_PA18 1338
31 #define MT99XX_INITIAL_WAIT 500
32 #define MT99XX_PACKET_SIZE 9
34 //#define FORCE_A180_ID
35 //#define FORCE_DRAGON_ID
36 //#define FORCE_F949G_ID
37 #define FORCE_PA18_ID1
38 //#define FORCE_PA18_ID2
47 // flags going to packet[6] (MT99xx, H7)
48 FLAG_MT_RATE1 = 0x01, // (H7 & A180 high rate)
49 FLAG_MT_RATE2 = 0x02, // (MT9916 only)
51 FLAG_MT_SNAPSHOT= 0x20,
56 // flags going to packet[6] (LS)
57 FLAG_LS_INVERT = 0x01,
59 FLAG_LS_HEADLESS= 0x10,
60 FLAG_LS_SNAPSHOT= 0x20,
66 // flags going to packet[7] (FY805)
67 FLAG_FY805_HEADLESS= 0x10,
71 // flags going to packet[6] (A180)
72 FLAG_A180_3D6G = 0x01,
73 FLAG_A180_RATE = 0x02,
77 // flags going to packet[6] (DRAGON)
78 FLAG_DRAGON_RATE = 0x01,
79 FLAG_DRAGON_RTH = 0x80,
80 FLAG_DRAGON_UNK = 0x04,
84 // flags going to packet[6] (F949G)
85 FLAG_F949G_LIGHT = 0x01,
86 FLAG_F949G_RATES = 0x02,
87 FLAG_F949G_3D6G = 0x20,
88 FLAG_BF109_RATES = 0x01, // short press right
89 FLAG_BF109_LIGHT = 0x02, // short press left
90 FLAG_BF109_UNK1 = 0x08, // long press right
91 FLAG_BF109_UNK2 = 0x10, // long press left
94 // flags going to packet[6] (PA18)
96 FLAG_PA18_FLIP = 0x80,
99 const uint8_t h7_mys_byte[] = {
100 0x01, 0x11, 0x02, 0x12, 0x03, 0x13, 0x04, 0x14,
101 0x05, 0x15, 0x06, 0x16, 0x07, 0x17, 0x00, 0x10
104 const uint8_t ls_mys_byte[] = {
105 0x05, 0x15, 0x25, 0x06, 0x16, 0x26,
106 0x07, 0x17, 0x27, 0x00, 0x10, 0x20,
107 0x01, 0x11, 0x21, 0x02, 0x12, 0x22,
108 0x03, 0x13, 0x23, 0x04, 0x14, 0x24
111 const uint8_t yz_p4_seq[] = {0xa0, 0x20, 0x60};
113 #ifdef MT99XX_HUB_TELEMETRY
114 const uint8_t DRAGON_seq[] = {0x20, 0x60, 0x20, 0x80};
117 static void __attribute__((unused)) MT99XX_send_packet()
119 static uint8_t seq_num=0;
122 if(sub_protocol == LS)
123 XN297_RFChannel(0x2D); // LS always transmits on the same channel
125 if(sub_protocol==FY805)
126 XN297_RFChannel(0x4B); // FY805 always transmits on the same channel
127 else // MT99 & H7 & YZ & A180 & DRAGON & F949G & PA18
128 XN297_Hopping(hopping_frequency_no);
130 if(IS_BIND_IN_PROGRESS)
151 default: // MT99 & H7 & A180 & DRAGON & F949G & PA18
157 packet[4] = rx_tx_addr[0];
158 packet[5] = rx_tx_addr[1];
159 packet[6] = rx_tx_addr[2];
160 if(sub_protocol == PA18+8)
162 packet[7] = num_ch; // checksum offset
163 packet[8] = 0x55; // fixed
167 packet[7] = crc8; // checksum offset
168 if(sub_protocol != F949G)
169 packet[8] = 0xAA; // fixed
176 if(sub_protocol != YZ)
177 { // MT99XX & H7 & LS & FY805 & A180 & DRAGON & F949G & PA18
178 packet[0] = convert_channel_16b_limit(THROTTLE,0xE1,0x00); // throttle
179 packet[1] = convert_channel_16b_limit(RUDDER ,0x00,0xE1); // rudder
180 packet[2] = convert_channel_16b_limit(AILERON ,0xE1,0x00); // aileron
181 packet[3] = convert_channel_16b_limit(ELEVATOR,0x00,0xE1); // elevator
182 packet[4] = 0x20; // pitch trim (0x3f-0x20-0x00)
183 packet[5] = 0x20; // roll trim (0x00-0x20-0x3f)
184 packet[6] = GET_FLAG( CH5_SW, FLAG_MT_FLIP );
185 if(sub_protocol != PA18+8)
186 packet[7] = h7_mys_byte[hopping_frequency_no]; // next rf channel index ?
188 packet[7] = (packet[7]&0xBF)|0x20;
192 packet[6] |= 0x40 | FLAG_MT_RATE2 // max rate on MT99xx
193 | GET_FLAG( CH7_SW, FLAG_MT_SNAPSHOT )
194 | GET_FLAG( CH8_SW, FLAG_MT_VIDEO );
197 packet[6] |= FLAG_MT_RATE1; // max rate on H7
200 packet[6] |= FLAG_LS_RATE // max rate
201 | GET_FLAG( CH6_SW, FLAG_LS_INVERT ) // invert
202 | GET_FLAG( CH7_SW, FLAG_LS_SNAPSHOT ) // snapshot
203 | GET_FLAG( CH8_SW, FLAG_LS_VIDEO ) // video
204 | GET_FLAG( CH9_SW, FLAG_LS_HEADLESS ); // Headless
205 packet[7] = ls_mys_byte[seq_num++];
206 if(seq_num >= sizeof(ls_mys_byte))
214 |GET_FLAG( CH5_SW, FLAG_MT_FLIP )
215 |GET_FLAG( CH9_SW, FLAG_FY805_HEADLESS ); //HEADLESS
219 packet[6] = GET_FLAG( !CH6_SW,FLAG_A180_RATE) // 0x02, A180=RATE, F949S=LED
220 |GET_FLAG( CH5_SW, FLAG_A180_3D6G ) // 0x01, A180=3D_6G, F949S=RATE
221 |GET_FLAG( CH7_SW, 0x20 ); // 0x20, F949S=3D_6G
225 if(CH5_SW) // Advanced mode
228 if(Channel_data[CH5] > CHANNEL_MIN_COMMAND) // Beginner mode
230 packet[6] = FLAG_DRAGON_RATE
231 | GET_FLAG( CH6_SW, FLAG_DRAGON_RTH );
233 #ifdef MT99XX_HUB_TELEMETRY
235 if(hopping_frequency_no == 0)
240 if(packet_count > 11)
243 if(packet_count > 10) // Telemetry packet request every 10 or 11 packets
245 packet[6] |= 0x04; // Request telemetry flag
248 packet[7] = DRAGON_seq[seq_num]; // seq: 20 80 20 60 20 80 20 60... 80 changes to 80+batt from telem
250 packet[7] |= v_lipo1;
256 packet[6] = GET_FLAG( CH5_SW, FLAG_F949G_3D6G )
257 | GET_FLAG( CH6_SW, FLAG_F949G_LIGHT ) //FLAG_BF109_RATES
258 | GET_FLAG(!CH7_SW, FLAG_F949G_RATES ) //FLAG_BF109_LIGHT
259 | GET_FLAG( CH8_SW, FLAG_BF109_UNK1 ) //BF109 long press right, temporary flag
260 | GET_FLAG( CH9_SW, FLAG_BF109_UNK2 ); //BF109 long press left, temporary flag
264 if(Channel_data[CH5] > CHANNEL_MAX_COMMAND) // Expert mode
267 if(Channel_data[CH5] > CHANNEL_MIN_COMMAND) // Intermediate mode
269 packet[6] = GET_FLAG( CH6_SW, FLAG_PA18_FLIP ) // Flip
270 | GET_FLAG( CH7_SW, FLAG_PA18_RTH ); // RTH
271 if(hopping_frequency_no == 0)
276 for(uint8_t i=0; i<8; i++)
278 if(sub_protocol == PA18+8)
284 packet[0] = convert_channel_16b_limit(THROTTLE,0x00,0x64); // throttle
285 packet[1] = convert_channel_16b_limit(RUDDER ,0x64,0x00); // rudder
286 packet[2] = convert_channel_16b_limit(ELEVATOR,0x00,0x64); // elevator
287 packet[3] = convert_channel_16b_limit(AILERON ,0x64,0x00); // aileron
288 if(packet_count++ >= 23)
295 packet[4] = yz_p4_seq[seq_num];
296 packet[5] = 0x02 // expert ? (0=unarmed, 1=normal)
297 | GET_FLAG(CH8_SW, 0x10) //VIDEO
298 | GET_FLAG(CH5_SW, 0x80) //FLIP
299 | GET_FLAG(CH9_SW, 0x04) //HEADLESS
300 | GET_FLAG(CH7_SW, 0x20); //SNAPSHOT
301 packet[6] = GET_FLAG(CH6_SW, 0x80); //LED
302 packet[7] = packet[0];
303 for(uint8_t idx = 1; idx < MT99XX_PACKET_SIZE-2; idx++)
304 packet[7] += packet[idx];
310 hopping_frequency_no++;
311 if(sub_protocol == YZ || sub_protocol == A180 || sub_protocol == DRAGON || sub_protocol == F949G || sub_protocol == PA18+8)
312 hopping_frequency_no++; // skip every other channel
313 if(hopping_frequency_no > 15)
314 hopping_frequency_no = 0;
318 XN297_SetFreqOffset();
319 XN297_SetTxRxMode(TX_EN);
320 XN297_WritePayload(packet, MT99XX_PACKET_SIZE);
323 for(uint8_t i=0; i<MT99XX_PACKET_SIZE; i++)
324 debug(" %02X",packet[i]);
329 static void __attribute__((unused)) MT99XX_RF_init()
331 if(sub_protocol == YZ)
332 XN297_Configure(XN297_CRCEN, XN297_UNSCRAMBLED, XN297_250K);
333 else if(sub_protocol == F949G)
334 XN297_Configure(XN297_CRCEN, XN297_SCRAMBLED, XN297_250K);
336 XN297_Configure(XN297_CRCEN, XN297_SCRAMBLED, XN297_1M);
337 XN297_SetTXAddr((uint8_t *)"\xCC\xCC\xCC\xCC\xCC", 5);
338 XN297_HoppingCalib(16);
339 #ifdef MT99XX_HUB_TELEMETRY
340 XN297_SetRXAddr(rx_tx_addr, MT99XX_PACKET_SIZE);
345 static void __attribute__((unused)) MT99XX_initialize_txid()
347 num_ch = rx_tx_addr[1]; // PA18
348 rx_tx_addr[1] = rx_tx_addr[3]; // RX_Num
352 rx_tx_addr[0] = 0x53; // test (SB id)
353 rx_tx_addr[1] = 0x00;
354 rx_tx_addr[2] = 0x00;
357 rx_tx_addr[0] = 0x81; // test (SB id)
358 rx_tx_addr[1] = 0x0F;
359 rx_tx_addr[2] = 0x00;
362 rx_tx_addr[0] = 0xCC;
366 rx_tx_addr[0] = 0x84; // MikeHRC ID
367 rx_tx_addr[1] = 0x62;
368 rx_tx_addr[2] = 0x4A;
370 //channel_offset = 0x03;
373 #ifdef FORCE_DRAGON_ID
375 rx_tx_addr[0] = 0x6C; // Laurie ID
376 rx_tx_addr[1] = 0x00;
377 rx_tx_addr[2] = 0x22;
379 //channel_offset = 0x06
382 #ifdef FORCE_F949G_ID
384 rx_tx_addr[0] = 0x7E; // LilTeo14 ID
385 rx_tx_addr[1] = 0x2F;
386 rx_tx_addr[2] = 0x29;
388 //channel_offset = 0x03
391 #ifdef FORCE_PA18_ID1
393 rx_tx_addr[0] = 0xC9; // zebble ID
394 rx_tx_addr[1] = 0x02;
395 rx_tx_addr[2] = 0x13;
396 num_ch = 0x89; // additional crc init. How is this calculated? or could it be random?
398 //channel_offset = 0x03
399 //1Mb C=5 S=Y A= C9 02 13 CC CC P(9)= E1 70 70 70 20 20 00 20 1A -> 0x91 + 0x89 => 0x1A
400 // S=Y A= C9 02 13 CC CC P(9)= E1 70 70 70 20 A0 00 20 9A -> 0x11 + 0x89 => 0x9A
401 //bind S=Y A= CC CC CC CC CC P(9)= 20 14 03 25 C9 02 13 89 55
404 #ifdef FORCE_PA18_ID2
406 rx_tx_addr[0] = 0x0E;
407 rx_tx_addr[1] = 0x05;
408 rx_tx_addr[2] = 0x13;
409 num_ch = 0xD1; // additional crc init. How is this calculated? or could it be random?
411 //channel_offset = 0x00
412 //1Mb C=2 S=Y A= 0E 05 13 CC CC P(9)= E1 70 70 70 20 60 00 60 E2 -> 0x11 + 0xD1 => 0xE2
413 //bind S=Y A= CC CC CC CC CC P(9)= 20 14 03 25 0E 05 13 D1 55
416 default: //MT99 & H7 & A180 & DRAGON & F949G & PA18
417 rx_tx_addr[2] = 0x00;
418 if(sub_protocol == PA18+8)
419 rx_tx_addr[2] = 0x13;
423 rx_tx_addr[3] = 0xCC;
424 rx_tx_addr[4] = 0xCC;
426 crc8 = rx_tx_addr[0] + rx_tx_addr[1] + rx_tx_addr[2];
428 //memcpy(hopping_frequency,"\x02\x48\x0C\x3e\x16\x34\x20\x2A\x2A\x20\x34\x16\x3e\x0c\x48\x02",16);
429 for(uint8_t i=0; i<8; i++)
431 hopping_frequency[(i<<1) ]=0x02 + (10*i);
432 hopping_frequency[(i<<1)+1]=0x48 - (10*i);
434 hopping_frequency_no=0;
437 uint16_t MT99XX_callback()
443 telemetry_set_input_sync(packet_period);
448 if (bind_counter == 0)
450 // set tx address for data packets
451 XN297_SetTXAddr(rx_tx_addr, 5);
453 uint8_t channel_offset = ((crc8>>4) + (crc8 & 0x0f)) % 8;
454 for(uint8_t i=0;i<16;i++)
455 hopping_frequency[i] += channel_offset;
456 XN297_HoppingCalib(16);
460 MT99XX_send_packet();
462 #ifdef MT99XX_HUB_TELEMETRY
465 XN297_SetTxRxMode(TXRX_OFF);
466 XN297_SetTxRxMode(RX_EN);
468 return MT99XX_PACKET_PERIOD_DRAGON_TELEM - MT99XX_PACKET_PERIOD_DRAGON - 500;
474 if(XN297_ReadPayload(packet_in, MT99XX_PACKET_SIZE))
476 // C=48 S=Y A= 6C 00 22 CC CC P(9)= 6C 00 22 27 00 00 00 00 60
477 // C=48 S=Y A= 6C 00 22 CC CC P(9)= 6C 00 22 28 00 00 00 00 61
478 // C=18 S=Y A= 6C 00 22 CC CC P(9)= 6C 00 22 24 00 00 00 00 5D
479 // 6C 00 22 = TX address, 27/28/24=vbatt, check = sum(P[0..7]) + AB
480 // D2 EE 00 25 00 00 00 00 90 -> check also + AB
481 //for(uint8_t i=0; i<MT99XX_PACKET_SIZE; i++)
482 // debug(" %02X",packet_in[i]);
484 for(uint8_t i=0; i<8; i++)
485 check += packet_in[i];
486 if(packet_in[8] == check && packet_in[0] == rx_tx_addr[0] && packet_in[1] == rx_tx_addr[1] && packet_in[2] == rx_tx_addr[2])
487 { // checksum and address are ok
489 v_lipo1 = packet_in[3] & 0x7F; // Batt
490 v_lipo2 = packet_in[3] & 0x80; // Low batt flag
498 XN297_SetTxRxMode(TXRX_OFF);
499 XN297_SetTxRxMode(TX_EN);
504 return packet_period;
507 void MT99XX_init(void)
509 if(protocol == PROTO_MT99XX2)
510 sub_protocol|=0x08; // Increase the number of sub_protocols for MT99XX
512 bind_counter = MT99XX_BIND_COUNT;
515 if(sub_protocol != A180 && sub_protocol != DRAGON && sub_protocol != F949G && sub_protocol != PA18+8)
516 BIND_IN_PROGRESS; // autobind protocol
521 MT99XX_initialize_txid();
527 packet_period = MT99XX_PACKET_PERIOD_YZ;
530 packet_period = MT99XX_PACKET_PERIOD_FY805;
534 packet_period = MT99XX_PACKET_PERIOD_A180;
537 packet_period = MT99XX_PACKET_PERIOD_PA18;
540 packet_period = MT99XX_PACKET_PERIOD_MT;