367 lines
9.7 KiB
C++

/*
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/>.
*/
// Compatible with EAchine H8 mini, H10, BayangToys X6/X7/X9, JJRC JJ850 ...
// Last sync with hexfet new_protocols/bayang_nrf24l01.c dated 2015-12-22
#if defined(BAYANG_NRF24L01_INO)
#include "iface_nrf24l01.h"
#define BAYANG_BIND_COUNT 1000
#define BAYANG_PACKET_PERIOD 2000
#define BAYANG_PACKET_TELEM_PERIOD 5000
#define BAYANG_INITIAL_WAIT 500
#define BAYANG_PACKET_SIZE 15
#define BAYANG_RF_NUM_CHANNELS 4
#define BAYANG_RF_BIND_CHANNEL 0
#define BAYANG_RF_BIND_CHANNEL_X16_AH 10
#define BAYANG_ADDRESS_LENGTH 5
enum BAYANG_FLAGS {
// flags going to packet[2]
BAYANG_FLAG_RTH = 0x01,
BAYANG_FLAG_HEADLESS = 0x02,
BAYANG_FLAG_FLIP = 0x08,
BAYANG_FLAG_VIDEO = 0x10,
BAYANG_FLAG_PICTURE = 0x20,
// flags going to packet[3]
BAYANG_FLAG_INVERTED = 0x80, // inverted flight on Floureon H101
BAYANG_FLAG_TAKE_OFF = 0x20, // take off / landing on X16 AH
BAYANG_FLAG_EMG_STOP = 0x04|0x08, // 0x08 for VISUO XS809H-W-HD-G
};
enum BAYANG_OPTION_FLAGS {
BAYANG_OPTION_FLAG_TELEMETRY = 0x01,
BAYANG_OPTION_FLAG_ANALOGAUX = 0x02,
};
static void __attribute__((unused)) BAYANG_send_packet()
{
uint8_t i;
if (IS_BIND_IN_PROGRESS)
{
#ifdef BAYANG_HUB_TELEMETRY
if(option & BAYANG_OPTION_FLAG_TELEMETRY)
if(option & BAYANG_OPTION_FLAG_ANALOGAUX)
packet[0]= 0xA1; // telemetry and analog aux are enabled
else
packet[0]= 0xA3; // telemetry is enabled
else if(option & BAYANG_OPTION_FLAG_ANALOGAUX)
packet[0]= 0xA2; // analog aux is enabled
else
#else
if(option & BAYANG_OPTION_FLAG_ANALOGAUX)
packet[0]= 0xA2; // analog aux is enabled
else
#endif
packet[0]= 0xA4;
for(i=0;i<5;i++)
packet[i+1]=rx_tx_addr[i];
for(i=0;i<4;i++)
packet[i+6]=hopping_frequency[i];
switch (sub_protocol)
{
case X16_AH:
packet[10] = 0x00;
packet[11] = 0x00;
break;
case IRDRONE:
packet[10] = 0x30;
packet[11] = 0x01;
break;
case DHD_D4:
packet[10] = 0xC8;
packet[11] = 0x99;
break;
default:
packet[10] = rx_tx_addr[0]; // txid[0]
packet[11] = rx_tx_addr[1]; // txid[1]
break;
}
}
else
{
uint16_t val;
uint8_t dyntrim = 1;
switch (sub_protocol)
{
case X16_AH:
case IRDRONE:
packet[0] = 0xA6;
break;
default:
packet[0] = 0xA5;
break;
}
if (option & BAYANG_OPTION_FLAG_ANALOGAUX)
{
// Analog aux channel 1 (channel 14)
packet[1] = convert_channel_8b(CH14);
}
else
packet[1] = 0xFA; // normal mode is 0xF7, expert 0xFa , D4 normal is 0xF4
//Flags packet[2]
packet[2] = 0x00;
if(CH5_SW)
packet[2] = BAYANG_FLAG_FLIP;
if(CH6_SW)
packet[2] |= BAYANG_FLAG_RTH;
if(CH7_SW)
packet[2] |= BAYANG_FLAG_PICTURE;
if(CH8_SW)
packet[2] |= BAYANG_FLAG_VIDEO;
if(CH9_SW)
{
packet[2] |= BAYANG_FLAG_HEADLESS;
dyntrim = 0;
}
//Flags packet[3]
packet[3] = 0x00;
if(CH10_SW)
packet[3] = BAYANG_FLAG_INVERTED;
if(CH11_SW)
dyntrim = 0;
if(CH12_SW)
packet[3] |= BAYANG_FLAG_TAKE_OFF;
if(CH13_SW)
packet[3] |= BAYANG_FLAG_EMG_STOP;
//Aileron
val = convert_channel_10b(AILERON);
packet[4] = (val>>8) + (dyntrim ? ((val>>2) & 0xFC) : 0x7C);
packet[5] = val & 0xFF;
//Elevator
val = convert_channel_10b(ELEVATOR);
packet[6] = (val>>8) + (dyntrim ? ((val>>2) & 0xFC) : 0x7C);
packet[7] = val & 0xFF;
//Throttle
val = convert_channel_10b(THROTTLE);
packet[8] = (val>>8) + 0x7C;
packet[9] = val & 0xFF;
//Rudder
val = convert_channel_10b(RUDDER);
packet[10] = (val>>8) + (dyntrim ? ((val>>2) & 0xFC) : 0x7C);
packet[11] = val & 0xFF;
}
switch (sub_protocol)
{
case H8S3D:
packet[12] = rx_tx_addr[2]; // txid[2]
packet[13] = 0x34;
break;
case X16_AH:
packet[12] = 0;
packet[13] = 0;
break;
case IRDRONE:
packet[12] = 0xE0;
packet[13] = 0x2E;
break;
case DHD_D4:
packet[12] = 0x37; //0x17 during bind
packet[13] = 0xED;
break;
default:
packet[12] = rx_tx_addr[2]; // txid[2]
if (option & BAYANG_OPTION_FLAG_ANALOGAUX)
{ // Analog aux channel 2 (channel 15)
packet[13] = convert_channel_8b(CH15);
}
else
packet[13] = 0x0A;
break;
}
packet[14] = 0;
for (uint8_t i=0; i < BAYANG_PACKET_SIZE-1; i++)
packet[14] += packet[i];
NRF24L01_WriteReg(NRF24L01_05_RF_CH, IS_BIND_IN_PROGRESS ? rf_ch_num:hopping_frequency[hopping_frequency_no++]);
hopping_frequency_no%=BAYANG_RF_NUM_CHANNELS;
// Power on, TX mode, 2byte CRC
// Why CRC0? xn297 does not interpret it - either 16-bit CRC or nothing
NRF24L01_FlushTx();
NRF24L01_SetTxRxMode(TX_EN);
XN297_Configure(_BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO) | _BV(NRF24L01_00_PWR_UP));
XN297_WritePayload(packet, BAYANG_PACKET_SIZE);
NRF24L01_SetPower(); // Set tx_power
}
#ifdef BAYANG_HUB_TELEMETRY
static void __attribute__((unused)) BAYANG_check_rx(void)
{
if (NRF24L01_ReadReg(NRF24L01_07_STATUS) & _BV(NRF24L01_07_RX_DR))
{ // data received from model
XN297_ReadPayload(packet, BAYANG_PACKET_SIZE);
NRF24L01_WriteReg(NRF24L01_07_STATUS, 255);
NRF24L01_FlushRx();
uint8_t check = packet[0];
for (uint8_t i=1; i < BAYANG_PACKET_SIZE-1; i++)
check += packet[i];
// decode data , check sum is ok as well, since there is no crc
if (packet[0] == 0x85 && packet[14] == check)
{
// uncompensated battery volts*100/2
v_lipo1 = (packet[3]<<7) + (packet[4]>>2);
// compensated battery volts*100/2
v_lipo2 = (packet[5]<<7) + (packet[6]>>2);
// reception in packets / sec
RX_LQI = packet[7];
RX_RSSI = RX_LQI;
//Flags
//uint8_t flags = packet[3] >> 3;
// battery low: flags & 1
telemetry_counter++;
if(telemetry_lost==0)
telemetry_link=1;
}
}
NRF24L01_SetTxRxMode(TXRX_OFF);
}
#endif
static void __attribute__((unused)) BAYANG_init()
{
NRF24L01_Initialize();
NRF24L01_SetTxRxMode(TX_EN);
XN297_SetTXAddr((uint8_t *)"\x00\x00\x00\x00\x00", BAYANG_ADDRESS_LENGTH);
NRF24L01_FlushTx();
NRF24L01_FlushRx();
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknowldgement on all data pipes
NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0 only
NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, BAYANG_PACKET_SIZE);
NRF24L01_SetBitrate(NRF24L01_BR_1M); // 1Mbps
NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0x00); // No retransmits
NRF24L01_SetPower();
NRF24L01_Activate(0x73); // Activate feature register
NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 0x00); // Disable dynamic payload length on all pipes
NRF24L01_WriteReg(NRF24L01_1D_FEATURE, 0x01);
NRF24L01_Activate(0x73);
switch (sub_protocol)
{
case X16_AH:
case IRDRONE:
rf_ch_num = BAYANG_RF_BIND_CHANNEL_X16_AH;
break;
default:
rf_ch_num = BAYANG_RF_BIND_CHANNEL;
break;
}
}
enum {
BAYANG_BIND=0,
BAYANG_WRITE,
BAYANG_CHECK,
BAYANG_READ,
};
#define BAYANG_CHECK_DELAY 1000 // Time after write phase to check write complete
#define BAYANG_READ_DELAY 600 // Time before read phase
uint16_t BAYANG_callback()
{
#ifdef BAYANG_HUB_TELEMETRY
uint16_t start;
#endif
switch(phase)
{
case BAYANG_BIND:
if (bind_counter-- == 0)
{
XN297_SetTXAddr(rx_tx_addr, BAYANG_ADDRESS_LENGTH);
#ifdef BAYANG_HUB_TELEMETRY
XN297_SetRXAddr(rx_tx_addr, BAYANG_ADDRESS_LENGTH);
#endif
BIND_DONE;
phase++; //WRITE
}
else
BAYANG_send_packet();
break;
case BAYANG_WRITE:
#ifdef MULTI_SYNC
telemetry_set_input_sync((option & BAYANG_OPTION_FLAG_TELEMETRY)?BAYANG_PACKET_TELEM_PERIOD:BAYANG_PACKET_PERIOD);
#endif
BAYANG_send_packet();
#ifdef BAYANG_HUB_TELEMETRY
if (option & BAYANG_OPTION_FLAG_TELEMETRY)
{ // telemetry is enabled
state++;
if (state > 200)
{
state = 0;
//telemetry reception packet rate - packets per second
TX_LQI = telemetry_counter>>1;
telemetry_counter = 0;
telemetry_lost=0;
}
phase++; //CHECK
return BAYANG_CHECK_DELAY;
}
#endif
break;
#ifdef BAYANG_HUB_TELEMETRY
case BAYANG_CHECK:
// switch radio to rx as soon as packet is sent
start=(uint16_t)micros();
while ((uint16_t)((uint16_t)micros()-(uint16_t)start) < 1000) // Wait max 1ms
if((NRF24L01_ReadReg(NRF24L01_07_STATUS) & _BV(NRF24L01_07_TX_DS)))
break;
debugln("time: %d",(uint16_t)((uint16_t)micros()-(uint16_t)start));
NRF24L01_WriteReg(NRF24L01_00_CONFIG, 0x03);
phase++; // READ
return BAYANG_PACKET_TELEM_PERIOD - BAYANG_CHECK_DELAY - BAYANG_READ_DELAY;
case BAYANG_READ:
BAYANG_check_rx();
phase=BAYANG_WRITE;
return BAYANG_READ_DELAY;
#endif
}
return BAYANG_PACKET_PERIOD;
}
static void __attribute__((unused)) BAYANG_initialize_txid()
{
//Could be using txid[0..2] but using rx_tx_addr everywhere instead...
if(sub_protocol==DHD_D4)
hopping_frequency[0]=(rx_tx_addr[2]&0x07)|0x01;
else
hopping_frequency[0]=0;
hopping_frequency[1]=(rx_tx_addr[3]&0x1F)+0x10;
hopping_frequency[2]=hopping_frequency[1]+0x20;
hopping_frequency[3]=hopping_frequency[2]+0x20;
hopping_frequency_no=0;
}
uint16_t initBAYANG(void)
{
BIND_IN_PROGRESS; // autobind protocol
phase=BAYANG_BIND;
bind_counter = BAYANG_BIND_COUNT;
BAYANG_initialize_txid();
BAYANG_init();
packet_count=0;
return BAYANG_INITIAL_WAIT+BAYANG_PACKET_PERIOD;
}
#endif