Browse Source

cleanup multiprotocol

master
Schoenberger, Philipp 6 years ago
parent
commit
a380a747a0
  1. 59
      Multiprotocol/FrSkyD_cc2500.cpp
  2. 155
      Multiprotocol/FrSkyV_cc2500.cpp
  3. 39
      Multiprotocol/FrSkyV_cc2500.h
  4. 363
      Multiprotocol/FrSkyX_cc2500.cpp
  5. 37
      Multiprotocol/FrSkyX_cc2500.h
  6. 478
      Multiprotocol/Multiprotocol.h
  7. 588
      Multiprotocol/Multiprotocol.ino
  8. 248
      Multiprotocol/Validate.h
  9. 14
      Multiprotocol/cc2500_spi.cpp
  10. 33
      Multiprotocol/cc2500_spi.h
  11. 25
      Multiprotocol/common.cpp
  12. 14
      Multiprotocol/common.h
  13. 35
      Multiprotocol/config.cpp
  14. 14
      Multiprotocol/config.h
  15. 11
      Multiprotocol/debug.h
  16. 409
      Multiprotocol/input.cpp
  17. 76
      Multiprotocol/input.h
  18. 47
      Multiprotocol/state.cpp
  19. 11
      Multiprotocol/state.h
  20. 164
      Multiprotocol/tx_def.h

59
Multiprotocol/FrSkyD_cc2500.cpp

