Pascal Langer 984aa3f413 Switch all protocols to use a resolution of 2048
- Change how PPM is handled with a resolution of 2048 and scaled to match serial input range. PPM is now fully scaled for all protocols which was not the case before. If you are using PPM, you might have to adjust the end points depending on the protocols.
 - Change all range conversions to use 2048 where possible
 - Updated all protocols with new range functions
 - Protocols which are taking advantage of 2048 are Assan, FrSky V/D/X, DSM, Devo, WK2x01
 - Renamed AUX xto CHx for code readbility
2018-01-08 19:37:14 +01:00

290 lines
8.2 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 WLToys V2x2, JXD JD38x, JD39x, JJRC H6C, Yizhan Tarantula X6 ...
// Last sync with hexfet new_protocols/v202_nrf24l01.c dated 2015-03-15
#if defined(V2X2_NRF24L01_INO)
#include "iface_nrf24l01.h"
#define V2X2_BIND_COUNT 1000
// Timeout for callback in uSec, 4ms=4000us for V202
#define V2X2_PACKET_PERIOD 4000
//
// Time to wait for packet to be sent (no ACK, so very short)
#define V2X2_PACKET_CHKTIME 100
#define V2X2_PAYLOADSIZE 16
//
enum {
V2X2_FLAG_CAMERA = 0x01, // also automatic Missile Launcher and Hoist in one direction
V2X2_FLAG_VIDEO = 0x02, // also Sprayer, Bubbler, Missile Launcher(1), and Hoist in the other dir.
V2X2_FLAG_FLIP = 0x04,
V2X2_FLAG_UNK9 = 0x08,
V2X2_FLAG_LIGHT = 0x10,
V2X2_FLAG_UNK10 = 0x20,
V2X2_FLAG_BIND = 0xC0,
// flags going to byte 10
V2X2_FLAG_HEADLESS = 0x02,
V2X2_FLAG_MAG_CAL_X = 0x08,
V2X2_FLAG_MAG_CAL_Y = 0x20,
V2X2_FLAG_EMERGENCY = 0x80, // JXD-506
// flags going to byte 11 (JXD-506)
V2X2_FLAG_START_STOP = 0x40,
V2X2_FLAG_CAMERA_UP = 0x01,
V2X2_FLAG_CAMERA_DN = 0x02,
};
//
enum {
V202_INIT2 = 0,
V202_INIT2_NO_BIND,//1
V202_BIND1,//2
V202_BIND2,//3
V202_DATA//4
};
// This is frequency hopping table for V202 protocol
// The table is the first 4 rows of 32 frequency hopping
// patterns, all other rows are derived from the first 4.
// For some reason the protocol avoids channels, dividing
// by 16 and replaces them by subtracting 3 from the channel
// number in this case.
// The pattern is defined by 5 least significant bits of
// sum of 3 bytes comprising TX id
const uint8_t PROGMEM freq_hopping[][16] = {
{ 0x27, 0x1B, 0x39, 0x28, 0x24, 0x22, 0x2E, 0x36,
0x19, 0x21, 0x29, 0x14, 0x1E, 0x12, 0x2D, 0x18 }, // 00
{ 0x2E, 0x33, 0x25, 0x38, 0x19, 0x12, 0x18, 0x16,
0x2A, 0x1C, 0x1F, 0x37, 0x2F, 0x23, 0x34, 0x10 }, // 01
{ 0x11, 0x1A, 0x35, 0x24, 0x28, 0x18, 0x25, 0x2A,
0x32, 0x2C, 0x14, 0x27, 0x36, 0x34, 0x1C, 0x17 }, // 02
{ 0x22, 0x27, 0x17, 0x39, 0x34, 0x28, 0x2B, 0x1D,
0x18, 0x2A, 0x21, 0x38, 0x10, 0x26, 0x20, 0x1F } // 03
};
static void __attribute__((unused)) v202_init()
{
NRF24L01_Initialize();
// 2-bytes CRC, radio off
NRF24L01_WriteReg(NRF24L01_00_CONFIG, _BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO));
NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknoledgement
NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x3F); // Enable all data pipes
NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x03); // 5-byte RX/TX address
NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0xFF); // 4ms retransmit t/o, 15 tries
NRF24L01_WriteReg(NRF24L01_05_RF_CH, 0x08); // Channel 8
NRF24L01_SetBitrate(NRF24L01_BR_1M); // 1Mbps
NRF24L01_SetPower();
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
// NRF24L01_WriteReg(NRF24L01_08_OBSERVE_TX, 0x00); // no write bits in this field
// NRF24L01_WriteReg(NRF24L01_00_CD, 0x00); // same
NRF24L01_WriteReg(NRF24L01_0C_RX_ADDR_P2, 0xC3); // LSB byte of pipe 2 receive address
NRF24L01_WriteReg(NRF24L01_0D_RX_ADDR_P3, 0xC4);
NRF24L01_WriteReg(NRF24L01_0E_RX_ADDR_P4, 0xC5);
NRF24L01_WriteReg(NRF24L01_0F_RX_ADDR_P5, 0xC6);
NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, V2X2_PAYLOADSIZE); // bytes of data payload for pipe 1
NRF24L01_WriteReg(NRF24L01_12_RX_PW_P1, V2X2_PAYLOADSIZE);
NRF24L01_WriteReg(NRF24L01_13_RX_PW_P2, V2X2_PAYLOADSIZE);
NRF24L01_WriteReg(NRF24L01_14_RX_PW_P3, V2X2_PAYLOADSIZE);
NRF24L01_WriteReg(NRF24L01_15_RX_PW_P4, V2X2_PAYLOADSIZE);
NRF24L01_WriteReg(NRF24L01_16_RX_PW_P5, V2X2_PAYLOADSIZE);
NRF24L01_WriteReg(NRF24L01_17_FIFO_STATUS, 0x00); // Just in case, no real bits to write here
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, (uint8_t *)"\x66\x88\x68\x68\x68", 5);
NRF24L01_WriteRegisterMulti(NRF24L01_0B_RX_ADDR_P1, (uint8_t *)"\x88\x66\x86\x86\x86", 5);
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, (uint8_t *)"\x66\x88\x68\x68\x68", 5);
}
static void __attribute__((unused)) V202_init2()
{
NRF24L01_FlushTx();
packet_sent = 0;
hopping_frequency_no = 0;
// Turn radio power on
NRF24L01_SetTxRxMode(TX_EN);
//Done by TX_EN??? => NRF24L01_WriteReg(NRF24L01_00_CONFIG, _BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO) | _BV(NRF24L01_00_PWR_UP));
}
static void __attribute__((unused)) V2X2_set_tx_id(void)
{
uint8_t sum;
sum = rx_tx_addr[1] + rx_tx_addr[2] + rx_tx_addr[3];
// Higher 3 bits define increment to corresponding row
uint8_t increment = (sum & 0x1e) >> 2;
// Base row is defined by lowest 2 bits
sum &=0x03;
for (uint8_t i = 0; i < 16; ++i) {
uint8_t val = pgm_read_byte_near(&freq_hopping[sum][i]) + increment;
// Strange avoidance of channels divisible by 16
hopping_frequency[i] = (val & 0x0f) ? val : val - 3;
}
}
static void __attribute__((unused)) V2X2_add_pkt_checksum()
{
uint8_t sum = 0;
for (uint8_t i = 0; i < 15; ++i)
sum += packet[i];
packet[15] = sum;
}
static void __attribute__((unused)) V2X2_send_packet(uint8_t bind)
{
uint8_t flags2=0;
if (bind)
{
flags = V2X2_FLAG_BIND;
packet[0] = 0;
packet[1] = 0;
packet[2] = 0;
packet[3] = 0;
packet[4] = 0;
packet[5] = 0;
packet[6] = 0;
}
else
{
packet[0] = convert_channel_8b(THROTTLE);
packet[1] = convert_channel_s8b(RUDDER);
packet[2] = convert_channel_s8b(ELEVATOR);
packet[3] = convert_channel_s8b(AILERON);
// Trims, middle is 0x40
packet[4] = 0x40; // yaw
packet[5] = 0x40; // pitch
packet[6] = 0x40; // roll
//Flags
flags=0;
// Channel 5
if (CH5_SW) flags = V2X2_FLAG_FLIP;
// Channel 6
if (CH6_SW) flags |= V2X2_FLAG_LIGHT;
// Channel 7
if (CH7_SW) flags |= V2X2_FLAG_CAMERA;
// Channel 8
if (CH8_SW) flags |= V2X2_FLAG_VIDEO;
//Flags2
// Channel 9
if (CH9_SW)
flags2 = V2X2_FLAG_HEADLESS;
if(sub_protocol==JXD506)
{
// Channel 11
if (CH11_SW)
flags2 |= V2X2_FLAG_EMERGENCY;
}
else
{
// Channel 10
if (CH10_SW)
flags2 |= V2X2_FLAG_MAG_CAL_X;
// Channel 11
if (CH11_SW)
flags2 |= V2X2_FLAG_MAG_CAL_Y;
}
}
// TX id
packet[7] = rx_tx_addr[1];
packet[8] = rx_tx_addr[2];
packet[9] = rx_tx_addr[3];
// flags
packet[10] = flags2;
packet[11] = 0x00;
packet[12] = 0x00;
packet[13] = 0x00;
if(sub_protocol==JXD506)
{
// Channel 10
if (CH10_SW)
packet[11] = V2X2_FLAG_START_STOP;
// Channel 12
if(CH12_SW)
packet[11] |= V2X2_FLAG_CAMERA_UP;
else if(Channel_data[CH12] < CHANNEL_MIN_COMMAND)
packet[11] |= V2X2_FLAG_CAMERA_DN;
packet[12] = 0x40;
packet[13] = 0x40;
}
packet[14] = flags;
V2X2_add_pkt_checksum();
packet_sent = 0;
uint8_t rf_ch = hopping_frequency[hopping_frequency_no >> 1];
hopping_frequency_no = (hopping_frequency_no + 1) & 0x1F;
NRF24L01_WriteReg(NRF24L01_05_RF_CH, rf_ch);
NRF24L01_FlushTx();
NRF24L01_WritePayload(packet, V2X2_PAYLOADSIZE);
packet_sent = 1;
if (! hopping_frequency_no)
NRF24L01_SetPower();
}
uint16_t ReadV2x2()
{
switch (phase) {
case V202_INIT2:
V202_init2();
phase = V202_BIND2;
return 150;
break;
case V202_INIT2_NO_BIND:
V202_init2();
phase = V202_DATA;
return 150;
break;
case V202_BIND2:
if (packet_sent && NRF24L01_packet_ack() != PKT_ACKED)
return V2X2_PACKET_CHKTIME;
V2X2_send_packet(1);
if (--bind_counter == 0)
{
phase = V202_DATA;
BIND_DONE;
}
break;
case V202_DATA:
if (packet_sent && NRF24L01_packet_ack() != PKT_ACKED)
return V2X2_PACKET_CHKTIME;
V2X2_send_packet(0);
break;
}
// Packet every 4ms
return V2X2_PACKET_PERIOD;
}
uint16_t initV2x2()
{
v202_init();
//
if (IS_BIND_IN_PROGRESS)
{
bind_counter = V2X2_BIND_COUNT;
phase = V202_INIT2;
}
else
phase = V202_INIT2_NO_BIND;
V2X2_set_tx_id();
return 50000;
}
#endif