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 //**************************
16 // Telemetry serial code *
17 //**************************
20 uint8_t RetrySequence ;
22 #ifdef MULTI_TELEMETRY
23 uint32_t lastMulti = 0;
24 #define MULTI_TIME 500 //in ms
26 #define INPUT_SYNC_TIME 100 //in ms
27 #define INPUT_ADDITIONAL_DELAY 100 // in 10µs, 100 => 1000 µs
28 uint32_t lastInputSync = 0;
29 uint16_t inputDelay = 0;
31 #endif // MULTI_TELEMETRY
33 #if defined SPORT_TELEMETRY
34 #define FRSKY_SPORT_PACKET_SIZE 8
36 uint8_t Sport_Data = 0;
37 uint8_t pktx1[FRSKY_SPORT_PACKET_SIZE*FX_BUFFERS];
39 // Store for out of sequence packet
40 uint8_t FrSkyX_RX_ValidSeq ;
41 struct t_FrSkyX_RX_Frame
48 // Store for FrskyX telemetry
49 struct t_FrSkyX_RX_Frame FrSkyX_RX_Frames[4] ;
50 uint8_t FrSkyX_RX_NextFrame=0;
51 #endif // SPORT_TELEMETRY
53 #if defined HUB_TELEMETRY
54 #define USER_MAX_BYTES 6
57 struct t_FrSkyD_User_Frame
62 } FrSkyD_User_Frame[8];
63 uint8_t FrSkyD_User_Frame_Start=0, FrSkyD_User_Frame_End=0;
64 #endif // HUB_TELEMETRY
66 #define START_STOP 0x7e
67 #define BYTESTUFF 0x7d
68 #define STUFF_MASK 0x20
70 uint8_t pktx[MAX_PKTX];
73 #ifdef MULTI_TELEMETRY
74 static void multi_send_header(uint8_t type, uint8_t len)
83 static void telemetry_set_input_sync(uint16_t refreshRate)
85 #if defined(STM32_BOARD) && defined(DEBUG_PIN)
92 // Only record input Delay after a frame has really been received
93 // Otherwise protocols with faster refresh rates then the TX sends (e.g. 3ms vs 6ms) will screw up the calcualtion
94 inputRefreshRate = refreshRate;
95 if (last_serial_input != 0)
97 cli(); // Disable global int due to RW of 16 bits registers
99 sei(); // Enable global int
100 //inputDelay = (inputDelay - last_serial_input)>>1;
101 inputDelay -= last_serial_input;
102 //if(inputDelay & 0x8000)
103 // inputDelay = inputDelay - 0x8000;
110 static void mult_send_inputsync()
112 multi_send_header(MULTI_TELEMETRY_SYNC, 6);
113 Serial_write(inputRefreshRate >> 8);
114 Serial_write(inputRefreshRate & 0xff);
115 // Serial_write(inputDelay >> 8);
116 // Serial_write(inputDelay & 0xff);
117 Serial_write(inputDelay >> 9);
118 Serial_write(inputDelay >> 1);
119 Serial_write(INPUT_SYNC_TIME);
120 Serial_write(INPUT_ADDITIONAL_DELAY);
124 static void multi_send_status()
126 if(protocol == 0) return;
128 multi_send_header(MULTI_TELEMETRY_STATUS, 24);
132 if(IS_INPUT_SIGNAL_on)
134 if(mode_select==MODE_SERIAL)
136 if(remote_callback != 0)
138 if(multi_protocols_index != 0xFF && IS_SUB_PROTO_VALID)
139 flags |= 0x04; //Invalid protocol / sub protocol, can't make the distinction since there is no more flags...
143 if(IS_BIND_IN_PROGRESS)
145 if(multi_protocols_index != 0xFF)
147 if(multi_protocols[multi_protocols_index].chMap)
148 flags |= 0x40; //Disable_ch_mapping supported
149 #ifdef FAILSAFE_ENABLE
150 if(multi_protocols[multi_protocols_index].failSafe)
151 flags |= 0x20; //Failsafe supported
154 if(IS_DATA_BUFFER_LOW_on)
159 // Version number example: 1.1.6.1
160 Serial_write(VERSION_MAJOR);
161 Serial_write(VERSION_MINOR);
162 Serial_write(VERSION_REVISION);
163 Serial_write(VERSION_PATCH_LEVEL);
166 Serial_write(RUDDER<<6|THROTTLE<<4|ELEVATOR<<2|AILERON);
168 if(multi_protocols_index == 0xFF) // selection out of list... send first available protocol
170 Serial_write(multi_protocols[0].protocol); // begining of list
171 Serial_write(multi_protocols[0].protocol); // begining of list
172 for(uint8_t i=0;i<16;i++)
173 Serial_write(0x00); // everything else is invalid
177 // Protocol next/prev
178 if(multi_protocols[multi_protocols_index+1].protocol != 0xFF)
180 if(multi_protocols[multi_protocols_index+1].protocol == PROTO_SCANNER )//|| multi_protocols[multi_protocols_index+1].protocol == PROTO_CONFIG )
181 {// if next is scanner
182 if(multi_protocols[multi_protocols_index+2].protocol != 0xFF)
183 Serial_write(multi_protocols[multi_protocols_index+2].protocol); // skip to next protocol number
185 Serial_write(multi_protocols[multi_protocols_index].protocol); // or end of list
188 Serial_write(multi_protocols[multi_protocols_index+1].protocol); // next protocol number
191 Serial_write(multi_protocols[multi_protocols_index].protocol); // end of list
192 if(multi_protocols_index>0 && multi_protocols[multi_protocols_index-1].protocol != 0)
194 if(multi_protocols[multi_protocols_index-1].protocol == PROTO_SCANNER )//|| multi_protocols[multi_protocols_index-1].protocol == PROTO_CONFIG )
195 {// if prev is scanner
196 if(multi_protocols_index > 1)
197 Serial_write(multi_protocols[multi_protocols_index-2].protocol); // skip to prev protocol number
199 Serial_write(multi_protocols[multi_protocols_index].protocol); // begining of list
202 Serial_write(multi_protocols[multi_protocols_index-1].protocol); // prev protocol number
205 Serial_write(multi_protocols[multi_protocols_index].protocol); // begining of list
207 for(uint8_t i=0;i<7;i++)
208 Serial_write(multi_protocols[multi_protocols_index].ProtoString[i]); // protocol name
210 uint8_t nbr=multi_protocols[multi_protocols_index].nbrSubProto;
211 if(option_override>0x0F)
212 Serial_write(nbr | (multi_protocols[multi_protocols_index].optionType<<4)); // number of sub protocols && option type
214 Serial_write(nbr | (option_override<<4)); // number of sub protocols && option_override type
216 if(IS_SUB_PROTO_VALID)
218 uint8_t len=multi_protocols[multi_protocols_index].SubProtoString[0];
219 uint8_t offset=len*(sub_protocol&0x07)+1;
221 Serial_write(multi_protocols[multi_protocols_index].SubProtoString[j+offset]); // current sub protocol name
228 #ifdef MULTI_CONFIG_INO
231 multi_send_header(MULTI_TELEMETRY_CONFIG, 21);
232 for (uint8_t i = 0; i < 21; i++) // Config data
233 Serial_write(packet_in[i]);
237 #ifdef MLINK_FW_TELEMETRY
240 multi_send_header(MULTI_TELEMETRY_MLINK, 10);
241 Serial_write(TX_RSSI); // RSSI
242 Serial_write(TX_LQI); // LQI
243 for (uint8_t i = 0; i < 8; i++) // followed by 8 bytes of telemetry data
244 Serial_write(packet_in[i]);
251 if (packet_in[0] == 0x80)
253 multi_send_header(MULTI_TELEMETRY_DSMBIND, 10);
254 for (uint8_t i = 1; i < 11; i++) // 10 bytes of DSM bind response
255 Serial_write(packet_in[i]);
260 multi_send_header(MULTI_TELEMETRY_DSM, 17);
261 for (uint8_t i = 0; i < 17; i++) // RSSI value followed by 16 bytes of telemetry data
262 Serial_write(packet_in[i]);
267 #ifdef SCANNER_TELEMETRY
268 void spectrum_scanner_frame()
270 multi_send_header(MULTI_TELEMETRY_SCANNER, SCAN_CHANS_PER_PACKET + 1);
271 Serial_write(packet_in[0]); // start channel
272 for(uint8_t ch = 0; ch < SCAN_CHANS_PER_PACKET; ch++)
273 Serial_write(packet_in[ch+1]); // RSSI power levels
277 #if defined (FRSKY_RX_TELEMETRY) || defined (AFHDS2A_RX_TELEMETRY) || defined (BAYANG_RX_TELEMETRY) || defined (DSM_RX_CYRF6936_INO)
278 void receiver_channels_frame()
280 uint16_t len = packet_in[3] * 11; // 11 bit per channel
285 multi_send_header(MULTI_TELEMETRY_RX_CHANNELS, len);
286 for (uint8_t i = 0; i < len; i++)
287 Serial_write(packet_in[i]); // pps, rssi, ch start, ch count, 16x ch data
291 #ifdef AFHDS2A_FW_TELEMETRY
292 void AFHDSA_short_frame()
294 multi_send_header(packet_in[29]==0xAA?MULTI_TELEMETRY_AFHDS2A:MULTI_TELEMETRY_AFHDS2A_AC, 29);
295 for (uint8_t i = 0; i < 29; i++) // RSSI value followed by 4*7 bytes of telemetry data
296 Serial_write(packet_in[i]);
300 #ifdef HITEC_FW_TELEMETRY
301 void HITEC_short_frame()
303 multi_send_header(MULTI_TELEMETRY_HITEC, 8);
304 for (uint8_t i = 0; i < 8; i++) // TX RSSI and TX LQI values followed by frame number and 5 bytes of telemetry data
305 Serial_write(packet_in[i]);
309 #ifdef HOTT_FW_TELEMETRY
310 void HOTT_short_frame()
312 multi_send_header(MULTI_TELEMETRY_HOTT, 15);
313 for (uint8_t i = 0; i < 15; i++) // TX RSSI and TX LQI values followed by frame number and telemetry data
314 Serial_write(packet_in[i]);
318 static void multi_send_frskyhub()
320 multi_send_header(MULTI_TELEMETRY_HUB, 9);
321 for (uint8_t i = 0; i < 9; i++)
322 Serial_write(frame[i]);
325 #endif //MULTI_TELEMETRY
327 void frskySendStuffed()
329 Serial_write(START_STOP);
330 for (uint8_t i = 0; i < 9; i++)
332 if ((frame[i] == START_STOP) || (frame[i] == BYTESTUFF))
334 Serial_write(BYTESTUFF);
335 frame[i] ^= STUFF_MASK;
337 Serial_write(frame[i]);
339 Serial_write(START_STOP);
342 bool frsky_process_telemetry(uint8_t *buffer,uint8_t len)
344 if(protocol!=PROTO_FRSKY_R9)
346 if(buffer[1] != rx_tx_addr[3] || buffer[2] != rx_tx_addr[2] || len != buffer[0] + 3 )
347 return false; // Bad address or length...
348 // RSSI and LQI are the 2 last bytes
349 TX_RSSI = buffer[len-2];
355 telemetry_link|=1; // Telemetry data is available
357 #if defined FRSKYD_CC2500_INO
358 if (protocol==PROTO_FRSKYD)
360 TX_LQI = buffer[len-1]&0x7F;
361 //Save current buffer
362 for (uint8_t i=3;i<len-2;i++)
363 telemetry_in_buffer[i]=buffer[i]; // Buffer telemetry values to be sent
365 //Check incoming telemetry sequence
366 if(telemetry_in_buffer[6]>0 && telemetry_in_buffer[6]<=10)
367 { //Telemetry length ok
368 if ( ( telemetry_in_buffer[7] & 0x1F ) == (telemetry_counter & 0x1F) )
371 if ( telemetry_counter & 0x80 )
372 if ( ( telemetry_counter & 0x1F ) != RetrySequence )
374 telemetry_counter = ( (telemetry_counter+1)%32 ) | topBit ; // Request next telemetry frame
377 {//Incorrect sequence
378 RetrySequence = telemetry_in_buffer[7] & 0x1F ;
379 telemetry_counter |= 0x80 ;
380 telemetry_in_buffer[6]=0 ; // Discard current packet and wait for retransmit
384 telemetry_in_buffer[6]=0; // Discard packet
388 #if defined SPORT_TELEMETRY && (defined FRSKYX_CC2500_INO || defined FRSKYR9_SX1276_INO)
389 if (protocol==PROTO_FRSKYX||protocol==PROTO_FRSKYX2)
391 /*Telemetry frames(RF) SPORT info
393 SPORT frame valid 6+3 bytes
394 [00] PKLEN 0E 0E 0E 0E
395 [01] TXID1 DD DD DD DD
396 [02] TXID2 6D 6D 6D 6D
397 [03] CONST 02 02 02 02
398 [04] RS/RB 2C D0 2C CE //D0;CE=2*RSSI;....2C = RX battery voltage(5V from Bec)
399 [05] HD-SK 03 10 21 32 //TX/RX telemetry hand-shake bytes
400 [06] NO.BT 00 00 06 03 //No.of valid SPORT frame bytes in the frame
401 [07] STRM1 00 00 7E 00
402 [08] STRM2 00 00 1A 00
403 [09] STRM3 00 00 10 00
404 [10] STRM4 03 03 03 03
405 [11] STRM5 F1 F1 F1 F1
406 [12] STRM6 D1 D1 D0 D0
407 [13] CHKSUM1 --|2 CRC bytes sent by RX (calculated on RX side crc16/table)
409 //len=17 -> len-7=10 -> 3..12
410 uint16_t lcrc = FrSkyX_crc(&buffer[3], len-7 ) ;
411 if ( ( (lcrc >> 8) != buffer[len-4]) || ( (lcrc & 0x00FF ) != buffer[len-3]) )
412 return false; // Bad CRC
415 RX_RSSI=buffer[4] & 0x7F ;
417 v_lipo1 = (buffer[4]<<1) + 1 ;
418 #if defined(TELEMETRY_FRSKYX_TO_FRSKYD) && defined(ENABLE_PPM)
419 if(mode_select != MODE_SERIAL)
423 if (protocol==PROTO_FRSKYX||protocol==PROTO_FRSKYX2||protocol==PROTO_FRSKY_R9)
427 //Save outgoing telemetry sequence
428 FrSkyX_TX_IN_Seq=buffer[5] >> 4;
430 //Check incoming telemetry sequence
431 uint8_t packet_seq=buffer[5] & 0x03;
432 if ( buffer[5] & 0x08 )
434 FrSkyX_RX_Seq = 0x08 ;
435 FrSkyX_RX_NextFrame = 0x00 ;
436 FrSkyX_RX_Frames[0].valid = false ;
437 FrSkyX_RX_Frames[1].valid = false ;
438 FrSkyX_RX_Frames[2].valid = false ;
439 FrSkyX_RX_Frames[3].valid = false ;
441 else if ( packet_seq == (FrSkyX_RX_Seq & 0x03 ) )
443 struct t_FrSkyX_RX_Frame *p ;
446 // buffer[5] sequence control
447 // buffer[6] payload count
448 // buffer[7-12] payload
449 p = &FrSkyX_RX_Frames[packet_seq] ;
450 count = buffer[6]; // Payload length
454 for ( uint8_t i = 0 ; i < count ; i++ )
455 p->payload[i] = buffer[i+7] ;
458 p->count = 0 ; // Discard
461 FrSkyX_RX_Seq = ( FrSkyX_RX_Seq + 1 ) & 0x03 ; // Move to next sequence
463 if ( FrSkyX_RX_ValidSeq & 0x80 )
465 FrSkyX_RX_Seq = ( FrSkyX_RX_ValidSeq + 1 ) & 3 ;
466 FrSkyX_RX_ValidSeq &= 0x7F ;
472 struct t_FrSkyX_RX_Frame *q ;
475 // buffer[5] sequence control
476 // buffer[6] payload count
477 // buffer[7-12] payload
478 if ( packet_seq == ( ( FrSkyX_RX_Seq +1 ) & 3 ) )
479 {//Received next sequence -> save it
480 q = &FrSkyX_RX_Frames[packet_seq] ;
481 count = buffer[6]; // Payload length
485 for ( uint8_t i = 0 ; i < count ; i++ )
486 q->payload[i] = buffer[i+7] ;
492 FrSkyX_RX_ValidSeq = 0x80 | packet_seq ;
494 FrSkyX_RX_Seq = ( FrSkyX_RX_Seq & 0x03 ) | 0x04 ; // Request re-transmission of original sequence
501 void init_frskyd_link_telemetry()
512 #if defined HUB_TELEMETRY
513 FrSkyD_User_Frame_Start=FrSkyD_User_Frame_End=0;
517 void frsky_link_frame()
519 frame[0] = 0xFE; // Link frame
520 if (protocol==PROTO_FRSKYD)
522 frame[1] = telemetry_in_buffer[3]; // A1
523 frame[2] = telemetry_in_buffer[4]; // A2
524 frame[3] = telemetry_in_buffer[5]; // RX_RSSI
525 telemetry_link &= ~1 ; // Sent
526 telemetry_link |= 2 ; // Send hub if available
529 {//PROTO_HUBSAN, PROTO_AFHDS2A, PROTO_BAYANG, PROTO_NCC1701, PROTO_CABELL, PROTO_HITEC, PROTO_BUGS, PROTO_BUGSMINI, PROTO_FRSKYX, PROTO_FRSKYX2, PROTO_PROPEL, PROTO_DEVO, PROTO_RLINK, PROTO_OMP, PROTO_WFLY2, PROTO_LOLI, PROTO_MLINK, PROTO_MT99XX
533 telemetry_link &= ~1 ; // Sent
538 frame[7] = frame[8] = 0;
539 #if defined MULTI_TELEMETRY
540 multi_send_frskyhub();
546 #if defined HUB_TELEMETRY
547 void frsky_user_frame()
549 if(telemetry_in_buffer[6])
550 {//only send valid hub frames
551 frame[0] = 0xFD; // user frame
552 if(telemetry_in_buffer[6]>USER_MAX_BYTES)
554 frame[1]=USER_MAX_BYTES; // packet size
555 telemetry_in_buffer[6]-=USER_MAX_BYTES;
556 telemetry_link |= 2 ; // 2 packets need to be sent
560 frame[1]=telemetry_in_buffer[6]; // packet size
561 telemetry_link &= ~2; // only 1 packet or processing second packet
563 frame[2] = telemetry_in_buffer[7];
564 for(uint8_t i=0;i<USER_MAX_BYTES;i++)
565 frame[i+3]=telemetry_in_buffer[i+8];
566 if(telemetry_link & 2) // prepare the content of second packet
567 for(uint8_t i=8;i<USER_MAX_BYTES+8;i++)
568 telemetry_in_buffer[i]=telemetry_in_buffer[i+USER_MAX_BYTES];
569 #if defined MULTI_TELEMETRY
570 multi_send_frskyhub();
576 telemetry_link &= ~2;
580 packet_in[6]|(counter++)|00 01 02 03 04 05 06 07 08 09
582 01 08 5E 28 12 00 5E 5E 3A 06 00 5E
583 0A 09 28 12 00 5E 5E 3A 06 00 5E 5E
584 09 0A 3B 09 00 5E 5E 06 36 7D 5E 5E
585 03 0B 5E 28 11 00 5E 5E 06 06 6C 5E
586 0A 0C 00 5E 5E 3A 06 00 5E 5E 3B 09
587 07 0D 00 5E 5E 06 06 6C 5E 16 72 5E
588 05 0E 5E 28 11 00 5E 5E 3A 06 00 5E
589 0A 0F 5E 3A 06 00 5E 5E 3B 09 00 5E
590 05 10 5E 06 16 72 5E 5E 3A 06 00 5E
592 static void __attribute__((unused)) frsky_write_user_frame(uint8_t ID, uint8_t low, uint8_t high)
594 telemetry_in_buffer[6] = 0x04; // number of bytes in the payload
595 telemetry_in_buffer[7] = 0x00; // unknown?
596 telemetry_in_buffer[8] = 0x5E; // start of payload
597 telemetry_in_buffer[9] = ID; // ID must be less than 0x40
600 for(uint8_t i=0;i<2;i++)
602 if(value == 0x5D || value == 0x5E)
604 telemetry_in_buffer[pos+1] = value ^ 0x60;
605 telemetry_in_buffer[pos] = 0x5D;
606 telemetry_in_buffer[6]++; // 1 more byte in the payload
610 telemetry_in_buffer[pos++] = value;
613 telemetry_link |= 2; // request to send frame
616 static void __attribute__((unused)) frsky_send_user_frame(uint8_t ID, uint8_t low, uint8_t high)
620 uint8_t test = (FrSkyD_User_Frame_End + 1) & 0x07;
621 if(test == FrSkyD_User_Frame_Start)
622 return; // buffer full...
623 FrSkyD_User_Frame_End = test;
624 FrSkyD_User_Frame[FrSkyD_User_Frame_End].ID = ID;
625 FrSkyD_User_Frame[FrSkyD_User_Frame_End].low = low;
626 FrSkyD_User_Frame[FrSkyD_User_Frame_End].high = high;
628 else // send to TX direct
629 frsky_write_user_frame(ID, low, high);
632 static void __attribute__((unused)) frsky_check_user_frame()
634 if((telemetry_link&2) || FrSkyD_User_Frame_Start == FrSkyD_User_Frame_End)
635 return; // need to wait that the last frame is sent or buffer is empty
636 frsky_write_user_frame(FrSkyD_User_Frame[FrSkyD_User_Frame_Start].ID, FrSkyD_User_Frame[FrSkyD_User_Frame_Start].low, FrSkyD_User_Frame[FrSkyD_User_Frame_Start].high);
637 FrSkyD_User_Frame_Start++;
638 FrSkyD_User_Frame_Start &= 0x07;
643 #if defined SPORT_TELEMETRY
644 /* SPORT details serial
645 100K 8E2 normal-multiprotocol
646 -every 12ms-or multiple of 12; %36
647 1 2 3 4 5 6 7 8 9 CRC DESCR
648 7E 98 10 05 F1 20 23 0F 00 A6 SWR_ID
649 7E 98 10 01 F1 33 00 00 00 C9 RSSI_ID
650 7E 98 10 04 F1 58 00 00 00 A1 BATT_ID
651 7E BA 10 03 F1 E2 00 00 00 18 ADC2_ID
652 7E BA 10 03 F1 E2 00 00 00 18 ADC2_ID
653 7E BA 10 03 F1 E2 00 00 00 18 ADC2_ID
654 7E BA 10 03 F1 E2 00 00 00 18 ADC2_ID
655 7E BA 10 03 F1 E2 00 00 00 18 ADC2_ID
656 7E BA 10 03 F1 E2 00 00 00 18 ADC2_ID
659 Telemetry frames(RF) SPORT info
661 SPORT frame valid 6+3 bytes
662 [00] PKLEN 0E 0E 0E 0E
663 [01] TXID1 DD DD DD DD
664 [02] TXID2 6D 6D 6D 6D
665 [03] CONST 02 02 02 02
666 [04] RS/RB 2C D0 2C CE //D0;CE=2*RSSI;....2C = RX battery voltage(5V from Bec)
667 [05] HD-SK 03 10 21 32 //TX/RX telemetry hand-shake bytes
668 [06] NO.BT 00 00 06 03 //No.of valid SPORT frame bytes in the frame
669 [07] STRM1 00 00 7E 00
670 [08] STRM2 00 00 1A 00
671 [09] STRM3 00 00 10 00
672 [10] STRM4 03 03 03 03
673 [11] STRM5 F1 F1 F1 F1
674 [12] STRM6 D1 D1 D0 D0
675 [13] CHKSUM1 --|2 CRC bytes sent by RX (calculated on RX side crc16/table)
677 +2 appended bytes automatically RSSI and LQI/CRC bytes(len=0x0E+3);
679 0x06 0x06 0x06 0x06 0x06
681 0x7E 0x00 0x03 0x7E 0x00
682 0x1A 0x00 0xF1 0x1A 0x00
683 0x10 0x00 0xD7 0x10 0x00
684 0x03 0x7E 0x00 0x03 0x7E
685 0xF1 0x1A 0x00 0xF1 0x1A
686 0xD7 0x10 0x00 0xD7 0x10
688 0xE1 0x1C 0xD0 0xEE 0x33
689 0x34 0x0A 0xC3 0x56 0xF3
692 #if defined MULTI_TELEMETRY
693 const uint8_t PROGMEM Indices[] = { 0x00, 0xA1, 0x22, 0x83, 0xE4, 0x45,
694 0xC6, 0x67, 0x48, 0xE9, 0x6A, 0xCB,
695 0xAC, 0x0D, 0x8E, 0x2F, 0xD0, 0x71,
696 0xF2, 0x53, 0x34, 0x95, 0x16, 0xB7,
697 0x98, 0x39, 0xBA, 0x1B } ;
700 #ifdef MULTI_TELEMETRY
701 void sportSend(uint8_t *p)
703 multi_send_header(MULTI_TELEMETRY_SPORT, 9);
707 x = pgm_read_byte_near( &Indices[x] ) ;
709 for (uint8_t i = 1; i < 8; i++)
712 crc_s += p[i]; //0-1FF
713 crc_s += crc_s >> 8; //0-100
716 Serial_write(0xff - crc_s);
719 void sportSend(uint8_t *p)
722 Serial_write(START_STOP);//+9
724 for (uint8_t i = 1; i < 9; i++)
729 if ((p[i] == START_STOP) || (p[i] == BYTESTUFF))
731 Serial_write(BYTESTUFF);//stuff again
732 Serial_write(STUFF_MASK ^ p[i]);
737 crc_s += p[i]; //0-1FF
738 crc_s += crc_s >> 8; //0-100
746 #if !defined MULTI_TELEMETRY
747 Serial_write(START_STOP);
751 void sportSendFrame()
753 static uint8_t sport_counter=0;
756 sport_counter = (sport_counter + 1) %36;
769 switch (sport_counter)
774 frame[4] = 0x02; //dummy values if swr 20230f00
789 frame[4] = v_lipo1; //a1;
794 for (i=0;i<FRSKY_SPORT_PACKET_SIZE;i++)
799 uint8_t j = Sport_Data * FRSKY_SPORT_PACKET_SIZE ;
801 pktx1[i] = pktx1[i+FRSKY_SPORT_PACKET_SIZE] ;
814 void proces_sport_data(uint8_t data)
816 static uint8_t pass = 0, indx = 0;
820 if (data == START_STOP)
827 if (data == START_STOP) // Happens if missed packet
833 if(data == BYTESTUFF) //if they are stuffed
841 pktx[indx++] = data ^ STUFF_MASK; //unstuff bytes
845 if (indx >= FRSKY_SPORT_PACKET_SIZE)
847 if ( Sport_Data < FX_BUFFERS )
849 uint8_t dest = Sport_Data * FRSKY_SPORT_PACKET_SIZE ;
851 for ( i = 0 ; i < FRSKY_SPORT_PACKET_SIZE ; i++ )
852 pktx1[dest++] = pktx[i] ; // Triple buffer
853 Sport_Data += 1 ;//ok to send
865 void TelemetryUpdate()
867 // check for space in tx buffer
871 h = SerialControl.head ;
872 t = SerialControl.tail ;
874 t += TXBUFFER_SIZE - h ;
887 t += TXBUFFER_SIZE - h ;
892 debugln("TEL_BUF_FULL %d",t);
897 debugln("TEL_BUF %d",t);
900 #ifdef MULTI_TELEMETRY
901 uint32_t now = millis();
902 if ((IS_SEND_MULTI_STATUS_on || ((now - lastMulti) > MULTI_TIME))&& protocol != PROTO_SCANNER)
905 SEND_MULTI_STATUS_off;
910 if ( inputRefreshRate && (now - lastInputSync) > INPUT_SYNC_TIME )
912 mult_send_inputsync();
918 #if defined SPORT_TELEMETRY
919 if ((protocol==PROTO_FRSKYX || protocol==PROTO_FRSKYX2||protocol==PROTO_FRSKY_R9) && telemetry_link
920 #ifdef TELEMETRY_FRSKYX_TO_FRSKYD
921 && mode_select==MODE_SERIAL
927 struct t_FrSkyX_RX_Frame *p ;
929 p = &FrSkyX_RX_Frames[FrSkyX_RX_NextFrame] ;
933 for (uint8_t i=0; i < count ; i++)
934 proces_sport_data(p->payload[i]) ;
935 p->valid = false ; // Sent
936 FrSkyX_RX_NextFrame = ( FrSkyX_RX_NextFrame + 1 ) & 3 ;
944 #endif // SPORT_TELEMETRY
946 #ifdef MULTI_TELEMETRY
947 #if defined MULTI_CONFIG_INO
948 if(telemetry_link && protocol == PROTO_CONFIG)
955 #if defined MLINK_FW_TELEMETRY
956 if(telemetry_link && protocol == PROTO_MLINK)
963 #if defined DSM_TELEMETRY
964 if(telemetry_link && protocol == PROTO_DSM)
971 #if defined AFHDS2A_FW_TELEMETRY
972 if(telemetry_link == 2 && protocol == PROTO_AFHDS2A)
974 AFHDSA_short_frame();
979 #if defined HITEC_FW_TELEMETRY
980 if(telemetry_link == 2 && protocol == PROTO_HITEC)
987 #if defined HOTT_FW_TELEMETRY
988 if(telemetry_link == 2 && protocol == PROTO_HOTT)
995 #if defined SCANNER_TELEMETRY
996 if (telemetry_link && protocol == PROTO_SCANNER)
998 spectrum_scanner_frame();
1003 #if defined (FRSKY_RX_TELEMETRY) || defined(AFHDS2A_RX_TELEMETRY) || defined (BAYANG_RX_TELEMETRY) || defined (DSM_RX_CYRF6936_INO)
1004 if ((telemetry_link & 1) && (protocol == PROTO_FRSKY_RX || protocol == PROTO_AFHDS2A_RX || protocol == PROTO_BAYANG_RX || protocol == PROTO_DSM_RX) )
1006 receiver_channels_frame();
1007 telemetry_link &= ~1;
1011 #endif //MULTI_TELEMETRY
1013 if( telemetry_link & 1 )
1014 { // FrSkyD + Hubsan + AFHDS2A + Bayang + Cabell + Hitec + Bugs + BugsMini + NCC1701 + PROPEL + RLINK + OMP + MLINK + DEVO
1015 // FrSkyX telemetry if in PPM
1019 #if defined HUB_TELEMETRY
1020 if((telemetry_link & 2) && ( protocol == PROTO_FRSKYD || protocol == PROTO_BAYANG || protocol == PROTO_MLINK || protocol == PROTO_DEVO ) )
1021 { // FrSkyD + Bayang + MLINK + DEVO
1023 frsky_check_user_frame();
1030 /**************************/
1031 /**************************/
1032 /** Serial TX routines **/
1033 /**************************/
1034 /**************************/
1037 // Routines for normal serial output
1038 void Serial_write(uint8_t data)
1041 nextHead = tx_head + 1 ;
1042 if ( nextHead >= TXBUFFER_SIZE )
1044 tx_buff[nextHead]=data;
1045 tx_head = nextHead ;
1049 void initTXSerial( uint8_t speed)
1052 if(speed==SPEED_9600)
1055 USARTC0.BAUDCTRLA = 207 ;
1056 USARTC0.BAUDCTRLB = 0 ;
1057 USARTC0.CTRLB = 0x18 ;
1058 USARTC0.CTRLA = (USARTC0.CTRLA & 0xCF) | 0x10 ;
1059 USARTC0.CTRLC = 0x03 ;
1062 usart3_begin(9600,SERIAL_8N1); //USART3
1066 UCSR0A = 0 ; // Clear X2 bit
1067 //Set frame format to 8 data bits, none, 1 stop bit
1068 UCSR0C = (1<<UCSZ01)|(1<<UCSZ00);
1072 else if(speed==SPEED_57600)
1075 /*USARTC0.BAUDCTRLA = 207 ;
1076 USARTC0.BAUDCTRLB = 0 ;
1077 USARTC0.CTRLB = 0x18 ;
1078 USARTC0.CTRLA = (USARTC0.CTRLA & 0xCF) | 0x10 ;
1079 USARTC0.CTRLC = 0x03 ;*/
1082 usart3_begin(57600,SERIAL_8N1); //USART3
1086 UCSR0A = 0x02 ; // Set X2 bit
1087 //Set frame format to 8 data bits, none, 1 stop bit
1088 UCSR0C = (1<<UCSZ01)|(1<<UCSZ00);
1092 else if(speed==SPEED_125K)
1095 /*USARTC0.BAUDCTRLA = 207 ;
1096 USARTC0.BAUDCTRLB = 0 ;
1097 USARTC0.CTRLB = 0x18 ;
1098 USARTC0.CTRLA = (USARTC0.CTRLA & 0xCF) | 0x10 ;
1099 USARTC0.CTRLC = 0x03 ;*/
1102 usart3_begin(125000,SERIAL_8N1); //USART3
1106 UCSR0A = 0x00 ; // Clear X2 bit
1107 //Set frame format to 8 data bits, none, 1 stop bit
1108 UCSR0C = (1<<UCSZ01)|(1<<UCSZ00);
1117 UCSR0B |= (1<<TXEN0);//tx enable
1124 ISR(USARTC0_DRE_vect)
1129 ISR(USART_UDRE_vect)
1132 { // Transmit interrupt
1134 if(USART3_BASE->SR & USART_SR_TXE)
1137 if(tx_head!=tx_tail)
1139 if(++tx_tail>=TXBUFFER_SIZE)//head
1142 USART3_BASE->DR=tx_buff[tx_tail];//clears TXE bit
1144 UDR0=tx_buff[tx_tail];
1147 if (tx_tail == tx_head)
1149 tx_pause(); // Check if all data is transmitted. If yes disable transmitter UDRE interrupt.
1156 // Routines for bit-bashed serial output
1158 // Speed is 0 for 100K and 1 for 9600
1159 void initTXSerial( uint8_t speed)
1161 TIMSK0 = 0 ; // Stop all timer 0 interrupts
1162 #ifdef INVERT_SERIAL
1167 UCSR0B &= ~(1<<TXEN0) ;
1169 SerialControl.speed = speed ;
1170 if ( speed == SPEED_9600 )
1172 OCR0A = 207 ; // 104uS period
1174 TCCR0B = 0x0A ; // Fast PMM, 2MHz
1179 TCCR0B = 2 ; // Clock/8 (0.5uS)
1183 void Serial_write( uint8_t byte )
1189 #ifdef INVERT_SERIAL
1194 byteLo >>= 7 ; // Top bit
1195 if ( SerialControl.speed == SPEED_100K )
1197 #ifdef INVERT_SERIAL
1198 byteLo |= 0x02 ; // Parity bit
1200 byteLo |= 0xFC ; // Stop bits
1205 temp = byte ^ temp ;
1208 temp = temp ^ temp1 ;
1213 #ifdef INVERT_SERIAL
1221 byteLo |= 0xFE ; // Stop bit
1224 #ifdef INVERT_SERIAL
1225 byte |= 1 ; // Start bit
1227 uint8_t next = SerialControl.head + 2;
1228 if(next>=TXBUFFER_SIZE)
1230 if ( next != SerialControl.tail )
1232 SerialControl.data[SerialControl.head] = byte ;
1233 SerialControl.data[SerialControl.head+1] = byteLo ;
1234 SerialControl.head = next ;
1240 void resumeBashSerial()
1243 if ( SerialControl.busy == 0 )
1246 // Start the transmission here
1247 #ifdef INVERT_SERIAL
1252 if ( SerialControl.speed == SPEED_100K )
1255 OCR0B = TCNT0 + 40 ;
1256 OCR0A = OCR0B + 210 ;
1257 TIFR0 = (1<<OCF0A) | (1<<OCF0B) ;
1258 TIMSK0 |= (1<<OCIE0B) ;
1259 SerialControl.busy = 1 ;
1265 TIMSK0 |= (1<<TOIE0) ;
1266 SerialControl.busy = 1 ;
1275 // Assume timer0 at 0.5uS clock
1277 ISR(TIMER0_COMPA_vect)
1285 byte /= 2 ; // Generates shorter code than byte >>= 1
1287 if ( --GPIOR1 == 0 )
1289 TIMSK0 &= ~(1<<OCIE0A) ;
1296 ISR(TIMER0_COMPB_vect)
1304 byte /= 2 ; // Generates shorter code than byte >>= 1
1306 if ( --GPIOR1 == 0 )
1308 if ( IS_TX_PAUSE_on )
1310 SerialControl.busy = 0 ;
1311 TIMSK0 &= ~(1<<OCIE0B) ;
1315 // prepare next byte and allow for 2 stop bits
1316 volatile struct t_serial_bash *ptr = &SerialControl ;
1317 if ( ptr->head != ptr->tail )
1319 GPIOR0 = ptr->data[ptr->tail] ;
1320 GPIOR2 = ptr->data[ptr->tail+1] ;
1321 uint8_t nextTail = ptr->tail + 2 ;
1322 if ( nextTail >= TXBUFFER_SIZE )
1324 ptr->tail = nextTail ;
1326 OCR0A = OCR0B + 40 ;
1327 OCR0B = OCR0A + 8 * 20 ;
1328 TIMSK0 |= (1<<OCIE0A) ;
1332 SerialControl.busy = 0 ;
1333 TIMSK0 &= ~(1<<OCIE0B) ;
1341 ISR(TIMER0_OVF_vect)
1352 byte /= 2 ; // Generates shorter code than byte >>= 1
1357 if ( --GPIOR1 == 0 )
1358 { // prepare next byte
1359 volatile struct t_serial_bash *ptr = &SerialControl ;
1360 if ( ptr->head != ptr->tail )
1362 GPIOR0 = ptr->data[ptr->tail] ;
1363 GPIOR2 = ptr->data[ptr->tail+1] ;
1364 uint8_t nextTail = ptr->tail + 2 ;
1365 if ( nextTail >= TXBUFFER_SIZE )
1367 ptr->tail = nextTail ;
1372 SerialControl.busy = 0 ;
1373 TIMSK0 &= ~(1<<TOIE0) ;
1379 #endif // BASH_SERIAL