@ -17,6 +17,7 @@
#include "cc2500_spi.h"
#include "Multiprotocol.h"
uint16_t counter;
void frsky2way_init(uint8_t bind)
{
//debugln("frsky2way_init");
@ -105,12 +106,10 @@ uint16_t initFrSky_2way()
{
frsky2way_init(1);
state = FRSKY_BIND;
debugln("initFrSky_2way bind");
}
else
{
debugln("initFrSky_2way bind");
} else {
state = FRSKY_BIND_DONE;
debugln("initFrSky_2way bind done");
debugln("initFrSky_2way bind done");
}
return 10000;
}
@ -119,8 +118,7 @@ uint16_t ReadFrSky_2way()
{
//debugln("%s",__func__);
if (state < FRSKY_BIND_DONE)
{
if (state < FRSKY_BIND_DONE) {
frsky2way_build_bind_packet();
CC2500_Strobe(CC2500_SIDLE);
CC2500_WriteReg(CC2500_0A_CHANNR, 0x00);
@ -129,50 +127,43 @@ uint16_t ReadFrSky_2way()
CC2500_WriteData(packet, packet[0]+1);
if(IS_BIND_DONE) {
state = FRSKY_BIND;
debugln("%s bind done",__func__);
} else
state++;
if(state == FRSKY_BIND_DONE) {
debugln("%s bind done fr",__func__);
}
debugln("%s bind done",__func__);
} else {
// menu tells us to stop so do not inc state
//state++;
}
if(state == FRSKY_BIND_DONE) {
debugln("%s bind done fr",__func__);
}
return 9000;
}
if (state == FRSKY_BIND_DONE)
{
if (state == FRSKY_BIND_DONE) {
//debugln("%s bind done",__func__);
state = FRSKY_DATA2;
frsky2way_init(0);
counter = 0;
BIND_DONE;
}
else
if (state == FRSKY_DATA5)
{
} else if (state == FRSKY_DATA5) {
CC2500_Strobe(CC2500_SRX);//0x34 RX enable
state = FRSKY_DATA1;
return 9200;
}
counter = (counter + 1) % 188;
if (state == FRSKY_DATA4)
{ //telemetry receive
if (state == FRSKY_DATA4) { //telemetry receive
CC2500_SetTxRxMode(RX_EN);
CC2500_Strobe(CC2500_SIDLE);
CC2500_WriteReg(CC2500_0A_CHANNR, hopping_frequency[counter % 47]);
CC2500_WriteReg(CC2500_23_FSCAL3, 0x89);
state++;
return 1300;
}
else
{
if (state == FRSKY_DATA1)
{
} else {
if (state == FRSKY_DATA1) {
len = CC2500_ReadReg(CC2500_3B_RXBYTES | CC2500_READ_BURST) & 0x7F;
//debugln("%d len",len);
if (len && len<=(0x11+3))// 20bytes
{
if (len && len<=(0x11+3)) { // 20bytes
CC2500_ReadData(pkt, len); //received telemetry packets
#if defined(TELEMETRY)
if(pkt[len-1] & 0x80)
@ -181,13 +172,10 @@ uint16_t ReadFrSky_2way()
frsky_check_telemetry(pkt,len); //check if valid telemetry packets and buffer them.
}
#endif
}
else
{
} else {
packet_count++;
// restart sequence on missed packet - might need count or timeout instead of one missed
if(packet_count>100)
{//~1sec
if(packet_count > 100) {//~1sec
packet_count=0;
#if defined TELEMETRY
telemetry_link=0;//no link frames
@ -200,8 +188,7 @@ uint16_t ReadFrSky_2way()
}
CC2500_Strobe(CC2500_SIDLE);
CC2500_WriteReg(CC2500_0A_CHANNR, hopping_frequency[counter % 47]);
if ( prev_option != option )
{
if ( prev_option != option ) {
CC2500_WriteReg(CC2500_0C_FSCTRL0,option); // Frequency offset hack
prev_option = option ;
}

155
Multiprotocol/FrSkyV_cc2500.cpp

@ -1,155 +0,0 @@
/*
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/>.
*/
#define FRSKYV_BIND_COUNT 200
#include "FrSkyV_cc2500.h"
#include "cc2500_spi.h"
#include "common.h"
uint8_t FRSKYV_crc8(uint8_t result, uint8_t *data, uint8_t len)
{
for(uint8_t i = 0; i < len; i++)
{
result = result ^ data[i];
for(uint8_t j = 0; j < 8; j++)
if(result & 0x80)
result = (result << 1) ^ 0x07;
else
result = result << 1;
}
return result;
}
uint8_t FRSKYV_crc8_le(uint8_t *data, uint8_t len)
{
uint8_t result = 0xD6;
for(uint8_t i = 0; i < len; i++)
{
result = result ^ data[i];
for(uint8_t j = 0; j < 8; j++)
if(result & 0x01)
result = (result >> 1) ^ 0x83;
else
result = result >> 1;
}
return result;
}
void FRSKYV_build_bind_packet()
{
//0e 03 01 57 12 00 06 0b 10 15 1a 00 00 00 61
packet[0] = 0x0e; //Length
packet[1] = 0x03; //Packet type
packet[2] = 0x01; //Packet type
packet[3] = rx_tx_addr[3];
packet[4] = rx_tx_addr[2];
packet[5] = (binding_idx % 10) * 5;
packet[6] = packet[5] * 5 + 6;
packet[7] = packet[5] * 5 + 11;
packet[8] = packet[5] * 5 + 16;
packet[9] = packet[5] * 5 + 21;
packet[10] = packet[5] * 5 + 26;
packet[11] = 0x00;
packet[12] = 0x00;
packet[13] = 0x00;
packet[14] = FRSKYV_crc8(0x93, packet, 14);
}
uint8_t FRSKYV_calc_channel()
{
uint32_t temp=seed;
temp = (temp * 0xaa) % 0x7673;
seed = temp;
return (seed & 0xff) % 0x32;
}
void FRSKYV_build_data_packet()
{
uint8_t idx = 0; // transmit lower channels
packet[0] = 0x0e;
packet[1] = rx_tx_addr[3];
packet[2] = rx_tx_addr[2];
packet[3] = seed & 0xff;
packet[4] = seed >> 8;
if (phase == FRSKYV_DATA1 || phase == FRSKYV_DATA3)
packet[5] = 0x0f;
else
if(phase == FRSKYV_DATA2 || phase == FRSKYV_DATA4)
{
packet[5] = 0xf0;
idx=4; // transmit upper channels
}
else
packet[5] = 0x00;
for(uint8_t i = 0; i < 4; i++)
{
uint16_t value = convert_channel_frsky(i+idx);
packet[2*i + 6] = value & 0xff;
packet[2*i + 7] = value >> 8;
}
packet[14] = FRSKYV_crc8(crc8, packet, 14);
}
uint16_t ReadFRSKYV()
{
if(IS_BIND_DONE)
{ // Normal operation
uint8_t chan = FRSKYV_calc_channel();
CC2500_Strobe(CC2500_SIDLE);
if (option != prev_option)
{
CC2500_WriteReg(CC2500_0C_FSCTRL0, option);
prev_option=option;
}
CC2500_WriteReg(CC2500_0A_CHANNR, chan * 5 + 6);
FRSKYV_build_data_packet();
if (phase == FRSKYV_DATA5)
{
CC2500_SetPower();
phase = FRSKYV_DATA1;
}
else
phase++;
CC2500_WriteData(packet, packet[0]+1);
return 9006;
}
// Bind mode
FRSKYV_build_bind_packet();
CC2500_Strobe(CC2500_SIDLE);
CC2500_WriteReg(CC2500_0A_CHANNR, 0x00);
CC2500_WriteData(packet, packet[0]+1);
binding_idx++;
if(binding_idx>=FRSKYV_BIND_COUNT)
BIND_DONE;
return 53460;
}
uint16_t initFRSKYV()
{
//ID is 15 bits. Using rx_tx_addr[2] and rx_tx_addr[3] since we want to use RX_Num for model match
rx_tx_addr[2]&=0x7F;
crc8 = FRSKYV_crc8_le(rx_tx_addr+2, 2);
FRSKY_init_cc2500(FRSKYV_cc2500_conf);
seed = 1;
binding_idx=0;
phase = FRSKYV_DATA1;
return 10000;
}

39
Multiprotocol/FrSkyV_cc2500.h

@ -1,39 +0,0 @@
/*
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/>.
*/
#ifndef _FRSKYV_CC2500_H_
#define _FRSKYV_CC2500_H_
#define FRSKYV_BIND_COUNT 200
#include <stdint.h>
#include "Multiprotocol.h"
enum frskyv_data_e {
FRSKYV_DATA1=0,
FRSKYV_DATA2,
FRSKYV_DATA3,
FRSKYV_DATA4,
FRSKYV_DATA5
};
uint8_t FRSKYV_crc8(uint8_t result, uint8_t *data, uint8_t len);
uint8_t FRSKYV_crc8_le(uint8_t *data, uint8_t len);
void FRSKYV_build_bind_packet(void);
uint8_t FRSKYV_calc_channel(void);
void FRSKYV_build_data_packet(void);
uint16_t ReadFRSKYV(void);
uint16_t initFRSKYV(void);
#endif

363
Multiprotocol/FrSkyX_cc2500.cpp

@ -1,363 +0,0 @@
/* **************************
* By Midelic on RCGroups *
**************************
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/>.
*/
#include "Arduino.h"
#include "Multiprotocol.h"
#include "FrSkyX_cc2500.h"
#include <stdint.h>
#include "common.h"
#include "cc2500_spi.h"
uint8_t FrX_chanskip;
uint8_t FrX_send_seq ;
uint8_t FrX_receive_seq ;
void frskyX_set_start(uint8_t ch)
{
CC2500_Strobe(CC2500_SIDLE);
CC2500_WriteReg(CC2500_25_FSCAL1, calData[ch]);
CC2500_WriteReg(CC2500_0A_CHANNR, hopping_frequency[ch]);
}
void frskyX_init(void)
{
FRSKY_init_cc2500((sub_protocol&2)?FRSKYXEU_cc2500_conf:FRSKYX_cc2500_conf); // LBT or FCC
//
for(uint8_t c=0;c < 48;c++)
{//calibrate hop channels
CC2500_Strobe(CC2500_SIDLE);
CC2500_WriteReg(CC2500_0A_CHANNR,hopping_frequency[c]);
CC2500_Strobe(CC2500_SCAL);
delayMicroseconds(900);//
calData[c] = CC2500_ReadReg(CC2500_25_FSCAL1);
}
//#######END INIT########
}
void frskyX_initialize_data(uint8_t adr)
{
CC2500_WriteReg(CC2500_0C_FSCTRL0,option); // Frequency offset hack
CC2500_WriteReg(CC2500_18_MCSM0, 0x8);
CC2500_WriteReg(CC2500_09_ADDR, adr ? 0x03 : rx_tx_addr[3]);
CC2500_WriteReg(CC2500_07_PKTCTRL1,0x05);
}
//**CRC**
const uint16_t frskyX_CRC_Short[]={
0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF,
0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7 };
uint16_t frskyX_CRCTable(uint8_t val)
{
uint16_t word ;
word = pgm_read_word(&frskyX_CRC_Short[val&0x0F]) ;
val /= 16 ;
return word ^ (0x1081 * val) ;
}
uint16_t frskyX_crc_x(uint8_t *data, uint8_t len)
{
uint16_t crc = 0;
for(uint8_t i=0; i < len; i++)
crc = (crc<<8) ^ frskyX_CRCTable((uint8_t)(crc>>8) ^ *data++);
return crc;
}
void frskyX_build_bind_packet(void)
{
// debugln("%s:%d build bind", __func__, __LINE__);
packet[0] = (sub_protocol & 2 ) ? 0x20 : 0x1D ; // LBT or FCC
packet[1] = 0x03;
packet[2] = 0x01;
//
packet[3] = rx_tx_addr[3];
packet[4] = rx_tx_addr[2];
int idx = ((state -FRSKY_BIND) % 10) * 5;
packet[5] = idx;
packet[6] = hopping_frequency[idx++];
packet[7] = hopping_frequency[idx++];
packet[8] = hopping_frequency[idx++];
packet[9] = hopping_frequency[idx++];
packet[10] = hopping_frequency[idx++];
packet[11] = 0x02;
packet[12] = RX_num;
//
uint8_t limit = (sub_protocol & 2 ) ? 31 : 28 ;
memset(&packet[13], 0, limit - 13);
uint16_t lcrc = frskyX_crc_x(&packet[3], limit-3);
//
packet[limit++] = lcrc >> 8;
packet[limit] = lcrc;
//
}
// 0-2047, 0 = 817, 1024 = 1500, 2047 = 2182
//64=860,1024=1500,1984=2140//Taranis 125%
uint16_t frskyX_scaleForPXX(uint8_t i)
{ //mapped 860,2140(125%) range to 64,1984(PXX values);
uint16_t chan_val=convert_channel_frsky(i)-1226;
if(i>7) chan_val|=2048; // upper channels offset
return chan_val;
}
uint16_t frskyX_scaleForPXX_FS(uint8_t i)
{ //mapped 1,2046(125%) range to 64,1984(PXX values);
uint16_t chan_val=((Failsafe_data[i]*15)>>4)+64;
if(Failsafe_data[i]==FAILSAFE_CHANNEL_NOPULSES)
chan_val=FAILSAFE_CHANNEL_NOPULSES;
else if(Failsafe_data[i]==FAILSAFE_CHANNEL_HOLD)
chan_val=FAILSAFE_CHANNEL_HOLD;
if(i>7) chan_val|=2048; // upper channels offset
return chan_val;
}
void frskyX_data_frame(void)
{
//0x1D 0xB3 0xFD 0x02 0x56 0x07 0x15 0x00 0x00 0x00 0x04 0x40 0x00 0x04 0x40 0x00 0x04 0x40 0x00 0x04 0x40 0x08 0x00 0x00 0x00 0x00 0x00 0x00 0x96 0x12
//
static uint8_t chan_offset=0;
uint16_t chan_0 ;
uint16_t chan_1 ;
//
// data frames sent every 9ms; failsafe every 9 seconds
#ifdef FAILSAFE_ENABLE
static uint16_t failsafe_count=0;
static uint8_t FS_flag=0,failsafe_chan=0;
if (FS_flag == 0 && failsafe_count > FRX_FAILSAFE_TIME && chan_offset == 0 && IS_FAILSAFE_VALUES_on)
{
FS_flag = 0x10;
failsafe_chan = 0;
} else if (FS_flag & 0x10 && failsafe_chan < (sub_protocol & 0x01 ? 8-1:16-1))
{
FS_flag = 0x10 | ((FS_flag + 2) & 0x0F); //10, 12, 14, 16, 18, 1A, 1C, 1E - failsafe packet
failsafe_chan ++;
} else if (FS_flag & 0x10)
{
FS_flag = 0;
failsafe_count = 0;
}
failsafe_count++;
#endif
packet[0] = (sub_protocol & 0x02 ) ? 0x20 : 0x1D ; // LBT or FCC
packet[1] = rx_tx_addr[3];
packet[2] = rx_tx_addr[2];
packet[3] = 0x02;
//
packet[4] = (FrX_chanskip<<6)|hopping_frequency_no;
packet[5] = FrX_chanskip>>2;
packet[6] = RX_num;
//packet[7] = FLAGS 00 - standard packet
//10, 12, 14, 16, 18, 1A, 1C, 1E - failsafe packet
//20 - range check packet
#ifdef FAILSAFE_ENABLE
packet[7] = FS_flag;
#else
packet[7] = 0;
#endif
packet[8] = 0;
//
uint8_t startChan = chan_offset; for(uint8_t i = 0; i <12 ; i+=3)
{//12 bytes of channel data
#ifdef FAILSAFE_ENABLE
if( (FS_flag & 0x10) && ((failsafe_chan & 0x07) == (startChan & 0x07)) )
chan_0 = frskyX_scaleForPXX_FS(failsafe_chan);
else
#endif
chan_0 = frskyX_scaleForPXX(startChan);
startChan++;
//
#ifdef FAILSAFE_ENABLE
if( (FS_flag & 0x10) && ((failsafe_chan & 0x07) == (startChan & 0x07)) )
chan_1 = frskyX_scaleForPXX_FS(failsafe_chan);
else
#endif
chan_1 = frskyX_scaleForPXX(startChan);
startChan++;
//
packet[9+i] = lowByte(chan_0); //3 bytes*4
packet[9+i+1]=(((chan_0>>8) & 0x0F)|(chan_1 << 4));
packet[9+i+2]=chan_1>>4;
}
packet[21] = (FrX_receive_seq << 4) | FrX_send_seq ;//8 at start
if(sub_protocol & 0x01 ) // in X8 mode send only 8ch every 9ms
chan_offset = 0 ;
else
chan_offset^=0x08;
uint8_t limit = (sub_protocol & 2 ) ? 31 : 28 ;
for (uint8_t i=22;i<limit;i++)
packet[i]=0;
#if defined SPORT_POLLING
uint8_t idxs=0;
if(ok_to_send)
for (uint8_t i=23;i<limit;i++)
{//
if(sport_index==sport_idx)
{//no new data
ok_to_send=false;
break;
}
packet[i]=SportData[sport_index];
sport_index= (sport_index+1)& (MAX_SPORT_BUFFER-1);
idxs++;
}
packet[22]= idxs;
#ifdef DEBUG_SERIAL
for(uint8_t i=0;i<idxs;i++)
{
Serial.print(packet[23+i],HEX);
Serial.print(" ");
}
Serial.println(" ");
#endif
#endif // SPORT_POLLING
uint16_t lcrc = frskyX_crc_x(&packet[3], limit-3);
packet[limit++]=lcrc>>8;//high byte
packet[limit]=lcrc;//low byte
}
uint16_t ReadFrSkyX(void)
{
switch(state)
{
default:
frskyX_set_start(47);
CC2500_SetPower();
CC2500_Strobe(CC2500_SFRX);
//
frskyX_build_bind_packet();
CC2500_Strobe(CC2500_SIDLE);
CC2500_WriteData(packet, packet[0]+1);
if(IS_BIND_DONE) {
state = FRSKY_BIND_DONE;
//debugln("%s:%d bind done", __func__, __LINE__);
}
else
state++;
return 9000;
case FRSKY_BIND_DONE:
frskyX_initialize_data(0);
hopping_frequency_no=0;
BIND_DONE;
state++;
break;
case FRSKY_DATA1:
if ( prev_option != option )
{
CC2500_WriteReg(CC2500_0C_FSCTRL0,option); // Frequency offset hack
prev_option = option ;
}
CC2500_SetTxRxMode(TX_EN);
frskyX_set_start(hopping_frequency_no);
CC2500_SetPower();
CC2500_Strobe(CC2500_SFRX);
hopping_frequency_no = (hopping_frequency_no+FrX_chanskip)%47;
CC2500_Strobe(CC2500_SIDLE);
CC2500_WriteData(packet, packet[0]+1);
//
// frskyX_data_frame();
state++;
return 5200;
case FRSKY_DATA2:
CC2500_SetTxRxMode(RX_EN);
CC2500_Strobe(CC2500_SIDLE);
state++;
return 200;
case FRSKY_DATA3:
CC2500_Strobe(CC2500_SRX);
state++;
return 3100;
case FRSKY_DATA4:
len = CC2500_ReadReg(CC2500_3B_RXBYTES | CC2500_READ_BURST) & 0x7F;
if (len && (len<=(0x0E + 3))) //Telemetry frame is 17
{
packet_count=0;
CC2500_ReadData(pkt, len);
#if defined TELEMETRY
frsky_check_telemetry(pkt,len); //check if valid telemetry packets
//parse telemetry packets here
//The same telemetry function used by FrSky(D8).
#endif
}
else
{
packet_count++;
// restart sequence on missed packet - might need count or timeout instead of one missed
if(packet_count>100)
{//~1sec
// seq_last_sent = 0;
// seq_last_rcvd = 8;
FrX_send_seq = 0x08 ;
// FrX_receive_seq = 0 ;
packet_count=0;
#if defined TELEMETRY
telemetry_lost=1;
#endif
}
CC2500_Strobe(CC2500_SFRX); //flush the RXFIFO
}
frskyX_data_frame();
if ( FrX_send_seq != 0x08 )
{
FrX_send_seq = ( FrX_send_seq + 1 ) & 0x03 ;
}
state = FRSKY_DATA1;
return 500;
}
return 1;
}
uint16_t initFrSkyX(void)
{
set_rx_tx_addr(MProtocol_id_master);
Frsky_init_hop();
packet_count=0;
while(!FrX_chanskip)
FrX_chanskip=random(0xfefefefe)%47;
//for test***************
rx_tx_addr[3]=0xB3;
rx_tx_addr[2]=0xFD;
//************************
frskyX_init();
#if defined SPORT_POLLING
#ifdef INVERT_SERIAL
start_timer4() ;
#endif
#endif
//
if(IS_BIND_IN_PROGRESS)
{
state = FRSKY_BIND;
frskyX_initialize_data(1);
}
else
{
state = FRSKY_DATA1;
frskyX_initialize_data(0);
}
// seq_last_sent = 0;
// seq_last_rcvd = 8;
FrX_send_seq = 0x08 ;
FrX_receive_seq = 0 ;
return 10000;
}

37
Multiprotocol/FrSkyX_cc2500.h

@ -1,37 +0,0 @@
/* **************************
* By Midelic on RCGroups *
**************************
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/>.
*/
#ifndef _FRSKYX_CC2500_H_
#define _FRSKYX_CC2500_H_
#include <stdint.h>
#define FRX_FAILSAFE_TIMEOUT 1032
#define FRX_FAILSAFE_TIME 1032
void frskyX_set_start(uint8_t ch);
void frskyX_init(void);
void frskyX_initialize_data(uint8_t adr);
uint16_t frskyX_CRCTable(uint8_t val);
uint16_t frskyX_crc_x(uint8_t *data, uint8_t len);
void frskyX_build_bind_packet(void);
uint16_t frskyX_scaleForPXX(uint8_t i);
uint16_t frskyX_scaleForPXX_FS(uint8_t i);
void frskyX_data_frame(void);
uint16_t ReadFrSkyX(void);
uint16_t initFrSkyX(void);
#endif

478
Multiprotocol/Multiprotocol.h

@ -25,7 +25,6 @@
void set_rx_tx_addr(uint32_t id);
#define MAX_PKT 29
extern volatile uint16_t PPM_data[NUM_CHN];
extern uint8_t hopping_frequency_no;
extern uint8_t sub_protocol;
extern uint8_t calData[48];
@ -34,11 +33,8 @@ extern uint8_t protocol_flags;
extern uint8_t protocol_flags2;
extern uint8_t pkt[MAX_PKT];//telemetry receiving packets
extern uint8_t prev_option;
extern uint8_t prev_power; // unused power value
extern uint16_t counter;
extern uint8_t hopping_frequency[50];
extern uint8_t crc8;
extern uint16_t Channel_data[NUM_CHN];
extern uint8_t packet_count;
extern uint8_t RX_num;
extern uint8_t binding_idx;
@ -67,14 +63,13 @@ enum MultiPacketTypes
};
// Macros
#ifndef _BV
#define _BV(i) (1<<i)
#endif
//***************
//*** Flags ***
//***************
#define RX_FLAG_on protocol_flags |= _BV(0)
#define RX_FLAG_off protocol_flags &= ~_BV(0)
#define IS_RX_FLAG_on ( ( protocol_flags & _BV(0) ) !=0 )
//
#define CHANGE_PROTOCOL_FLAG_on protocol_flags |= _BV(1)
#define CHANGE_PROTOCOL_FLAG_off protocol_flags &= ~_BV(1)
@ -95,35 +90,15 @@ enum MultiPacketTypes
#define BIND_BUTTON_FLAG_on protocol_flags |= _BV(5)
#define BIND_BUTTON_FLAG_off protocol_flags &= ~_BV(5)
#define IS_BIND_BUTTON_FLAG_on ( ( protocol_flags & _BV(5) ) !=0 )
//PPM RX OK
#define PPM_FLAG_off protocol_flags &= ~_BV(6)
#define PPM_FLAG_on protocol_flags |= _BV(6)
#define IS_PPM_FLAG_on ( ( protocol_flags & _BV(6) ) !=0 )
//Bind flag
#define BIND_IN_PROGRESS protocol_flags &= ~_BV(7)
#define BIND_DONE protocol_flags |= _BV(7)
#define IS_BIND_DONE ( ( protocol_flags & _BV(7) ) !=0 )
#define IS_BIND_IN_PROGRESS ( ( protocol_flags & _BV(7) ) ==0 )
//
#define FAILSAFE_VALUES_off protocol_flags2 &= ~_BV(0)
#define FAILSAFE_VALUES_on protocol_flags2 |= _BV(0)
#define IS_FAILSAFE_VALUES_on ( ( protocol_flags2 & _BV(0) ) !=0 )
//
#define RX_DONOTUPDATE_off protocol_flags2 &= ~_BV(1)
#define RX_DONOTUPDATE_on protocol_flags2 |= _BV(1)
#define IS_RX_DONOTUPDATE_on ( ( protocol_flags2 & _BV(1) ) !=0 )
//
#define RX_MISSED_BUFF_off protocol_flags2 &= ~_BV(2)
#define RX_MISSED_BUFF_on protocol_flags2 |= _BV(2)
#define IS_RX_MISSED_BUFF_on ( ( protocol_flags2 & _BV(2) ) !=0 )
//TX Pause
#define TX_MAIN_PAUSE_off protocol_flags2 &= ~_BV(3)
#define TX_MAIN_PAUSE_on protocol_flags2 |= _BV(3)
#define IS_TX_MAIN_PAUSE_on ( ( protocol_flags2 & _BV(3) ) !=0 )
#define TX_RX_PAUSE_off protocol_flags2 &= ~_BV(4)
#define TX_RX_PAUSE_on protocol_flags2 |= _BV(4)
#define IS_TX_RX_PAUSE_on ( ( protocol_flags2 & _BV(4) ) !=0 )
#define IS_TX_PAUSE_on ( ( protocol_flags2 & (_BV(4)|_BV(3)) ) !=0 )
//Bind from channel
#define BIND_CH_PREV_off protocol_flags2 &= ~_BV(6)
#define BIND_CH_PREV_on protocol_flags2 |= _BV(6)
@ -135,456 +110,7 @@ enum MultiPacketTypes
#define IS_WAIT_BIND_on ( ( protocol_flags2 & _BV(7) ) !=0 )
#define IS_WAIT_BIND_off ( ( protocol_flags2 & _BV(7) ) ==0 )
// Failsafe
#define FAILSAFE_CHANNEL_HOLD 2047
#define FAILSAFE_CHANNEL_NOPULSES 0
#include "debug.h"
//********************
//*** Blink timing ***
//********************
#define BLINK_BIND_TIME 100
#define BLINK_SERIAL_TIME 500
#define BLINK_PPM_TIME 1000
#define BLINK_BAD_PROTO_TIME_HIGH 50
#define BLINK_BAD_PROTO_TIME_LOW 1000
#define BLINK_WAIT_BIND_TIME_HIGH 1000
#define BLINK_WAIT_BIND_TIME_LOW 100
#define BLINK_BANK_TIME_HIGH 50
#define BLINK_BANK_TIME_LOW 500
#define BLINK_BANK_REPEAT 1500
//*******************
//*** AUX flags ***
//*******************
#define GET_FLAG(ch, mask) ( ch ? mask : 0)
#define CH5_SW (Channel_AUX & _BV(0))
#define CH6_SW (Channel_AUX & _BV(1))
#define CH7_SW (Channel_AUX & _BV(2))
#define CH8_SW (Channel_AUX & _BV(3))
#define CH9_SW (Channel_AUX & _BV(4))
#define CH10_SW (Channel_AUX & _BV(5))
#define CH11_SW (Channel_AUX & _BV(6))
#define CH12_SW (Channel_AUX & _BV(7))
#define CH13_SW (Channel_data[CH13]>CHANNEL_SWITCH)
#define CH14_SW (Channel_data[CH14]>CHANNEL_SWITCH)
#define CH15_SW (Channel_data[CH15]>CHANNEL_SWITCH)
#define CH16_SW (Channel_data[CH16]>CHANNEL_SWITCH)
//************************
//*** Power settings ***
//************************
enum {
TXPOWER_100uW,
TXPOWER_300uW,
TXPOWER_1mW,
TXPOWER_3mW,
TXPOWER_10mW,
TXPOWER_30mW,
TXPOWER_100mW,
TXPOWER_150mW
};
// A7105 power
// Power amp is ~+16dBm so:
enum A7105_POWER
{
A7105_POWER_0 = 0x00<<3 | 0x00, // TXPOWER_100uW = -23dBm == PAC=0 TBG=0
A7105_POWER_1 = 0x00<<3 | 0x01, // TXPOWER_300uW = -20dBm == PAC=0 TBG=1
A7105_POWER_2 = 0x00<<3 | 0x02, // TXPOWER_1mW = -16dBm == PAC=0 TBG=2
A7105_POWER_3 = 0x00<<3 | 0x04, // TXPOWER_3mW = -11dBm == PAC=0 TBG=4
A7105_POWER_4 = 0x01<<3 | 0x05, // TXPOWER_10mW = -6dBm == PAC=1 TBG=5
A7105_POWER_5 = 0x02<<3 | 0x07, // TXPOWER_30mW = 0dBm == PAC=2 TBG=7
A7105_POWER_6 = 0x03<<3 | 0x07, // TXPOWER_100mW = 1dBm == PAC=3 TBG=7
A7105_POWER_7 = 0x03<<3 | 0x07 // TXPOWER_150mW = 1dBm == PAC=3 TBG=7
};
#define A7105_HIGH_POWER A7105_POWER_7
#define A7105_LOW_POWER A7105_POWER_3
#define A7105_RANGE_POWER A7105_POWER_0
#define A7105_BIND_POWER A7105_POWER_0
// NRF Power
// Power setting is 0..3 for nRF24L01
// Claimed power amp for nRF24L01 from eBay is 20dBm.
enum NRF_POWER
{ // Raw w 20dBm PA
NRF_POWER_0 = 0x00, // 0 : -18dBm (16uW) 2dBm (1.6mW)
NRF_POWER_1 = 0x01, // 1 : -12dBm (60uW) 8dBm (6mW)
NRF_POWER_2 = 0x02, // 2 : -6dBm (250uW) 14dBm (25mW)
NRF_POWER_3 = 0x03 // 3 : 0dBm (1mW) 20dBm (100mW)
};
#define NRF_HIGH_POWER NRF_POWER_3
#define NRF_LOW_POWER NRF_POWER_1
#define NRF_RANGE_POWER NRF_POWER_0
#define NRF_BIND_POWER NRF_POWER_0
// CC2500 power output from the chip itself
// The numbers do not take into account any outside amplifier
enum CC2500_POWER
{
CC2500_POWER_0 = 0x00, // -55dbm or less
CC2500_POWER_1 = 0x50, // -30dbm
CC2500_POWER_2 = 0x44, // -28dbm
CC2500_POWER_3 = 0xC0, // -26dbm
CC2500_POWER_4 = 0x84, // -24dbm
CC2500_POWER_5 = 0x81, // -22dbm
CC2500_POWER_6 = 0x46, // -20dbm
CC2500_POWER_7 = 0x93, // -18dbm
CC2500_POWER_8 = 0x55, // -16dbm
CC2500_POWER_9 = 0x8D, // -14dbm
CC2500_POWER_10 = 0xC6, // -12dbm
CC2500_POWER_11 = 0x97, // -10dbm
CC2500_POWER_12 = 0x6E, // -8dbm
CC2500_POWER_13 = 0x7F, // -6dbm
CC2500_POWER_14 = 0xA9, // -4dbm
CC2500_POWER_15 = 0xBB, // -2dbm
CC2500_POWER_16 = 0xFE, // 0dbm
CC2500_POWER_17 = 0xFF // +1dbm
};
#define CC2500_HIGH_POWER CC2500_POWER_1
#define CC2500_LOW_POWER CC2500_POWER_1
#define CC2500_RANGE_POWER CC2500_POWER_1
#define CC2500_BIND_POWER CC2500_POWER_1
// CYRF power
enum CYRF_POWER
{
CYRF_POWER_0 = 0x00, // -35dbm
CYRF_POWER_1 = 0x01, // -30dbm
CYRF_POWER_2 = 0x02, // -24dbm
CYRF_POWER_3 = 0x03, // -18dbm
CYRF_POWER_4 = 0x04, // -13dbm
CYRF_POWER_5 = 0x05, // -5dbm
CYRF_POWER_6 = 0x06, // 0dbm
CYRF_POWER_7 = 0x07 // +4dbm
};
#define CYRF_HIGH_POWER CYRF_POWER_7
#define CYRF_LOW_POWER CYRF_POWER_3
#define CYRF_RANGE_POWER CYRF_POWER_1 // 1/30 of the full power distance
#define CYRF_BIND_POWER CYRF_POWER_0
enum TXRX_State {
TXRX_OFF,
TX_EN,
RX_EN
};
// Packet ack status values
enum {
PKT_PENDING = 0,
PKT_ACKED,
PKT_TIMEOUT
};
// baudrate defines for serial
#define SPEED_100K 0
#define SPEED_9600 1
#define SPEED_57600 2
#define SPEED_125K 3
/** EEPROM Layout */
#define EEPROM_ID_OFFSET 10 // Module ID (4 bytes)
#define EEPROM_BANK_OFFSET 15 // Current bank number (1 byte)
#define EEPROM_ID_VALID_OFFSET 20 // 1 byte flag that ID is valid
#define MODELMODE_EEPROM_OFFSET 30 // Autobind mode, 1 byte per model, end is 30+16=46
#define AFHDS2A_EEPROM_OFFSET 50 // RX ID, 4 byte per model id, end is 50+64=114
#define BUGS_EEPROM_OFFSET 114 // RX ID, 4 byte per model id, end is 114+64=178
//#define CONFIG_EEPROM_OFFSET 178 // Current configuration of the multimodule
//****************************************
//*** MULTI protocol serial definition ***
//****************************************
/*
**************************
16 channels serial protocol
**************************
Serial: 100000 Baud 8e2 _ xxxx xxxx p --
Total of 26 bytes
Stream[0] = 0x55 sub_protocol values are 0..31 Stream contains channels
Stream[0] = 0x54 sub_protocol values are 32..63 Stream contains channels
Stream[0] = 0x57 sub_protocol values are 0..31 Stream contains failsafe
Stream[0] = 0x56 sub_protocol values are 32..63 Stream contains failsafe
header
Stream[1] = sub_protocol|BindBit|RangeCheckBit|AutoBindBit;
sub_protocol is 0..31 (bits 0..4), value should be added with 32 if Stream[0] = 0x54
=> Reserved 0
Flysky 1
Hubsan 2
FrskyD 3
Hisky 4
V2x2 5
DSM 6
Devo 7
YD717 8
KN 9
SymaX 10
SLT 11
CX10 12
CG023 13
Bayang 14
FrskyX 15
ESky 16
MT99XX 17
MJXQ 18
SHENQI 19
FY326 20
SFHSS 21
J6PRO 22
FQ777 23
ASSAN 24
FrskyV 25
HONTAI 26
OpenLRS 27
AFHDS2A 28
Q2X2 29
WK2x01 30
Q303 31
GW008 32
DM002 33
CABELL 34
ESKY150 35
H8_3D 36
CORONA 37
CFlie 38
Hitec 39
WFLY 40
BUGS 41
BindBit=> 0x80 1=Bind/0=No
AutoBindBit=> 0x40 1=Yes /0=No
RangeCheck=> 0x20 1=Yes /0=No
Stream[2] = RxNum | Power | Type;
RxNum value is 0..15 (bits 0..3)
Type is 0..7 <<4 (bit 4..6)
sub_protocol==Flysky
Flysky 0
V9x9 1
V6x6 2
V912 3
CX20 4
sub_protocol==Hubsan
H107 0
H301 1
H501 2
sub_protocol==Hisky
Hisky 0
HK310 1
sub_protocol==DSM
DSM2_22 0
DSM2_11 1
DSMX_22 2
DSMX_11 3
DSM_AUTO 4
sub_protocol==YD717
YD717 0
SKYWLKR 1
SYMAX4 2
XINXUN 3
NIHUI 4
sub_protocol==KN
WLTOYS 0
FEILUN 1
sub_protocol==SYMAX
SYMAX 0
SYMAX5C 1
sub_protocol==CX10
CX10_GREEN 0
CX10_BLUE 1 // also compatible with CX10-A, CX12
DM007 2
--- 3
JC3015_1 4
JC3015_2 5
MK33041 6
sub_protocol==Q2X2
Q222 0
Q242 1
Q282 2
sub_protocol==CG023
CG023 0
YD829 1
sub_protocol==BAYANG
BAYANG 0
H8S3D 1
X16_AH 2
IRDRONE 3
sub_protocol==MT99XX
MT99 0
H7 1
YZ 2
LS 3
FY805 4
sub_protocol==MJXQ
WLH08 0
X600 1
X800 2
H26D 3
E010 4
H26WH 5
sub_protocol==FRSKYX
CH_16 0
CH_8 1
EU_16 2
EU_8 3
sub_protocol==HONTAI
HONTAI 0
JJRCX1 1
X5C1 2
FQ777_951 3
sub_protocol==AFHDS2A
PWM_IBUS 0
PPM_IBUS 1
PWM_SBUS 2
PPM_SBUS 3
sub_protocol==V2X2
V2X2 0
JXD506 1
sub_protocol==FY326
FY326 0
FY319 1
sub_protocol==WK2x01
WK2801 0
WK2401 1
W6_5_1 2
W6_6_1 3
W6_HEL 4
W6_HEL_I 5
sub_protocol==Q303
Q303 0
CX35 1
CX10D 2
CX10WD 3
sub_protocol==CABELL
CABELL_V3 0
CABELL_V3_TELEMETRY 1
CABELL_SET_FAIL_SAFE 6
CABELL_UNBIND 7
sub_protocol==H8_3D
H8_3D 0
H20H 1
H20MINI 2
H30MINI 3
sub_protocol==CORONA
COR_V1 0
COR_V2 1
FD_V3 2
sub_protocol==HITEC
OPT_FW 0
OPT_HUB 1
MINIMA 2
sub_protocol==SLT
SLT_V1 0
SLT_V2 1
Q100 2
Q200 3
MR100 4
Power value => 0x80 0=High/1=Low
Stream[3] = option_protocol;
option_protocol value is -128..127
Stream[4] to [25] = Channels or failsafe depending on Steam[0]
16 Channels on 11 bits (0..2047)
0 -125%
204 -100%
1024 0%
1843 +100%
2047 +125%
Values are concatenated to fit in 22 bytes like in SBUS protocol.
Failsafe values have exactly the same range/values than normal channels except the extremes where
0=hold, 2047=no pulse. If failsafe is not set or RX then failsafe packets should not be sent.
*/
/*
Multimodule Status
Based on #define MULTI_STATUS
Serial: 100000 Baud 8e2 (same as input)
Format: header (2 bytes) + data (variable)
[0] = 'M' (0x4d)
[1] Length (excluding the 2 header bytes)
[2-xx] data
Type = 0x01 Multimodule Status:
[2] Flags
0x01 = Input signal detected
0x02 = Serial mode enabled
0x04 = Protocol is valid
0x08 = Module is in binding mode
0x10 = Module waits a bind event to load the protocol
0x20 = Failsafe supported by currently running protocol
[3] major
[4] minor
[5] revision
[6] patchlevel,
version of multi code, should be displayed as major.minor.revision.patchlevel
*/
/*
Multiprotocol telemetry/command definition for OpenTX
Based on #define MULTI_TELEMETRY enables OpenTX to get the multimodule status and select the correct telemetry type automatically.
Serial: 100000 Baud 8e2 (same as input)
TLV Protocol (type, length, value), allows a TX to ignore unknown messages
Format: header (4 byte) + data (variable)
[0] = 'M' (0x4d)
[1] = 'P' (0x50)
The first byte is deliberatly chosen to be different from other telemetry protocols
(e.g. 0xAA for DSM/Multi, 0xAA for FlySky and 0x7e for Frsky) to allow a TX to detect
the telemetry format of older versions
[2] Type (see below)
[3] Length (excluding the 4 header bytes)
[4-xx] data#define EEPROM_BANK_OFFSET 15 // Current bank number (1 byte)
Commands from TX to multi cannot be longer than 22 bytes (RXLen -4byte header)
Type = 0x01 Multimodule Status:
[4] Flags
0x01 = Input signal detected
0x02 = Serial mode enabled
0x04 = protocol is valid
0x08 = module is in binding mode
0x10 = module waits a bind event to load the protocol
[5] major
[6] minor
[7] revision
[8] patchlevel,
version of multi code, should be displayed as major.minor.revision.patchlevel
more information can be added by specifing a longer length of the type, the TX will just ignore these bytes
Type 0x02 Frksy S.port telemetry
Type 0x03 Frsky Hub telemetry
*No* usual frsky byte stuffing and without start/stop byte (0x7e)
Type 0x04 Spektrum telemetry data
data[0] TX RSSI
data[1-15] telemetry data
Type 0x05 DSM bind data
data[0-16] DSM bind data
technically DSM bind data is only 10 bytes but multi sends 16
like with telemtery, check length field)
Type 0x06 Flysky AFHDS2 telemetry data
length: 29
data[0] = RSSI value
data[1-28] telemetry data
Type 0x0A Hitec telemetry data
length: 8
data[0] = TX RSSI value
data[1] = TX LQI value
data[2] = frame number
data[3-7] telemetry data
Full description at the bottom of Hitec_cc2500.ino
*/
#endif

588
Multiprotocol/Multiprotocol.ino

@ -22,18 +22,13 @@
*/
//#define DEBUG_PIN // Use pin TX for AVR and SPI_CS for STM32 => DEBUG_PIN_on, DEBUG_PIN_off, DEBUG_PIN_toggle
#define DEBUG_SERIAL // Only for STM32_BOARD compiled with Upload method "Serial"->usart1, "STM32duino bootloader"->USB serial
#if defined (ARDUINO_AVR_XMEGA32D4) || defined (ARDUINO_MULTI_ORANGERX)
#include "MultiOrange.h"
#endif
#include "config.h"
#include "tx_def.h"
#include "Multiprotocol.h"
//Multiprotocol module configuration file
#include "pins.h"
#include "Validate.h"
@ -42,8 +37,8 @@
#include "input.h"
#include "cc2500_spi.h"
#include "FrSkyX_cc2500.h"
#include "FrSkyV_cc2500.h"
//#include "FrSkyX_cc2500.h"
//#include "FrSkyV_cc2500.h"
#include "FrSkyD_cc2500.h"
//Global constants/variables
@ -52,13 +47,11 @@ uint32_t MProtocol_id_master;
uint32_t blink=0,last_signal=0;
uint8_t protocol_flags=0,protocol_flags2=0;
//
uint16_t counter;
uint8_t channel;
uint8_t packet[40];
// Servo data
uint16_t Channel_data[NUM_CHN];
uint8_t Channel_AUX;
uint16_t seed;
// Protocol variables
uint8_t cyrfmfg_id[6];//for dsm2 and devo
@ -80,7 +73,6 @@ uint8_t throttle, rudder, elevator, aileron;
uint8_t flags;
uint16_t crc;
uint8_t crc8;
uint16_t seed;
uint16_t failsafe_count;
uint16_t state;
uint8_t len;
@ -89,18 +81,12 @@ uint8_t len;
uint8_t calData[48];
#endif
//Channel mapping for protocols
const uint8_t CH_AETR[]={AILERON, ELEVATOR, THROTTLE, RUDDER, CH5, CH6, CH7, CH8, CH9, CH10, CH11, CH12, CH13, CH14, CH15, CH16};
const uint8_t CH_TAER[]={THROTTLE, AILERON, ELEVATOR, RUDDER, CH5, CH6, CH7, CH8, CH9, CH10, CH11, CH12, CH13, CH14, CH15, CH16};
const uint8_t CH_RETA[]={RUDDER, ELEVATOR, THROTTLE, AILERON, CH5, CH6, CH7, CH8, CH9, CH10, CH11, CH12, CH13, CH14, CH15, CH16};
const uint8_t CH_EATR[]={ELEVATOR, AILERON, THROTTLE, RUDDER, CH5, CH6, CH7, CH8, CH9, CH10, CH11, CH12, CH13, CH14, CH15, CH16};
// Mode_select variables
uint8_t mode_select;
#ifdef ENABLE_PPM
// PPM variable
volatile uint16_t PPM_data[NUM_CHN];
volatile uint8_t PPM_chan_max=0;
#endif
@ -115,7 +101,6 @@ uint8_t protocol;
uint8_t option;
uint8_t cur_protocol[3];
uint8_t prev_option;
uint8_t prev_power=0xFD; // unused power value
uint8_t RX_num;
//Serial RX variables
@ -136,36 +121,24 @@ void_function_t remote_callback = 0;
void setup()
{
// Setup diagnostic uart before anything else
#ifdef DEBUG_SERIAL
#ifdef ENABLE_DBEUG
Serial.begin(115200,SERIAL_8N1);
while (!Serial); // Wait for ever for the serial port to connect...
debugln("Multiprotocol startup");
debugln("time %s ", __TIME__);
#endif
// General pinout
//ATMEGA328p
// all inputs
// outputs
SDI_output;
SCLK_output;
CC25_CSN_output;
// Timer1 config
#ifdef TCCR1A
TCCR1A = 0;
TCCR1B = (1 << CS11); //prescaler8, set timer1 to increment every 0.5us(16Mhz) and start timer
#endif
// Random
//random_init();
CC25_CSN_on;
// Set SPI lines
#ifdef STM32_BOARD
initSPI2();
#else
SDI_on;
SCLK_off;
#endif
//Wait for every component to start
delay(100);
@ -217,13 +190,6 @@ void setup()
}
debugln("Protocol selection switch reads as %d", mode_select);
#ifdef ENABLE_PPM
uint8_t bank=bank_switch();
#endif
// Set default channels' value
InitChannel();
InitPPM();
// Update LED
LED_off;
LED_output;
@ -231,18 +197,20 @@ void setup()
//Init RF modules
modules_reset();
randomSeed(42);
{
seed = analogRead(PA0);
randomSeed(seed);
}
// Read or create protocol id
MProtocol_id_master=random_id(10,false);
MProtocol_id_master=random_id(false);
debugln("Module Id: %lx", MProtocol_id_master);
#ifdef ENABLE_PPM
//Protocol and interrupts initialization
if(mode_select != MODE_SERIAL)
{ // PPM
uint8_t line=bank*14+mode_select-1;
{
uint8_t line=curr_bank*14+mode_select-1;
protocol = PPM_prot[line].protocol;
cur_protocol[1] = protocol;
sub_protocol = PPM_prot[line].sub_proto;
@ -265,8 +233,7 @@ void setup()
debugln("freq offset: %d", option);
if(PPM_prot[line].power)
POWER_FLAG_on;
if(PPM_prot[line].autobind)
{
if(PPM_prot[line].autobind) {
AUTOBIND_FLAG_on;
BIND_IN_PROGRESS; // Force a bind at protocol startup
}
@ -274,11 +241,7 @@ void setup()
protocol_init();
#if defined(TELEMETRY)
PPM_Telemetry_serial_init();// Configure serial for telemetry
#endif
}
else
#endif //ENABLE_PPM
debugln("Init complete");
input.init();
@ -310,8 +273,15 @@ void loop()
next_callback = remote_callback();
if (next_callback > 4000) {
uint32_t s;
s =micros();
input.update();
//update_state();
debugln("input took %lu", (micros()-s));
s =micros();
update_state();
debugln("state took %lu", (micros()-s));
}
uint32_t wait_until = start + next_callback;
@ -328,47 +298,21 @@ void loop()
}
uint8_t Update_All() {
#ifdef ENABLE_SERIAL
if(mode_select==MODE_SERIAL && IS_RX_FLAG_on) // Serial mode and something has been received
{
update_serial_data(); // Update protocol and data
update_channels_aux();
last_signal=millis();
}
#endif //ENABLE_SERIAL
#ifdef ENABLE_PPM
if(mode_select!=MODE_SERIAL && IS_PPM_FLAG_on) // PPM mode and a full frame has been received
{
debugln("%s:%d",__func__, __LINE__);
for(uint8_t i=0;i<PPM_chan_max;i++) {
// update servo data without interrupts to prevent bad read
uint16_t val;
cli(); // disable global int
val = PPM_data[i];
sei(); // enable global int
val=map16b(val,PPM_MIN_100*2,PPM_MAX_100*2,CHANNEL_MIN_100,CHANNEL_MAX_100);
if(val&0x8000) val=CHANNEL_MIN_125;
else if(val>CHANNEL_MAX_125) val=CHANNEL_MAX_125;
//Channel_data[i]=val;
}
PPM_FLAG_off; // wait for next frame before update
update_channels_aux();
last_signal=millis();
}
#endif //ENABLE_PPM
#ifdef ENABLE_BIND_CH
if(IS_AUTOBIND_FLAG_on && IS_BIND_CH_PREV_off && Channel_data[BIND_CH-1]>CHANNEL_MAX_COMMAND && Channel_data[THROTTLE]<(CHANNEL_MIN_100+50))
{ // Autobind is on and BIND_CH went up and Throttle is low
if(IS_AUTOBIND_FLAG_on &&
IS_BIND_CH_PREV_off &&
Channel_data[BIND_CH-1] > CHANNEL_MAX_COMMAND &&
Channel_data[Input::CH_THROTTLE] < (CHANNEL_MIN_100+50)
) { // Autobind is on and BIND_CH went up and Throttle is low
CHANGE_PROTOCOL_FLAG_on; //reload protocol
BIND_IN_PROGRESS; //enable bind
debugln("%s:%d set bind prog",__func__, __LINE__);
debugln("%s:%d set bind prog",__func__, __LINE__);
BIND_CH_PREV_on;
}
if(IS_AUTOBIND_FLAG_on && IS_BIND_CH_PREV_on && Channel_data[BIND_CH-1]<CHANNEL_MIN_COMMAND)
{ // Autobind is on and BIND_CH went down
if(IS_AUTOBIND_FLAG_on && IS_BIND_CH_PREV_on && Channel_data[BIND_CH-1]<CHANNEL_MIN_COMMAND) {
// Autobind is on and BIND_CH went down
BIND_CH_PREV_off;
//Request protocol to terminate bind
#if defined(FRSKYD_CC2500_INO) || defined(FRSKYX_CC2500_INO) || defined(FRSKYV_CC2500_INO)
@ -383,8 +327,7 @@ uint8_t Update_All() {
input.update();
if(IS_CHANGE_PROTOCOL_FLAG_on)
{
if(IS_CHANGE_PROTOCOL_FLAG_on) {
debugln("%s:%d set bind prog",__func__, __LINE__);
// Protocol needs to be changed or relaunched for bind
protocol_init(); //init new protocol
@ -393,137 +336,6 @@ uint8_t Update_All() {
return 0;
}
// Update channels direction and Channel_AUX flags based on servo AUX positions
static void update_channels_aux(void) {
//Reverse channels direction
#ifdef REVERSE_AILERON
reverse_channel(AILREON);
#endif
#ifdef REVERSE_ELEVATOR
reverse_channel(ELEVATOR);
#endif
#ifdef REVERSE_THROTTLE
reverse_channel(THROTTLE);
#endif
#ifdef REVERSE_RUDDER
reverse_channel(RUDDER);
#endif
//Calc AUX flags
Channel_AUX=0;
for(uint8_t i=0;i<8;i++)
if(Channel_data[CH5+i]>CHANNEL_SWITCH)
Channel_AUX|=1<<i;
}
#ifdef ENABLE_PPM
uint8_t bank_switch(void) {
uint8_t bank= curr_bank;
if(bank>=NBR_BANKS)
{ // Wrong number of bank
curr_bank = 0; // set bank to 0
bank=0;
}
debugln("Using bank %d", bank);
phase=3;
uint32_t check=millis();
blink=millis();
while(mode_select==15)
{ //loop here if the dial is on position 15 for user to select the bank
if(blink<millis())
{
switch(phase & 0x03)
{ // Flash bank number of times
case 0:
blink+=BLINK_BANK_TIME_HIGH;
phase++;
break;
case 1:
blink+=BLINK_BANK_TIME_LOW;
phase++;
break;
case 2:
if( (phase>>2) >= bank)
{
phase=0;
blink+=BLINK_BANK_REPEAT;
}
else
phase+=2;
break;
case 3:
blink+=BLINK_BANK_TIME_LOW;
phase=0;
break;
}
}
if(check<millis())
{
bool test_bind=true/*IS_BIND_BUTTON_on*/;
if( test_bind )
{ // Increase bank
bank++;
if(bank>=NBR_BANKS)
bank=0;
curr_bank = bank;
debugln("Using bank %d", bank);
phase=3;
blink+=BLINK_BANK_REPEAT;
check+=2*BLINK_BANK_REPEAT;
}
check+=1;
}
}
return bank;
}
#endif
inline void tx_pause()
{
#ifdef TELEMETRY
// Pause telemetry by disabling transmitter interrupt
#ifdef ORANGE_TX
USARTC0.CTRLA &= ~0x03 ;
#else
#ifndef BASH_SERIAL
#ifdef STM32_BOARD
USART3_BASE->CR1 &= ~ USART_CR1_TXEIE;
#else
UCSR0B &= ~_BV(UDRIE0);
#endif
#endif
#endif
#endif
}
inline void tx_resume()
{
#ifdef TELEMETRY
// Resume telemetry by enabling transmitter interrupt
#ifndef SPORT_POLLING
if(!IS_TX_PAUSE_on)
#endif
{
#ifdef ORANGE_TX
cli() ;
USARTC0.CTRLA = (USARTC0.CTRLA & 0xFC) | 0x01 ;
sei() ;
#else
#ifndef BASH_SERIAL
#ifdef STM32_BOARD
USART3_BASE->CR1 |= USART_CR1_TXEIE;
#else
UCSR0B |= _BV(UDRIE0);
#endif
#else
resumeBashSerial();
#endif
#endif
}
#endif
}
// Protocol start
static void protocol_init() {
static uint16_t next_callback;
@ -536,10 +348,6 @@ static void protocol_init() {
MProtocol_id = RX_num + MProtocol_id_master;
set_rx_tx_addr(MProtocol_id);
#ifdef FAILSAFE_ENABLE
InitFailsafe();
#endif
blink=millis();
debugln("Protocol selected: %d, sub proto %d, rxnum %d, option %d", protocol, sub_protocol, RX_num, option);
@ -550,20 +358,12 @@ static void protocol_init() {
next_callback = initFrSky_2way();
remote_callback = ReadFrSky_2way;
break;
case PROTO_FRSKYV:
next_callback = initFRSKYV();
remote_callback = ReadFRSKYV;
break;
case PROTO_FRSKYX:
next_callback = initFrSkyX();
remote_callback = ReadFrSkyX;
break;
}
}
#if defined(WAIT_FOR_BIND) && defined(ENABLE_BIND_CH)
if( IS_AUTOBIND_FLAG_on && IS_BIND_CH_PREV_off && (cur_protocol[1]&0x80)==0 && mode_select == MODE_SERIAL)
{ // Autobind is active but no bind requested by either BIND_CH or BIND. But do not wait if in PPM mode...
if( IS_AUTOBIND_FLAG_on && IS_BIND_CH_PREV_off && (cur_protocol[1]&0x80)==0 && mode_select == MODE_SERIAL) {
// Autobind is active but no bind requested by either BIND_CH or BIND. But do not wait if in PPM mode...
WAIT_BIND_on;
return;
}
@ -577,74 +377,36 @@ static void protocol_init() {
void update_serial_data()
{
RX_DONOTUPDATE_on;
RX_FLAG_off; //data is being processed
#ifdef SAMSON // Extremely dangerous, do not enable this unless you know what you are doing...
if( rx_ok_buff[0]==0x55 && (rx_ok_buff[1]&0x1F)==PROTO_FRSKYD && rx_ok_buff[2]==0x7F && rx_ok_buff[24]==217 && rx_ok_buff[25]==202 )
{//proto==FRSKYD+sub==7+rx_num==7+CH15==73%+CH16==73%
rx_ok_buff[1]=(rx_ok_buff[1]&0xE0) | PROTO_FLYSKY; // change the protocol to Flysky
memcpy((void*)(rx_ok_buff+4),(void*)(rx_ok_buff+4+11),11); // reassign channels 9-16 to 1-8
}
#endif
if(rx_ok_buff[1]&0x20) //check range
RANGE_FLAG_on;
else
RANGE_FLAG_off;
if(rx_ok_buff[1]&0x40) //check autobind
AUTOBIND_FLAG_on;
else
AUTOBIND_FLAG_off;
if(rx_ok_buff[2]&0x80) //if rx_ok_buff[2] ==1,power is low ,0-power high
POWER_FLAG_off; //power low
else
POWER_FLAG_on; //power high
//Forced frequency tuning values for CC2500 protocols
#if defined(FORCE_FRSKYD_TUNING) && defined(FRSKYD_CC2500_INO)
#if defined(FORCE_FRSKYD_TUNING)
if(protocol==PROTO_FRSKYD)
option=FORCE_FRSKYD_TUNING; // Use config-defined tuning value for FrSkyD
else
#endif
#if defined(FORCE_FRSKYV_TUNING) && defined(FRSKYV_CC2500_INO)
if(protocol==PROTO_FRSKYV)
option=FORCE_FRSKYV_TUNING; // Use config-defined tuning value for FrSkyV
else
#endif
#if defined(FORCE_FRSKYX_TUNING) && defined(FRSKYX_CC2500_INO)
if(protocol==PROTO_FRSKYX)
option=FORCE_FRSKYX_TUNING; // Use config-defined tuning value for FrSkyX
else
#endif
#if defined(FORCE_SFHSS_TUNING) && defined(SFHSS_CC2500_INO)
if (protocol==PROTO_SFHSS)
option=FORCE_SFHSS_TUNING; // Use config-defined tuning value for SFHSS
else
#endif
#if defined(FORCE_CORONA_TUNING) && defined(CORONA_CC2500_INO)
if (protocol==PROTO_CORONA)
option=FORCE_CORONA_TUNING; // Use config-defined tuning value for CORONA
else
#endif
#if defined(FORCE_HITEC_TUNING) && defined(HITEC_CC2500_INO)
if (protocol==PROTO_HITEC)
option=FORCE_HITEC_TUNING; // Use config-defined tuning value for HITEC
else
#endif
option=rx_ok_buff[3]; // Use radio-defined option value
#ifdef FAILSAFE_ENABLE
bool failsafe=false;
if(rx_ok_buff[0]&0x02)
{ // Packet contains failsafe instead of channels
if(rx_ok_buff[0]&0x02) { // Packet contains failsafe instead of channels
failsafe=true;
rx_ok_buff[0]&=0xFD; //remove the failsafe flag
FAILSAFE_VALUES_on; //failsafe data has been received
}
#endif
#ifdef BONI
if(CH14_SW)
rx_ok_buff[2]=(rx_ok_buff[2]&0xF0)|((rx_ok_buff[2]+1)&0x0F); // Extremely dangerous, do not enable this!!! This is really for a special case...
#endif
if( (rx_ok_buff[0] != cur_protocol[0]) || ((rx_ok_buff[1]&0x5F) != (cur_protocol[1]&0x5F)) || ( (rx_ok_buff[2]&0x7F) != (cur_protocol[2]&0x7F) ) )
{ // New model has been selected
CHANGE_PROTOCOL_FLAG_on; //change protocol
@ -656,14 +418,11 @@ void update_serial_data()
protocol=(rx_ok_buff[0]==0x55?0:32) + (rx_ok_buff[1]&0x1F); //protocol no (0-63) bits 4-6 of buff[1] and bit 0 of buf[0]
sub_protocol=(rx_ok_buff[2]>>4)& 0x07; //subprotocol no (0-7) bits 4-6
RX_num=rx_ok_buff[2]& 0x0F; // rx_num bits 0---3
}
else
if( ((rx_ok_buff[1]&0x80)!=0) && ((cur_protocol[1]&0x80)==0) ) // Bind flag has been set
} else if( ((rx_ok_buff[1]&0x80)!=0) && ((cur_protocol[1]&0x80)==0) ) // Bind flag has been set
{ // Restart protocol with bind
CHANGE_PROTOCOL_FLAG_on;
BIND_IN_PROGRESS;
}
else
} else {
if( ((rx_ok_buff[1]&0x80)==0) && ((cur_protocol[1]&0x80)!=0) ) // Bind flag has been reset
{ // Request protocol to end bind
#if defined(FRSKYD_CC2500_INO) || defined(FRSKYX_CC2500_INO) || defined(FRSKYV_CC2500_INO)
@ -674,6 +433,7 @@ void update_serial_data()
if(bind_counter>2)
bind_counter=2;
}
}
//store current protocol values
for(uint8_t i=0;i<3;i++)
@ -682,104 +442,35 @@ void update_serial_data()
// decode channel/failsafe values
volatile uint8_t *p=rx_ok_buff+3;
uint8_t dec=-3;
for(uint8_t i=0;i<NUM_CHN;i++)
{
for(uint8_t i=0;i<NUM_TX_CHN;i++) {
dec+=3;
if(dec>=8)
{
if(dec>=8) {
dec-=8;
p++;
}
p++;
uint16_t temp=((*((uint32_t *)p))>>dec)&0x7FF;
#ifdef FAILSAFE_ENABLE
if(failsafe)
Failsafe_data[i]=temp; //value range 0..2047, 0=no pulses, 2047=hold
else
#endif
Channel_data[i]=temp; //value range 0..2047, 0=-125%, 2047=+125%
}
RX_DONOTUPDATE_off;
cli();
if(IS_RX_MISSED_BUFF_on) // If the buffer is still valid
{ memcpy((void*)rx_ok_buff,(const void*)rx_buff,RXBUFFER_SIZE);// Duplicate the buffer
RX_FLAG_on; // data to be processed next time...
RX_MISSED_BUFF_off;
}
sei();
#ifdef FAILSAFE_ENABLE
if(failsafe)
debugln("RX_FS:%d,%d,%d,%d",Failsafe_data[0],Failsafe_data[1],Failsafe_data[2],Failsafe_data[3]);
#endif
}
void modules_reset()
{
#ifdef CC2500_INSTALLED
CC2500_Reset();
#endif
#ifdef A7105_INSTALLED
A7105_Reset();
#endif
#ifdef CYRF6936_INSTALLED
CYRF_Reset();
#endif
#ifdef NRF24L01_INSTALLED
NRF24L01_Reset();
#endif
CC2500_Reset();
//Wait for every component to reset
delay(100);
prev_power=0xFD; // unused power value
}
#ifdef STM32_BOARD
void usart2_begin(uint32_t baud,uint32_t config )
{
usart_init(USART2);
usart_config_gpios_async(USART2,GPIOA,PIN_MAP[PA3].gpio_bit,GPIOA,PIN_MAP[PA2].gpio_bit,config);
LED2_output;
usart_set_baud_rate(USART2, STM32_PCLK1, baud);
usart_enable(USART2);
}
void usart3_begin(uint32_t baud,uint32_t config )
{
usart_init(USART3);
usart_config_gpios_async(USART3,GPIOB,PIN_MAP[PB11].gpio_bit,GPIOB,PIN_MAP[PB10].gpio_bit,config);
usart_set_baud_rate(USART3, STM32_PCLK1, baud);
usart_enable(USART3);
}
void init_HWTimer()
{
HWTimer2.pause(); // Pause the timer2 while we're configuring it
TIMER2_BASE->PSC = 35; // 36-1;for 72 MHZ /0.5sec/(35+1)
TIMER2_BASE->ARR = 0xFFFF; // Count until 0xFFFF
HWTimer2.setMode(TIMER_CH1, TIMER_OUTPUT_COMPARE); // Main scheduler
HWTimer2.setMode(TIMER_CH2, TIMER_OUTPUT_COMPARE); // Serial check
TIMER2_BASE->SR = 0x1E5F & ~TIMER_SR_CC2IF; // Clear Timer2/Comp2 interrupt flag
HWTimer2.attachInterrupt(TIMER_CH2,ISR_COMPB); // Assign function to Timer2/Comp2 interrupt
TIMER2_BASE->DIER &= ~TIMER_DIER_CC2IE; // Disable Timer2/Comp2 interrupt
HWTimer2.refresh(); // Refresh the timer's count, prescale, and overflow
HWTimer2.resume();
}
#endif
#if defined(TELEMETRY)
void PPM_Telemetry_serial_init()
{
if( (protocol==PROTO_FRSKYD))
initTXSerial( SPEED_9600 ) ;
if(protocol==PROTO_FRSKYX)
initTXSerial( SPEED_57600 ) ;
if(protocol==PROTO_DSM)
initTXSerial( SPEED_125K ) ;
}
#endif
// Convert 32b id to rx_tx_addr
void set_rx_tx_addr(uint32_t id)
{ // Used by almost all protocols
@ -790,18 +481,19 @@ void set_rx_tx_addr(uint32_t id)
rx_tx_addr[4] = (rx_tx_addr[2]&0xF0)|(rx_tx_addr[3]&0x0F);
}
uint32_t random_id(uint16_t address, uint8_t create_new)
uint32_t random_id(bool create_new)
{
#ifndef FORCE_GLOBAL_ID
#ifdef FORCE_GLOBAL_ID
(void)create_new;
return FORCE_GLOBAL_ID;
#else
uint32_t id=0;
#if 0
//(eeprom_read_byte((EE_ADDR)(address+10))==0xf0 && !create_new)
{ // TXID exists in EEPROM
for(uint8_t i=4;i>0;i--)
{
if (eeprom_read_byte((EE_ADDR)(10))==0xf0 && !create_new) {
// TXID exists in EEPROM
for(uint8_t i=4;i>0;i--) {
id<<=8;
id|=eeprom_read_byte((EE_ADDR)address+i-1);
id|=eeprom_read_byte((EE_ADDR)i-1);
}
if(id!=0x2AD141A7) //ID with seed=0
{
@ -809,18 +501,14 @@ uint32_t random_id(uint16_t address, uint8_t create_new)
return id;
}
}
// Generate a random ID
#if defined STM32_BOARD
// Generate a random ID from UUID
#define STM32_UUID ((uint32_t *)0x1FFFF7E8)
if (!create_new)
{
if (!create_new) {
id = STM32_UUID[0] ^ STM32_UUID[1] ^ STM32_UUID[2];
debugln("Generated ID from STM32 UUID");
debugln("Generated ID from STM32 UUID %x", id);
} else {
id = random(0xfefefefe) + ((uint32_t)random(0xfefefefe) << 16);
}
else
#endif
#endif
id = random(0xfefefefe) + ((uint32_t)random(0xfefefefe) << 16);
#if 0
for(uint8_t i=0;i<4;i++)
@ -828,166 +516,6 @@ uint32_t random_id(uint16_t address, uint8_t create_new)
eeprom_write_byte((EE_ADDR)(address+10),0xf0);//write bind flag in eeprom.
#endif
return id;
#else
(void)address;
(void)create_new;
return FORCE_GLOBAL_ID;
#endif
}
/**************************/
/**************************/
/** Interrupt routines **/
/**************************/
/**************************/
//PPM
#ifdef blubber // ENABLE_PPM
#ifdef ORANGE_TX
#if PPM_pin == 2
ISR(PORTD_INT0_vect)
#else
ISR(PORTD_INT1_vect)
#endif
#elif defined STM32_BOARD
void PPM_decode()
#else
#if PPM_pin == 2
ISR(INT0_vect, ISR_NOBLOCK)
#else
ISR(INT1_vect, ISR_NOBLOCK)
#endif
#endif
{ // Interrupt on PPM pin
static int8_t chan=0,bad_frame=1;
static uint16_t Prev_TCNT1=0;
uint16_t Cur_TCNT1;
Cur_TCNT1 = TCNT1 - Prev_TCNT1 ; // Capture current Timer1 value
if(Cur_TCNT1<1600)
bad_frame=1; // bad frame
else
if(Cur_TCNT1>4400)
{ //start of frame
if(chan>=MIN_PPM_CHANNELS)
{
PPM_FLAG_on; // good frame received if at least 4 channels have been seen
if(chan>PPM_chan_max) PPM_chan_max=chan; // Saving the number of channels received
}
chan=0; // reset channel counter
bad_frame=0;
}
else
if(bad_frame==0) // need to wait for start of frame
{ //servo values between 800us and 2200us will end up here
PPM_data[chan]=Cur_TCNT1;
if(chan++>=MAX_PPM_CHANNELS)
bad_frame=1; // don't accept any new channels
}
Prev_TCNT1+=Cur_TCNT1;
}
#endif //ENABLE_PPM
//Serial RX
#ifdef ENABLE_SERIAL
#ifdef ORANGE_TX
ISR(USARTC0_RXC_vect)
#elif defined STM32_BOARD
void __irq_usart2()
#else
ISR(USART_RX_vect)
#endif
{ // RX interrupt
static uint8_t idx=0;
#ifdef ORANGE_TX
if((USARTC0.STATUS & 0x1C)==0) // Check frame error, data overrun and parity error
#elif defined STM32_BOARD
if((USART2_BASE->SR & USART_SR_RXNE) && (USART2_BASE->SR &0x0F)==0)
#else
UCSR0B &= ~_BV(RXCIE0) ; // RX interrupt disable
sei() ;
if((UCSR0A&0x1C)==0) // Check frame error, data overrun and parity error
#endif
{ // received byte is ok to process
if(idx==0||discard_frame==1)
{ // Let's try to sync at this point
idx=0;discard_frame=0;
RX_MISSED_BUFF_off; // If rx_buff was good it's not anymore...
rx_buff[0]=UDR0;
#ifdef FAILSAFE_ENABLE
if((rx_buff[0]&0xFC)==0x54) // If 1st byte is 0x54, 0x55, 0x56 or 0x57 it looks ok
#else
if((rx_buff[0]&0xFE)==0x54) // If 1st byte is 0x54 or 0x55 it looks ok
#endif
{
TX_RX_PAUSE_on;
tx_pause();
#if defined STM32_BOARD
TIMER2_BASE->CCR2=TIMER2_BASE->CNT+(6500L); // Full message should be received within timer of 3250us
TIMER2_BASE->SR = 0x1E5F & ~TIMER_SR_CC2IF; // Clear Timer2/Comp2 interrupt flag
TIMER2_BASE->DIER |= TIMER_DIER_CC2IE; // Enable Timer2/Comp2 interrupt
#else
OCR1B = TCNT1+(6500L) ; // Full message should be received within timer of 3250us
TIFR1 = OCF1B_bm ; // clear OCR1B match flag
SET_TIMSK1_OCIE1B ; // enable interrupt on compare B match
#endif
idx++;
}
}
else
{
rx_buff[idx++]=UDR0; // Store received byte
if(idx>=RXBUFFER_SIZE)
{ // A full frame has been received
if(!IS_RX_DONOTUPDATE_on)
{ //Good frame received and main is not working on the buffer
memcpy((void*)rx_ok_buff,(const void*)rx_buff,RXBUFFER_SIZE);// Duplicate the buffer
RX_FLAG_on; // flag for main to process servo data
}
else
RX_MISSED_BUFF_on; // notify that rx_buff is good
discard_frame=1; // start again
}
}
}
else
{
idx=UDR0; // Dummy read
discard_frame=1; // Error encountered discard full frame...
debugln("Bad frame RX");
}
if(discard_frame==1)
{
#ifdef STM32_BOARD
TIMER2_BASE->DIER &= ~TIMER_DIER_CC2IE; // Disable Timer2/Comp2 interrupt
#else
CLR_TIMSK1_OCIE1B; // Disable interrupt on compare B match
#endif
TX_RX_PAUSE_off;
tx_resume();
}
#if not defined (ORANGE_TX) && not defined (STM32_BOARD)
cli() ;
UCSR0B |= _BV(RXCIE0) ; // RX interrupt enable
#endif
}
//Serial timer
#ifdef ORANGE_TX
ISR(TCC1_CCB_vect)
#elif defined STM32_BOARD
void ISR_COMPB()
#else
ISR(TIMER1_COMPB_vect, ISR_NOBLOCK )
#endif
{ // Timer1 compare B interrupt
discard_frame=1;
#ifdef STM32_BOARD
TIMER2_BASE->DIER &= ~TIMER_DIER_CC2IE; // Disable Timer2/Comp2 interrupt
debugln("Bad frame timer");
#else
CLR_TIMSK1_OCIE1B; // Disable interrupt on compare B match
#endif
tx_resume();
}
#endif //ENABLE_SERIAL
}

248
Multiprotocol/Validate.h

@ -3,69 +3,6 @@
#include "config.h"
#include "tx_def.h"
// Check selected board type
#if defined (STM32_BOARD) && defined (ORANGE_TX)
#error You must comment the board type STM32_BOARD in _Config.h to compile ORANGE_TX
#endif
#if not defined (ORANGE_TX) && not defined (STM32_BOARD)
//Atmega328p
#if (not defined(ARDUINO_AVR_PRO) && not defined(ARDUINO_AVR_LEONARDO) )&& not defined(ARDUINO_MULTI_NO_BOOT) && not defined(ARDUINO_MULTI_FLASH_FROM_TX) && not defined(ARDUINO_AVR_MINI) && not defined(ARDUINO_AVR_NANO)
#warning You must select one of these boards: "Multi 4-in-1", "Arduino Pro or Pro Mini" or "Arduino Mini"
#endif
#if F_CPU != 16000000L || not defined(__AVR_ATmega328P__) || not defined(__AVR_ATmega32U4__)
#warning You must select the processor type "ATmega328(5V, 16MHz)"
#endif
#endif
#if defined (STM32_BOARD) && not defined (ORANGE_TX)
//STM32
#if not defined(ARDUINO_GENERIC_STM32F103C) && not defined(ARDUINO_MULTI_STM32_FLASH_FROM_TX) && not defined(ARDUINO_MULTI_STM32_NO_BOOT) && not defined(ARDUINO_MULTI_STM32_WITH_BOOT)
#error You must select one of these boards: "Multi 4-in-1 (STM32F103CB)" or "Generic STM32F103C series"
#endif
#endif
// Check for minimum version of multi-module boards
#define MIN_AVR_BOARD 103
#define MIN_ORX_BOARD 103
#define MIN_STM32_BOARD 104
//AVR
#if (defined(ARDUINO_MULTI_NO_BOOT) && ARDUINO_MULTI_NO_BOOT < MIN_AVR_BOARD) || (defined(ARDUINO_MULTI_FLASH_FROM_TX) && ARDUINO_MULTI_FLASH_FROM_TX < MIN_AVR_BOARD)
#error You need to update your Multi 4-in-1 board definition. Open Boards Manager and update to the latest version of the Multi 4-in-1 AVR Boards.
#endif
//OrangeRX
#if (defined(ARDUINO_MULTI_ORANGERX) && ARDUINO_MULTI_ORANGERX < MIN_ORX_BOARD)
#error You need to update your Multi 4-in-1 board definition. Open Boards Manager and update to the latest version of the Multi 4-in-1 AVR Boards.
#endif
//STM32
#if (defined(ARDUINO_MULTI_STM32_NO_BOOT) && ARDUINO_MULTI_STM32_NO_BOOT < MIN_STM32_BOARD) || (defined(ARDUINO_MULTI_STM32_FLASH_FROM_TX) && ARDUINO_MULTI_STM32_FLASH_FROM_TX < MIN_STM32_BOARD) || (defined(ARDUINO_MULTI_STM32_WITH_BOOT) && ARDUINO_MULTI_STM32_WITH_BOOT < MIN_STM32_BOARD)
#error You need to update your Multi 4-in-1 board definition. Open Boards Manager and update to the latest version of the Multi 4-in-1 STM32 Board.
#endif
// Error if CHECK_FOR_BOOTLOADER is not enabled but a FLASH_FROM_TX board is selected
#if (defined(ARDUINO_MULTI_FLASH_FROM_TX) || defined(ARDUINO_MULTI_STM32_FLASH_FROM_TX)) &! defined(CHECK_FOR_BOOTLOADER)
#if defined(STM32_BOARD)
#error "You have selected the 'Flash from TX' upload method but not enabled CHECK_FOR_BOOTLOADER."
#else
#error "You have selected the 'Flash from TX' bootloader but not enabled CHECK_FOR_BOOTLOADER."
#endif
#endif
// Error if CHECK_FOR_BOOTLOADER is enabled but the 'Flash from TX' bootloader
#if defined(ARDUINO_MULTI_NO_BOOT) && defined(CHECK_FOR_BOOTLOADER)
#error "You have enabled CHECK_FOR_BOOTLOADER but not selected the 'Flash from TX' bootloader."
#endif
//Check number of banks
#if NBR_BANKS < 1 || NBR_BANKS > 5
#error "You need to select a number of banks between 1 and 5."
#endif
//Check failsafe throttle value
#ifdef FAILSAFE_ENABLE
#if ( FAILSAFE_THROTTLE_LOW < -125 ) || ( FAILSAFE_THROTTLE_LOW > 125 )
#error "The failsafe value for throttle is outside of the range -125..125."
#endif
#endif
// Check forced tuning values are valid
#ifdef FORCE_FRSKYD_TUNING
#if ( FORCE_FRSKYD_TUNING < -127 ) || ( FORCE_FRSKYD_TUNING > 127 )
@ -82,179 +19,7 @@
#error "The FrSkyX forced frequency tuning value is outside of the range -127..127."
#endif
#endif
#ifdef FORCE_SFHSS_TUNING
#if ( FORCE_SFHSS_TUNING < -127 ) || ( FORCE_SFHSS_TUNING > 127 )
#error "The SFHSS forced frequency tuning value is outside of the range -127..127."
#endif
#endif
#ifdef FORCE_CORONA_TUNING
#if ( FORCE_CORONA_TUNING < -127 ) || ( FORCE_CORONA_TUNING > 127 )
#error "The CORONA forced frequency tuning value is outside of the range -127..127."
#endif
#endif
#ifdef FORCE_HITEC_TUNING
#if ( FORCE_HITEC_TUNING < -127 ) || ( FORCE_HITEC_TUNING > 127 )
#error "The HITEC forced frequency tuning value is outside of the range -127..127."
#endif
#endif
#ifdef FORCE_FLYSKY_TUNING
#if ( FORCE_FLYSKY_TUNING < -300 ) || ( FORCE_FLYSKY_TUNING > 300 )
#error "The Flysky forced frequency tuning value is outside of the range -300..300."
#endif
#endif
#ifdef FORCE_HUBSAN_TUNING
#if ( FORCE_HUBSAN_TUNING < -300 ) || ( FORCE_HUBSAN_TUNING > 300 )
#error "The Hubsan forced frequency tuning value is outside of the range -300..300."
#endif
#endif
#ifdef FORCE_AFHDS2A_TUNING
#if ( FORCE_AFHDS2A_TUNING < -300 ) || ( FORCE_AFHDS2A_TUNING > 300 )
#error "The AFHDS2A forced frequency tuning value is outside of the range -300..300."
#endif
#endif
#ifndef USE_A7105_CH15_TUNING
#ifndef FORCE_FLYSKY_TUNING
#define FORCE_FLYSKY_TUNING 0
#endif
#ifndef FORCE_HUBSAN_TUNING
#define FORCE_HUBSAN_TUNING 0
#endif
#ifndef FORCE_AFHDS2A_TUNING
#define FORCE_AFHDS2A_TUNING 0
#endif
#endif
//Change/Force configuration if OrangeTX
#ifdef ORANGE_TX
#undef ENABLE_PPM // Disable PPM for OrangeTX module
#undef A7105_INSTALLED // Disable A7105 for OrangeTX module
#undef A7105_CSN_pin
#undef CC2500_INSTALLED // Disable CC2500 for OrangeTX module
#undef CC25_CSN_pin
#undef NRF24L01_INSTALLED // Disable NRF for OrangeTX module
#undef NRF_CSN_pin
#define TELEMETRY // Enable telemetry
#define INVERT_TELEMETRY // Enable invert telemetry
#define DSM_TELEMETRY // Enable DSM telemetry
#endif
//Make sure protocols are selected correctly
#ifndef A7105_INSTALLED
#undef FLYSKY_A7105_INO
#undef HUBSAN_A7105_INO
#undef AFHDS2A_A7105_INO
#undef BUGS_A7105_INO
#endif
#ifndef CYRF6936_INSTALLED
#undef DEVO_CYRF6936_INO
#undef DSM_CYRF6936_INO
#undef J6PRO_CYRF6936_INO
#undef WFLY_CYRF6936_INO
#undef WK2x01_CYRF6936_INO
#endif
#ifndef CC2500_INSTALLED
#undef FRSKYD_CC2500_INO
#undef FRSKYV_CC2500_INO
#undef FRSKYX_CC2500_INO
#undef SFHSS_CC2500_INO
#undef CORONA_CC2500_INO
#undef HITEC_CC2500_INO
#endif
#ifndef NRF24L01_INSTALLED
#undef BAYANG_NRF24L01_INO
#undef CG023_NRF24L01_INO
#undef CX10_NRF24L01_INO
#undef ESKY_NRF24L01_INO
#undef HISKY_NRF24L01_INO
#undef KN_NRF24L01_INO
#undef SLT_NRF24L01_INO
#undef SYMAX_NRF24L01_INO
#undef V2X2_NRF24L01_INO
#undef YD717_NRF24L01_INO
#undef MT99XX_NRF24L01_INO
#undef MJXQ_NRF24L01_INO
#undef SHENQI_NRF24L01_INO
#undef FY326_NRF24L01_INO
#undef FQ777_NRF24L01_INO
#undef ASSAN_NRF24L01_INO
#undef HONTAI_NRF24L01_INO
#undef Q303_NRF24L01_INO
#undef GW008_NRF24L01_INO
#undef DM002_NRF24L01_INO
#undef CABELL_NRF24L01_INO
#undef ESKY150_NRF24L01_INO
#undef H8_3D_NRF24L01_INO
#undef CFLIE_NRF24L01_INO
#endif
//Make sure telemetry is selected correctly
#ifndef TELEMETRY
#undef INVERT_TELEMETRY
#undef AFHDS2A_FW_TELEMETRY
#undef AFHDS2A_HUB_TELEMETRY
#undef HITEC_FW_TELEMETRY
#undef HITEC_HUB_TELEMETRY
#undef BAYANG_HUB_TELEMETRY
#undef CABELL_HUB_TELEMETRY
#undef HUBSAN_HUB_TELEMETRY
#undef BUGS_HUB_TELEMETRY
#undef HUB_TELEMETRY
#undef SPORT_TELEMETRY
#undef SPORT_POLLING
#undef DSM_TELEMETRY
#undef MULTI_STATUS
#undef MULTI_TELEMETRY
#else
#if defined MULTI_TELEMETRY && not defined INVERT_TELEMETRY
#warning MULTI_TELEMETRY has been defined but not INVERT_TELEMETRY. They should be both enabled for OpenTX telemetry and status to work.
#endif
#if not defined(BAYANG_NRF24L01_INO)
#undef BAYANG_HUB_TELEMETRY
#endif
#if not defined(CABELL_NRF24L01_INO)
#undef CABELL_HUB_TELEMETRY
#endif
#if not defined(HUBSAN_A7105_INO)
#undef HUBSAN_HUB_TELEMETRY
#endif
#if not defined(AFHDS2A_A7105_INO)
#undef AFHDS2A_HUB_TELEMETRY
#undef AFHDS2A_FW_TELEMETRY
#endif
#if not defined(HITEC_CC2500_INO)
#undef HITEC_HUB_TELEMETRY
#undef HITEC_FW_TELEMETRY
#endif
#if not defined(FRSKYD_CC2500_INO)
#undef HUB_TELEMETRY
#endif
#if not defined(FRSKYX_CC2500_INO)
#undef SPORT_TELEMETRY
#undef SPORT_POLLING
#endif
#if not defined (SPORT_TELEMETRY) || not defined (STM32_BOARD)
#undef SPORT_POLLING
#endif
#if defined SPORT_POLLING && not defined INVERT_TELEMETRY
#error SPORT_POLLING has been defined but not INVERT_TELEMETRY. They should be both enabled to work.
#endif
#if not defined(DSM_CYRF6936_INO)
#undef DSM_TELEMETRY
#endif
#if not defined(DSM_TELEMETRY) && not defined(SPORT_TELEMETRY) && not defined(HUB_TELEMETRY) && not defined(HUBSAN_HUB_TELEMETRY) && not defined(BUGS_HUB_TELEMETRY) && not defined(BAYANG_HUB_TELEMETRY) && not defined(CABELL_HUB_TELEMETRY) && not defined(AFHDS2A_HUB_TELEMETRY) && not defined(AFHDS2A_FW_TELEMETRY) && not defined(MULTI_TELEMETRY) && not defined(MULTI_STATUS) && not defined(HITEC_HUB_TELEMETRY) && not defined(HITEC_FW_TELEMETRY)
#undef TELEMETRY
#undef INVERT_TELEMETRY
#undef SPORT_POLLING
#endif
#endif
//Make sure TX is defined correctly
#ifndef AILERON
#error You must select a correct channel order.
#endif
#if not defined(PPM_MAX_100) || not defined(PPM_MIN_100)
#error You must set correct PPM end points for your TX.
#endif
#if defined(ENABLE_BIND_CH)
#if BIND_CH<4
@ -265,17 +30,4 @@
#endif
#endif
#if MIN_PPM_CHANNELS>16
#error MIN_PPM_CHANNELS must be below or equal to 16. The default for this value is 4.
#endif
#if MIN_PPM_CHANNELS<2
#error MIN_PPM_CHANNELS must be larger than 1. The default for this value is 4.
#endif
#if MAX_PPM_CHANNELS<MIN_PPM_CHANNELS
#error MAX_PPM_CHANNELS must be higher than MIN_PPM_CHANNELS. The default for this value is 16.
#endif
#if MAX_PPM_CHANNELS>16
#error MAX_PPM_CHANNELS must be below or equal to 16. The default for this value is 16.
#endif
#endif

14
Multiprotocol/cc2500_spi.cpp

@ -23,6 +23,7 @@
#include "cc2500_spi.h"
#include "spi.h"
uint8_t prev_power=0xFD; // unused power value
void CC2500_WriteReg(uint8_t address, uint8_t data)
{
CC25_CSN_off;
@ -85,14 +86,12 @@ void CC2500_SetTxRxMode(uint8_t mode)
//from deviation firmware
CC2500_WriteReg(CC2500_00_IOCFG2, 0x2F);
CC2500_WriteReg(CC2500_02_IOCFG0, 0x2F | 0x40);
} else {
if (mode == RX_EN) {
} else if (mode == RX_EN) {
CC2500_WriteReg(CC2500_02_IOCFG0, 0x2F);
CC2500_WriteReg(CC2500_00_IOCFG2, 0x2F | 0x40);
} else {
} else {
CC2500_WriteReg(CC2500_02_IOCFG0, 0x2F);
CC2500_WriteReg(CC2500_00_IOCFG2, 0x2F);
}
}
}
uint8_t CC2500_Reset()
@ -100,21 +99,22 @@ uint8_t CC2500_Reset()
CC2500_Strobe(CC2500_SRES);
delay(1);
CC2500_SetTxRxMode(TXRX_OFF);
prev_power=0xFD; // unused power value
return CC2500_ReadReg(CC2500_0E_FREQ1) == 0xC4;//check if reset
}
void CC2500_SetPower()
{
uint8_t power=CC2500_BIND_POWER;
if(IS_BIND_DONE)
if(IS_BIND_DONE) {
#ifdef CC2500_ENABLE_LOW_POWER
power=IS_POWER_FLAG_on?CC2500_HIGH_POWER:CC2500_LOW_POWER;
#else
power=CC2500_HIGH_POWER;
#endif
}
if(IS_RANGE_FLAG_on)
power=CC2500_RANGE_POWER;
if(prev_power != power)
{
if(prev_power != power) {
CC2500_WriteReg(CC2500_3E_PATABLE, power);
prev_power=power;
}

33
Multiprotocol/cc2500_spi.h

@ -160,4 +160,37 @@ enum {
#define CC2500_LQI_CRC_OK_BM 0x80
#define CC2500_LQI_EST_BM 0x7F
// CC2500 power output from the chip itself
// The numbers do not take into account any outside amplifier
enum CC2500_POWER
{
CC2500_POWER_0 = 0x00, // -55dbm or less
CC2500_POWER_1 = 0x50, // -30dbm
CC2500_POWER_2 = 0x44, // -28dbm
CC2500_POWER_3 = 0xC0, // -26dbm
CC2500_POWER_4 = 0x84, // -24dbm
CC2500_POWER_5 = 0x81, // -22dbm
CC2500_POWER_6 = 0x46, // -20dbm
CC2500_POWER_7 = 0x93, // -18dbm
CC2500_POWER_8 = 0x55, // -16dbm
CC2500_POWER_9 = 0x8D, // -14dbm
CC2500_POWER_10 = 0xC6, // -12dbm
CC2500_POWER_11 = 0x97, // -10dbm
CC2500_POWER_12 = 0x6E, // -8dbm
CC2500_POWER_13 = 0x7F, // -6dbm
CC2500_POWER_14 = 0xA9, // -4dbm
CC2500_POWER_15 = 0xBB, // -2dbm
CC2500_POWER_16 = 0xFE, // 0dbm
CC2500_POWER_17 = 0xFF // +1dbm
};
#define CC2500_HIGH_POWER CC2500_POWER_1
#define CC2500_LOW_POWER CC2500_POWER_1
#define CC2500_RANGE_POWER CC2500_POWER_1
#define CC2500_BIND_POWER CC2500_POWER_1
enum TXRX_State {
TXRX_OFF,
TX_EN,
RX_EN
};
#endif

25
Multiprotocol/common.cpp

@ -18,32 +18,9 @@
#include "Multiprotocol.h"
#include "cc2500_spi.h"
#ifdef FAILSAFE_ENABLE
uint16_t Failsafe_data[NUM_CHN];
#endif
#include "input.h"
void InitFailsafe(void)
{
for (uint8_t i = 0; i < NUM_CHN; i++)
Failsafe_data[i] = 1024;
Failsafe_data[THROTTLE] = (uint16_t)204; //1=-125%, 204=-100%
FAILSAFE_VALUES_on;
}
void InitPPM(void)
{
for(uint8_t i=0;i<NUM_CHN;i++)
PPM_data[i]=PPM_MAX_100+PPM_MIN_100;
PPM_data[THROTTLE]=PPM_MIN_100*2;
}
void InitChannel(void)
{
for (uint8_t i = 0; i < NUM_CHN; i++)
Channel_data[i] = 1024;
Channel_data[THROTTLE] = 204;
}
/************************/
/** Convert routines **/
/************************/

14
Multiprotocol/common.h

@ -18,8 +18,6 @@
#include "config.h"
#include "tx_def.h"
void InitFailsafe(void);
void InitPPM(void);
void InitChannel(void);
void reverse_channel(uint8_t num);
uint16_t convert_channel_ppm(uint8_t num);
@ -53,25 +51,13 @@ void Frsky_init_hop(void);
#if defined(FRSKYV_CC2500_INO) || defined(FRSKYD_CC2500_INO) || defined(FRSKYX_CC2500_INO)
extern uint8_t FRSKY_common_startreg_cc2500_conf[];
#if defined(FRSKYV_CC2500_INO)
extern uint8_t FRSKYV_cc2500_conf[];
#endif
#if defined(FRSKYD_CC2500_INO)
extern uint8_t FRSKYD_cc2500_conf[];
#endif
#if defined(FRSKYX_CC2500_INO)
extern uint8_t FRSKYX_cc2500_conf[];
extern uint8_t FRSKYXEU_cc2500_conf[];
#endif
extern uint8_t FRSKY_common_end_cc2500_conf[][2];
void FRSKY_init_cc2500(const uint8_t *ptr);
#ifdef FAILSAFE_ENABLE
extern uint16_t Failsafe_data[NUM_CHN];
#endif
#endif
#endif

35
Multiprotocol/config.cpp

@ -14,7 +14,7 @@
*/
#include "config.h"
uint8_t curr_bank = 0;
const PPM_Parameters PPM_prot[14*NBR_BANKS]= {
const PPM_Parameters PPM_prot[14]= {
//****************************** BANK 1 ******************************
// Switch Protocol Sub protocol RX_Num Power Auto Bind Option
/* 1 */ {PROTO_FRSKYD, 0 , 0 , P_LOW , AUTOBIND , 0 },
@ -31,38 +31,7 @@ const PPM_Parameters PPM_prot[14*NBR_BANKS]= {
/* 12 */ {PROTO_FRSKYD, 0 , 0 , P_LOW , AUTOBIND , 220 }, // option=fine freq tuning
/* 13 */ {PROTO_FRSKYD, 0 , 0 , P_LOW , AUTOBIND , 240 },
/* 14 */ {PROTO_FRSKYD, 0 , 0 , P_LOW , AUTOBIND , 255 },
//****************************** BANK 2 ******************************
// Switch Protocol Sub protocol RX_Num Power Auto Bind Option
/* 1 */ {PROTO_FRSKYX, EU_16 , 0 , P_LOW , AUTOBIND , -120 },
/* 2 */ {PROTO_FRSKYX, EU_16 , 0 , P_LOW , AUTOBIND , -100 },
/* 3 */ {PROTO_FRSKYX, EU_16 , 0 , P_LOW , AUTOBIND , -80 },
/* 4 */ {PROTO_FRSKYX, EU_16 , 0 , P_LOW , AUTOBIND , -60 },
/* 5 */ {PROTO_FRSKYX, EU_16 , 0 , P_LOW , AUTOBIND , -40 },
/* 6 */ {PROTO_FRSKYX, EU_16 , 0 , P_LOW , AUTOBIND , -20 },
/* 7 */ {PROTO_FRSKYX, EU_16 , 0 , P_LOW , AUTOBIND , 0 },
/* 8 */ {PROTO_FRSKYX, EU_16 , 0 , P_LOW , AUTOBIND , 10 },
/* 9 */ {PROTO_FRSKYX, EU_16 , 0 , P_LOW , AUTOBIND , 20 },
/* 10 */ {PROTO_FRSKYX, EU_16 , 0 , P_LOW , AUTOBIND , 40 },
/* 11 */ {PROTO_FRSKYX, EU_16 , 0 , P_LOW , AUTOBIND , 60 },
/* 12 */ {PROTO_FRSKYX, EU_16 , 0 , P_LOW , AUTOBIND , 80 }, // option=fine freq tuning
/* 13 */ {PROTO_FRSKYX, EU_16 , 0 , P_LOW , AUTOBIND , 100 },
/* 14 */ {PROTO_FRSKYX, EU_16 , 0 , P_LOW , AUTOBIND , 120 },
//****************************** BANK 3 ******************************
// Switch Protocol Sub protocol RX_Num Power Auto Bind Option
/* 1 */ {PROTO_FRSKYX, CH_16 , 0 , P_LOW , AUTOBIND , -120 },
/* 2 */ {PROTO_FRSKYX, CH_16 , 0 , P_LOW , AUTOBIND , -100 },
/* 3 */ {PROTO_FRSKYX, CH_16 , 0 , P_LOW , AUTOBIND , -80 },
/* 4 */ {PROTO_FRSKYX, CH_16 , 0 , P_LOW , AUTOBIND , -60 },
/* 5 */ {PROTO_FRSKYX, CH_16 , 0 , P_LOW , AUTOBIND , -40 },
/* 6 */ {PROTO_FRSKYX, CH_16 , 0 , P_LOW , AUTOBIND , -20 },
/* 7 */ {PROTO_FRSKYX, CH_16 , 0 , P_LOW , AUTOBIND , 0 },
/* 8 */ {PROTO_FRSKYX, CH_16 , 0 , P_LOW , AUTOBIND , 10 },
/* 9 */ {PROTO_FRSKYX, CH_16 , 0 , P_LOW , AUTOBIND , 20 },
/* 10 */ {PROTO_FRSKYX, CH_16 , 0 , P_LOW , AUTOBIND , 40 },
/* 11 */ {PROTO_FRSKYX, CH_16 , 0 , P_LOW , AUTOBIND , 60 },
/* 12 */ {PROTO_FRSKYX, CH_16 , 0 , P_LOW , AUTOBIND , 80 }, // option=fine freq tuning
/* 13 */ {PROTO_FRSKYX, CH_16 , 0 , P_LOW , AUTOBIND , 100 },
/* 14 */ {PROTO_FRSKYX, CH_16 , 0 , P_LOW , AUTOBIND , 120 },
};
/* Available protocols and associated sub protocols to pick and choose from
PROTO_FLYSKY

14
Multiprotocol/config.h

@ -168,18 +168,6 @@
//!!!! This is a work in progress!!! Do not enable unless you want to test and report
//#define SPORT_POLLING
/****************************/
/*** SERIAL MODE SETTINGS ***/
/****************************/
//In this section you can configure the serial mode.
//The serial mode enables full editing of all the parameters in the GUI of the radio. It is enabled by placing the rotary switch on position 0.
//This is available natively for ER9X, ERSKY9X and OpenTX.
//If you do not plan to use the Serial mode comment this line using "//" to save Flash space
//#define ENABLE_SERIAL
/*************************/
/*** PPM MODE SETTINGS ***/
/*************************/
@ -214,7 +202,7 @@
// The default value is 16 to receive all possible channels but you might want to filter some "bad" channels from the PPM frame like the ones above 6 on the Walkera PL0811.
#define MAX_PPM_CHANNELS 16
#define NBR_BANKS 3
#define NBR_BANKS 1
extern uint8_t curr_bank;
struct PPM_Parameters

11
Multiprotocol/debug.h

@ -6,11 +6,22 @@
//********************
//** Debug messages **
//********************
#define ENABLE_DBEUG // ~1k
#ifdef ENABLE_DBEUG
#define debug(msg, ...) { char buf[256]; sprintf(buf, msg, ##__VA_ARGS__); Serial.println(buf);}
#define debugln(msg, ...) { char buf[256]; sprintf(buf, msg "\r\n", ##__VA_ARGS__); Serial.println(buf);}
#define debug_time(msg) { uint16_t debug_time_TCNT1=TCNT1; debug_time=debug_time_TCNT1-debug_time; debugln(msg "%u", debug_time); debug_time=debug_time_TCNT1; }
#define debugln_input(msg, ...) { char buf[256]; sprintf(buf, "input:" msg "\r\n", ##__VA_ARGS__); Serial.println(buf);}
#define debug_input(msg, ...) { char buf[256]; sprintf(buf, "input:" msg , ##__VA_ARGS__); Serial.println(buf);}
#else
#define debug(msg, ...)
#define debugln(msg, ...)
#define debug_time(msg)
#define debugln_input(msg, ...)
#define debug_input(msg, ...)
#endif
#endif

409
Multiprotocol/input.cpp

@ -8,10 +8,37 @@
#include "state.h"
Input input;
uint16_t Channel_data[NUM_TX_CHN];
uint16_t Failsafe_data[NUM_TX_CHN];
const char* ch_name[NUM_TX_CHN] = {
"CH_ROLL",
"CH_PITCH",
"CH_THROTTLE",
"CH_YAW",
"CH_AUX1",
"CH_AUX2",
"CH_AUX3",
"CH_AUX4",
"CH_AUX5",
"CH_AUX6"
};
Input::Input(void) {
this->curr = &(this->input[0]);
this->old = &(this->input[1]);
memset(this->input,0, sizeof(this->input));
//InitFailsafe
for (uint8_t i = 0; i < NUM_TX_CHN; i++)
Failsafe_data[i] = (CHANNEL_MAX_100 - CHANNEL_MIN_100) / 2 + CHANNEL_MIN_100;
Failsafe_data[CH_THROTTLE] = CHANNEL_MIN_100; //1=-125%, 204=-100%
// init channel
for (uint8_t i = 0; i < NUM_TX_CHN; i++)
Channel_data[i] = 1024;
Channel_data[CH_THROTTLE] = 204;
}
void Input::mark_processed(void) {
struct data* temp = this->old;
@ -28,40 +55,63 @@ struct Input::data* Input::get_old_input(void) {
}
void Input::init() {
analogReadResolution(16);
pinMode(Throttle_pin,INPUT);
pinMode(Yaw_pin,INPUT);
pinMode(Roll_pin,INPUT);
pinMode(Aux1_pin,INPUT);
pinMode(Aux2_pin,INPUT);
pinMode(Aux3_pin,INPUT);
pinMode(Aux4_pin,INPUT);
pinMode(Aux5_pin,INPUT);
pinMode(Aux6_pin,INPUT);
this->pins[CH_THROTTLE] = Throttle_pin;
this->ch_config[CH_THROTTLE].is_analog = true;
this->pins[CH_YAW] = Yaw_pin;
this->ch_config[CH_YAW].is_analog = true;
this->pins[CH_PITCH] = Pitch_pin;
this->ch_config[CH_PITCH].is_analog = true;
this->pins[CH_ROLL] = Roll_pin;
this->ch_config[CH_ROLL].is_analog = true;
this->pins[CH_AUX1] = Aux1_pin;
this->ch_config[CH_AUX1].is_analog = false;
this->pins[CH_AUX2] = Aux2_pin;
this->ch_config[CH_AUX2].is_analog = false;
this->pins[CH_AUX3] = Aux3_pin;
this->ch_config[CH_AUX3].is_analog = false;
this->pins[CH_AUX4] = Aux4_pin;
this->ch_config[CH_AUX4].is_analog = false;
this->pins[CH_AUX5] = Aux5_pin;
this->ch_config[CH_AUX5].is_analog = false;
this->pins[CH_AUX6] = Aux6_pin;
this->ch_config[CH_AUX6].is_analog = false;
for (uint8_t i = 0; i < CH_COUNT; ++i) {
pinMode(this->pins[i], INPUT);
}
pinMode(Menu_pin,INPUT);
this->throttle.inverted = true;
this->yaw.inverted = false;
this->roll.inverted = false;
this->pitch.inverted = false;
this->aux[0].inverted = false;
this->aux[1].inverted = false;
this->aux[2].inverted = false;
this->aux[3].inverted = false;
this->aux[4].inverted = false;
this->aux[5].inverted = false;
this->throttle.min = 500;
this->yaw.min = 500;
this->roll.min = 500;
this->pitch.min = 500;
this->throttle.max = 500;
this->yaw.max = 500;
this->roll.max = 500;
this->pitch.max = 500;
//analogReadResolution(16);
// move this to eeprom later
this->ch_config[CH_THROTTLE].inverted = false;
this->ch_config[CH_YAW].inverted = false;
this->ch_config[CH_ROLL].inverted = false;
this->ch_config[CH_PITCH].inverted = false;
this->ch_config[CH_AUX1].inverted = false;
this->ch_config[CH_AUX2].inverted = false;
this->ch_config[CH_AUX3].inverted = false;
this->ch_config[CH_AUX4].inverted = false;
this->ch_config[CH_AUX5].inverted = false;
this->ch_config[CH_THROTTLE].min = 0;
this->ch_config[CH_YAW].min = 0;
this->ch_config[CH_ROLL].min = 0;
this->ch_config[CH_PITCH].min = 0;
this->ch_config[CH_THROTTLE].max = 4096;
this->ch_config[CH_YAW].max = 4096;
this->ch_config[CH_ROLL].max = 4096;
this->ch_config[CH_PITCH].max = 4096;
}
void Input::do_calibration(void) {
int8_t turns = 50;
@ -71,24 +121,19 @@ void Input::do_calibration(void) {
i = turns;
while(i > 0) {
this->update();
if (true == this->save_calibration()) {
if (true == this->calibration_update()) {
i = turns;
debugln("new values t %d-%d r %d-%d p %d-%d y %d-%d",
this->throttle.min,this->throttle.max,
this->roll.min, this->roll.max,
this->pitch.min, this->pitch.max,
this->yaw.min, this->yaw.max);
this->ch_config[CH_THROTTLE].min, this->ch_config[CH_THROTTLE].max,
this->ch_config[CH_ROLL].min, this->ch_config[CH_ROLL].max,
this->ch_config[CH_PITCH].min, this->ch_config[CH_PITCH].max,
this->ch_config[CH_YAW].min, this->ch_config[CH_YAW].max);
}else {
i -= 1;
}
delay(100);
}
debugln("end values t %d-%d r %d-%d p %d-%d y %d-%d",
this->throttle.min,this->throttle.max,
this->roll.min, this->roll.max,
this->pitch.min, this->pitch.max,
this->yaw.min, this->yaw.max);
// center
debugln("now center all sticks");
@ -104,199 +149,64 @@ void Input::do_calibration(void) {
}
debugln("now Move throttle to max");
for (int ch = 0; ch < 4 ; ++ch) {
debugln("now Move %s to max", ch_name[ch]);
i = turns;
while(i>0) {
delay(100);
delay(50);
this->update();
if (true == this->is_throttle_up()) {
if (true == this->is_high((enum input_channels)ch)) {
debug("u");
i--;
continue;
}
if (true == this->is_throttle_down()) {
this->throttle.inverted = ! this->throttle.inverted;
i = turns;
continue;
}
}
debugln("throttle invert is %d", this->throttle.inverted);
debugln("now Move yaw to max");
i = turns;
while(i>0) {
delay(100);
this->update();
if (true == this->is_yaw_up()) {
i--;
continue;
}
if (true == this->is_yaw_down()) {
this->yaw.inverted = ! this->yaw.inverted;
i = turns;
continue;
}
}
debugln("yaw invert is %d", this->yaw.inverted);
debugln("now Move pitch to max");
i = turns;
while(i>0) {
delay(100);
this->update();
if (true == this->is_pitch_up()) {
i--;
continue;
}
if (true == this->is_pitch_down()) {
this->pitch.inverted = ! this->pitch.inverted;
i = turns;
continue;
}
}
debugln("pitch invert is %d", this->pitch.inverted);
debugln("now Move roll to max");
if (true == this->is_low((enum input_channels)ch)) {
debug("dI");
this->ch_config[CH_THROTTLE].inverted = !this->ch_config[CH_THROTTLE].inverted;
i = turns;
while(i>0) {
delay(100);
this->update();
if (true == this->is_roll_up()) {
i--;
continue;
}
if (true == this->is_roll_down()) {
this->roll.inverted = ! this->roll.inverted;
i = turns;
continue;
}
}
debugln("roll invert is %d", this->roll.inverted);
}
bool Input::is_centered(void) {
return this->is_centered_left() && this->is_centered_right();
return
this->is_centered(CH_ROLL) &&
this->is_centered(CH_PITCH) &&
this->is_centered(CH_THROTTLE) &&
this->is_centered(CH_YAW);
}
bool Input::is_centered_left(void) {
uint16_t range;
uint16_t delta;
range = this->throttle.max - this->throttle.min;
delta = range >>4;
if ( this->curr->throttle < this->throttle.min + range/2 - delta ||
this->curr->throttle > this->throttle.min + range/2 + delta
) {
// throttle is not centered
return false;
}
bool Input::is_centered(enum Input::input_channels ch) {
uint16_t range = this->ch_config[ch].max - this->ch_config[ch].min;
uint16_t delta = range / 5;
range = this->yaw.max - this->yaw.min;
delta = range >>4;
if ( this->curr->yaw < this->yaw.min + range/2 - delta ||
this->curr->yaw > this->yaw.min + range/2 + delta
) {
// yaw is not centered
return false;
}
return true;
}
bool Input::is_centered_right(void) {
uint16_t range;
uint16_t delta;
range = this->pitch.max - this->pitch.min;
delta = range >>4;
if ( this->curr->pitch < this->pitch.min + range/2 - delta ||
this->curr->pitch > this->pitch.min + range/2 + delta
if ( this->curr->ch_data[ch] < this->ch_config[ch].min + range / 2 - delta ||
this->curr->ch_data[ch] > this->ch_config[ch].min + range / 2 + delta
) {
// pitch is not centered
return false;
}
range = this->roll.max - this->roll.min;
delta = range >>4;
if ( this->curr->roll < this->roll.min + range/2 - delta ||
this->curr->roll > this->roll.min + range/2 + delta
) {
// roll is not centered
return false;
}
return true;
}
bool Input::is_menu_left(void) {
return this->is_roll_down();
}
bool Input::is_menu_right(void) {
return this->is_roll_up();
}
bool Input::is_menu_down(void) {
return this->is_pitch_down();
}
bool Input::is_menu_up(void) {
return this->is_pitch_up();
}
bool Input::is_throttle_down(void) {
uint16_t delta = (this->throttle.max - this->throttle.min)/3;
if ( this->curr->throttle < this->throttle.min + delta) {
bool Input::is_high(enum Input::input_channels ch) {
uint16_t range = this->ch_config[ch].max - this->ch_config[ch].min;
uint16_t delta = range / 3;
if ( this->curr->ch_data[ch] < this->ch_config[ch].max - delta) {
return true;
}
return false;
}
bool Input::is_throttle_up(void) {
uint16_t delta = (this->throttle.max - this->throttle.min)/3;
if ( this->curr->throttle > this->throttle.max - delta) {
return true;
}
return false;
}
bool Input::is_yaw_up(void) {
uint16_t delta = (this->yaw.max - this->yaw.min)/3;
if ( this->curr->yaw > this->yaw.max - delta) {
return true;
}
return false;
}
bool Input::is_yaw_down(void) {
uint16_t delta = (this->yaw.max - this->yaw.min)/3;
if ( this->curr->yaw > this->yaw.min + delta) {
return true;
}
return false;
}
bool Input::is_roll_down(void) {
uint16_t delta = (this->roll.max - this->roll.min)/3;
if ( this->curr->roll < this->roll.min + delta) {
return true;
}
return false;
}
bool Input::is_roll_up(void) {
uint16_t delta = (this->roll.max - this->roll.min)/3;
if ( this->curr->roll > this->roll.max - delta) {
return true;
}
return false;
}
bool Input::is_pitch_up(void) {
uint16_t delta = (this->pitch.max - this->pitch.min)/3;
if ( this->curr->pitch > this->pitch.max - delta) {
return true;
}
return false;
}
bool Input::is_pitch_down(void) {
uint16_t delta = (this->pitch.max - this->pitch.min)/3;
if ( this->curr->pitch > this->pitch.min + delta) {
bool Input::is_low(enum Input::input_channels ch) {
uint16_t range = this->ch_config[ch].max - this->ch_config[ch].min;
uint16_t delta = range / 3;
if ( this->curr->ch_data[ch] < this->ch_config[ch].min + delta) {
return true;
}
return false;
@ -306,56 +216,48 @@ bool Input::is_menu_triggered(void) {
return this->curr->menu;
}
bool Input::save_calibration(void) {
bool Input::calibration_update(void) {
bool changed = false;
if (this->throttle.min > this->curr->throttle){
changed = true;
this->throttle.min = this->curr->throttle;
} else if (this->throttle.max < this->curr->throttle) {
changed = true;
this->throttle.max = this->curr->throttle;
}
if (this->yaw.min > this->curr->yaw){
for (uint8_t ch = 0; ch < CH_COUNT; ch++) {
if (this->ch_config[ch].min > this->ch_raw[ch]) {
this->ch_config[ch].min = this->ch_raw[ch];
changed = true;
this->yaw.min = this->curr->yaw;
} else if (this->yaw.max < this->curr->yaw) {
} else if (this->ch_config[ch].max < this->ch_raw[ch]) {
changed = true;
this->yaw.max = this->curr->yaw;
this->ch_config[ch].max = this->ch_raw[ch];
}
if (this->roll.min > this->curr->roll){
changed = true;
this->roll.min = this->curr->roll;
} else if (this->roll.max < this->curr->roll) {
changed = true;
this->roll.max = this->curr->roll;
}
if (this->pitch.min > this->curr->pitch){
changed = true;
this->pitch.min = this->curr->pitch;
} else if (this->roll.max < this->curr->pitch) {
changed = true;
this->pitch.max = this->curr->pitch;
}
// TODO save in eeprom
return changed;
}
void Input::update(void) {
this->curr->throttle = analogRead(Throttle_pin);
this->curr->yaw = analogRead(Yaw_pin);
this->curr->roll = analogRead(Roll_pin);
this->curr->pitch = analogRead(Pitch_pin);
this->curr->aux[0] = digitalRead(Aux1_pin);
this->curr->aux[1] = digitalRead(Aux2_pin);
this->curr->aux[2] = digitalRead(Aux3_pin);
this->curr->aux[3] = digitalRead(Aux4_pin);
this->curr->aux[4] = digitalRead(Aux5_pin);
this->curr->aux[5] = digitalRead(Aux6_pin);
for (uint8_t ch = 0; ch < CH_MAX; ch ++) {
if (this->ch_config[ch].is_analog)
this->ch_raw[ch] = analogRead(this->pins[ch]);
else
this->ch_raw[ch] = digitalRead(this->pins[ch]) == HIGH;
this->curr->menu = digitalRead(Menu_pin);
// do inverting
if (this->ch_config[ch].inverted)
this->curr->ch_data[ch] = this->ch_config[ch].max - this->ch_raw[ch];
else
this->curr->ch_data[ch] = this->ch_raw[ch];
// cap on max
if (this->ch_config[ch].min > this->curr->ch_data[ch]) {
this->curr->ch_data[ch] = this->ch_config[ch].min;
} else if (this->ch_config[ch].max < this->curr->ch_data[ch]) {
this->curr->ch_data[ch] = this->ch_config[ch].max;
}
}
this->curr->menu = digitalRead(Menu_pin) == HIGH;
/*debug_input("t%d y%d r%d p%d a1_%d a2_%d a3_%d a4_%d a5_%d m%d",
@ -368,32 +270,7 @@ void Input::update(void) {
if (curr_state != s_fly)
return;
if(this->throttle.inverted)
Channel_data[THROTTLE] = map(this->curr->throttle, this->throttle.min, this->throttle.max, CHANNEL_MAX_100, CHANNEL_MIN_100);
else
Channel_data[THROTTLE] = map(this->curr->throttle, this->throttle.min, this->throttle.max, CHANNEL_MIN_100, CHANNEL_MAX_100);
if(this->yaw.inverted)
Channel_data[RUDDER] = map(this->curr->yaw, this->yaw.min, this->yaw.max, CHANNEL_MAX_100, CHANNEL_MIN_100);
else
Channel_data[RUDDER] = map(this->curr->yaw, this->yaw.min, this->yaw.max, CHANNEL_MIN_100, CHANNEL_MAX_100);
if(this->roll.inverted)
Channel_data[AILERON] = map(this->curr->roll, this->roll.min, this->roll.max, CHANNEL_MAX_100, CHANNEL_MIN_100);
else
Channel_data[AILERON] = map(this->curr->roll, this->roll.min, this->roll.max, CHANNEL_MIN_100, CHANNEL_MAX_100);
if(this->pitch.inverted)
Channel_data[ELEVATOR] = map(this->curr->pitch, this->pitch.min, this->pitch.max, CHANNEL_MAX_100, CHANNEL_MIN_100);
else
Channel_data[ELEVATOR] = map(this->curr->pitch, this->pitch.min, this->pitch.max, CHANNEL_MIN_100, CHANNEL_MAX_100);
for (uint8_t i = 0; i<6; ++i) {
if(this->aux[i].inverted)
Channel_data[CH5+i] = (this->curr->aux[i]) ? CHANNEL_MIN_100 : CHANNEL_MAX_100;
else
Channel_data[CH5+i] = (this->curr->aux[i]) ? CHANNEL_MAX_100 : CHANNEL_MIN_100;
for (uint8_t ch = 0; ch < CH_COUNT; ++ch) {
Channel_data[ch] = map(this->curr->ch_data[ch], this->ch_config[ch].min, this->ch_config[ch].max, CHANNEL_MAX_100, CHANNEL_MIN_100);
}
}

76
Multiprotocol/input.h

@ -3,31 +3,37 @@
#include <stdint.h>
#include "tx_def.h"
#define NUM_TX_CHN 16
extern uint16_t Channel_data[NUM_TX_CHN];
extern uint16_t Failsafe_data[NUM_TX_CHN];
class Input {
private:
struct data {
uint16_t throttle;
uint16_t yaw;
uint16_t roll;
uint16_t pitch;
public:
enum input_channels {
CH_ROLL = 0,
CH_PITCH = 1,
CH_THROTTLE = 2,
CH_YAW = 3,
bool aux[6];
CH_AUX1 = 4,
CH_AUX2 = 5,
CH_AUX3 = 6,
CH_AUX4 = 7,
CH_AUX5 = 8,
CH_AUX6 = 8,
bool menu;
CH_MAX = 8,
CH_COUNT = 9,
MENU_UP_DOWN = CH_PITCH,
MENU_LEFT_RIGHT = CH_ROLL,
};
struct data input[2];
struct data* curr;
struct data* old;
struct {
uint16_t max;
uint16_t min;
uint8_t inverted;
} throttle, yaw, roll, pitch, aux[5];
struct data {
uint16_t ch_data[CH_COUNT];
bool menu;
};
bool save_calibration(void);
public:
Input(void);
void init(void);
@ -40,27 +46,31 @@ class Input {
void mark_processed(void);
bool is_centered(void);
bool is_centered_left(void);
bool is_centered_right(void);
bool is_centered(enum input_channels ch);
bool is_low(enum input_channels ch);
bool is_high(enum input_channels ch);
// menu inputs
bool is_menu_triggered(void);
bool is_menu_left(void);
bool is_menu_right(void);
bool is_menu_down(void);
bool is_menu_up(void);
private:
struct data input[2];
struct data* curr;
struct data* old;
uint16_t ch_raw[CH_COUNT];
struct {
uint16_t max;
uint16_t min;
bool inverted;
bool is_analog;
} ch_config[CH_COUNT];
bool is_throttle_up(void);
bool is_throttle_down(void);
bool is_yaw_up(void);
bool is_yaw_down(void);
uint32_t pins[CH_COUNT];
bool is_roll_up(void);
bool is_roll_down(void);
bool is_pitch_up(void);
bool is_pitch_down(void);
bool calibration_update(void);
};
extern uint16_t Channel_data[NUM_CHN];
extern uint16_t Channel_data[NUM_TX_CHN];
extern Input input;
#endif

47
Multiprotocol/state.cpp

@ -10,10 +10,11 @@ LiquidCrystal_I2C lcd(0x27,16,2);
State *curr_state = NULL;
State *new_state = NULL;
State *s_init = new LCD_state_init();
State *s_bind = new LCD_state_bind();
State *s_fly = new LCD_state_fly();
State *s_menu = new LCD_state_menu();
State *s_init = NULL;
State *s_bind = NULL;
State *s_fly = NULL;
State *s_joy = NULL;
State *s_menu = NULL;
enum lcd_special_chars {
@ -58,11 +59,17 @@ void install_special_caracters(void)
}
void init_state(void) {
#if 0
Wire.setSDA(PB9);
Wire.setSCL(PB8);
#endif
Wire.begin();
lcd.init();
s_init = new LCD_state_init();
s_bind = new LCD_state_bind();
s_fly = new LCD_state_fly();
s_menu = new LCD_state_menu();
lcd.backlight();
curr_state = NULL;
new_state = s_init;
@ -89,14 +96,12 @@ void update_state(void) {
//LCD_state_init
LCD_state_init::LCD_state_init(void) {
snprintf(this->line[0],sizeof(this->line[0])," wellcome ");
snprintf(this->line[1],sizeof(this->line[1])," phschoen ");
}
void LCD_state_init::enter(void) {
lcd.setCursor(0,0);
lcd.print(this->line[0]);
lcd.print(" wellcome ");
lcd.setCursor(0,1);
lcd.print(this->line[1]);
lcd.print(" phschoen ");
this->time_enter = millis();
}
void LCD_state_init::update(void)
@ -113,28 +118,29 @@ void LCD_state_init::leave(void)
}
//LCD_state_bind
LCD_state_bind::LCD_state_bind(void) {
snprintf(this->line[0],sizeof(this->line[0]),"bind mode ");
snprintf(this->line[1],sizeof(this->line[1])," ");
this->bind_time = 20;
}
void LCD_state_bind::enter(void) {
lcd.setCursor(0,0);
lcd.print(this->line[0]);
lcd.print("bind mode ");
lcd.setCursor(0,1);
lcd.print(this->line[1]);
lcd.print(" ");
this->time_enter = millis();
}
void LCD_state_bind::update(void)
{
debugln("blubber\n");
char line[17];
unsigned long time_in_ms = millis() - this->time_enter;
unsigned long time_in_s = time_in_ms/1000; // to sec
unsigned long remain_s = this->bind_time - time_in_s;
snprintf(this->line[0],sizeof(this->line[1]),"remaining sec %02d",remain_s);
snprintf(line,sizeof(line),"remaining sec %02d",remain_s);
lcd.setCursor(0,1);
lcd.print(this->line[0]);
lcd.print(line);
// cange to menu when done
if (time_in_s >= this->bind_time)
new_state = s_menu;
}
@ -146,15 +152,12 @@ void LCD_state_bind::leave(void)
// LCD_state_menu
LCD_state_menu::LCD_state_menu(void) {
snprintf(this->line[0],sizeof(this->line[0]),"Menubind mode ");
snprintf(this->line[1],sizeof(this->line[1])," ");
this->curr_selected = 0;
}
void LCD_state_menu::enter(void) {
lcd.setCursor(0,0);
lcd.print(this->line[0]);
lcd.print("menu mode ");
lcd.setCursor(0,1);
lcd.print(this->line[1]);
lcd.print(" ");
this->time_enter = millis();
}
@ -169,15 +172,13 @@ void LCD_state_menu::leave(void)
// LCD_state_fly
LCD_state_fly::LCD_state_fly(void) {
snprintf(this->line[0],sizeof(this->line[0]),"fly mode ");
snprintf(this->line[1],sizeof(this->line[1])," ");
}
void LCD_state_fly::enter(void) {
lcd.setCursor(0,0);
lcd.print(this->line[0]);
lcd.print("fly mode ");
lcd.setCursor(0,1);
lcd.print(this->line[1]);
lcd.print(" ");
this->time_enter = millis();
}

11
Multiprotocol/state.h

@ -12,7 +12,6 @@ void update_state(void);
class State {
protected:
char line[2][17];
public:
virtual void enter(void) {
@ -73,11 +72,21 @@ public:
void leave(void);
};
class LCD_state_calibration: public State {
private:
unsigned long time_enter;
public:
LCD_state_calibration(void);
void enter(void);
void update(void);
void leave(void);
};
extern State *curr_state;
extern State *new_state;
extern State *s_init;
extern State *s_bind;
extern State *s_fly;
extern State *s_joy;
extern State *s_menu;
#endif /*_STATE_H_*/

164
Multiprotocol/tx_def.h

@ -48,170 +48,6 @@
#define CHANNEL_MAX_COMMAND 1424 // 1750us
//Channel definitions
#ifdef AETR
#define AILERON 0
#define ELEVATOR 1
#define THROTTLE 2
#define RUDDER 3
#endif
#ifdef AERT
#define AILERON 0
#define ELEVATOR 1
#define THROTTLE 3
#define RUDDER 2
#endif
#ifdef ARET
#define AILERON 0
#define ELEVATOR 2
#define THROTTLE 3
#define RUDDER 1
#endif
#ifdef ARTE
#define AILERON 0
#define ELEVATOR 3
#define THROTTLE 2
#define RUDDER 1
#endif
#ifdef ATRE
#define AILERON 0
#define ELEVATOR 3
#define THROTTLE 1
#define RUDDER 2
#endif
#ifdef ATER
#define AILERON 0
#define ELEVATOR 2
#define THROTTLE 1
#define RUDDER 3
#endif
#ifdef EATR
#define AILERON 1
#define ELEVATOR 0
#define THROTTLE 2
#define RUDDER 3
#endif
#ifdef EART
#define AILERON 1
#define ELEVATOR 0
#define THROTTLE 3
#define RUDDER 2
#endif
#ifdef ERAT
#define AILERON 2
#define ELEVATOR 0
#define THROTTLE 3
#define RUDDER 1
#endif
#ifdef ERTA
#define AILERON 3
#define ELEVATOR 0
#define THROTTLE 2
#define RUDDER 1
#endif
#ifdef ETRA
#define AILERON 3
#define ELEVATOR 0
#define THROTTLE 1
#define RUDDER 2
#endif
#ifdef ETAR
#define AILERON 2
#define ELEVATOR 0
#define THROTTLE 1
#define RUDDER 3
#endif
#ifdef TEAR
#define AILERON 2
#define ELEVATOR 1
#define THROTTLE 0
#define RUDDER 3
#endif
#ifdef TERA
#define AILERON 3
#define ELEVATOR 1
#define THROTTLE 0
#define RUDDER 2
#endif
#ifdef TREA
#define AILERON 3
#define ELEVATOR 2
#define THROTTLE 0
#define RUDDER 1
#endif
#ifdef TRAE
#define AILERON 2
#define ELEVATOR 3
#define THROTTLE 0
#define RUDDER 1
#endif
#ifdef TARE
#define AILERON 1
#define ELEVATOR 3
#define THROTTLE 0
#define RUDDER 2
#endif
#ifdef TAER
#define AILERON 1
#define ELEVATOR 2
#define THROTTLE 0
#define RUDDER 3
#endif
#ifdef RETA
#define AILERON 3
#define ELEVATOR 1
#define THROTTLE 2
#define RUDDER 0
#endif
#ifdef REAT
#define AILERON 2
#define ELEVATOR 1
#define THROTTLE 3
#define RUDDER 0
#endif
#ifdef RAET
#define AILERON 1
#define ELEVATOR 2
#define THROTTLE 3
#define RUDDER 0
#endif
#ifdef RATE
#define AILERON 1
#define ELEVATOR 3
#define THROTTLE 2
#define RUDDER 0
#endif
#ifdef RTAE
#define AILERON 2
#define ELEVATOR 3
#define THROTTLE 1
#define RUDDER 0
#endif
#ifdef RTEA
#define AILERON 3
#define ELEVATOR 2
#define THROTTLE 1
#define RUDDER 0
#endif
#define CH1 0
#define CH2 1
#define CH3 2
#define CH4 3
#define CH5 4
#define CH6 5
#define CH7 6
#define CH8 7
#define CH9 8
#define CH10 9
#define CH11 10
#define CH12 11
#define CH13 12
#define CH14 13
#define CH15 14
#define CH16 15
#define NUM_CHN 16
#endif /* _TX_DEV_H_ */
Loading…
Cancel
Save