mirror of
https://github.com/pascallanger/DIY-Multiprotocol-TX-Module.git
synced 2025-07-12 01:37:52 +00:00
Merge 89bea4c38b3ab47eaa01bf1197179fe4732b0d49 into 8f4bffa9509ea607ea841f1892e4a174eaa79096
This commit is contained in:
commit
d19f56f549
BIN
AVR8_Burn-O-Mat_2_1_2_setup.exe
Normal file
BIN
AVR8_Burn-O-Mat_2_1_2_setup.exe
Normal file
Binary file not shown.
164
Multiprotocol/A7105_joysway.ino
Normal file
164
Multiprotocol/A7105_joysway.ino
Normal file
@ -0,0 +1,164 @@
|
||||
/*
|
||||
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.
|
||||
|
||||
Deviation 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 Deviation. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if defined JOYSWAY_A7105_INO
|
||||
#include "iface_a7105.h"
|
||||
|
||||
|
||||
#define EVEN_ODD 0x00
|
||||
//#define EVEN_ODD 0x01
|
||||
static const uint8_t A7105_regs[] = {
|
||||
0x00, 0x62, -1, 0x0f, 0x00, -1 , -1 , 0x00, 0x00, 0x05, 0x00, 0x01, 0x00, 0xf5, 0x00, 0x15,
|
||||
0x9e, 0x4b, 0x00, 0x03, 0x56, 0x2b, 0x12, 0x4a, 0x02, 0x80, 0x80, 0x00, 0x0e, 0x91, 0x03, 0x0f,
|
||||
0x16, 0x2a, 0x00, -1, -1, -1, 0x3a, 0x06, 0x1f, 0x47, 0x80, 0x01, 0x05, 0x45, 0x18, 0x00,
|
||||
0x01, 0x0f, 0x00
|
||||
};
|
||||
|
||||
static uint8_t next_ch;
|
||||
|
||||
static int joysway_init()
|
||||
{
|
||||
int i;
|
||||
uint8_t if_calibration1;
|
||||
//uint8_t vco_calibration0;
|
||||
//uint8_t vco_calibration1;
|
||||
|
||||
phase = 0;
|
||||
next_ch = 0x30;
|
||||
|
||||
for (i = 0; i < 0x33; i++)
|
||||
if((uint8_t)A7105_regs[i] != -1)
|
||||
A7105_WriteReg(i, A7105_regs[i]);
|
||||
A7105_WriteID(0x5475c52a);
|
||||
|
||||
A7105_Strobe(A7105_PLL);
|
||||
|
||||
//IF Filter Bank Calibration
|
||||
A7105_WriteReg(0x02, 1);
|
||||
A7105_ReadReg(0x02);
|
||||
uint32_t ms = micros();
|
||||
while(micros() - ms < 500) {
|
||||
if(! A7105_ReadReg(0x02))
|
||||
break;
|
||||
}
|
||||
if (micros() - ms >= 500)
|
||||
return 0;
|
||||
A7105_Strobe(A7105_STANDBY);
|
||||
if_calibration1 = A7105_ReadReg(0x22);
|
||||
if(if_calibration1 & A7105_MASK_FBCF) {
|
||||
//Calibration failed...what do we do?
|
||||
return 0;
|
||||
}
|
||||
|
||||
//VCO Current Calibration
|
||||
A7105_WriteReg(0x24, 0x13); //Recomended calibration from A7105 Datasheet
|
||||
A7105_WriteReg(0x25, 0x09); //Recomended calibration from A7105 Datasheet
|
||||
|
||||
A7105_WriteID(MProtocol_id_master);
|
||||
A7105_Strobe(A7105_PLL);
|
||||
A7105_WriteReg(0x02, 1);
|
||||
ms = micros();
|
||||
while(micros() - ms < 500) {
|
||||
if(! A7105_ReadReg(0x02))
|
||||
break;
|
||||
}
|
||||
if (micros() - ms >= 500)
|
||||
return 0;
|
||||
A7105_Strobe(A7105_STANDBY);
|
||||
if_calibration1 = A7105_ReadReg(0x22);
|
||||
if(if_calibration1 & A7105_MASK_FBCF) {
|
||||
//Calibration failed...what do we do?
|
||||
return 0;
|
||||
}
|
||||
A7105_WriteReg(0x24, 0x13); //Recomended calibration from A7105 Datasheet
|
||||
A7105_WriteReg(0x25, 0x09); //Recomended calibration from A7105 Datasheet
|
||||
|
||||
A7105_SetTxRxMode(TX_EN);
|
||||
A7105_SetPower();
|
||||
|
||||
A7105_Strobe(A7105_STANDBY);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void joysway_build_packet()
|
||||
{
|
||||
int i;
|
||||
//-100% =~ 0x03e8
|
||||
//+100% =~ 0x07ca
|
||||
//Calculate:
|
||||
//Center = 0x5d9
|
||||
//1 % = 5
|
||||
packet[0] = phase == 0 ? 0xdd : 0xff;
|
||||
packet[1] = (MProtocol_id_master >> 24) & 0xff;
|
||||
packet[2] = (MProtocol_id_master >> 16) & 0xff;
|
||||
packet[3] = (MProtocol_id_master >> 8) & 0xff;
|
||||
packet[4] = (MProtocol_id_master >> 0) & 0xff;
|
||||
packet[5] = 0x00;
|
||||
static const int chmap[4] = {6, 7, 10, 11};
|
||||
for (i = 0; i < 4; i++) {
|
||||
// if (i >= Model.num_channels) { packet[chmap[i]] = 0x64; continue; }
|
||||
uint32_t value = (uint32_t)Servo_data[i] * 0x66 / PPM_MAX + 0x66;
|
||||
if (value < 0) { value = 0; }
|
||||
if (value > 0xff) { value = 0xff; }
|
||||
packet[chmap[i]] = value;
|
||||
}
|
||||
packet[8] = 0x64;
|
||||
packet[9] = 0x64;
|
||||
packet[12] = 0x64;
|
||||
packet[13] = 0x64;
|
||||
packet[14] = phase == 0 ? 0x30 : 0xaa;
|
||||
uint8_t value = 0;
|
||||
for (int i = 0; i < 15; i++) { value += packet[i]; }
|
||||
packet[15] = value;
|
||||
}
|
||||
|
||||
static uint16_t joysway_cb()
|
||||
{
|
||||
uint8_t ch;
|
||||
if (phase == 254) {
|
||||
phase = 0;
|
||||
A7105_WriteID(0x5475c52a);
|
||||
ch = 0x0a;
|
||||
} else if (phase == 2) {
|
||||
A7105_WriteID(MProtocol_id_master);
|
||||
ch = 0x30;
|
||||
} else {
|
||||
if ((phase & 0x01) ^ EVEN_ODD) {
|
||||
ch = 0x30;
|
||||
} else {
|
||||
ch = next_ch;
|
||||
}
|
||||
}
|
||||
if (! ((phase & 0x01) ^ EVEN_ODD)) {
|
||||
next_ch++;
|
||||
if (next_ch == 0x45)
|
||||
next_ch = 0x30;
|
||||
}
|
||||
joysway_build_packet();
|
||||
A7105_Strobe(A7105_STANDBY);
|
||||
A7105_WriteData(16, ch);
|
||||
phase++;
|
||||
return 6000;
|
||||
}
|
||||
|
||||
static uint16_t JOYSWAY_Setup() {
|
||||
while(1) {
|
||||
A7105_Reset();
|
||||
if (joysway_init())
|
||||
break;
|
||||
}
|
||||
return 2400;
|
||||
}
|
||||
#endif
|
@ -25,6 +25,10 @@
|
||||
#define Q282_PACKET_SIZE 21
|
||||
#define CX10_PACKET_PERIOD 1316 // Timeout for callback in uSec
|
||||
#define CX10A_PACKET_PERIOD 6000
|
||||
<<<<<<< HEAD
|
||||
#define CX10A_BIND_COUNT 400 // 2 seconds
|
||||
=======
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
|
||||
#define CX10_INITIAL_WAIT 500
|
||||
|
||||
@ -197,15 +201,30 @@ uint16_t CX10_callback()
|
||||
}
|
||||
break;
|
||||
case CX10_BIND2:
|
||||
<<<<<<< HEAD
|
||||
bind_counter--;
|
||||
if(bind_counter==0)
|
||||
{ // Needed for some CX-10A to properly finish the bind
|
||||
CX10_init();
|
||||
bind_counter=CX10A_BIND_COUNT;
|
||||
}
|
||||
if( NRF24L01_ReadReg(NRF24L01_07_STATUS) & BV(NRF24L01_07_RX_DR))
|
||||
=======
|
||||
if( NRF24L01_ReadReg(NRF24L01_07_STATUS) & _BV(NRF24L01_07_RX_DR))
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
{ // RX fifo data ready
|
||||
XN297_ReadPayload(packet, packet_length);
|
||||
NRF24L01_SetTxRxMode(TXRX_OFF);
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
if(packet[9] == 1)
|
||||
{
|
||||
<<<<<<< HEAD
|
||||
phase = CX10_BIND1;
|
||||
bind_counter=0;
|
||||
=======
|
||||
BIND_DONE;
|
||||
phase = CX10_DATA;
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -215,7 +234,11 @@ uint16_t CX10_callback()
|
||||
NRF24L01_FlushTx();
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
CX10_Write_Packet(1);
|
||||
<<<<<<< HEAD
|
||||
delayMicroseconds(400); // 300µs in deviation but not working so using 400µs instead
|
||||
=======
|
||||
delayMicroseconds(400);
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
// switch to RX mode
|
||||
NRF24L01_SetTxRxMode(TXRX_OFF);
|
||||
NRF24L01_FlushRx();
|
||||
@ -265,6 +288,10 @@ uint16_t initCX10(void)
|
||||
packet_period = CX10A_PACKET_PERIOD;
|
||||
|
||||
phase = CX10_BIND2;
|
||||
<<<<<<< HEAD
|
||||
bind_counter=CX10A_BIND_COUNT;
|
||||
=======
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
|
||||
for(uint8_t i=0; i<4; i++)
|
||||
packet[5+i] = 0xff; // clear aircraft id
|
||||
|
@ -192,11 +192,18 @@ static void CYRF_StartReceive()
|
||||
CYRF_ReadRegisterMulti(CYRF_21_RX_BUFFER, dpbuffer, 0x10);
|
||||
}
|
||||
*/
|
||||
<<<<<<< HEAD
|
||||
static void CYRF_ReadDataPacketLen(uint8_t dpbuffer[], uint8_t length)
|
||||
=======
|
||||
void CYRF_ReadDataPacketLen(uint8_t dpbuffer[], uint8_t length)
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
{
|
||||
CYRF_ReadRegisterMulti(CYRF_21_RX_BUFFER, dpbuffer, length);
|
||||
}
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
static void CYRF_WriteDataPacketLen(const uint8_t dpbuffer[], uint8_t len)
|
||||
{
|
||||
CYRF_WriteRegister(CYRF_01_TX_LENGTH, len);
|
||||
|
277
Multiprotocol/CYRF6936_j6pro.ino
Normal file
277
Multiprotocol/CYRF6936_j6pro.ino
Normal file
@ -0,0 +1,277 @@
|
||||
/*
|
||||
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.
|
||||
|
||||
Deviation 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 Deviation. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if defined(J6PRO_CYRF6936_INO)
|
||||
#include "iface_cyrf6936.h"
|
||||
|
||||
#define NUM_WAIT_LOOPS (100 / 5) //each loop is ~5us. Do not wait more than 100us
|
||||
|
||||
//For Debug
|
||||
//#define NO_SCRAMBLE
|
||||
|
||||
enum J6ProState {
|
||||
J6PRO_BIND,
|
||||
J6PRO_BIND_01,
|
||||
J6PRO_BIND_03_START,
|
||||
J6PRO_BIND_03_CHECK,
|
||||
J6PRO_BIND_05_1,
|
||||
J6PRO_BIND_05_2,
|
||||
J6PRO_BIND_05_3,
|
||||
J6PRO_BIND_05_4,
|
||||
J6PRO_BIND_05_5,
|
||||
J6PRO_BIND_05_6,
|
||||
J6PRO_CHANSEL,
|
||||
J6PRO_CHAN_1,
|
||||
J6PRO_CHAN_2,
|
||||
J6PRO_CHAN_3,
|
||||
J6PRO_CHAN_4,
|
||||
};
|
||||
|
||||
static const uint8_t J6Pro_sopcodes[][8] = {
|
||||
/* Note these are in order transmitted (LSB 1st) */
|
||||
{0x3C, 0x37, 0xCC, 0x91, 0xE2, 0xF8, 0xCC, 0x91},
|
||||
{0x9B, 0xC5, 0xA1, 0x0F, 0xAD, 0x39, 0xA2, 0x0F},
|
||||
{0xEF, 0x64, 0xB0, 0x2A, 0xD2, 0x8F, 0xB1, 0x2A},
|
||||
{0x66, 0xCD, 0x7C, 0x50, 0xDD, 0x26, 0x7C, 0x50},
|
||||
{0x5C, 0xE1, 0xF6, 0x44, 0xAD, 0x16, 0xF6, 0x44},
|
||||
{0x5A, 0xCC, 0xAE, 0x46, 0xB6, 0x31, 0xAE, 0x46},
|
||||
{0xA1, 0x78, 0xDC, 0x3C, 0x9E, 0x82, 0xDC, 0x3C},
|
||||
{0xB9, 0x8E, 0x19, 0x74, 0x6F, 0x65, 0x18, 0x74},
|
||||
{0xDF, 0xB1, 0xC0, 0x49, 0x62, 0xDF, 0xC1, 0x49},
|
||||
{0x97, 0xE5, 0x14, 0x72, 0x7F, 0x1A, 0x14, 0x72},
|
||||
{0x82, 0xC7, 0x90, 0x36, 0x21, 0x03, 0xFF, 0x17},
|
||||
{0xE2, 0xF8, 0xCC, 0x91, 0x3C, 0x37, 0xCC, 0x91}, //Note: the '03' was '9E' in the Cypress recommended table
|
||||
{0xAD, 0x39, 0xA2, 0x0F, 0x9B, 0xC5, 0xA1, 0x0F}, //The following are the same as the 1st 8 above,
|
||||
{0xD2, 0x8F, 0xB1, 0x2A, 0xEF, 0x64, 0xB0, 0x2A}, //but with the upper and lower word swapped
|
||||
{0xDD, 0x26, 0x7C, 0x50, 0x66, 0xCD, 0x7C, 0x50},
|
||||
{0xAD, 0x16, 0xF6, 0x44, 0x5C, 0xE1, 0xF6, 0x44},
|
||||
{0xB6, 0x31, 0xAE, 0x46, 0x5A, 0xCC, 0xAE, 0x46},
|
||||
{0x9E, 0x82, 0xDC, 0x3C, 0xA1, 0x78, 0xDC, 0x3C},
|
||||
{0x6F, 0x65, 0x18, 0x74, 0xB9, 0x8E, 0x19, 0x74},
|
||||
};
|
||||
const uint8_t bind_sop_code[] = {0x62, 0xdf, 0xc1, 0x49, 0xdf, 0xb1, 0xc0, 0x49};
|
||||
const uint8_t data_code[] = {0x02, 0xf9, 0x93, 0x97, 0x02, 0xfa, 0x5c, 0xe3, 0x01, 0x2b, 0xf1, 0xdb, 0x01, 0x32, 0xbe, 0x6f};
|
||||
|
||||
static uint8_t stateJ6P;
|
||||
static uint8_t radio_ch[4];
|
||||
static uint8_t num_channels;
|
||||
|
||||
void J6Pro_build_bind_packet()
|
||||
{
|
||||
packet[0] = 0x01; //Packet type
|
||||
packet[1] = 0x01; //FIXME: What is this? Model number maybe?
|
||||
packet[2] = 0x56; //FIXME: What is this?
|
||||
packet[3] = cyrfmfg_id[0];
|
||||
packet[4] = cyrfmfg_id[1];
|
||||
packet[5] = cyrfmfg_id[2];
|
||||
packet[6] = cyrfmfg_id[3];
|
||||
packet[7] = cyrfmfg_id[4];
|
||||
packet[8] = cyrfmfg_id[5];
|
||||
}
|
||||
void J6Pro_build_data_packet()
|
||||
{
|
||||
uint8_t i;
|
||||
uint32_t upperbits = 0;
|
||||
packet[0] = 0xaa; //FIXME what is this?
|
||||
for (i = 0; i < 12; i++) {
|
||||
if (i >= num_channels) {
|
||||
packet[i+1] = 0xff;
|
||||
continue;
|
||||
}
|
||||
uint32_t value = (uint32_t)Servo_data[i] * 0x200 / PPM_MAX + 0x200;
|
||||
if (value < 0)
|
||||
value = 0;
|
||||
if (value > 0x3ff)
|
||||
value = 0x3ff;
|
||||
packet[i+1] = value & 0xff;
|
||||
upperbits |= (value >> 8) << (i * 2);
|
||||
}
|
||||
packet[13] = upperbits & 0xff;
|
||||
packet[14] = (upperbits >> 8) & 0xff;
|
||||
packet[15] = (upperbits >> 16) & 0xff;
|
||||
}
|
||||
|
||||
static void J6Pro_cyrf_init()
|
||||
{
|
||||
/* Initialise CYRF chip */
|
||||
CYRF_WriteRegister(CYRF_28_CLK_EN, 0x02);
|
||||
CYRF_WriteRegister(CYRF_32_AUTO_CAL_TIME, 0x3c);
|
||||
CYRF_WriteRegister(CYRF_35_AUTOCAL_OFFSET, 0x14);
|
||||
CYRF_WriteRegister(CYRF_1C_TX_OFFSET_MSB, 0x05);
|
||||
CYRF_WriteRegister(CYRF_1B_TX_OFFSET_LSB, 0x55);
|
||||
CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x25);
|
||||
CYRF_WriteRegister(CYRF_03_TX_CFG, 0x05 | CYRF_BIND_POWER);
|
||||
CYRF_WriteRegister(CYRF_06_RX_CFG, 0x8a);
|
||||
CYRF_WriteRegister(CYRF_03_TX_CFG, 0x28 | CYRF_BIND_POWER);
|
||||
CYRF_WriteRegister(CYRF_12_DATA64_THOLD, 0x0e);
|
||||
CYRF_WriteRegister(CYRF_10_FRAMING_CFG, 0xee);
|
||||
CYRF_WriteRegister(CYRF_1F_TX_OVERRIDE, 0x00);
|
||||
CYRF_WriteRegister(CYRF_1E_RX_OVERRIDE, 0x00);
|
||||
CYRF_ConfigDataCode(data_code, 16);
|
||||
CYRF_WritePreamble(0x023333);
|
||||
}
|
||||
static void J6Pro_cyrf_bindinit()
|
||||
{
|
||||
/* Use when binding */
|
||||
//0.060470# 03 2f
|
||||
CYRF_WriteRegister(CYRF_03_TX_CFG, 0x28 | 0x07); //Use max power for binding in case there is no telem module
|
||||
|
||||
CYRF_ConfigRFChannel(0x52);
|
||||
CYRF_ConfigSOPCode(bind_sop_code);
|
||||
CYRF_ConfigCRCSeed(0x0000);
|
||||
CYRF_WriteRegister(CYRF_06_RX_CFG, 0x4a);
|
||||
CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x83);
|
||||
//0.061511# 13 20
|
||||
|
||||
CYRF_ConfigRFChannel(0x52);
|
||||
//0.062684# 0f 05
|
||||
CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x25);
|
||||
//0.062792# 0f 05
|
||||
CYRF_WriteRegister(CYRF_02_TX_CTRL, 0x40);
|
||||
J6Pro_build_bind_packet(); //01 01 e9 49 ec a9 c4 c1 ff
|
||||
//CYRF_WriteDataPacketLen(packet, 0x09);
|
||||
}
|
||||
static void J6Pro_cyrf_datainit()
|
||||
{
|
||||
/* Use when already bound */
|
||||
//0.094007# 0f 05
|
||||
uint8_t sop_idx = (0xff & (cyrfmfg_id[0] + cyrfmfg_id[1] + cyrfmfg_id[2] + cyrfmfg_id[3] - cyrfmfg_id[5])) % 19;
|
||||
uint16_t crc = (0xff & (cyrfmfg_id[1] - cyrfmfg_id[4] + cyrfmfg_id[5])) |
|
||||
((0xff & (cyrfmfg_id[2] + cyrfmfg_id[3] - cyrfmfg_id[4] + cyrfmfg_id[5])) << 8);
|
||||
CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x25);
|
||||
CYRF_ConfigSOPCode(J6Pro_sopcodes[sop_idx]);
|
||||
CYRF_ConfigCRCSeed(crc);
|
||||
}
|
||||
|
||||
static void J6Pro_set_radio_channels()
|
||||
{
|
||||
//FIXME: Query free channels
|
||||
//lowest channel is 0x08, upper channel is 0x4d?
|
||||
CYRF_FindBestChannels(radio_ch, 3, 5, 8, 77);
|
||||
radio_ch[3] = radio_ch[0];
|
||||
}
|
||||
|
||||
static uint16_t j6pro_cb()
|
||||
{
|
||||
switch(stateJ6P) {
|
||||
case J6PRO_BIND:
|
||||
J6Pro_cyrf_bindinit();
|
||||
stateJ6P = J6PRO_BIND_01;
|
||||
//no break because we want to send the 1st bind packet now
|
||||
case J6PRO_BIND_01:
|
||||
CYRF_ConfigRFChannel(0x52);
|
||||
CYRF_SetTxRxMode(TX_EN);
|
||||
//0.062684# 0f 05
|
||||
CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x25);
|
||||
//0.062684# 0f 05
|
||||
CYRF_WriteDataPacketLen(packet, 0x09);
|
||||
stateJ6P = J6PRO_BIND_03_START;
|
||||
return 3000; //3msec
|
||||
case J6PRO_BIND_03_START:
|
||||
{
|
||||
int i = 0;
|
||||
while (! (CYRF_ReadRegister(0x04) & 0x06))
|
||||
if(++i > NUM_WAIT_LOOPS)
|
||||
break;
|
||||
}
|
||||
CYRF_ConfigRFChannel(0x53);
|
||||
CYRF_SetTxRxMode(RX_EN);
|
||||
CYRF_WriteRegister(CYRF_06_RX_CFG, 0x4a);
|
||||
CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x83);
|
||||
stateJ6P = J6PRO_BIND_03_CHECK;
|
||||
return 30000; //30msec
|
||||
case J6PRO_BIND_03_CHECK:
|
||||
{
|
||||
uint8_t rx = CYRF_ReadRegister(CYRF_07_RX_IRQ_STATUS);
|
||||
if((rx & 0x1a) == 0x1a) {
|
||||
rx = CYRF_ReadRegister(CYRF_0A_RX_LENGTH);
|
||||
if(rx == 0x0f) {
|
||||
rx = CYRF_ReadRegister(CYRF_09_RX_COUNT);
|
||||
if(rx == 0x0f) {
|
||||
//Expected and actual length are both 15
|
||||
CYRF_ReadDataPacketLen(packet, rx);
|
||||
if (packet[0] == 0x03 &&
|
||||
packet[3] == cyrfmfg_id[0] &&
|
||||
packet[4] == cyrfmfg_id[1] &&
|
||||
packet[5] == cyrfmfg_id[2] &&
|
||||
packet[6] == cyrfmfg_id[3] &&
|
||||
packet[7] == cyrfmfg_id[4] &&
|
||||
packet[8] == cyrfmfg_id[5])
|
||||
{
|
||||
//Send back Ack
|
||||
packet[0] = 0x05;
|
||||
CYRF_ConfigRFChannel(0x54);
|
||||
CYRF_SetTxRxMode(TX_EN);
|
||||
stateJ6P = J6PRO_BIND_05_1;
|
||||
return 2000; //2msec
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
stateJ6P = J6PRO_BIND_01;
|
||||
return 500;
|
||||
}
|
||||
case J6PRO_BIND_05_1:
|
||||
case J6PRO_BIND_05_2:
|
||||
case J6PRO_BIND_05_3:
|
||||
case J6PRO_BIND_05_4:
|
||||
case J6PRO_BIND_05_5:
|
||||
case J6PRO_BIND_05_6:
|
||||
CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x25);
|
||||
CYRF_WriteDataPacketLen(packet, 0x0f);
|
||||
stateJ6P = stateJ6P + 1;
|
||||
return 4600; //4.6msec
|
||||
case J6PRO_CHANSEL:
|
||||
BIND_DONE;
|
||||
J6Pro_set_radio_channels();
|
||||
J6Pro_cyrf_datainit();
|
||||
stateJ6P = J6PRO_CHAN_1;
|
||||
case J6PRO_CHAN_1:
|
||||
//Keep transmit power updated
|
||||
CYRF_SetPower(CYRF_HIGH_POWER);
|
||||
J6Pro_build_data_packet();
|
||||
//return 3400;
|
||||
case J6PRO_CHAN_2:
|
||||
//return 3500;
|
||||
case J6PRO_CHAN_3:
|
||||
//return 3750
|
||||
case J6PRO_CHAN_4:
|
||||
CYRF_ConfigRFChannel(radio_ch[stateJ6P - J6PRO_CHAN_1]);
|
||||
CYRF_SetTxRxMode(TX_EN);
|
||||
CYRF_WriteDataPacket(packet);
|
||||
if (stateJ6P == J6PRO_CHAN_4) {
|
||||
stateJ6P = J6PRO_CHAN_1;
|
||||
return 13900;
|
||||
}
|
||||
stateJ6P = stateJ6P + 1;
|
||||
return 3550;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint16_t j6pro_setup()
|
||||
{
|
||||
CYRF_Reset();
|
||||
J6Pro_cyrf_init();
|
||||
num_channels = 8;
|
||||
if (IS_AUTOBIND_FLAG_on) {
|
||||
stateJ6P = J6PRO_BIND;
|
||||
BIND_IN_PROGRESS;
|
||||
} else {
|
||||
stateJ6P = J6PRO_CHANSEL;
|
||||
}
|
||||
return 2400;
|
||||
}
|
||||
#endif
|
183
Multiprotocol/Cc2500_skyartec.ino
Normal file
183
Multiprotocol/Cc2500_skyartec.ino
Normal file
@ -0,0 +1,183 @@
|
||||
/*
|
||||
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.
|
||||
|
||||
Deviation 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 Deviation. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if defined(SKYARTEC_CC2500_INO)
|
||||
#include "iface_cc2500.h"
|
||||
|
||||
#define TX_ADDR ((binding_idx >> 16) & 0xff)
|
||||
#define TX_CHANNEL ((binding_idx >> 24) & 0xff)
|
||||
|
||||
enum {
|
||||
SKYARTEC_PKT1 = 0,
|
||||
SKYARTEC_SLEEP1,
|
||||
SKYARTEC_PKT2,
|
||||
SKYARTEC_SLEEP2,
|
||||
SKYARTEC_PKT3,
|
||||
SKYARTEC_SLEEP3,
|
||||
SKYARTEC_PKT4,
|
||||
SKYARTEC_SLEEP4,
|
||||
SKYARTEC_PKT5,
|
||||
SKYARTEC_SLEEP5,
|
||||
SKYARTEC_PKT6,
|
||||
SKYARTEC_LAST,
|
||||
};
|
||||
|
||||
static void skyartec_init() {
|
||||
CC2500_Reset();
|
||||
|
||||
cc2500_writeReg(CC2500_16_MCSM2, 0x07);
|
||||
cc2500_writeReg(CC2500_17_MCSM1, 0x30);
|
||||
cc2500_writeReg(CC2500_1E_WOREVT1, 0x87);
|
||||
cc2500_writeReg(CC2500_1F_WOREVT0, 0x6b);
|
||||
cc2500_writeReg(CC2500_20_WORCTRL, 0xf8);
|
||||
cc2500_writeReg(CC2500_2A_PTEST, 0x7f);
|
||||
cc2500_writeReg(CC2500_2B_AGCTEST, 0x3f);
|
||||
cc2500_writeReg(CC2500_0B_FSCTRL1, 0x09);
|
||||
cc2500_writeReg(CC2500_0C_FSCTRL0, 0x00);
|
||||
cc2500_writeReg(CC2500_0D_FREQ2, 0x5d);
|
||||
cc2500_writeReg(CC2500_0E_FREQ1, 0x93);
|
||||
cc2500_writeReg(CC2500_0F_FREQ0, 0xb1);
|
||||
cc2500_writeReg(CC2500_10_MDMCFG4, 0x2d);
|
||||
cc2500_writeReg(CC2500_11_MDMCFG3, 0x20);
|
||||
cc2500_writeReg(CC2500_12_MDMCFG2, 0x73);
|
||||
cc2500_writeReg(CC2500_13_MDMCFG1, 0x22);
|
||||
cc2500_writeReg(CC2500_14_MDMCFG0, 0xf8);
|
||||
cc2500_writeReg(CC2500_0A_CHANNR, 0xcd);
|
||||
cc2500_writeReg(CC2500_15_DEVIATN, 0x50);
|
||||
cc2500_writeReg(CC2500_21_FREND1, 0xb6);
|
||||
cc2500_writeReg(CC2500_22_FREND0, 0x10);
|
||||
cc2500_writeReg(CC2500_18_MCSM0, 0x18);
|
||||
cc2500_writeReg(CC2500_19_FOCCFG, 0x1d);
|
||||
cc2500_writeReg(CC2500_1A_BSCFG, 0x1c);
|
||||
cc2500_writeReg(CC2500_1B_AGCCTRL2, 0xc7);
|
||||
cc2500_writeReg(CC2500_1C_AGCCTRL1, 0x00);
|
||||
cc2500_writeReg(CC2500_1D_AGCCTRL0, 0xb2);
|
||||
cc2500_writeReg(CC2500_23_FSCAL3, 0xea);
|
||||
cc2500_writeReg(CC2500_24_FSCAL2, 0x0a);
|
||||
cc2500_writeReg(CC2500_25_FSCAL1, 0x00);
|
||||
cc2500_writeReg(CC2500_26_FSCAL0, 0x11);
|
||||
cc2500_writeReg(CC2500_29_FSTEST, 0x59);
|
||||
cc2500_writeReg(CC2500_2C_TEST2, 0x88);
|
||||
cc2500_writeReg(CC2500_2D_TEST1, 0x31);
|
||||
cc2500_writeReg(CC2500_2E_TEST0, 0x0b);
|
||||
cc2500_writeReg(CC2500_07_PKTCTRL1, 0x05);
|
||||
cc2500_writeReg(CC2500_08_PKTCTRL0, 0x05);
|
||||
cc2500_writeReg(CC2500_09_ADDR, 0x43);
|
||||
cc2500_writeReg(CC2500_06_PKTLEN, 0xff);
|
||||
cc2500_writeReg(CC2500_04_SYNC1, 0x13);
|
||||
cc2500_writeReg(CC2500_05_SYNC0, 0x18);
|
||||
CC2500_SetTxRxMode(TX_EN);
|
||||
CC2500_SetPower();
|
||||
cc2500_strobe(CC2500_SFTX);
|
||||
cc2500_strobe(CC2500_SFRX);
|
||||
cc2500_strobe(CC2500_SXOFF);
|
||||
cc2500_strobe(CC2500_SIDLE);
|
||||
}
|
||||
|
||||
static void add_pkt_suffix() {
|
||||
int xor1 = 0;
|
||||
int xor2 = 0;
|
||||
for(int i = 3; i <= 16; i++) { xor1 ^= packet[i]; }
|
||||
for(int i = 3; i <= 14; i++) { xor2 ^= packet[i]; }
|
||||
|
||||
int sum = packet[3] + packet[5] + packet[7] + packet[9] + packet[11] + packet[13];
|
||||
packet[17] = xor1;
|
||||
packet[18] = xor2;
|
||||
packet[19] = sum & 0xff;
|
||||
}
|
||||
|
||||
static void send_data_packet() {
|
||||
//13 c5 01 0259 0168 0000 0259 030c 021a 0489 f3 7e 0a
|
||||
packet[0] = 0x13; //Length
|
||||
packet[1] = TX_ADDR; //Tx Addr?
|
||||
packet[2] = 0x01; //???
|
||||
for(int i = 0; i < 7; i++) {
|
||||
uint32_t value = (uint32_t)Servo_data[i] * 0x280 / PPM_MAX + 0x280;
|
||||
if(value < 0) { value = 0; }
|
||||
if(value > 0x500) { value = 0x500; }
|
||||
packet[3+2*i] = value >> 8;
|
||||
packet[4+2*i] = value & 0xff;
|
||||
}
|
||||
add_pkt_suffix();
|
||||
//for(int i = 0; i < 20; i++) printf("%02x ", packet[i]); printf("\n");
|
||||
cc2500_writeReg(CC2500_04_SYNC1, ((binding_idx >> 0) & 0xff));
|
||||
cc2500_writeReg(CC2500_05_SYNC0, ((binding_idx >> 8) & 0xff));
|
||||
cc2500_writeReg(CC2500_09_ADDR, TX_ADDR);
|
||||
cc2500_writeReg(CC2500_0A_CHANNR, TX_CHANNEL);
|
||||
cc2500_writeFifo(packet, 20);
|
||||
}
|
||||
|
||||
static void send_bind_packet() {
|
||||
//0b 7d 01 01 b2 c5 4a 2f 00 00 c5 d6
|
||||
packet[0] = 0x0b; //Length
|
||||
packet[1] = 0x7d;
|
||||
packet[2] = 0x01;
|
||||
packet[3] = 0x01;
|
||||
packet[4] = (binding_idx >> 24) & 0xff;
|
||||
packet[5] = (binding_idx >> 16) & 0xff;
|
||||
packet[6] = (binding_idx >> 8) & 0xff;
|
||||
packet[7] = (binding_idx >> 0) & 0xff;
|
||||
packet[8] = 0x00;
|
||||
packet[9] = 0x00;
|
||||
packet[10] = TX_ADDR;
|
||||
uint8_t xore = 0;
|
||||
for(int i = 3; i < 11; i++) { xore ^= packet[i]; }
|
||||
packet[11] = xore;
|
||||
cc2500_writeReg(CC2500_04_SYNC1, 0x7d);
|
||||
cc2500_writeReg(CC2500_05_SYNC0, 0x7d);
|
||||
cc2500_writeReg(CC2500_09_ADDR, 0x7d);
|
||||
cc2500_writeReg(CC2500_0A_CHANNR, 0x7d);
|
||||
cc2500_writeFifo(packet, 12);
|
||||
}
|
||||
|
||||
static uint16_t skyartec_cb() {
|
||||
if (state & 0x01) {
|
||||
cc2500_strobe(CC2500_SIDLE);
|
||||
if (state == SKYARTEC_LAST) { CC2500_SetPower(); state = SKYARTEC_PKT1; }
|
||||
else { state++; }
|
||||
return 3000;
|
||||
}
|
||||
if (state == SKYARTEC_PKT1 && bind_phase) {
|
||||
send_bind_packet();
|
||||
bind_phase--;
|
||||
if(bind_phase == 0) { printf("Done binding\n"); }
|
||||
} else { send_data_packet(); }
|
||||
state++;
|
||||
return 3000;
|
||||
}
|
||||
|
||||
static uint8_t skyartec_setup() {
|
||||
skyartec_init();
|
||||
/* binding_idx = 0xb2c54a2f;
|
||||
if (Model.fixed_id) {
|
||||
binding_idx ^= Model.binding_idx + (Model.fixed_id << 16);
|
||||
} else {
|
||||
int partnum = CC2500_ReadReg(0xF0);
|
||||
int vernum = CC2500_ReadReg(0xF1);
|
||||
binding_idx ^= partnum << 24;
|
||||
binding_idx ^= vernum << 16;
|
||||
binding_idx ^= (vernum << 4 | partnum >> 4) << 8;
|
||||
binding_idx ^= (partnum << 4 | vernum >> 4) << 8;
|
||||
}
|
||||
*/
|
||||
binding_idx = MProtocol_id;
|
||||
if (0 == (binding_idx & 0xff000000)) { binding_idx |= 0xb2; }
|
||||
if (0 == (binding_idx & 0x00ff0000)) { binding_idx |= 0xc5; }
|
||||
if (0 == (binding_idx & 0x0000ff00)) { binding_idx |= 0x4a; }
|
||||
if (0 == (binding_idx & 0x000000ff)) { binding_idx |= 0x2f; }
|
||||
bind_phase = 10000;
|
||||
state = SKYARTEC_PKT1;
|
||||
}
|
||||
#endif
|
449
Multiprotocol/Cyrf6936_wk2x01.ino
Normal file
449
Multiprotocol/Cyrf6936_wk2x01.ino
Normal file
@ -0,0 +1,449 @@
|
||||
/*
|
||||
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.
|
||||
Deviation 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 Deviation. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#if defined(WK2x01_CYRF6936_INO)
|
||||
#include "iface_cyrf6936.h"
|
||||
|
||||
#define PKTS_PER_CHANNEL 4
|
||||
|
||||
//Fewer bind packets in the emulator so we can get right to the important bits
|
||||
#define WK_BIND_COUNT 2980
|
||||
|
||||
#define NUM_WAIT_LOOPS (100 / 5) //each loop is ~5us. Do not wait more than 100us
|
||||
|
||||
|
||||
#define WK_BIND 0
|
||||
#define WK_BOUND_1 1
|
||||
#define WK_BOUND_2 2
|
||||
#define WK_BOUND_3 3
|
||||
#define WK_BOUND_4 4
|
||||
#define WK_BOUND_5 5
|
||||
#define WK_BOUND_6 6
|
||||
#define WK_BOUND_7 7
|
||||
#define WK_BOUND_8 8
|
||||
|
||||
static const uint8_t sopcode[8] = {
|
||||
/* Note these are in order transmitted (LSB 1st) */
|
||||
0xDF,0xB1,0xC0,0x49,0x62,0xDF,0xC1,0x49 //0x49C1DF6249C0B1DF
|
||||
};
|
||||
static const uint8_t fail_map[8] = {2, 1, 0, 3, 4, 5, 6, 7};
|
||||
|
||||
static uint8_t wk_pkt_num;
|
||||
static uint8_t *radio_ch_ptr;
|
||||
static uint16_t WK_BIND_COUNTer;
|
||||
static uint8_t last_beacon;
|
||||
/*
|
||||
static const char * const wk2601_opts[] = {
|
||||
_tr_noop("Chan mode"), _tr_noop("5+1"), _tr_noop("Heli"), _tr_noop("6+1"), NULL,
|
||||
_tr_noop("COL Inv"), _tr_noop("Normal"), _tr_noop("Inverted"), NULL,
|
||||
_tr_noop("COL Limit"), "-100", "100", NULL,
|
||||
NULL
|
||||
};
|
||||
#define WK2601_OPT_CHANMODE 0
|
||||
#define WK2601_OPT_PIT_INV 1
|
||||
#define WK2601_OPT_PIT_LIMIT 2
|
||||
#define LAST_PROTO_OPT 3
|
||||
*/
|
||||
|
||||
static void add_pkt_crc(uint8_t init) {
|
||||
uint8_t add = init;
|
||||
uint8_t xou = init;
|
||||
int i;
|
||||
for (i = 0; i < 14; i++) { add += packet[i]; xou ^= packet[i]; }
|
||||
packet[14] = xou;
|
||||
packet[15] = add & 0xff;
|
||||
}
|
||||
static const char init_2801[] = {0xc5, 0x34, 0x60, 0x00, 0x25};
|
||||
static const char init_2601[] = {0xb9, 0x45, 0xb0, 0xf1, 0x3a};
|
||||
static const char init_2401[] = {0xa5, 0x23, 0xd0, 0xf0, 0x00};
|
||||
static void build_bind_pkt(const char *init) {
|
||||
packet[0] = init[0];
|
||||
packet[1] = init[1];
|
||||
packet[2] = rx_tx_addr[0];
|
||||
packet[3] = rx_tx_addr[1];
|
||||
packet[4] = init[2];
|
||||
packet[5] = rx_tx_addr[2];
|
||||
packet[6] = 0xff;
|
||||
packet[7] = 0x00;
|
||||
packet[8] = 0x00;
|
||||
packet[9] = 0x32;
|
||||
if (sub_protocol == WK2401) { packet[10] = 0x10 | ((fixed_id >> 0) & 0x0e); }
|
||||
else { packet[10] = (fixed_id >> 0) & 0xff; }
|
||||
packet[11] = (fixed_id >> 8) & 0xff;
|
||||
packet[12] = ((fixed_id >> 12) & 0xf0) | wk_pkt_num;
|
||||
packet[13] = init[3];
|
||||
add_pkt_crc(init[4]);
|
||||
}
|
||||
|
||||
static uint16_t get_channel(uint8_t ch, uint32_t scale, uint32_t center, uint32_t range) {
|
||||
uint32_t value = (uint32_t)Servo_data[ch] * scale / PPM_MAX + center;
|
||||
if (value < center - range) { value = center - range; }
|
||||
if (value > center + range) { value = center + range; }
|
||||
return value;
|
||||
}
|
||||
|
||||
static void build_data_pkt_2401() {
|
||||
uint8_t i;
|
||||
uint16_t msb = 0;
|
||||
uint8_t offset = 0;
|
||||
for (i = 0; i < 4; i++) {
|
||||
if (i == 2) { offset = 1; }
|
||||
uint16_t value = get_channel(i, 0x800, 0, 0xA00); //12 bits, allow value to go to 125%
|
||||
uint16_t base = abs(value) >> 2; //10 bits is the base value
|
||||
uint16_t trim = abs(value) & 0x03; //lowest 2 bits represent trim
|
||||
if (base >= 0x200) { //if value is > 100%, remainder goes to trim
|
||||
trim = 4 *(base - 0x200);
|
||||
base = 0x1ff;
|
||||
}
|
||||
base = (value >= 0) ? 0x200 + base : 0x200 - base;
|
||||
trim = (value >= 0) ? 0x200 + trim : 0x200 - trim;
|
||||
|
||||
packet[2*i+offset] = base & 0xff;
|
||||
packet[2*i+offset+1] = trim & 0xff;
|
||||
msb = (msb << 4) | ((base >> 6) & 0x0c) | ((trim >> 8) & 0x03);
|
||||
}
|
||||
packet[4] = msb >> 8; //Ele/Ail MSB
|
||||
packet[9] = msb & 0xff; //Thr/Rud MSB
|
||||
packet[10] = 0xe0 | ((fixed_id >> 0) & 0x0e);
|
||||
packet[11] = (fixed_id >> 8) & 0xff;
|
||||
packet[12] = ((fixed_id >> 12) & 0xf0) | wk_pkt_num;
|
||||
packet[13] = 0xf0; //FIXME - What is this?
|
||||
add_pkt_crc(0x00);
|
||||
}
|
||||
|
||||
#define PCT(pct, max) (((max) * (pct) + 1L) / 1000)
|
||||
#define MAXTHR 426 //Measured to provide equal value at +/-0
|
||||
static void channels_6plus1_2601(int frame, int *_v1, int *_v2) {
|
||||
uint16_t thr = get_channel(2, 1000, 0, 1000);
|
||||
int v1;
|
||||
int thr_rev = 0, pitch_rev = 0;
|
||||
if(thr > 0) {
|
||||
if(thr >= 780) { //78%
|
||||
v1 = 0; //thr = 60% * (x - 78%) / 22% + 40%
|
||||
thr = PCT(1000-MAXTHR,512) * (thr-PCT(780,1000)) / PCT(220,1000) + PCT(MAXTHR,512);
|
||||
} else {
|
||||
v1 = 1023 - 1023 * thr / 780;
|
||||
thr = PCT(MAXTHR, 512); //40%
|
||||
}
|
||||
}
|
||||
else {
|
||||
thr = -thr;
|
||||
thr_rev = 1;
|
||||
if(thr >= 780) { //78%
|
||||
v1 = 1023; //thr = 60% * (x - 78%) / 22% + 40%
|
||||
thr = PCT(1000-MAXTHR,512) * (thr-PCT(780,1000)) / PCT(220,1000) + PCT(MAXTHR,512);
|
||||
if (thr >= 512) { thr = 511; }
|
||||
}
|
||||
else {
|
||||
v1 = 1023 * thr / 780;
|
||||
thr = PCT(MAXTHR, 512); //40%
|
||||
}
|
||||
}
|
||||
if (thr >= 512) { thr = 511; }
|
||||
packet[2] = thr & 0xff;
|
||||
packet[4] = (packet[4] & 0xF3) | ((thr >> 6) & 0x04);
|
||||
|
||||
uint16_t pitch= get_channel(5, 0x400, 0, 0x400);
|
||||
if (pitch < 0) {
|
||||
pitch_rev = 1;
|
||||
pitch = -pitch;
|
||||
}
|
||||
if (frame == 1) {
|
||||
//Pitch curve and range
|
||||
if (thr > PCT(MAXTHR, 512)) { *_v2 = pitch - pitch * 16 * (thr - PCT(MAXTHR, 512)) / PCT(1000 - MAXTHR, 512) / 100; }
|
||||
else { *_v2 = pitch; }
|
||||
*_v1 = 0;
|
||||
}
|
||||
else if (frame == 2) {
|
||||
//Throttle curve & Expo
|
||||
*_v1 = v1;
|
||||
*_v2 = 512;
|
||||
}
|
||||
packet[7] = (thr_rev << 5) | (pitch_rev << 2); //reverse bits
|
||||
packet[8] = 0;
|
||||
}
|
||||
|
||||
static void channels_5plus1_2601(int frame, int *v1, int *v2) {
|
||||
(void)v1;
|
||||
//Zero out pitch, provide ail, ele, thr, rud, gyr + gear
|
||||
if (frame == 1) { *v2 = 0; } //Pitch curve and range
|
||||
packet[7] = 0;
|
||||
packet[8] = 0;
|
||||
}
|
||||
static void channels_heli_2601(int frame, int *v1, int *v2) {
|
||||
(void)frame;
|
||||
//pitch is controlled by rx
|
||||
//we can only control fmode, pit-reverse and pit/thr rate
|
||||
int pit_rev = 0;
|
||||
if ((option/10)%10) { pit_rev = 1; }
|
||||
uint16_t pit_rate = get_channel(5, 0x400, 0, 0x400);
|
||||
int fmode = 1;
|
||||
if (pit_rate < 0) { pit_rate = -pit_rate; fmode = 0; }
|
||||
if (frame == 1) {
|
||||
//Pitch curve and range
|
||||
*v1 = pit_rate;
|
||||
*v2 = ((option/100) ? -100 : 100) * 0x400 / 100 + 0x400;
|
||||
}
|
||||
packet[7] = (pit_rev << 2); //reverse bits
|
||||
packet[8] = fmode ? 0x02 : 0x00;
|
||||
}
|
||||
|
||||
static void build_data_pkt_2601() {
|
||||
uint8_t i;
|
||||
uint8_t msb = 0;
|
||||
uint8_t frame = (wk_pkt_num % 3);
|
||||
for (i = 0; i < 4; i++) {
|
||||
uint16_t value = get_channel(i, 0x190, 0, 0x1FF);
|
||||
uint16_t mag = value < 0 ? -value : value;
|
||||
packet[i] = mag & 0xff;
|
||||
msb = (msb << 2) | ((mag >> 8) & 0x01) | (value < 0 ? 0x02 : 0x00);
|
||||
}
|
||||
packet[4] = msb;
|
||||
int v1 = 0x200, v2 = 0x200;
|
||||
if (frame == 0) {
|
||||
//Gyro & Rudder mix
|
||||
v1 = get_channel(6, 0x200, 0x200, 0x200);
|
||||
v2 = 0;
|
||||
}
|
||||
if (option%10 == 1) { channels_heli_2601(frame, &v1, &v2); }
|
||||
else if (option%10 == 2) { channels_6plus1_2601(frame, &v1, &v2); }
|
||||
else { channels_5plus1_2601(frame, &v1, &v2); }
|
||||
if (v1 > 1023) { v1 = 1023; }
|
||||
if (v2 > 1023) { v2 = 1023; }
|
||||
packet[5] = v2 & 0xff;
|
||||
packet[6] = v1 & 0xff;
|
||||
//packet[7] handled by channel code
|
||||
packet[8] |= (get_channel(4, 0x190, 0, 0x1FF) > 0 ? 1 : 0);
|
||||
packet[9] = ((v1 >> 4) & 0x30) | ((v2 >> 2) & 0xc0) | 0x04 | frame;
|
||||
packet[10] = (fixed_id >> 0) & 0xff;
|
||||
packet[11] = (fixed_id >> 8) & 0xff;
|
||||
packet[12] = ((fixed_id >> 12) & 0xf0) | wk_pkt_num;
|
||||
packet[13] = 0xff;
|
||||
|
||||
add_pkt_crc(0x3A);
|
||||
}
|
||||
|
||||
static void build_data_pkt_2801() {
|
||||
uint8_t i;
|
||||
uint16_t msb = 0;
|
||||
uint8_t offset = 0;
|
||||
uint8_t sign = 0;
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (i == 4) { offset = 1; }
|
||||
uint16_t value = get_channel(i, 0x190, 0, 0x3FF);
|
||||
uint16_t mag = value < 0 ? -value : value;
|
||||
packet[i+offset] = mag & 0xff;
|
||||
msb = (msb << 2) | ((mag >> 8) & 0x03);
|
||||
if (value < 0) { sign |= 1 << i; }
|
||||
}
|
||||
packet[4] = msb >> 8;
|
||||
packet[9] = msb & 0xff;
|
||||
packet[10] = (fixed_id >> 0) & 0xff;
|
||||
packet[11] = (fixed_id >> 8) & 0xff;
|
||||
packet[12] = ((fixed_id >> 12) & 0xf0) | wk_pkt_num;
|
||||
packet[13] = sign;
|
||||
add_pkt_crc(0x25);
|
||||
}
|
||||
|
||||
static void build_beacon_pkt_2801() {
|
||||
last_beacon ^= 1;
|
||||
uint8_t i;
|
||||
uint8_t en = 0;
|
||||
uint8_t bind_state;
|
||||
if (WK_BIND_COUNTer) { bind_state = 0xe4; }
|
||||
else { bind_state = 0x1b; }
|
||||
for (i = 0; i < 4; i++) {
|
||||
/* if (Model.limits[fail_map[i + last_beacon * 4]].flags & CH_FAILSAFE_EN) {
|
||||
uint32_t value = Model.limits[fail_map[i + last_beacon * 4]].failsafe + 128;
|
||||
if (value > 255) { value = 255; }
|
||||
if (value < 0) { value = 0; }
|
||||
packet[i+1] = value;
|
||||
en |= 1 << i;
|
||||
} else
|
||||
*/ { packet[i+1] = 0; }
|
||||
}
|
||||
packet[0] = en;
|
||||
packet[5] = packet[4];
|
||||
packet[4] = last_beacon << 6;
|
||||
packet[6] = rx_tx_addr[0];
|
||||
packet[7] = rx_tx_addr[1];
|
||||
packet[8] = rx_tx_addr[2];
|
||||
packet[9] = bind_state;
|
||||
packet[10] = (fixed_id >> 0) & 0xff;
|
||||
packet[11] = (fixed_id >> 8) & 0xff;
|
||||
packet[12] = ((fixed_id >> 12) & 0xf0) | wk_pkt_num;
|
||||
packet[13] = 0x00; //Does this matter? in the docs it is the same as the data packet
|
||||
add_pkt_crc(0x1C);
|
||||
}
|
||||
|
||||
static void wk2x01_cyrf_init() {
|
||||
/* Initialise CYRF chip */
|
||||
CYRF_WriteRegister(CYRF_03_TX_CFG, 0x28 | CYRF_HIGH_POWER);
|
||||
CYRF_WriteRegister(CYRF_06_RX_CFG, 0x4A);
|
||||
CYRF_WriteRegister(CYRF_0B_PWR_CTRL, 0x00);
|
||||
CYRF_WriteRegister(CYRF_0C_XTAL_CTRL, 0xC0);
|
||||
CYRF_WriteRegister(CYRF_0D_IO_CFG, 0x04);
|
||||
CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x2C);
|
||||
CYRF_WriteRegister(CYRF_10_FRAMING_CFG, 0xEE);
|
||||
CYRF_WriteRegister(CYRF_1B_TX_OFFSET_LSB, 0x55);
|
||||
CYRF_WriteRegister(CYRF_1C_TX_OFFSET_MSB, 0x05);
|
||||
CYRF_WriteRegister(CYRF_1D_MODE_OVERRIDE, 0x18);
|
||||
CYRF_WriteRegister(CYRF_32_AUTO_CAL_TIME, 0x3C);
|
||||
CYRF_WriteRegister(CYRF_35_AUTOCAL_OFFSET, 0x14);
|
||||
CYRF_WriteRegister(CYRF_1E_RX_OVERRIDE, 0x90);
|
||||
CYRF_WriteRegister(CYRF_1F_TX_OVERRIDE, 0x00);
|
||||
CYRF_WriteRegister(CYRF_01_TX_LENGTH, 0x10);
|
||||
CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x2C);
|
||||
CYRF_WriteRegister(CYRF_28_CLK_EN, 0x02);
|
||||
CYRF_WriteRegister(CYRF_27_CLK_OVERRIDE, 0x02);
|
||||
CYRF_ConfigSOPCode(sopcode);
|
||||
CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x28);
|
||||
CYRF_WriteRegister(CYRF_1E_RX_OVERRIDE, 0x10);
|
||||
CYRF_WriteRegister(CYRF_0E_GPIO_CTRL, 0x20);
|
||||
CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x2C);
|
||||
}
|
||||
|
||||
void WK_BuildPacket_2801() {
|
||||
switch(phase) {
|
||||
case WK_BIND:
|
||||
build_bind_pkt(init_2801);
|
||||
// if ((--WK_BIND_COUNTer == 0) || PROTOCOL_SticksMoved(0)) {
|
||||
if ((--WK_BIND_COUNTer == 0)) {
|
||||
WK_BIND_COUNTer = 0;
|
||||
BIND_DONE;
|
||||
phase = WK_BOUND_1;
|
||||
}
|
||||
break;
|
||||
case WK_BOUND_1:
|
||||
case WK_BOUND_2:
|
||||
case WK_BOUND_3:
|
||||
case WK_BOUND_4:
|
||||
case WK_BOUND_5:
|
||||
case WK_BOUND_6:
|
||||
case WK_BOUND_7:
|
||||
build_data_pkt_2801();
|
||||
phase++;
|
||||
break;
|
||||
case WK_BOUND_8:
|
||||
build_beacon_pkt_2801();
|
||||
phase = WK_BOUND_1;
|
||||
if (WK_BIND_COUNTer) {
|
||||
WK_BIND_COUNTer--;
|
||||
if (WK_BIND_COUNTer == 0) { BIND_DONE; }
|
||||
}
|
||||
break;
|
||||
}
|
||||
wk_pkt_num = (wk_pkt_num + 1) % 12;
|
||||
}
|
||||
|
||||
void WK_BuildPacket_2601() {
|
||||
if (WK_BIND_COUNTer) {
|
||||
WK_BIND_COUNTer--;
|
||||
build_bind_pkt(init_2601);
|
||||
if ((WK_BIND_COUNTer == 0)) {
|
||||
WK_BIND_COUNTer = 0;
|
||||
BIND_DONE;
|
||||
}
|
||||
}
|
||||
else { build_data_pkt_2601(); }
|
||||
wk_pkt_num = (wk_pkt_num + 1) % 12;
|
||||
}
|
||||
|
||||
void WK_BuildPacket_2401() {
|
||||
if (WK_BIND_COUNTer) {
|
||||
WK_BIND_COUNTer--;
|
||||
build_bind_pkt(init_2401);
|
||||
if ((WK_BIND_COUNTer == 0)) {
|
||||
WK_BIND_COUNTer = 0;
|
||||
BIND_DONE;
|
||||
}
|
||||
}
|
||||
else { build_data_pkt_2401(); }
|
||||
wk_pkt_num = (wk_pkt_num + 1) % 12;
|
||||
}
|
||||
|
||||
static uint16_t wk_cb() {
|
||||
if (packet_sent == 0) {
|
||||
packet_sent = 1;
|
||||
if(sub_protocol == WK2801) { WK_BuildPacket_2801(); }
|
||||
else if(sub_protocol == WK2601) { WK_BuildPacket_2601(); }
|
||||
else if(sub_protocol == WK2401) { WK_BuildPacket_2401(); }
|
||||
CYRF_WriteDataPacket(packet);
|
||||
return 1600;
|
||||
}
|
||||
packet_sent = 0;
|
||||
int i = 0;
|
||||
while (! (CYRF_ReadRegister(0x04) & 0x02)) { if(++i > NUM_WAIT_LOOPS) { break; } }
|
||||
if((wk_pkt_num & 0x03) == 0) {
|
||||
radio_ch_ptr = radio_ch_ptr == &rx_tx_addr[2] ? rx_tx_addr : radio_ch_ptr + 1;
|
||||
CYRF_ConfigRFChannel(*radio_ch_ptr);
|
||||
//Keep transmit power updated
|
||||
CYRF_WriteRegister(CYRF_03_TX_CFG, 0x28 | CYRF_HIGH_POWER);
|
||||
}
|
||||
return 1200;
|
||||
}
|
||||
|
||||
static void wk_bind() {
|
||||
if((sub_protocol != WK2801)) { return; }
|
||||
fixed_id = ((MProtocol_id_master << 2) & 0x0ffc00) | ((MProtocol_id_master >> 10) & 0x000300) | ((MProtocol_id_master) & 0x0000ff);
|
||||
WK_BIND_COUNTer = WK_BIND_COUNT / 8 + 1;
|
||||
BIND_IN_PROGRESS;
|
||||
}
|
||||
|
||||
static uint16_t wk_setup() {
|
||||
CYRF_Reset();
|
||||
wk2x01_cyrf_init();
|
||||
CYRF_SetTxRxMode(TX_EN);
|
||||
CYRF_FindBestChannels(rx_tx_addr, 3, 4, 4, 80);
|
||||
|
||||
radio_ch_ptr = rx_tx_addr;
|
||||
CYRF_ConfigRFChannel(*radio_ch_ptr);
|
||||
|
||||
wk_pkt_num = 0;
|
||||
packet_sent = 0;
|
||||
last_beacon = 0;
|
||||
fixed_id = ((MProtocol_id_master << 2) & 0x0ffc00) | ((MProtocol_id_master >> 10) & 0x000300) | ((MProtocol_id_master) & 0x0000ff);
|
||||
if (sub_protocol == WK2401) { fixed_id |= 0x01; } //Fixed ID must be odd for 2401
|
||||
if(sub_protocol != WK2801) {
|
||||
WK_BIND_COUNTer = WK_BIND_COUNT;
|
||||
phase = WK_BIND;
|
||||
BIND_IN_PROGRESS;
|
||||
}
|
||||
else {
|
||||
phase = WK_BOUND_1;
|
||||
WK_BIND_COUNTer = 0;
|
||||
}
|
||||
CYRF_ConfigRFChannel(*radio_ch_ptr);
|
||||
return 2800;
|
||||
}
|
||||
/*
|
||||
const void *WK2x01_Cmds(enum ProtoCmds cmd) {
|
||||
switch(cmd) {
|
||||
case PROTOCMD_INIT: initialize(); return 0;
|
||||
case PROTOCMD_DEINIT: return 0;
|
||||
case PROTOCMD_CHECK_AUTOBIND:
|
||||
return (Model.protocol == WK2801 && Model.fixed_id) ? 0 : (void *)1L;
|
||||
case PROTOCMD_BIND: wk_bind(); return 0;
|
||||
case PROTOCMD_DEFAULT_NUMCHAN: return (Model.protocol == WK2801)
|
||||
? (void *)8L
|
||||
: (Model.protocol == WK2601)
|
||||
? (void *)6L
|
||||
: (void *)4L;
|
||||
case PROTOCMD_NUMCHAN: return (Model.protocol == WK2801)
|
||||
? (void *)8L
|
||||
: (Model.protocol == WK2601)
|
||||
? (void *)7L
|
||||
: (void *)4L;
|
||||
case PROTOCMD_GETOPTIONS:
|
||||
if(Model.protocol == WK2601)
|
||||
return wk2601_opts;
|
||||
break;
|
||||
case PROTOCMD_TELEMETRYSTATE: return (void *)(long)PROTO_TELEM_UNSUPPORTED;
|
||||
default: break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
*/
|
||||
#endif
|
538
Multiprotocol/DSM2_cyrf6936.ino
Normal file
538
Multiprotocol/DSM2_cyrf6936.ino
Normal file
@ -0,0 +1,538 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
|
||||
#if defined(DSM2_CYRF6936_INO)
|
||||
|
||||
#include "iface_cyrf6936.h"
|
||||
|
||||
#define RANDOM_CHANNELS 0 // disabled
|
||||
//#define RANDOM_CHANNELS 1 // enabled
|
||||
#define BIND_CHANNEL 0x0d //13 This can be any odd channel
|
||||
#define NUM_WAIT_LOOPS (100 / 5) //each loop is ~5us. Do not wait more than 100us
|
||||
|
||||
//During binding we will send BIND_COUNT/2 packets
|
||||
//One packet each 10msec
|
||||
#define BIND_COUNT1 600
|
||||
|
||||
enum {
|
||||
DSM2_BIND = 0,
|
||||
DSM2_CHANSEL = BIND_COUNT1 + 0,
|
||||
DSM2_CH1_WRITE_A = BIND_COUNT1 + 1,
|
||||
DSM2_CH1_CHECK_A = BIND_COUNT1 + 2,
|
||||
DSM2_CH2_WRITE_A = BIND_COUNT1 + 3,
|
||||
DSM2_CH2_CHECK_A = BIND_COUNT1 + 4,
|
||||
DSM2_CH2_READ_A = BIND_COUNT1 + 5,
|
||||
DSM2_CH1_WRITE_B = BIND_COUNT1 + 6,
|
||||
DSM2_CH1_CHECK_B = BIND_COUNT1 + 7,
|
||||
DSM2_CH2_WRITE_B = BIND_COUNT1 + 8,
|
||||
DSM2_CH2_CHECK_B = BIND_COUNT1 + 9,
|
||||
DSM2_CH2_READ_B = BIND_COUNT1 + 10,
|
||||
};
|
||||
|
||||
const uint8_t PROGMEM pncodes[5][9][8] = {
|
||||
/* Note these are in order transmitted (LSB 1st) */
|
||||
{ /* Row 0 */
|
||||
/* Col 0 */ {0x03, 0xBC, 0x6E, 0x8A, 0xEF, 0xBD, 0xFE, 0xF8},
|
||||
/* Col 1 */ {0x88, 0x17, 0x13, 0x3B, 0x2D, 0xBF, 0x06, 0xD6},
|
||||
/* Col 2 */ {0xF1, 0x94, 0x30, 0x21, 0xA1, 0x1C, 0x88, 0xA9},
|
||||
/* Col 3 */ {0xD0, 0xD2, 0x8E, 0xBC, 0x82, 0x2F, 0xE3, 0xB4},
|
||||
/* Col 4 */ {0x8C, 0xFA, 0x47, 0x9B, 0x83, 0xA5, 0x66, 0xD0},
|
||||
/* Col 5 */ {0x07, 0xBD, 0x9F, 0x26, 0xC8, 0x31, 0x0F, 0xB8},
|
||||
/* Col 6 */ {0xEF, 0x03, 0x95, 0x89, 0xB4, 0x71, 0x61, 0x9D},
|
||||
/* Col 7 */ {0x40, 0xBA, 0x97, 0xD5, 0x86, 0x4F, 0xCC, 0xD1},
|
||||
/* Col 8 */ {0xD7, 0xA1, 0x54, 0xB1, 0x5E, 0x89, 0xAE, 0x86}
|
||||
},
|
||||
{ /* Row 1 */
|
||||
/* Col 0 */ {0x83, 0xF7, 0xA8, 0x2D, 0x7A, 0x44, 0x64, 0xD3},
|
||||
/* Col 1 */ {0x3F, 0x2C, 0x4E, 0xAA, 0x71, 0x48, 0x7A, 0xC9},
|
||||
/* Col 2 */ {0x17, 0xFF, 0x9E, 0x21, 0x36, 0x90, 0xC7, 0x82},
|
||||
/* Col 3 */ {0xBC, 0x5D, 0x9A, 0x5B, 0xEE, 0x7F, 0x42, 0xEB},
|
||||
/* Col 4 */ {0x24, 0xF5, 0xDD, 0xF8, 0x7A, 0x77, 0x74, 0xE7},
|
||||
/* Col 5 */ {0x3D, 0x70, 0x7C, 0x94, 0xDC, 0x84, 0xAD, 0x95},
|
||||
/* Col 6 */ {0x1E, 0x6A, 0xF0, 0x37, 0x52, 0x7B, 0x11, 0xD4},
|
||||
/* Col 7 */ {0x62, 0xF5, 0x2B, 0xAA, 0xFC, 0x33, 0xBF, 0xAF},
|
||||
/* Col 8 */ {0x40, 0x56, 0x32, 0xD9, 0x0F, 0xD9, 0x5D, 0x97}
|
||||
},
|
||||
{ /* Row 2 */
|
||||
/* Col 0 */ {0x40, 0x56, 0x32, 0xD9, 0x0F, 0xD9, 0x5D, 0x97},
|
||||
/* Col 1 */ {0x8E, 0x4A, 0xD0, 0xA9, 0xA7, 0xFF, 0x20, 0xCA},
|
||||
/* Col 2 */ {0x4C, 0x97, 0x9D, 0xBF, 0xB8, 0x3D, 0xB5, 0xBE},
|
||||
/* Col 3 */ {0x0C, 0x5D, 0x24, 0x30, 0x9F, 0xCA, 0x6D, 0xBD},
|
||||
/* Col 4 */ {0x50, 0x14, 0x33, 0xDE, 0xF1, 0x78, 0x95, 0xAD},
|
||||
/* Col 5 */ {0x0C, 0x3C, 0xFA, 0xF9, 0xF0, 0xF2, 0x10, 0xC9},
|
||||
/* Col 6 */ {0xF4, 0xDA, 0x06, 0xDB, 0xBF, 0x4E, 0x6F, 0xB3},
|
||||
/* Col 7 */ {0x9E, 0x08, 0xD1, 0xAE, 0x59, 0x5E, 0xE8, 0xF0},
|
||||
/* Col 8 */ {0xC0, 0x90, 0x8F, 0xBB, 0x7C, 0x8E, 0x2B, 0x8E}
|
||||
},
|
||||
{ /* Row 3 */
|
||||
/* Col 0 */ {0xC0, 0x90, 0x8F, 0xBB, 0x7C, 0x8E, 0x2B, 0x8E},
|
||||
/* Col 1 */ {0x80, 0x69, 0x26, 0x80, 0x08, 0xF8, 0x49, 0xE7},
|
||||
/* Col 2 */ {0x7D, 0x2D, 0x49, 0x54, 0xD0, 0x80, 0x40, 0xC1},
|
||||
/* Col 3 */ {0xB6, 0xF2, 0xE6, 0x1B, 0x80, 0x5A, 0x36, 0xB4},
|
||||
/* Col 4 */ {0x42, 0xAE, 0x9C, 0x1C, 0xDA, 0x67, 0x05, 0xF6},
|
||||
/* Col 5 */ {0x9B, 0x75, 0xF7, 0xE0, 0x14, 0x8D, 0xB5, 0x80},
|
||||
/* Col 6 */ {0xBF, 0x54, 0x98, 0xB9, 0xB7, 0x30, 0x5A, 0x88},
|
||||
/* Col 7 */ {0x35, 0xD1, 0xFC, 0x97, 0x23, 0xD4, 0xC9, 0x88},
|
||||
/* Col 8 */ {0x88, 0xE1, 0xD6, 0x31, 0x26, 0x5F, 0xBD, 0x40}
|
||||
},
|
||||
{ /* Row 4 */
|
||||
/* Col 0 */ {0xE1, 0xD6, 0x31, 0x26, 0x5F, 0xBD, 0x40, 0x93},
|
||||
/* Col 1 */ {0xDC, 0x68, 0x08, 0x99, 0x97, 0xAE, 0xAF, 0x8C},
|
||||
/* Col 2 */ {0xC3, 0x0E, 0x01, 0x16, 0x0E, 0x32, 0x06, 0xBA},
|
||||
/* Col 3 */ {0xE0, 0x83, 0x01, 0xFA, 0xAB, 0x3E, 0x8F, 0xAC},
|
||||
/* Col 4 */ {0x5C, 0xD5, 0x9C, 0xB8, 0x46, 0x9C, 0x7D, 0x84},
|
||||
/* Col 5 */ {0xF1, 0xC6, 0xFE, 0x5C, 0x9D, 0xA5, 0x4F, 0xB7},
|
||||
/* Col 6 */ {0x58, 0xB5, 0xB3, 0xDD, 0x0E, 0x28, 0xF1, 0xB0},
|
||||
/* Col 7 */ {0x5F, 0x30, 0x3B, 0x56, 0x96, 0x45, 0xF4, 0xA1},
|
||||
/* Col 8 */ {0x03, 0xBC, 0x6E, 0x8A, 0xEF, 0xBD, 0xFE, 0xF8}
|
||||
},
|
||||
};
|
||||
|
||||
static void __attribute__((unused)) read_code(uint8_t *buf, uint8_t row, uint8_t col, uint8_t len)
|
||||
{
|
||||
for(uint8_t i=0;i<len;i++)
|
||||
buf[i]=pgm_read_byte_near( &pncodes[row][col][i] );
|
||||
}
|
||||
|
||||
//
|
||||
uint8_t chidx;
|
||||
uint8_t sop_col;
|
||||
uint8_t data_col;
|
||||
uint16_t cyrf_state;
|
||||
uint8_t crcidx;
|
||||
uint8_t binding;
|
||||
|
||||
static void __attribute__((unused)) build_bind_packet()
|
||||
{
|
||||
uint8_t i;
|
||||
uint16_t sum = 384 - 0x10;//
|
||||
packet[0] = crc >> 8;
|
||||
packet[1] = crc & 0xff;
|
||||
packet[2] = 0xff ^ cyrfmfg_id[2];
|
||||
packet[3] = (0xff ^ cyrfmfg_id[3]) + RX_num;
|
||||
packet[4] = packet[0];
|
||||
packet[5] = packet[1];
|
||||
packet[6] = packet[2];
|
||||
packet[7] = packet[3];
|
||||
for(i = 0; i < 8; i++)
|
||||
sum += packet[i];
|
||||
packet[8] = sum >> 8;
|
||||
packet[9] = sum & 0xff;
|
||||
packet[10] = 0x01; //???
|
||||
packet[11] = option>3?option:option+4;
|
||||
if(sub_protocol==DSMX) //DSMX type
|
||||
packet[12] = 0xb2; // Telemetry off: packet[12] = num_channels < 8 && Model.proto_opts[PROTOOPTS_TELEMETRY] == TELEM_OFF ? 0xa2 : 0xb2;
|
||||
else
|
||||
packet[12] = option<8?0x01:0x02;
|
||||
packet[13] = 0x00; //???
|
||||
for(i = 8; i < 14; i++)
|
||||
sum += packet[i];
|
||||
packet[14] = sum >> 8;
|
||||
packet[15] = sum & 0xff;
|
||||
}
|
||||
|
||||
static uint8_t __attribute__((unused)) PROTOCOL_SticksMoved(uint8_t init)
|
||||
{
|
||||
#define STICK_MOVEMENT 15*(PPM_MAX-PPM_MIN)/100 // defines when the bind dialog should be interrupted (stick movement STICK_MOVEMENT %)
|
||||
static uint16_t ele_start, ail_start;
|
||||
uint16_t ele = Servo_data[ELEVATOR];//CHAN_ReadInput(MIXER_MapChannel(INP_ELEVATOR));
|
||||
uint16_t ail = Servo_data[AILERON];//CHAN_ReadInput(MIXER_MapChannel(INP_AILERON));
|
||||
if(init) {
|
||||
ele_start = ele;
|
||||
ail_start = ail;
|
||||
return 0;
|
||||
}
|
||||
uint16_t ele_diff = ele_start - ele;//abs(ele_start - ele);
|
||||
uint16_t ail_diff = ail_start - ail;//abs(ail_start - ail);
|
||||
return ((ele_diff + ail_diff) > STICK_MOVEMENT);//
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) build_data_packet(uint8_t upper)//
|
||||
{
|
||||
uint8_t i;
|
||||
uint8_t bits;
|
||||
|
||||
uint8_t ch_map[] = {3, 2, 1, 5, 0, 4, 6, 7, 8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; //9 Channels - DM9 TX
|
||||
switch(option>3?option:option+4) // Create channel map based on number of channels
|
||||
{
|
||||
case 12:
|
||||
ch_map[11]=11; // 12 channels
|
||||
case 11:
|
||||
ch_map[10]=10; // 11 channels
|
||||
case 10:
|
||||
ch_map[9]=9; // 10 channels
|
||||
break;
|
||||
case 8:
|
||||
memcpy(ch_map,"\x01\x05\x02\x03\x06\xFF\xFF\x04\x00\x07",10); // 8 channels - DX8 TX
|
||||
break;
|
||||
case 7:
|
||||
memcpy(ch_map,"\x01\x05\x02\x04\x03\x06\x00",7); // 7 channels - DX6i TX
|
||||
break;
|
||||
case 6:
|
||||
memcpy(ch_map,"\x01\x05\x02\x03\x00\x04\xFF",7); // 6 channels - HP6DSM TX
|
||||
break;
|
||||
case 4:
|
||||
case 5:
|
||||
memcpy(ch_map,"\x00\x01\x02\x03\xFF\xFF\xFF",7); // 4 channels - Guess
|
||||
if(option&0x01)
|
||||
ch_map[4]=4; // 5 channels - Guess
|
||||
break;
|
||||
}
|
||||
//
|
||||
if( binding && PROTOCOL_SticksMoved(0) )
|
||||
binding = 0;
|
||||
if (sub_protocol==DSMX)
|
||||
{
|
||||
packet[0] = cyrfmfg_id[2];
|
||||
packet[1] = cyrfmfg_id[3] + RX_num;
|
||||
bits=11;
|
||||
}
|
||||
else
|
||||
{
|
||||
packet[0] = (0xff ^ cyrfmfg_id[2]);
|
||||
packet[1] = (0xff ^ cyrfmfg_id[3]) + RX_num;
|
||||
bits=10;
|
||||
}
|
||||
//
|
||||
uint16_t max = 1 << bits;//max=2048 for DSMX & 1024 for DSM2 less than 8 ch and 2048 otherwise
|
||||
//uint16_t pct_100 = (uint32_t)max * 100 / 150;//682 1024*100/150
|
||||
//
|
||||
for (i = 0; i < 7; i++)
|
||||
{
|
||||
uint8_t idx = ch_map[upper * 7 + i];//1,5,2,3,0,4
|
||||
uint16_t value;
|
||||
if (idx == 0xff)
|
||||
value = 0xffff;
|
||||
else
|
||||
{
|
||||
if (binding)
|
||||
{ // Failsafe position during binding
|
||||
value=max/2; //all channels to middle
|
||||
if(idx==0)
|
||||
value=1; //except throttle
|
||||
}
|
||||
else
|
||||
{
|
||||
switch(idx)
|
||||
{
|
||||
case 0:
|
||||
value=Servo_data[THROTTLE];//85.75-938.25=125%//171-853=100%
|
||||
break;
|
||||
case 1:
|
||||
value=Servo_data[AILERON];
|
||||
break;
|
||||
case 2:
|
||||
value=Servo_data[ELEVATOR];
|
||||
break;
|
||||
case 3:
|
||||
value=Servo_data[RUDDER];
|
||||
break;
|
||||
case 4:
|
||||
value=Servo_data[AUX1];
|
||||
break;
|
||||
case 5:
|
||||
value=Servo_data[AUX2];
|
||||
break;
|
||||
case 6:
|
||||
value=Servo_data[AUX3];
|
||||
break;
|
||||
case 7:
|
||||
value=Servo_data[AUX4];
|
||||
break;
|
||||
}
|
||||
value=map(value,PPM_MIN,PPM_MAX,0,max-1);
|
||||
}
|
||||
value |= (upper && i == 0 ? 0x8000 : 0) | (idx << bits);
|
||||
}
|
||||
packet[i*2+2] = (value >> 8) & 0xff;
|
||||
packet[i*2+3] = (value >> 0) & 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t __attribute__((unused)) get_pn_row(uint8_t channel)
|
||||
{
|
||||
return (sub_protocol == DSMX ? (channel - 2) % 5 : channel % 5);
|
||||
}
|
||||
|
||||
const uint8_t init_vals[][2] = {
|
||||
{CYRF_02_TX_CTRL, 0x00},
|
||||
{CYRF_05_RX_CTRL, 0x00},
|
||||
{CYRF_28_CLK_EN, 0x02},
|
||||
{CYRF_32_AUTO_CAL_TIME, 0x3c},
|
||||
{CYRF_35_AUTOCAL_OFFSET, 0x14},
|
||||
{CYRF_06_RX_CFG, 0x4A},
|
||||
{CYRF_1B_TX_OFFSET_LSB, 0x55},
|
||||
{CYRF_1C_TX_OFFSET_MSB, 0x05},
|
||||
{CYRF_0F_XACT_CFG, 0x24}, // Force Idle
|
||||
{CYRF_03_TX_CFG, 0x38 | CYRF_BIND_POWER}, //Set 64chip, SDR mode
|
||||
{CYRF_12_DATA64_THOLD, 0x0a},
|
||||
{CYRF_0F_XACT_CFG, 0x04}, // Idle
|
||||
{CYRF_39_ANALOG_CTRL, 0x01},
|
||||
{CYRF_0F_XACT_CFG, 0x24}, //Force IDLE
|
||||
{CYRF_29_RX_ABORT, 0x00}, //Clear RX abort
|
||||
{CYRF_12_DATA64_THOLD, 0x0a}, //set pn correlation threshold
|
||||
{CYRF_10_FRAMING_CFG, 0x4a}, //set sop len and threshold
|
||||
{CYRF_29_RX_ABORT, 0x0f}, //Clear RX abort?
|
||||
{CYRF_03_TX_CFG, 0x38 | CYRF_BIND_POWER}, //Set 64chip, SDR mode
|
||||
{CYRF_10_FRAMING_CFG, 0x4a}, //set sop len and threshold
|
||||
{CYRF_1F_TX_OVERRIDE, 0x04}, //disable tx CRC
|
||||
{CYRF_1E_RX_OVERRIDE, 0x14}, //disable rx crc
|
||||
{CYRF_14_EOP_CTRL, 0x02}, //set EOP sync == 2
|
||||
{CYRF_01_TX_LENGTH, 0x10}, //16byte packet
|
||||
};
|
||||
|
||||
static void __attribute__((unused)) cyrf_config()
|
||||
{
|
||||
for(uint8_t i = 0; i < sizeof(init_vals) / 2; i++)
|
||||
CYRF_WriteRegister(init_vals[i][0], init_vals[i][1]);
|
||||
CYRF_WritePreamble(0x333304);
|
||||
CYRF_ConfigRFChannel(0x61);
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) initialize_bind_state()
|
||||
{
|
||||
uint8_t code[32];
|
||||
|
||||
CYRF_ConfigRFChannel(BIND_CHANNEL); //This seems to be random?
|
||||
uint8_t pn_row = get_pn_row(BIND_CHANNEL);
|
||||
//printf("Ch: %d Row: %d SOP: %d Data: %d\n", BIND_CHANNEL, pn_row, sop_col, data_col);
|
||||
CYRF_ConfigCRCSeed(crc);
|
||||
|
||||
read_code(code,pn_row,sop_col,8);
|
||||
CYRF_ConfigSOPCode(code);
|
||||
read_code(code,pn_row,data_col,16);
|
||||
read_code(code+16,0,8,8);
|
||||
memcpy(code + 24, "\xc6\x94\x22\xfe\x48\xe6\x57\x4e", 8);
|
||||
CYRF_ConfigDataCode(code, 32);
|
||||
|
||||
build_bind_packet();
|
||||
}
|
||||
|
||||
const uint8_t data_vals[][2] = {
|
||||
{CYRF_05_RX_CTRL, 0x83}, //Initialize for reading RSSI
|
||||
{CYRF_29_RX_ABORT, 0x20},
|
||||
{CYRF_0F_XACT_CFG, 0x24},
|
||||
{CYRF_29_RX_ABORT, 0x00},
|
||||
{CYRF_03_TX_CFG, 0x08 | CYRF_HIGH_POWER},
|
||||
{CYRF_10_FRAMING_CFG, 0xea},
|
||||
{CYRF_1F_TX_OVERRIDE, 0x00},
|
||||
{CYRF_1E_RX_OVERRIDE, 0x00},
|
||||
{CYRF_03_TX_CFG, 0x28 | CYRF_HIGH_POWER},
|
||||
{CYRF_12_DATA64_THOLD, 0x3f},
|
||||
{CYRF_10_FRAMING_CFG, 0xff},
|
||||
{CYRF_0F_XACT_CFG, 0x24}, //Switch from reading RSSI to Writing
|
||||
{CYRF_29_RX_ABORT, 0x00},
|
||||
{CYRF_12_DATA64_THOLD, 0x0a},
|
||||
{CYRF_10_FRAMING_CFG, 0xea},
|
||||
};
|
||||
|
||||
static void __attribute__((unused)) cyrf_configdata()
|
||||
{
|
||||
for(uint8_t i = 0; i < sizeof(data_vals) / 2; i++)
|
||||
CYRF_WriteRegister(data_vals[i][0], data_vals[i][1]);
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) set_sop_data_crc()
|
||||
{
|
||||
uint8_t code[16];
|
||||
uint8_t pn_row = get_pn_row(hopping_frequency[chidx]);
|
||||
//printf("Ch: %d Row: %d SOP: %d Data: %d\n", ch[chidx], pn_row, sop_col, data_col);
|
||||
CYRF_ConfigRFChannel(hopping_frequency[chidx]);
|
||||
CYRF_ConfigCRCSeed(crcidx ? ~crc : crc);
|
||||
|
||||
read_code(code,pn_row,sop_col,8);
|
||||
CYRF_ConfigSOPCode(code);
|
||||
read_code(code,pn_row,data_col,16);
|
||||
CYRF_ConfigDataCode(code, 16);
|
||||
|
||||
if(sub_protocol == DSMX)
|
||||
chidx = (chidx + 1) % 23;
|
||||
else
|
||||
chidx = (chidx + 1) % 2;
|
||||
crcidx = !crcidx;
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) calc_dsmx_channel()
|
||||
{
|
||||
uint8_t idx = 0;
|
||||
uint32_t id = ~(((uint32_t)cyrfmfg_id[0] << 24) | ((uint32_t)cyrfmfg_id[1] << 16) | ((uint32_t)cyrfmfg_id[2] << 8) | (cyrfmfg_id[3] << 0));
|
||||
uint32_t id_tmp = id;
|
||||
while(idx < 23)
|
||||
{
|
||||
uint8_t i;
|
||||
uint8_t count_3_27 = 0, count_28_51 = 0, count_52_76 = 0;
|
||||
id_tmp = id_tmp * 0x0019660D + 0x3C6EF35F; // Randomization
|
||||
uint8_t next_ch = ((id_tmp >> 8) % 0x49) + 3; // Use least-significant byte and must be larger than 3
|
||||
if (((next_ch ^ id) & 0x01 )== 0)
|
||||
continue;
|
||||
for (i = 0; i < idx; i++)
|
||||
{
|
||||
if(hopping_frequency[i] == next_ch)
|
||||
break;
|
||||
if(hopping_frequency[i] <= 27)
|
||||
count_3_27++;
|
||||
else
|
||||
if (hopping_frequency[i] <= 51)
|
||||
count_28_51++;
|
||||
else
|
||||
count_52_76++;
|
||||
}
|
||||
if (i != idx)
|
||||
continue;
|
||||
if ((next_ch < 28 && count_3_27 < 8)
|
||||
||(next_ch >= 28 && next_ch < 52 && count_28_51 < 7)
|
||||
||(next_ch >= 52 && count_52_76 < 8))
|
||||
hopping_frequency[idx++] = next_ch;
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t ReadDsm2()
|
||||
{
|
||||
#define CH1_CH2_DELAY 4010 // Time between write of channel 1 and channel 2
|
||||
#define WRITE_DELAY 1650 // 1550 original, Time after write to verify write complete
|
||||
#define READ_DELAY 400 // Time before write to check read state, and switch channels
|
||||
uint8_t i = 0;
|
||||
|
||||
switch(cyrf_state)
|
||||
{
|
||||
default:
|
||||
//Binding
|
||||
cyrf_state++;
|
||||
if(cyrf_state & 1)
|
||||
{
|
||||
//Send packet on even states
|
||||
//Note state has already incremented,
|
||||
// so this is actually 'even' state
|
||||
CYRF_WriteDataPacket(packet);
|
||||
return 8500;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Check status on odd states
|
||||
CYRF_ReadRegister(CYRF_04_TX_IRQ_STATUS);
|
||||
return 1500;
|
||||
}
|
||||
case DSM2_CHANSEL:
|
||||
BIND_DONE;
|
||||
//Select channels and configure for writing data
|
||||
//CYRF_FindBestChannels(ch, 2, 10, 1, 79);
|
||||
cyrf_configdata();
|
||||
CYRF_SetTxRxMode(TX_EN);
|
||||
chidx = 0;
|
||||
crcidx = 0;
|
||||
cyrf_state = DSM2_CH1_WRITE_A; // in fact cyrf_state++
|
||||
set_sop_data_crc();
|
||||
return 10000;
|
||||
case DSM2_CH1_WRITE_A:
|
||||
case DSM2_CH1_WRITE_B:
|
||||
build_data_packet(cyrf_state == DSM2_CH1_WRITE_B);//compare state and DSM2_CH1_WRITE_B return 0 or 1
|
||||
case DSM2_CH2_WRITE_A:
|
||||
case DSM2_CH2_WRITE_B:
|
||||
CYRF_WriteDataPacket(packet);
|
||||
cyrf_state++; // change from WRITE to CHECK mode
|
||||
return WRITE_DELAY;
|
||||
case DSM2_CH1_CHECK_A:
|
||||
case DSM2_CH1_CHECK_B:
|
||||
while (! (CYRF_ReadRegister(CYRF_04_TX_IRQ_STATUS) & 0x02))
|
||||
if(++i > NUM_WAIT_LOOPS)
|
||||
break;
|
||||
set_sop_data_crc();
|
||||
cyrf_state++; // change from CH1_CHECK to CH2_WRITE
|
||||
return CH1_CH2_DELAY - WRITE_DELAY;
|
||||
case DSM2_CH2_CHECK_A:
|
||||
case DSM2_CH2_CHECK_B:
|
||||
while (! (CYRF_ReadRegister(CYRF_04_TX_IRQ_STATUS) & 0x02))
|
||||
if(++i > NUM_WAIT_LOOPS)
|
||||
break;
|
||||
if (cyrf_state == DSM2_CH2_CHECK_A)
|
||||
CYRF_SetPower(0x28); //Keep transmit power in sync
|
||||
// No telemetry...
|
||||
set_sop_data_crc();
|
||||
if (cyrf_state == DSM2_CH2_CHECK_A)
|
||||
{
|
||||
if(option < 8)
|
||||
{
|
||||
cyrf_state = DSM2_CH1_WRITE_A; // change from CH2_CHECK_A to CH1_WRITE_A (ie no upper)
|
||||
if(option>3)
|
||||
return 11000 - CH1_CH2_DELAY - WRITE_DELAY ; // force 11ms if option>3 ie 4,5,6,7 channels @11ms
|
||||
else
|
||||
return 22000 - CH1_CH2_DELAY - WRITE_DELAY ; // normal 22ms mode if option<=3 ie 4,5,6,7 channels @22ms
|
||||
}
|
||||
else
|
||||
cyrf_state = DSM2_CH1_WRITE_B; // change from CH2_CHECK_A to CH1_WRITE_A (to transmit upper)
|
||||
}
|
||||
else
|
||||
cyrf_state = DSM2_CH1_WRITE_A; // change from CH2_CHECK_B to CH1_WRITE_A (upper already transmitted so transmit lower)
|
||||
return 11000 - CH1_CH2_DELAY - WRITE_DELAY;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t initDsm2()
|
||||
{
|
||||
CYRF_Reset();
|
||||
CYRF_GetMfgData(cyrfmfg_id);//
|
||||
|
||||
cyrf_config();
|
||||
|
||||
if (sub_protocol ==DSMX)
|
||||
calc_dsmx_channel();
|
||||
else
|
||||
{
|
||||
#if RANDOM_CHANNELS == 1
|
||||
uint8_t tmpch[10];
|
||||
CYRF_FindBestChannels(tmpch, 10, 5, 3, 75);
|
||||
//
|
||||
randomSeed((uint32_t)analogRead(A6)<<10|analogRead(A7));//seed
|
||||
uint8_t idx = random(0xfefefefe) % 10;
|
||||
hopping_frequency[0] = tmpch[idx];
|
||||
while(1)
|
||||
{
|
||||
idx = random(0xfefefefe) % 10;
|
||||
if (tmpch[idx] != hopping_frequency[0])
|
||||
break;
|
||||
}
|
||||
hopping_frequency[1] = tmpch[idx];
|
||||
#else
|
||||
hopping_frequency[0] = (cyrfmfg_id[0] + cyrfmfg_id[2] + cyrfmfg_id[4]) % 39 + 1;
|
||||
hopping_frequency[1] = (cyrfmfg_id[1] + cyrfmfg_id[3] + cyrfmfg_id[5]) % 40 + 40;
|
||||
#endif
|
||||
}
|
||||
|
||||
///}
|
||||
crc = ~((cyrfmfg_id[0] << 8) + cyrfmfg_id[1]); //The crc for channel 'a' is NOT(mfgid[1] << 8 + mfgid[0])
|
||||
crcidx = 0;//The crc for channel 'b' is (mfgid[1] << 8 + mfgid[0])
|
||||
//
|
||||
sop_col = (cyrfmfg_id[0] + cyrfmfg_id[1] + cyrfmfg_id[2] + 2) & 0x07;//Ok
|
||||
data_col = 7 - sop_col;//ok
|
||||
|
||||
CYRF_SetTxRxMode(TX_EN);
|
||||
//
|
||||
if(IS_AUTOBIND_FLAG_on)
|
||||
{
|
||||
cyrf_state = DSM2_BIND;
|
||||
PROTOCOL_SticksMoved(1); //Initialize Stick position
|
||||
initialize_bind_state();
|
||||
binding = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
cyrf_state = DSM2_CHANSEL;//
|
||||
binding = 0;
|
||||
}
|
||||
return 10000;
|
||||
}
|
||||
|
||||
#endif
|
@ -43,7 +43,31 @@ enum {
|
||||
DEVO_BOUND_10,
|
||||
};
|
||||
|
||||
<<<<<<< HEAD
|
||||
const uint8_t sopcodes[][8] = {
|
||||
/* Note these are in order transmitted (LSB 1st) */
|
||||
/* 0 */ {0x3C,0x37,0xCC,0x91,0xE2,0xF8,0xCC,0x91}, //0x91CCF8E291CC373C
|
||||
/* 1 */ {0x9B,0xC5,0xA1,0x0F,0xAD,0x39,0xA2,0x0F}, //0x0FA239AD0FA1C59B
|
||||
/* 2 */ {0xEF,0x64,0xB0,0x2A,0xD2,0x8F,0xB1,0x2A}, //0x2AB18FD22AB064EF
|
||||
/* 3 */ {0x66,0xCD,0x7C,0x50,0xDD,0x26,0x7C,0x50}, //0x507C26DD507CCD66
|
||||
/* 4 */ {0x5C,0xE1,0xF6,0x44,0xAD,0x16,0xF6,0x44}, //0x44F616AD44F6E15C
|
||||
/* 5 */ {0x5A,0xCC,0xAE,0x46,0xB6,0x31,0xAE,0x46}, //0x46AE31B646AECC5A
|
||||
/* 6 */ {0xA1,0x78,0xDC,0x3C,0x9E,0x82,0xDC,0x3C}, //0x3CDC829E3CDC78A1
|
||||
/* 7 */ {0xB9,0x8E,0x19,0x74,0x6F,0x65,0x18,0x74}, //0x7418656F74198EB9
|
||||
/* 8 */ {0xDF,0xB1,0xC0,0x49,0x62,0xDF,0xC1,0x49}, //0x49C1DF6249C0B1DF
|
||||
/* 9 */ {0x97,0xE5,0x14,0x72,0x7F,0x1A,0x14,0x72}, //0x72141A7F7214E597
|
||||
};
|
||||
|
||||
uint8_t txState;
|
||||
uint8_t pkt_num;
|
||||
uint8_t ch_idx;
|
||||
uint8_t use_fixed_id;
|
||||
uint8_t failsafe_pkt;
|
||||
|
||||
static void __attribute__((unused)) scramble_pkt()
|
||||
=======
|
||||
static void __attribute__((unused)) DEVO_scramble_pkt()
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
{
|
||||
#ifdef NO_SCRAMBLE
|
||||
return;
|
||||
@ -53,7 +77,11 @@ static void __attribute__((unused)) DEVO_scramble_pkt()
|
||||
#endif
|
||||
}
|
||||
|
||||
<<<<<<< HEAD
|
||||
static void __attribute__((unused)) add_pkt_suffix()
|
||||
=======
|
||||
static void __attribute__((unused)) DEVO_add_pkt_suffix()
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
{
|
||||
uint8_t bind_state;
|
||||
#ifdef ENABLE_PPM
|
||||
@ -91,7 +119,11 @@ static void __attribute__((unused)) DEVO_add_pkt_suffix()
|
||||
packet[15] = (MProtocol_id >> 16) & 0xff;
|
||||
}
|
||||
|
||||
<<<<<<< HEAD
|
||||
static void __attribute__((unused)) build_beacon_pkt(uint8_t upper)
|
||||
=======
|
||||
static void __attribute__((unused)) DEVO_build_beacon_pkt(uint8_t upper)
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
{
|
||||
packet[0] = (DEVO_NUM_CHANNELS << 4) | 0x07;
|
||||
uint8_t max = 8;
|
||||
@ -106,7 +138,11 @@ static void __attribute__((unused)) DEVO_build_beacon_pkt(uint8_t upper)
|
||||
DEVO_add_pkt_suffix();
|
||||
}
|
||||
|
||||
<<<<<<< HEAD
|
||||
static void __attribute__((unused)) build_bind_pkt()
|
||||
=======
|
||||
static void __attribute__((unused)) DEVO_build_bind_pkt()
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
{
|
||||
packet[0] = (DEVO_NUM_CHANNELS << 4) | 0x0a;
|
||||
packet[1] = bind_counter & 0xff;
|
||||
@ -126,7 +162,11 @@ static void __attribute__((unused)) DEVO_build_bind_pkt()
|
||||
packet[15] ^= cyrfmfg_id[2];
|
||||
}
|
||||
|
||||
<<<<<<< HEAD
|
||||
static void __attribute__((unused)) build_data_pkt()
|
||||
=======
|
||||
static void __attribute__((unused)) DEVO_build_data_pkt()
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
{
|
||||
static uint8_t ch_idx=0;
|
||||
|
||||
@ -150,7 +190,11 @@ static void __attribute__((unused)) DEVO_build_data_pkt()
|
||||
DEVO_add_pkt_suffix();
|
||||
}
|
||||
|
||||
<<<<<<< HEAD
|
||||
static void __attribute__((unused)) cyrf_set_bound_sop_code()
|
||||
=======
|
||||
static void __attribute__((unused)) DEVO_cyrf_set_bound_sop_code()
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
{
|
||||
/* crc == 0 isn't allowed, so use 1 if the math results in 0 */
|
||||
uint8_t crc = (cyrfmfg_id[0] + (cyrfmfg_id[1] >> 6) + cyrfmfg_id[2]);
|
||||
@ -163,6 +207,9 @@ static void __attribute__((unused)) DEVO_cyrf_set_bound_sop_code()
|
||||
CYRF_SetPower(0x08);
|
||||
}
|
||||
|
||||
<<<<<<< HEAD
|
||||
static void __attribute__((unused)) cyrf_init()
|
||||
=======
|
||||
const uint8_t PROGMEM DEVO_init_vals[][2] = {
|
||||
{ CYRF_1D_MODE_OVERRIDE, 0x38 },
|
||||
{ CYRF_03_TX_CFG, 0x08 },
|
||||
@ -186,13 +233,18 @@ const uint8_t PROGMEM DEVO_init_vals[][2] = {
|
||||
};
|
||||
|
||||
static void __attribute__((unused)) DEVO_cyrf_init()
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
{
|
||||
/* Initialise CYRF chip */
|
||||
for(uint8_t i = 0; i < sizeof(DEVO_init_vals) / 2; i++)
|
||||
CYRF_WriteRegister(pgm_read_byte( &DEVO_init_vals[i][0]), pgm_read_byte( &DEVO_init_vals[i][1]) );
|
||||
}
|
||||
|
||||
<<<<<<< HEAD
|
||||
static void __attribute__((unused)) set_radio_channels()
|
||||
=======
|
||||
static void __attribute__((unused)) DEVO_set_radio_channels()
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
{
|
||||
CYRF_FindBestChannels(hopping_frequency, 3, 4, 4, 80);
|
||||
hopping_frequency[3] = hopping_frequency[0];
|
||||
@ -285,6 +337,35 @@ uint16_t devo_callback()
|
||||
return 1200;
|
||||
}
|
||||
|
||||
<<<<<<< HEAD
|
||||
/*static void __attribute__((unused)) devo_bind()
|
||||
{
|
||||
fixed_id = Model_fixed_id;
|
||||
bind_counter = DEVO_BIND_COUNT;
|
||||
use_fixed_id = 1;
|
||||
//PROTOCOL_SetBindState(0x1388 * 2400 / 1000); //msecs 12000ms
|
||||
}
|
||||
|
||||
|
||||
static void __attribute__((unused)) generate_fixed_id_bind(){
|
||||
if(BIND_0){
|
||||
//randomSeed((uint32_t)analogRead(A6)<<10|analogRead(A7));//seed
|
||||
uint8_t txid[4];
|
||||
//Model_fixed_id = random(0xfefefefe) + ((uint32_t)random(0xfefefefe) << 16);
|
||||
Model_fixed_id=0x332211;
|
||||
txid[0]= (id &0xFF);
|
||||
txid[1] = ((id >> 8) & 0xFF);
|
||||
txid[2] = ((id >> 16) & 0xFF);
|
||||
//txid[3] = ((id >> 24) & 0xFF);
|
||||
eeprom_write_block((const void*)txid,(void*)40,3);
|
||||
devo_bind();
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
=======
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
uint16_t DevoInit()
|
||||
{
|
||||
DEVO_cyrf_init();
|
||||
|
@ -15,21 +15,38 @@
|
||||
// Last sync with hexfet new_protocols/fy326_nrf24l01.c dated 2015-07-29
|
||||
|
||||
#if defined(FY326_NRF24L01_INO)
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
#include "iface_nrf24l01.h"
|
||||
|
||||
#define FY326_INITIAL_WAIT 500
|
||||
#define FY326_PACKET_PERIOD 1500
|
||||
#define FY326_PACKET_CHKTIME 300
|
||||
#define FY326_PACKET_SIZE 15
|
||||
<<<<<<< HEAD
|
||||
#define FY326_BIND_COUNT 16
|
||||
=======
|
||||
#define FY326_BIND_COUNT 16
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
#define FY326_RF_BIND_CHANNEL 0x17
|
||||
#define FY326_NUM_RF_CHANNELS 5
|
||||
|
||||
enum {
|
||||
<<<<<<< HEAD
|
||||
FY326_INIT1 = 0,
|
||||
FY326_BIND1,
|
||||
FY326_BIND2,
|
||||
FY326_DATA,
|
||||
FY319_INIT1,
|
||||
FY319_BIND1,
|
||||
FY319_BIND2,
|
||||
=======
|
||||
FY326_BIND1=0,
|
||||
FY326_BIND2,
|
||||
FY326_DATA
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
};
|
||||
|
||||
#define rxid channel
|
||||
@ -39,7 +56,11 @@ static void __attribute__((unused)) FY326_send_packet(uint8_t bind)
|
||||
{
|
||||
packet[0] = rx_tx_addr[3];
|
||||
if(bind)
|
||||
<<<<<<< HEAD
|
||||
packet[1] = 0x55;
|
||||
=======
|
||||
packet[1] = 0x55;
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
else
|
||||
packet[1] = GET_FLAG(Servo_AUX3, 0x80) // Headless
|
||||
| GET_FLAG(Servo_AUX2, 0x40) // RTH
|
||||
@ -50,6 +71,23 @@ static void __attribute__((unused)) FY326_send_packet(uint8_t bind)
|
||||
packet[3] = convert_channel_8b_scale(ELEVATOR, 0, 200); // elevator
|
||||
packet[4] = 200 - convert_channel_8b_scale(RUDDER, 0, 200); // rudder
|
||||
packet[5] = convert_channel_8b_scale(THROTTLE, 0, 200); // throttle
|
||||
<<<<<<< HEAD
|
||||
if(sub_protocol == FY319) {
|
||||
packet[6] = 255 - scale_channel(AILERON, 0, 255);
|
||||
packet[7] = scale_channel(ELEVATOR, 0, 255);
|
||||
packet[8] = 255 - scale_channel(RUDDER, 0, 255);
|
||||
}
|
||||
else {
|
||||
packet[6] = rx_tx_addr[0];
|
||||
packet[7] = rx_tx_addr[1];
|
||||
packet[8] = rx_tx_addr[2];
|
||||
}
|
||||
packet[9] = CHAN_TO_TRIM(packet[2]); // aileron_trim;
|
||||
packet[10] = CHAN_TO_TRIM(packet[3]); // elevator_trim;
|
||||
packet[11] = CHAN_TO_TRIM(packet[4]); // rudder_trim;
|
||||
packet[12] = 0; // throttle_trim;
|
||||
packet[13] = rxid;
|
||||
=======
|
||||
packet[6] = rx_tx_addr[0];
|
||||
packet[7] = rx_tx_addr[1];
|
||||
packet[8] = rx_tx_addr[2];
|
||||
@ -58,6 +96,7 @@ static void __attribute__((unused)) FY326_send_packet(uint8_t bind)
|
||||
packet[11] = CHAN_TO_TRIM(packet[4]); // rudder_trim;
|
||||
packet[12] = 0; // throttle_trim;
|
||||
packet[13] = rxid;
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
packet[14] = rx_tx_addr[4];
|
||||
|
||||
if (bind)
|
||||
@ -66,11 +105,20 @@ static void __attribute__((unused)) FY326_send_packet(uint8_t bind)
|
||||
{
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no++]);
|
||||
hopping_frequency_no %= FY326_NUM_RF_CHANNELS;
|
||||
<<<<<<< HEAD
|
||||
|
||||
}
|
||||
|
||||
// clear packet status bits and TX FIFO
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
|
||||
NRF24L01_FlushTx();
|
||||
=======
|
||||
}
|
||||
|
||||
// clear packet status bits and TX FIFO
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
|
||||
NRF24L01_FlushTx();
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
|
||||
NRF24L01_WritePayload(packet, FY326_PACKET_SIZE);
|
||||
|
||||
@ -79,9 +127,18 @@ static void __attribute__((unused)) FY326_send_packet(uint8_t bind)
|
||||
|
||||
static void __attribute__((unused)) FY326_init()
|
||||
{
|
||||
<<<<<<< HEAD
|
||||
NRF24L01_Initialize();
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
if(sub_protocol == FY319)
|
||||
NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x03); // Five-byte rx/tx address
|
||||
else
|
||||
NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x01); // Three-byte rx/tx address
|
||||
=======
|
||||
NRF24L01_Initialize();
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x01); // Three-byte rx/tx address
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, (uint8_t *)"\x15\x59\x23\xc6\x29", 5);
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, (uint8_t *)"\x15\x59\x23\xc6\x29", 5);
|
||||
NRF24L01_FlushTx();
|
||||
@ -93,13 +150,112 @@ static void __attribute__((unused)) FY326_init()
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, FY326_RF_BIND_CHANNEL);
|
||||
NRF24L01_SetBitrate(NRF24L01_BR_250K);
|
||||
NRF24L01_SetPower();
|
||||
<<<<<<< HEAD
|
||||
|
||||
NRF24L01_Activate(0x73);
|
||||
=======
|
||||
|
||||
NRF24L01_Activate(0x73);
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 0x3f);
|
||||
NRF24L01_WriteReg(NRF24L01_1D_FEATURE, 0x07);
|
||||
NRF24L01_Activate(0x73);
|
||||
}
|
||||
|
||||
<<<<<<< HEAD
|
||||
uint16_t fy326_callback()
|
||||
{
|
||||
uint8_t i;
|
||||
switch (phase) {
|
||||
case FY319_INIT1:
|
||||
NRF24L01_SetTxRxMode(TXRX_OFF);
|
||||
NRF24L01_FlushRx();
|
||||
NRF24L01_SetTxRxMode(RX_EN);
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, RF_BIND_CHANNEL);
|
||||
phase = FY319_BIND1;
|
||||
BIND_IN_PROGRESS;
|
||||
return FY326_CHKTIME;
|
||||
break;
|
||||
|
||||
case FY319_BIND1:
|
||||
if(NRF24L01_ReadReg(NRF24L01_07_STATUS) & BV(NRF24L01_07_RX_DR)) {
|
||||
NRF24L01_ReadPayload(packet, FY326_SIZE);
|
||||
rxid = packet[13];
|
||||
packet[0] = txid[3];
|
||||
packet[1] = 0x80;
|
||||
packet[14]= txid[4];
|
||||
bind_counter = FY326_BIND_COUNT;
|
||||
NRF24L01_SetTxRxMode(TXRX_OFF);
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
|
||||
NRF24L01_FlushTx();
|
||||
bind_counter = 255;
|
||||
for(i=2; i<6; i++)
|
||||
packet[i] = rf_chans[0];
|
||||
phase = FY319_BIND2;
|
||||
}
|
||||
return FY326_CHKTIME;
|
||||
break;
|
||||
|
||||
case FY319_BIND2:
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
|
||||
NRF24L01_FlushTx();
|
||||
NRF24L01_WritePayload(packet, FY326_SIZE);
|
||||
if(bind_counter == 250)
|
||||
packet[1] = 0x40;
|
||||
if(--bind_counter == 0) {
|
||||
BIND_DONE;
|
||||
phase = FY326_DATA;
|
||||
}
|
||||
break;
|
||||
|
||||
case FY326_INIT1:
|
||||
bind_counter = FY326_BIND_COUNT;
|
||||
phase = FY326_BIND2;
|
||||
send_packet(1);
|
||||
return FY326_CHKTIME;
|
||||
break;
|
||||
|
||||
case FY326_BIND1:
|
||||
if( NRF24L01_ReadReg(NRF24L01_07_STATUS) & BV(NRF24L01_07_RX_DR))
|
||||
{ // RX fifo data ready
|
||||
NRF24L01_ReadPayload(packet, FY326_PACKET_SIZE);
|
||||
rxid = packet[13];
|
||||
rx_tx_addr[0] = 0xAA;
|
||||
NRF24L01_SetTxRxMode(TXRX_OFF);
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
BIND_DONE;
|
||||
phase = FY326_DATA;
|
||||
}
|
||||
else
|
||||
if (bind_counter-- == 0)
|
||||
{
|
||||
bind_counter = FY326_BIND_COUNT;
|
||||
NRF24L01_SetTxRxMode(TXRX_OFF);
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
FY326_send_packet(1);
|
||||
phase = FY326_BIND2;
|
||||
return FY326_PACKET_CHKTIME;
|
||||
}
|
||||
break;
|
||||
|
||||
case FY326_BIND2:
|
||||
if( NRF24L01_ReadReg(NRF24L01_07_STATUS) & BV(NRF24L01_07_TX_DS))
|
||||
{ // TX data sent -> switch to RX mode
|
||||
NRF24L01_SetTxRxMode(TXRX_OFF);
|
||||
NRF24L01_FlushRx();
|
||||
NRF24L01_SetTxRxMode(RX_EN);
|
||||
phase = FY326_BIND1;
|
||||
}
|
||||
else
|
||||
return FY326_PACKET_CHKTIME;
|
||||
break;
|
||||
|
||||
case FY326_DATA:
|
||||
FY326_send_packet(0);
|
||||
break;
|
||||
}
|
||||
=======
|
||||
uint16_t FY326_callback()
|
||||
{
|
||||
switch (phase)
|
||||
@ -141,26 +297,54 @@ uint16_t FY326_callback()
|
||||
FY326_send_packet(0);
|
||||
break;
|
||||
}
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
return FY326_PACKET_PERIOD;
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) FY326_initialize_txid()
|
||||
{
|
||||
<<<<<<< HEAD
|
||||
if(sub_protocol == FY319) {
|
||||
hopping_frequency[0] = (rx_tx_addr[0]&0x0f) & ~0x80;
|
||||
hopping_frequency[1] = (rx_tx_addr[0] >> 4) & ~0x80;
|
||||
hopping_frequency[2] = (rx_tx_addr[1]&0x0f) & ~0x80;
|
||||
hopping_frequency[3] = (rx_tx_addr[1] >> 4) & ~0x80;
|
||||
hopping_frequency[4] = (rx_tx_addr[2] >> 4) & ~0x80;
|
||||
} else {
|
||||
hopping_frequency[0] = (rx_tx_addr[0]&0x0f);
|
||||
hopping_frequency[1] = 0x10 + (rx_tx_addr[0] >> 4);
|
||||
hopping_frequency[2] = 0x20 + (rx_tx_addr[1]&0x0f);
|
||||
hopping_frequency[3] = 0x30 + (rx_tx_addr[1] >> 4);
|
||||
hopping_frequency[4] = 0x40 + (rx_tx_addr[2] >> 4);
|
||||
}
|
||||
=======
|
||||
hopping_frequency[0] = (rx_tx_addr[0]&0x0f);
|
||||
hopping_frequency[1] = 0x10 + (rx_tx_addr[0] >> 4);
|
||||
hopping_frequency[2] = 0x20 + (rx_tx_addr[1]&0x0f);
|
||||
hopping_frequency[3] = 0x30 + (rx_tx_addr[1] >> 4);
|
||||
hopping_frequency[4] = 0x40 + (rx_tx_addr[2] >> 4);
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
}
|
||||
|
||||
uint16_t initFY326(void)
|
||||
{
|
||||
BIND_IN_PROGRESS; // autobind protocol
|
||||
<<<<<<< HEAD
|
||||
rxid = 0xaa;
|
||||
bind_counter = 0;
|
||||
FY326_initialize_txid();
|
||||
fy326_init();
|
||||
if(sub_protocol == FY319)
|
||||
phase = FY319_INIT1;
|
||||
else
|
||||
phase = FY326_INIT1;
|
||||
=======
|
||||
rxid = 0xAA;
|
||||
bind_counter = 0;
|
||||
FY326_initialize_txid();
|
||||
FY326_init();
|
||||
phase=FY326_BIND1;
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
return FY326_INITIAL_WAIT;
|
||||
}
|
||||
|
||||
|
@ -21,6 +21,34 @@
|
||||
//FlySky constants & variables
|
||||
#define FLYSKY_BIND_COUNT 2500
|
||||
|
||||
<<<<<<< HEAD
|
||||
const uint8_t PROGMEM tx_channels[] = {
|
||||
0x0a, 0x5a, 0x14, 0x64, 0x1e, 0x6e, 0x28, 0x78, 0x32, 0x82, 0x3c, 0x8c, 0x46, 0x96, 0x50, 0xa0,
|
||||
0xa0, 0x50, 0x96, 0x46, 0x8c, 0x3c, 0x82, 0x32, 0x78, 0x28, 0x6e, 0x1e, 0x64, 0x14, 0x5a, 0x0a,
|
||||
0x0a, 0x5a, 0x50, 0xa0, 0x14, 0x64, 0x46, 0x96, 0x1e, 0x6e, 0x3c, 0x8c, 0x28, 0x78, 0x32, 0x82,
|
||||
0x82, 0x32, 0x78, 0x28, 0x8c, 0x3c, 0x6e, 0x1e, 0x96, 0x46, 0x64, 0x14, 0xa0, 0x50, 0x5a, 0x0a,
|
||||
0x28, 0x78, 0x0a, 0x5a, 0x50, 0xa0, 0x14, 0x64, 0x1e, 0x6e, 0x3c, 0x8c, 0x32, 0x82, 0x46, 0x96,
|
||||
0x96, 0x46, 0x82, 0x32, 0x8c, 0x3c, 0x6e, 0x1e, 0x64, 0x14, 0xa0, 0x50, 0x5a, 0x0a, 0x78, 0x28,
|
||||
0x50, 0xa0, 0x28, 0x78, 0x0a, 0x5a, 0x1e, 0x6e, 0x3c, 0x8c, 0x32, 0x82, 0x46, 0x96, 0x14, 0x64,
|
||||
0x64, 0x14, 0x96, 0x46, 0x82, 0x32, 0x8c, 0x3c, 0x6e, 0x1e, 0x5a, 0x0a, 0x78, 0x28, 0xa0, 0x50,
|
||||
0x50, 0xa0, 0x46, 0x96, 0x3c, 0x8c, 0x28, 0x78, 0x0a, 0x5a, 0x32, 0x82, 0x1e, 0x6e, 0x14, 0x64,
|
||||
0x64, 0x14, 0x6e, 0x1e, 0x82, 0x32, 0x5a, 0x0a, 0x78, 0x28, 0x8c, 0x3c, 0x96, 0x46, 0xa0, 0x50,
|
||||
0x46, 0x96, 0x3c, 0x8c, 0x50, 0xa0, 0x28, 0x78, 0x0a, 0x5a, 0x1e, 0x6e, 0x32, 0x82, 0x14, 0x64,
|
||||
0x64, 0x14, 0x82, 0x32, 0x6e, 0x1e, 0x5a, 0x0a, 0x78, 0x28, 0xa0, 0x50, 0x8c, 0x3c, 0x96, 0x46,
|
||||
0x46, 0x96, 0x0a, 0x5a, 0x3c, 0x8c, 0x14, 0x64, 0x50, 0xa0, 0x28, 0x78, 0x1e, 0x6e, 0x32, 0x82,
|
||||
0x82, 0x32, 0x6e, 0x1e, 0x78, 0x28, 0xa0, 0x50, 0x64, 0x14, 0x8c, 0x3c, 0x5a, 0x0a, 0x96, 0x46,
|
||||
0x46, 0x96, 0x0a, 0x5a, 0x50, 0xa0, 0x3c, 0x8c, 0x28, 0x78, 0x1e, 0x6e, 0x32, 0x82, 0x14, 0x64,
|
||||
0x64, 0x14, 0x82, 0x32, 0x6e, 0x1e, 0x78, 0x28, 0x8c, 0x3c, 0xa0, 0x50, 0x5a, 0x0a, 0x96, 0x46
|
||||
};
|
||||
|
||||
enum {
|
||||
// flags going to byte 10
|
||||
FLAG_V9X9_VIDEO = 0x40,
|
||||
FLAG_V9X9_CAMERA= 0x80,
|
||||
// flags going to byte 12
|
||||
FLAG_V9X9_FLIP = 0x10,
|
||||
FLAG_V9X9_LED = 0x20,
|
||||
=======
|
||||
enum {
|
||||
// flags going to byte 10
|
||||
FLAG_V9X9_VIDEO = 0x40,
|
||||
@ -28,26 +56,27 @@ enum {
|
||||
// flags going to byte 12
|
||||
FLAG_V9X9_FLIP = 0x10,
|
||||
FLAG_V9X9_LED = 0x20,
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
};
|
||||
|
||||
enum {
|
||||
// flags going to byte 13
|
||||
FLAG_V6X6_HLESS1= 0x80,
|
||||
// flags going to byte 14
|
||||
FLAG_V6X6_VIDEO = 0x01,
|
||||
FLAG_V6X6_YCAL = 0x02,
|
||||
FLAG_V6X6_XCAL = 0x04,
|
||||
FLAG_V6X6_RTH = 0x08,
|
||||
FLAG_V6X6_CAMERA= 0x10,
|
||||
FLAG_V6X6_HLESS2= 0x20,
|
||||
FLAG_V6X6_LED = 0x40,
|
||||
FLAG_V6X6_FLIP = 0x80,
|
||||
// flags going to byte 13
|
||||
FLAG_V6X6_HLESS1= 0x80,
|
||||
// flags going to byte 14
|
||||
FLAG_V6X6_VIDEO = 0x01,
|
||||
FLAG_V6X6_YCAL = 0x02,
|
||||
FLAG_V6X6_XCAL = 0x04,
|
||||
FLAG_V6X6_RTH = 0x08,
|
||||
FLAG_V6X6_CAMERA= 0x10,
|
||||
FLAG_V6X6_HLESS2= 0x20,
|
||||
FLAG_V6X6_LED = 0x40,
|
||||
FLAG_V6X6_FLIP = 0x80,
|
||||
};
|
||||
|
||||
enum {
|
||||
// flags going to byte 14
|
||||
FLAG_V912_TOPBTN= 0x40,
|
||||
FLAG_V912_BTMBTN= 0x80,
|
||||
// flags going to byte 14
|
||||
FLAG_V912_TOPBTN= 0x40,
|
||||
FLAG_V912_BTMBTN= 0x80,
|
||||
};
|
||||
|
||||
const uint8_t PROGMEM V912_X17_SEQ[10] = { 0x14, 0x31, 0x40, 0x49, 0x49, // sometime first byte is 0x15 ?
|
||||
@ -55,6 +84,79 @@ const uint8_t PROGMEM V912_X17_SEQ[10] = { 0x14, 0x31, 0x40, 0x49, 0x49, //
|
||||
|
||||
static void __attribute__((unused)) flysky_apply_extension_flags()
|
||||
{
|
||||
<<<<<<< HEAD
|
||||
const uint8_t V912_X17_SEQ[10] = { 0x14, 0x31, 0x40, 0x49, 0x49, // sometime first byte is 0x15 ?
|
||||
0x49, 0x49, 0x49, 0x49, 0x49, };
|
||||
static uint8_t seq_counter;
|
||||
switch(sub_protocol)
|
||||
{
|
||||
case V9X9:
|
||||
if(Servo_AUX1)
|
||||
packet[12] |= FLAG_V9X9_FLIP;
|
||||
if(Servo_AUX2)
|
||||
packet[12] |= FLAG_V9X9_LED;
|
||||
if(Servo_AUX3)
|
||||
packet[10] |= FLAG_V9X9_CAMERA;
|
||||
if(Servo_AUX4)
|
||||
packet[10] |= FLAG_V9X9_VIDEO;
|
||||
break;
|
||||
|
||||
case V6X6:
|
||||
packet[13] = 0x03; // 3 = 100% rate (0=40%, 1=60%, 2=80%)
|
||||
packet[14] = 0x00;
|
||||
if(Servo_AUX1)
|
||||
packet[14] |= FLAG_V6X6_FLIP;
|
||||
if(Servo_AUX2)
|
||||
packet[14] |= FLAG_V6X6_LED;
|
||||
if(Servo_AUX3)
|
||||
packet[14] |= FLAG_V6X6_CAMERA;
|
||||
if(Servo_AUX4)
|
||||
packet[14] |= FLAG_V6X6_VIDEO;
|
||||
if(Servo_AUX5)
|
||||
{
|
||||
packet[13] |= FLAG_V6X6_HLESS1;
|
||||
packet[14] |= FLAG_V6X6_HLESS2;
|
||||
}
|
||||
if(Servo_AUX6) //use option to manipulate these bytes
|
||||
packet[14] |= FLAG_V6X6_RTH;
|
||||
if(Servo_AUX7)
|
||||
packet[14] |= FLAG_V6X6_XCAL;
|
||||
if(Servo_AUX8)
|
||||
packet[14] |= FLAG_V6X6_YCAL;
|
||||
packet[15] = 0x10; // unknown
|
||||
packet[16] = 0x10; // unknown
|
||||
packet[17] = 0xAA; // unknown
|
||||
packet[18] = 0xAA; // unknown
|
||||
packet[19] = 0x60; // unknown, changes at irregular interval in stock TX
|
||||
packet[20] = 0x02; // unknown
|
||||
break;
|
||||
|
||||
case V912:
|
||||
seq_counter++;
|
||||
if( seq_counter > 9)
|
||||
seq_counter = 0;
|
||||
packet[12] |= 0x20; // bit 6 is always set ?
|
||||
packet[13] = 0x00; // unknown
|
||||
packet[14] = 0x00;
|
||||
if(Servo_AUX1)
|
||||
packet[14] = FLAG_V912_BTMBTN;
|
||||
if(Servo_AUX2)
|
||||
packet[14] |= FLAG_V912_TOPBTN;
|
||||
packet[15] = 0x27; // [15] and [16] apparently hold an analog channel with a value lower than 1000
|
||||
packet[16] = 0x03; // maybe it's there for a pitch channel for a CP copter ?
|
||||
packet[17] = V912_X17_SEQ[seq_counter]; // not sure what [17] & [18] are for
|
||||
if(seq_counter == 0) // V912 Rx does not even read those bytes... [17-20]
|
||||
packet[18] = 0x02;
|
||||
else
|
||||
packet[18] = 0x00;
|
||||
packet[19] = 0x00; // unknown
|
||||
packet[20] = 0x00; // unknown
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
=======
|
||||
static uint8_t seq_counter;
|
||||
switch(sub_protocol)
|
||||
{
|
||||
@ -124,39 +226,78 @@ static void __attribute__((unused)) flysky_apply_extension_flags()
|
||||
default:
|
||||
break;
|
||||
}
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) flysky_build_packet(uint8_t init)
|
||||
{
|
||||
uint8_t i;
|
||||
//servodata timing range for flysky.
|
||||
////-100% =~ 0x03e8//=1000us(min)
|
||||
//+100% =~ 0x07ca//=1994us(max)
|
||||
//Center = 0x5d9//=1497us(center)
|
||||
//channel order AIL;ELE;THR;RUD;AUX1;AUX2;AUX3;AUX4
|
||||
//servodata timing range for flysky.
|
||||
////-100% =~ 0x03e8//=1000us(min)
|
||||
//+100% =~ 0x07ca//=1994us(max)
|
||||
//Center = 0x5d9//=1497us(center)
|
||||
//channel order AIL;ELE;THR;RUD;AUX1;AUX2;AUX3;AUX4
|
||||
packet[0] = init ? 0xaa : 0x55;
|
||||
packet[1] = rx_tx_addr[3];
|
||||
packet[2] = rx_tx_addr[2];
|
||||
packet[3] = rx_tx_addr[1];
|
||||
packet[4] = rx_tx_addr[0];
|
||||
<<<<<<< HEAD
|
||||
const uint8_t ch[]={AILERON, ELEVATOR, THROTTLE, RUDDER, AUX1, AUX2, AUX3, AUX4};
|
||||
for(i = 0; i < 8; i++)
|
||||
{
|
||||
packet[5+2*i]=lowByte(Servo_data[ch[i]]); //low byte of servo timing(1000-2000us)
|
||||
packet[6+2*i]=highByte(Servo_data[ch[i]]); //high byte of servo timing(1000-2000us)
|
||||
}
|
||||
=======
|
||||
for(i = 0; i < 8; i++)
|
||||
{
|
||||
packet[5 + i*2]=Servo_data[CH_AETR[i]]&0xFF; //low byte of servo timing(1000-2000us)
|
||||
packet[6 + i*2]=(Servo_data[CH_AETR[i]]>>8)&0xFF; //high byte of servo timing(1000-2000us)
|
||||
}
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
flysky_apply_extension_flags();
|
||||
}
|
||||
|
||||
uint16_t ReadFlySky()
|
||||
{
|
||||
if (bind_counter)
|
||||
{
|
||||
{
|
||||
flysky_build_packet(1);
|
||||
A7105_WriteData(21, 1);
|
||||
bind_counter--;
|
||||
if (! bind_counter)
|
||||
BIND_DONE;
|
||||
}
|
||||
<<<<<<< HEAD
|
||||
else
|
||||
{
|
||||
flysky_build_packet(0);
|
||||
A7105_WriteData(21, pgm_read_byte_near(&tx_channels[chanrow*16+chancol])-chanoffset);
|
||||
chancol = (chancol + 1) % 16;
|
||||
if (! chancol) //Keep transmit power updated
|
||||
A7105_SetPower();
|
||||
}
|
||||
return 1460;
|
||||
}
|
||||
|
||||
uint16_t initFlySky() {
|
||||
//A7105_Reset();
|
||||
A7105_Init(INIT_FLYSKY); //flysky_init();
|
||||
|
||||
if (rx_tx_addr[3] > 0x90) // limit offset to 9 as higher values don't work with some RX (ie V912)
|
||||
rx_tx_addr[3] = rx_tx_addr[3] - 0x70;
|
||||
chanrow=rx_tx_addr[3] % 16;
|
||||
chancol=0;
|
||||
chanoffset=rx_tx_addr[3] / 16;
|
||||
|
||||
|
||||
if(IS_AUTOBIND_FLAG_on)
|
||||
bind_counter = FLYSKY_BIND_COUNT;
|
||||
else
|
||||
bind_counter = 0;
|
||||
return 2400;
|
||||
=======
|
||||
else
|
||||
{
|
||||
flysky_build_packet(0);
|
||||
@ -211,5 +352,7 @@ uint16_t initFlySky()
|
||||
else
|
||||
bind_counter = 0;
|
||||
return 2400;
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -17,9 +17,297 @@
|
||||
*/
|
||||
|
||||
#if defined(FRSKYX_CC2500_INO)
|
||||
|
||||
#include "iface_cc2500.h"
|
||||
|
||||
uint8_t chanskip;
|
||||
uint8_t calData[48][3];
|
||||
uint8_t channr;
|
||||
uint8_t pass_ = 1 ;
|
||||
uint8_t counter_rst;
|
||||
uint8_t ctr;
|
||||
uint8_t FS_flag=0;
|
||||
// uint8_t ptr[4]={0x01,0x12,0x23,0x30};
|
||||
//uint8_t ptr[4]={0x00,0x11,0x22,0x33};
|
||||
|
||||
const PROGMEM uint8_t hop_data[]={
|
||||
0x02, 0xD4, 0xBB, 0xA2, 0x89,
|
||||
0x70, 0x57, 0x3E, 0x25, 0x0C,
|
||||
0xDE, 0xC5, 0xAC, 0x93, 0x7A,
|
||||
0x61, 0x48, 0x2F, 0x16, 0xE8,
|
||||
0xCF, 0xB6, 0x9D, 0x84, 0x6B,
|
||||
0x52, 0x39, 0x20, 0x07, 0xD9,
|
||||
0xC0, 0xA7, 0x8E, 0x75, 0x5C,
|
||||
0x43, 0x2A, 0x11, 0xE3, 0xCA,
|
||||
0xB1, 0x98, 0x7F, 0x66, 0x4D,
|
||||
0x34, 0x1B, 0x00, 0x1D, 0x03
|
||||
};
|
||||
|
||||
#include "iface_cc2500.h"
|
||||
static uint8_t __attribute__((unused)) hop(uint8_t byte)
|
||||
{
|
||||
return pgm_read_byte_near(&hop_data[byte]);
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) set_start(uint8_t ch )
|
||||
{
|
||||
cc2500_strobe(CC2500_SIDLE);
|
||||
cc2500_writeReg(CC2500_23_FSCAL3, calData[ch][0]);
|
||||
cc2500_writeReg(CC2500_24_FSCAL2, calData[ch][1]);
|
||||
cc2500_writeReg(CC2500_25_FSCAL1, calData[ch][2]);
|
||||
cc2500_writeReg(CC2500_0A_CHANNR, ch==47?0:pgm_read_word(&hop_data[ch]));
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) frskyX_init()
|
||||
{
|
||||
CC2500_Reset();
|
||||
|
||||
for(uint8_t i=0;i<36;i++)
|
||||
{
|
||||
uint8_t reg=pgm_read_byte_near(&cc2500_conf[i][0]);
|
||||
uint8_t val=pgm_read_byte_near(&cc2500_conf[i][1]);
|
||||
|
||||
if(reg==CC2500_06_PKTLEN)
|
||||
val=0x1E;
|
||||
else
|
||||
if(reg==CC2500_08_PKTCTRL0)
|
||||
val=0x01;
|
||||
else
|
||||
if(reg==CC2500_0B_FSCTRL1)
|
||||
val=0x0A;
|
||||
else
|
||||
if(reg==CC2500_10_MDMCFG4)
|
||||
val=0x7B;
|
||||
else
|
||||
if(reg==CC2500_11_MDMCFG3)
|
||||
val=0x61;
|
||||
else
|
||||
if(reg==CC2500_12_MDMCFG2)
|
||||
val=0x13;
|
||||
else
|
||||
if(reg==CC2500_15_DEVIATN)
|
||||
val=0x51;
|
||||
|
||||
cc2500_writeReg(reg,val);
|
||||
}
|
||||
|
||||
cc2500_writeReg(CC2500_07_PKTCTRL1, 0x04);
|
||||
cc2500_writeReg(CC2500_0C_FSCTRL0, option);
|
||||
cc2500_strobe(CC2500_SIDLE);
|
||||
//
|
||||
for(uint8_t c=0;c < 47;c++){//calibrate hop channels
|
||||
cc2500_strobe(CC2500_SIDLE);
|
||||
cc2500_writeReg(CC2500_0A_CHANNR,pgm_read_word(&hop_data[c]));
|
||||
cc2500_strobe(CC2500_SCAL);
|
||||
delayMicroseconds(900);//
|
||||
calData[c][0] = cc2500_readReg(CC2500_23_FSCAL3);
|
||||
calData[c][1] = cc2500_readReg(CC2500_24_FSCAL2);
|
||||
calData[c][2] = cc2500_readReg(CC2500_25_FSCAL1);
|
||||
}
|
||||
cc2500_strobe(CC2500_SIDLE);
|
||||
cc2500_writeReg(CC2500_0A_CHANNR,0x00);
|
||||
cc2500_strobe(CC2500_SCAL);
|
||||
delayMicroseconds(900);
|
||||
calData[47][0] = cc2500_readReg(CC2500_23_FSCAL3);
|
||||
calData[47][1] = cc2500_readReg(CC2500_24_FSCAL2);
|
||||
calData[47][2] = cc2500_readReg(CC2500_25_FSCAL1);
|
||||
//#######END INIT########
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) 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);
|
||||
}
|
||||
|
||||
static uint8_t __attribute__((unused)) crc_Byte( uint8_t byte )
|
||||
{
|
||||
crc = (crc<<8) ^ pgm_read_word(&CRCTable[((uint8_t)(crc>>8) ^ byte) & 0xFF]);
|
||||
return byte;
|
||||
}
|
||||
|
||||
static uint16_t __attribute__((unused)) scaleForPXX( uint8_t i )
|
||||
{ //mapped 860,2140(125%) range to 64,1984(PXX values);
|
||||
return (uint16_t)(((Servo_data[i]-PPM_MIN)*3)>>1)+64;
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) frskyX_build_bind_packet()
|
||||
{
|
||||
crc=0;
|
||||
packet[0] = 0x1D;
|
||||
packet[1] = 0x03;
|
||||
packet[2] = 0x01;
|
||||
//
|
||||
packet[3] = crc_Byte(rx_tx_addr[3]);
|
||||
packet[4] = crc_Byte(rx_tx_addr[2]);
|
||||
int idx = ((state -FRSKY_BIND) % 10) * 5;
|
||||
packet[5] = crc_Byte(idx);
|
||||
packet[6] = crc_Byte(pgm_read_word(&hop_data[idx++]));
|
||||
packet[7] = crc_Byte(pgm_read_word(&hop_data[idx++]));
|
||||
packet[8] = crc_Byte(pgm_read_word(&hop_data[idx++]));
|
||||
packet[9] = crc_Byte(pgm_read_word(&hop_data[idx++]));
|
||||
packet[10] = crc_Byte(pgm_read_word(&hop_data[idx++]));
|
||||
packet[11] = crc_Byte(0x02);
|
||||
packet[12] = crc_Byte(RX_num);
|
||||
//
|
||||
for(uint8_t i=13;i<28;i++)
|
||||
packet[i]=crc_Byte(0);
|
||||
//
|
||||
packet[28]=highByte(crc);
|
||||
packet[29]=lowByte(crc);
|
||||
//
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) frskyX_data_frame()
|
||||
{
|
||||
//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
|
||||
//
|
||||
uint8_t lpass = pass_ ;
|
||||
uint16_t chan_0 ;
|
||||
uint16_t chan_1 ;
|
||||
uint8_t flag2 = 0;
|
||||
uint8_t startChan = 0;
|
||||
crc = 0;
|
||||
//static uint8_t p = 0;
|
||||
//
|
||||
packet[0] = 0x1D;
|
||||
packet[1] = rx_tx_addr[3];
|
||||
packet[2] = rx_tx_addr[2];
|
||||
packet[3] = crc_Byte(0x02);
|
||||
//
|
||||
packet[4] = crc_Byte((ctr<<6)+channr); //*64
|
||||
packet[5] = crc_Byte(counter_rst);
|
||||
packet[6] = crc_Byte(RX_num);
|
||||
// FLAGS 00 - standard packet
|
||||
//10, 12, 14, 16, 18, 1A, 1C, 1E - failsafe packet
|
||||
//20 - range check packet
|
||||
packet[7] = crc_Byte(FS_flag);
|
||||
packet[8] = crc_Byte(flag2);
|
||||
//
|
||||
if ( lpass & 1 )
|
||||
startChan += 8 ;
|
||||
|
||||
for(uint8_t i = 0; i <12 ; i+=3)
|
||||
{//12 bytes
|
||||
chan_0 = scaleForPXX(startChan);
|
||||
if(lpass & 1 )
|
||||
chan_0+=2048;
|
||||
|
||||
packet[9+i] = crc_Byte(lowByte(chan_0));//3 bytes*4
|
||||
startChan++;
|
||||
chan_1 = scaleForPXX(startChan);
|
||||
if(lpass & 1 )
|
||||
chan_1+= 2048;
|
||||
|
||||
startChan++;
|
||||
packet[9+i+1]=crc_Byte((((chan_0>>8) & 0x0F)|(chan_1 << 4)));
|
||||
packet[9+i+2]=crc_Byte(chan_1>>4);
|
||||
}
|
||||
//packet[21]=crc_Byte(0x08);//first
|
||||
packet[21]=crc_Byte(0x80);//??? when received first telemetry frame is changed to 0x80
|
||||
//packet[21]=crc_Byte(ptr[p]);//???
|
||||
//p=(p+1)%4;//repeating 4 bytes sequence pattern every 4th frame.
|
||||
|
||||
pass_=lpass+1;
|
||||
|
||||
for (uint8_t i=22;i<28;i++)
|
||||
packet[i]=crc_Byte(0);
|
||||
|
||||
packet[28]=highByte(crc);
|
||||
packet[29]=lowByte(crc);
|
||||
}
|
||||
|
||||
<<<<<<< HEAD
|
||||
uint16_t ReadFrSkyX()
|
||||
{
|
||||
switch(state)
|
||||
{
|
||||
default:
|
||||
set_start(47);
|
||||
CC2500_SetPower();
|
||||
cc2500_strobe(CC2500_SFRX);
|
||||
//
|
||||
frskyX_build_bind_packet();
|
||||
cc2500_strobe(CC2500_SIDLE);
|
||||
cc2500_writeFifo(packet, packet[0]+1);
|
||||
state++;
|
||||
return 9000;
|
||||
case FRSKY_BIND_DONE:
|
||||
initialize_data(0);
|
||||
channr=0;
|
||||
BIND_DONE;
|
||||
state++;
|
||||
break;
|
||||
case FRSKY_DATA1:
|
||||
LED_ON;
|
||||
CC2500_SetTxRxMode(TX_EN);
|
||||
set_start(channr);
|
||||
CC2500_SetPower();
|
||||
cc2500_strobe(CC2500_SFRX);
|
||||
channr = (channr+chanskip)%47;
|
||||
cc2500_strobe(CC2500_SIDLE);
|
||||
cc2500_writeFifo(packet, packet[0]+1);
|
||||
//
|
||||
frskyX_data_frame();
|
||||
state++;
|
||||
return 5500;
|
||||
case FRSKY_DATA2:
|
||||
CC2500_SetTxRxMode(RX_EN);
|
||||
cc2500_strobe(CC2500_SIDLE);
|
||||
state++;
|
||||
return 200;
|
||||
case FRSKY_DATA3:
|
||||
cc2500_strobe(CC2500_SRX);
|
||||
state++;
|
||||
return 3000;
|
||||
case FRSKY_DATA4:
|
||||
len = cc2500_readReg(CC2500_3B_RXBYTES | CC2500_READ_BURST) & 0x7F;
|
||||
if (len &&(len<MAX_PKT))
|
||||
{
|
||||
cc2500_readFifo(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
|
||||
}
|
||||
state = FRSKY_DATA1;
|
||||
return 300;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint16_t initFrSkyX()
|
||||
{
|
||||
while(!chanskip)
|
||||
{
|
||||
randomSeed((uint32_t)analogRead(A6) << 10 | analogRead(A7));
|
||||
chanskip=random(0xfefefefe)%47;
|
||||
}
|
||||
while((chanskip-ctr)%4)
|
||||
ctr=(ctr+1)%4;
|
||||
|
||||
counter_rst=(chanskip-ctr)>>2;
|
||||
//for test***************
|
||||
//rx_tx_addr[3]=0xB3;
|
||||
//rx_tx_addr[2]=0xFD;
|
||||
//************************
|
||||
frskyX_init();
|
||||
//
|
||||
if(IS_AUTOBIND_FLAG_on)
|
||||
{
|
||||
state = FRSKY_BIND;
|
||||
initialize_data(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
state = FRSKY_DATA1;
|
||||
initialize_data(0);
|
||||
}
|
||||
return 10000;
|
||||
}
|
||||
=======
|
||||
uint8_t chanskip;
|
||||
uint8_t counter_rst;
|
||||
uint8_t ctr;
|
||||
@ -329,4 +617,5 @@ uint16_t initFrSkyX()
|
||||
seq_last_rcvd = 8;
|
||||
return 10000;
|
||||
}
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
#endif
|
219
Multiprotocol/FrSky_cc2500.ino
Normal file
219
Multiprotocol/FrSky_cc2500.ino
Normal file
@ -0,0 +1,219 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
|
||||
#if defined(FRSKY_CC2500_INO)
|
||||
|
||||
#include "iface_cc2500.h"
|
||||
|
||||
//##########Variables########
|
||||
//uint32_t state;
|
||||
//uint8_t len;
|
||||
|
||||
/*
|
||||
enum {
|
||||
FRSKY_BIND = 0,
|
||||
FRSKY_BIND_DONE = 1000,
|
||||
FRSKY_DATA1,
|
||||
FRSKY_DATA2,
|
||||
FRSKY_DATA3,
|
||||
FRSKY_DATA4,
|
||||
FRSKY_DATA5
|
||||
};
|
||||
*/
|
||||
|
||||
static void __attribute__((unused)) frsky2way_init(uint8_t bind)
|
||||
{
|
||||
// Configure cc2500 for tx mode
|
||||
CC2500_Reset();
|
||||
//
|
||||
for(uint8_t i=0;i<36;i++)
|
||||
{
|
||||
uint8_t reg=pgm_read_byte_near(&cc2500_conf[i][0]);
|
||||
uint8_t val=pgm_read_byte_near(&cc2500_conf[i][1]);
|
||||
|
||||
if(reg==CC2500_0C_FSCTRL0)
|
||||
val=option;
|
||||
else
|
||||
if(reg==CC2500_1B_AGCCTRL2)
|
||||
val=bind ? 0x43 : 0x03;
|
||||
cc2500_writeReg(reg,val);
|
||||
}
|
||||
|
||||
CC2500_SetTxRxMode(TX_EN);
|
||||
CC2500_SetPower();
|
||||
|
||||
cc2500_strobe(CC2500_SIDLE);
|
||||
|
||||
cc2500_writeReg(CC2500_09_ADDR, bind ? 0x03 : rx_tx_addr[3]);
|
||||
cc2500_writeReg(CC2500_07_PKTCTRL1, 0x05);
|
||||
cc2500_strobe(CC2500_SIDLE); // Go to idle...
|
||||
//
|
||||
cc2500_writeReg(CC2500_0A_CHANNR, 0x00);
|
||||
cc2500_writeReg(CC2500_23_FSCAL3, 0x89);
|
||||
cc2500_strobe(CC2500_SFRX);
|
||||
//#######END INIT########
|
||||
}
|
||||
|
||||
static uint8_t __attribute__((unused)) get_chan_num(uint16_t idx)
|
||||
{
|
||||
uint8_t ret = (idx * 0x1e) % 0xeb;
|
||||
if(idx == 3 || idx == 23 || idx == 47)
|
||||
ret++;
|
||||
if(idx > 47)
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) frsky2way_build_bind_packet()
|
||||
{
|
||||
//11 03 01 d7 2d 00 00 1e 3c 5b 78 00 00 00 00 00 00 01
|
||||
//11 03 01 19 3e 00 02 8e 2f bb 5c 00 00 00 00 00 00 01
|
||||
packet[0] = 0x11;
|
||||
packet[1] = 0x03;
|
||||
packet[2] = 0x01;
|
||||
packet[3] = rx_tx_addr[3];
|
||||
packet[4] = rx_tx_addr[2];
|
||||
uint16_t idx = ((state -FRSKY_BIND) % 10) * 5;
|
||||
packet[5] = idx;
|
||||
packet[6] = get_chan_num(idx++);
|
||||
packet[7] = get_chan_num(idx++);
|
||||
packet[8] = get_chan_num(idx++);
|
||||
packet[9] = get_chan_num(idx++);
|
||||
packet[10] = get_chan_num(idx++);
|
||||
packet[11] = 0x00;
|
||||
packet[12] = 0x00;
|
||||
packet[13] = 0x00;
|
||||
packet[14] = 0x00;
|
||||
packet[15] = 0x00;
|
||||
packet[16] = 0x00;
|
||||
packet[17] = 0x01;
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) frsky2way_data_frame()
|
||||
{//pachet[4] is telemetry user frame counter(hub)
|
||||
//11 d7 2d 22 00 01 c9 c9 ca ca 88 88 ca ca c9 ca 88 88
|
||||
//11 57 12 00 00 01 f2 f2 f2 f2 06 06 ca ca ca ca 18 18
|
||||
packet[0] = 0x11; //Length
|
||||
packet[1] = rx_tx_addr[3];
|
||||
packet[2] = rx_tx_addr[2];
|
||||
packet[3] = counter;//
|
||||
#if defined TELEMETRY
|
||||
packet[4] = telemetry_counter;
|
||||
#else
|
||||
packet[4] = 0x00;
|
||||
#endif
|
||||
|
||||
packet[5] = 0x01;
|
||||
//
|
||||
packet[10] = 0;
|
||||
packet[11] = 0;
|
||||
packet[16] = 0;
|
||||
packet[17] = 0;
|
||||
for(uint8_t i = 0; i < 8; i++)
|
||||
{
|
||||
uint16_t value;
|
||||
value = convert_channel_frsky(i);
|
||||
if(i < 4)
|
||||
{
|
||||
packet[6+i] = value & 0xff;
|
||||
packet[10+(i>>1)] |= ((value >> 8) & 0x0f) << (4 *(i & 0x01));
|
||||
}
|
||||
else
|
||||
{
|
||||
packet[8+i] = value & 0xff;
|
||||
packet[16+((i-4)>>1)] |= ((value >> 8) & 0x0f) << (4 * ((i-4) & 0x01));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t initFrSky_2way()
|
||||
{
|
||||
if(IS_AUTOBIND_FLAG_on)
|
||||
{
|
||||
frsky2way_init(1);
|
||||
state = FRSKY_BIND;//
|
||||
}
|
||||
else
|
||||
{
|
||||
frsky2way_init(0);
|
||||
state = FRSKY_DATA2;
|
||||
}
|
||||
return 10000;
|
||||
}
|
||||
|
||||
uint16_t ReadFrSky_2way()
|
||||
{
|
||||
if (state < FRSKY_BIND_DONE)
|
||||
{
|
||||
frsky2way_build_bind_packet();
|
||||
cc2500_strobe(CC2500_SIDLE);
|
||||
cc2500_writeReg(CC2500_0A_CHANNR, 0x00);
|
||||
cc2500_writeReg(CC2500_23_FSCAL3, 0x89);
|
||||
cc2500_strobe(CC2500_SFRX);//0x3A
|
||||
cc2500_writeFifo(packet, packet[0]+1);
|
||||
state++;
|
||||
return 9000;
|
||||
}
|
||||
if (state == FRSKY_BIND_DONE)
|
||||
{
|
||||
state = FRSKY_DATA2;
|
||||
frsky2way_init(0);
|
||||
counter = 0;
|
||||
BIND_DONE;
|
||||
}
|
||||
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
|
||||
CC2500_SetTxRxMode(RX_EN);
|
||||
cc2500_strobe(CC2500_SIDLE);
|
||||
cc2500_writeReg(CC2500_0A_CHANNR, get_chan_num(counter % 47));
|
||||
cc2500_writeReg(CC2500_23_FSCAL3, 0x89);
|
||||
state++;
|
||||
return 1300;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (state == FRSKY_DATA1)
|
||||
{
|
||||
len = cc2500_readReg(CC2500_3B_RXBYTES | CC2500_READ_BURST) & 0x7F;
|
||||
if (len<=MAX_PKT)//27 bytes
|
||||
{
|
||||
cc2500_readFifo(pkt, len); //received telemetry packets
|
||||
#if defined(TELEMETRY)
|
||||
//parse telemetry packet here
|
||||
frsky_check_telemetry(pkt,len); //check if valid telemetry packets and buffer them.
|
||||
#endif
|
||||
}
|
||||
CC2500_SetTxRxMode(TX_EN);
|
||||
CC2500_SetPower(); // Set tx_power
|
||||
}
|
||||
cc2500_strobe(CC2500_SIDLE);
|
||||
cc2500_writeReg(CC2500_0A_CHANNR, get_chan_num(counter % 47));
|
||||
cc2500_writeReg(CC2500_23_FSCAL3, 0x89);
|
||||
cc2500_strobe(CC2500_SFRX);
|
||||
frsky2way_data_frame();
|
||||
cc2500_writeFifo(packet, packet[0]+1);
|
||||
state++;
|
||||
}
|
||||
return state == FRSKY_DATA4 ? 7500 : 9000;
|
||||
}
|
||||
#endif
|
@ -246,7 +246,11 @@ static void __attribute__((unused)) kn_init()
|
||||
|
||||
NRF24L01_Initialize();
|
||||
|
||||
<<<<<<< HEAD
|
||||
NRF24L01_WriteReg(NRF24L01_00_CONFIG, BV(NRF24L01_00_EN_CRC) | BV(NRF24L01_00_CRCO));
|
||||
=======
|
||||
NRF24L01_WriteReg(NRF24L01_00_CONFIG, _BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO));
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknoledgement
|
||||
NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0
|
||||
NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x03); // 5-byte RX/TX address
|
||||
@ -259,7 +263,11 @@ static void __attribute__((unused)) kn_init()
|
||||
NRF24L01_Activate(0x73);
|
||||
NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 1); // Dynamic payload for data pipe 0
|
||||
// Enable: Dynamic Payload Length to enable PCF
|
||||
<<<<<<< HEAD
|
||||
NRF24L01_WriteReg(NRF24L01_1D_FEATURE, BV(NRF2401_1D_EN_DPL));
|
||||
=======
|
||||
NRF24L01_WriteReg(NRF24L01_1D_FEATURE, _BV(NRF2401_1D_EN_DPL));
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
|
||||
NRF24L01_SetPower();
|
||||
|
||||
|
@ -12,7 +12,11 @@
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
<<<<<<< HEAD
|
||||
// compatible with MJX WLH08, X600, X800, H26D
|
||||
=======
|
||||
// compatible with MJX WLH08, X600, X800, H26D, Eachine E010
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
// Last sync with hexfet new_protocols/mjxq_nrf24l01.c dated 2016-01-17
|
||||
|
||||
#if defined(MJXQ_NRF24L01_INO)
|
||||
@ -26,6 +30,8 @@
|
||||
#define MJXQ_RF_NUM_CHANNELS 4
|
||||
#define MJXQ_ADDRESS_LENGTH 5
|
||||
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
// haven't figured out txid<-->rf channel mapping for MJX models
|
||||
const uint8_t PROGMEM MJXQ_map_rfchan[][4] = {
|
||||
{0x0A, 0x46, 0x3A, 0x42},
|
||||
@ -37,6 +43,7 @@ const uint8_t PROGMEM MJXQ_map_txid[][3] = {
|
||||
{0x48, 0x6A, 0x40} };
|
||||
|
||||
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
#define MJXQ_PAN_TILT_COUNT 16 // for H26D - match stock tx timing
|
||||
#define MJXQ_PAN_DOWN 0x08
|
||||
#define MJXQ_PAN_UP 0x04
|
||||
@ -50,6 +57,16 @@ static uint8_t __attribute__((unused)) MJXQ_pan_tilt_value()
|
||||
packet_count++;
|
||||
if(packet_count & MJXQ_PAN_TILT_COUNT)
|
||||
{
|
||||
<<<<<<< HEAD
|
||||
if(Servo_AUX8)
|
||||
pan=MJXQ_PAN_UP;
|
||||
if(Servo_data[AUX8]<PPM_MIN_COMMAND)
|
||||
pan=MJXQ_PAN_DOWN;
|
||||
if(Servo_data[AUX9]>PPM_MIN_COMMAND)
|
||||
pan=MJXQ_TILT_UP;
|
||||
if(Servo_data[AUX9]<PPM_MIN_COMMAND)
|
||||
pan=MJXQ_TILT_DOWN;
|
||||
=======
|
||||
if(Servo_data[AUX8]>PPM_MAX_COMMAND)
|
||||
pan=MJXQ_PAN_UP;
|
||||
if(Servo_data[AUX8]<PPM_MIN_COMMAND)
|
||||
@ -58,6 +75,7 @@ static uint8_t __attribute__((unused)) MJXQ_pan_tilt_value()
|
||||
pan+=MJXQ_TILT_UP;
|
||||
if(Servo_data[AUX9]<PPM_MIN_COMMAND)
|
||||
pan+=MJXQ_TILT_DOWN;
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
}
|
||||
return pan;
|
||||
}
|
||||
@ -68,10 +86,17 @@ static void __attribute__((unused)) MJXQ_send_packet(uint8_t bind)
|
||||
packet[0] = convert_channel_8b(THROTTLE);
|
||||
packet[1] = convert_channel_s8b(RUDDER);
|
||||
packet[4] = 0x40; // rudder does not work well with dyntrim
|
||||
<<<<<<< HEAD
|
||||
packet[2] = convert_channel_s8b(ELEVATOR);
|
||||
packet[5] = MJXQ_CHAN2TRIM(packet[2]); // trim elevator
|
||||
packet[3] = convert_channel_s8b(AILERON);
|
||||
packet[6] = MJXQ_CHAN2TRIM(packet[3]); // trim aileron
|
||||
=======
|
||||
packet[2] = 0x80 ^ convert_channel_s8b(ELEVATOR);
|
||||
packet[5] = GET_FLAG(Servo_AUX5, 1) ? 0x40 : MJXQ_CHAN2TRIM(packet[2]); // trim elevator
|
||||
packet[3] = convert_channel_s8b(AILERON);
|
||||
packet[6] = GET_FLAG(Servo_AUX5, 1) ? 0x40 : MJXQ_CHAN2TRIM(packet[3]); // trim aileron
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
packet[7] = rx_tx_addr[0];
|
||||
packet[8] = rx_tx_addr[1];
|
||||
packet[9] = rx_tx_addr[2];
|
||||
@ -96,7 +121,10 @@ static void __attribute__((unused)) MJXQ_send_packet(uint8_t bind)
|
||||
packet[10]=MJXQ_pan_tilt_value();
|
||||
// fall through on purpose - no break
|
||||
case WLH08:
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
case E010:
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
packet[10] += GET_FLAG(Servo_AUX6, 0x02) //RTH
|
||||
| GET_FLAG(Servo_AUX5, 0x01); //HEADLESS
|
||||
if (!bind)
|
||||
@ -109,6 +137,14 @@ static void __attribute__((unused)) MJXQ_send_packet(uint8_t bind)
|
||||
}
|
||||
break;
|
||||
case X600:
|
||||
<<<<<<< HEAD
|
||||
if(Servo_AUX5) //HEADLESS
|
||||
{ // driven trims cause issues when headless is enabled
|
||||
packet[5] = 0x40;
|
||||
packet[6] = 0x40;
|
||||
}
|
||||
=======
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
packet[10] = GET_FLAG(!Servo_AUX2, 0x02); //LED
|
||||
packet[11] = GET_FLAG(Servo_AUX6, 0x01); //RTH
|
||||
if (!bind)
|
||||
@ -142,7 +178,11 @@ static void __attribute__((unused)) MJXQ_send_packet(uint8_t bind)
|
||||
if (sub_protocol == H26D)
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
else
|
||||
<<<<<<< HEAD
|
||||
XN297_Configure(BV(NRF24L01_00_EN_CRC) | BV(NRF24L01_00_CRCO) | BV(NRF24L01_00_PWR_UP));
|
||||
=======
|
||||
XN297_Configure(_BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO) | _BV(NRF24L01_00_PWR_UP));
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no++ / 2]);
|
||||
hopping_frequency_no %= 2 * MJXQ_RF_NUM_CHANNELS; // channels repeated
|
||||
@ -165,12 +205,20 @@ static void __attribute__((unused)) MJXQ_init()
|
||||
if (sub_protocol == WLH08)
|
||||
memcpy(hopping_frequency, "\x12\x22\x32\x42", MJXQ_RF_NUM_CHANNELS);
|
||||
else
|
||||
<<<<<<< HEAD
|
||||
if (sub_protocol == H26D)
|
||||
=======
|
||||
if (sub_protocol == H26D || sub_protocol == E010)
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
memcpy(hopping_frequency, "\x36\x3e\x46\x2e", MJXQ_RF_NUM_CHANNELS);
|
||||
else
|
||||
{
|
||||
memcpy(hopping_frequency, "\x0a\x35\x42\x3d", MJXQ_RF_NUM_CHANNELS);
|
||||
<<<<<<< HEAD
|
||||
memcpy(addr, "\x6d\x6a\x73\x73\x73", MJXQ_RF_NUM_CHANNELS);
|
||||
=======
|
||||
memcpy(addr, "\x6d\x6a\x73\x73\x73", MJXQ_ADDRESS_LENGTH);
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
}
|
||||
|
||||
|
||||
@ -189,25 +237,53 @@ static void __attribute__((unused)) MJXQ_init()
|
||||
NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0 only
|
||||
NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0x00); // no retransmits
|
||||
NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, MJXQ_PACKET_SIZE); // rx pipe 0 (used only for blue board)
|
||||
<<<<<<< HEAD
|
||||
NRF24L01_SetBitrate(NRF24L01_BR_1M); // 1Mbps
|
||||
=======
|
||||
if (sub_protocol == E010)
|
||||
NRF24L01_SetBitrate(NRF24L01_BR_250K); // 250K
|
||||
else
|
||||
NRF24L01_SetBitrate(NRF24L01_BR_1M); // 1Mbps
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
NRF24L01_SetPower();
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) MJXQ_init2()
|
||||
{
|
||||
<<<<<<< HEAD
|
||||
// haven't figured out txid<-->rf channel mapping for MJX models
|
||||
static const uint8_t rf_map[][4] = {
|
||||
{0x0A, 0x46, 0x3A, 0x42},
|
||||
{0x0A, 0x3C, 0x36, 0x3F},
|
||||
{0x0A, 0x43, 0x36, 0x3F} };
|
||||
if (sub_protocol == H26D)
|
||||
memcpy(hopping_frequency, "\x32\x3e\x42\x4e", MJXQ_RF_NUM_CHANNELS);
|
||||
else
|
||||
if (sub_protocol == WLH08)
|
||||
memcpy(hopping_frequency, rf_map[rx_tx_addr[0]%3], MJXQ_RF_NUM_CHANNELS);
|
||||
=======
|
||||
if (sub_protocol == H26D)
|
||||
memcpy(hopping_frequency, "\x32\x3e\x42\x4e", MJXQ_RF_NUM_CHANNELS);
|
||||
else
|
||||
if (sub_protocol != WLH08 && sub_protocol != E010)
|
||||
for(uint8_t i=0;i<MJXQ_RF_NUM_CHANNELS;i++)
|
||||
hopping_frequency[i]=pgm_read_byte_near( &MJXQ_map_rfchan[rx_tx_addr[4]%3][i] );
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) MJXQ_initialize_txid()
|
||||
{
|
||||
<<<<<<< HEAD
|
||||
// haven't figured out txid<-->rf channel mapping for MJX models
|
||||
static const uint8_t tx_map[][3]={
|
||||
{0xF8, 0x4F, 0x1C},
|
||||
{0xC8, 0x6E, 0x02},
|
||||
{0x48, 0x6A, 0x40} };
|
||||
if (sub_protocol == WLH08)
|
||||
rx_tx_addr[0]&=0xF8; // txid must be multiple of 8
|
||||
else
|
||||
memcpy(rx_tx_addr,tx_map[rx_tx_addr[0]%3],3);
|
||||
=======
|
||||
rx_tx_addr[0]&=0xF8;
|
||||
if (sub_protocol == E010)
|
||||
{
|
||||
@ -217,6 +293,7 @@ static void __attribute__((unused)) MJXQ_initialize_txid()
|
||||
else
|
||||
for(uint8_t i=0;i<3;i++)
|
||||
rx_tx_addr[i]=pgm_read_byte_near( &MJXQ_map_txid[rx_tx_addr[4]%3][i] );
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
}
|
||||
|
||||
uint16_t MJXQ_callback()
|
||||
|
@ -12,7 +12,11 @@
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
<<<<<<< HEAD
|
||||
// compatible with MT99xx, Eachine H7, Yi Zhan i6S
|
||||
=======
|
||||
// compatible with MT99xx, Eachine H7, Yi Zhan i6S and LS114/124
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
// Last sync with Goebish mt99xx_nrf24l01.c dated 2016-01-29
|
||||
|
||||
#if defined(MT99XX_NRF24L01_INO)
|
||||
@ -37,6 +41,8 @@ enum{
|
||||
FLAG_MT_FLIP = 0x80,
|
||||
};
|
||||
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
enum{
|
||||
// flags going to packet[6] (LS)
|
||||
FLAG_LS_INVERT = 0x01,
|
||||
@ -47,12 +53,43 @@ enum{
|
||||
FLAG_LS_FLIP = 0x80,
|
||||
};
|
||||
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
enum {
|
||||
MT99XX_INIT = 0,
|
||||
MT99XX_BIND,
|
||||
MT99XX_DATA
|
||||
};
|
||||
|
||||
<<<<<<< HEAD
|
||||
static void __attribute__((unused)) MT99XX_send_packet()
|
||||
{
|
||||
const uint8_t yz_p4_seq[] = {0xa0, 0x20, 0x60};
|
||||
const uint8_t mys_byte[] = {
|
||||
0x01, 0x11, 0x02, 0x12, 0x03, 0x13, 0x04, 0x14,
|
||||
0x05, 0x15, 0x06, 0x16, 0x07, 0x17, 0x00, 0x10
|
||||
};
|
||||
static uint8_t yz_seq_num=0;
|
||||
|
||||
if(sub_protocol != YZ)
|
||||
{ // MT99XX & H7
|
||||
packet[0] = convert_channel_8b_scale(THROTTLE,0x00,0xE1); // throttle
|
||||
packet[1] = convert_channel_8b_scale(RUDDER ,0x00,0xE1); // rudder
|
||||
packet[2] = convert_channel_8b_scale(AILERON ,0x00,0xE1); // aileron
|
||||
packet[3] = convert_channel_8b_scale(ELEVATOR,0x00,0xE1); // elevator
|
||||
packet[4] = 0x20; // pitch trim (0x3f-0x20-0x00)
|
||||
packet[5] = 0x20; // roll trim (0x00-0x20-0x3f)
|
||||
packet[6] = GET_FLAG( Servo_AUX1, FLAG_MT_FLIP )
|
||||
| GET_FLAG( Servo_AUX3, FLAG_MT_SNAPSHOT )
|
||||
| GET_FLAG( Servo_AUX4, FLAG_MT_VIDEO );
|
||||
if(sub_protocol==MT99)
|
||||
packet[6] |= 0x40 | FLAG_MT_RATE2;
|
||||
else
|
||||
packet[6] |= FLAG_MT_RATE1; // max rate on H7
|
||||
// todo: mys_byte = next channel index ?
|
||||
// low nibble: index in chan list ?
|
||||
// high nibble: 0->start from start of list, 1->start from end of list ?
|
||||
packet[7] = mys_byte[hopping_frequency_no];
|
||||
=======
|
||||
const uint8_t h7_mys_byte[] = {
|
||||
0x01, 0x11, 0x02, 0x12, 0x03, 0x13, 0x04, 0x14,
|
||||
0x05, 0x15, 0x06, 0x16, 0x07, 0x17, 0x00, 0x10
|
||||
@ -101,6 +138,7 @@ static void __attribute__((unused)) MT99XX_send_packet()
|
||||
ls_counter=0;
|
||||
}
|
||||
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
uint8_t result=checksum_offset;
|
||||
for(uint8_t i=0; i<8; i++)
|
||||
result += packet[i];
|
||||
@ -109,9 +147,15 @@ static void __attribute__((unused)) MT99XX_send_packet()
|
||||
else
|
||||
{ // YZ
|
||||
packet[0] = convert_channel_8b_scale(THROTTLE,0x00,0x64); // throttle
|
||||
<<<<<<< HEAD
|
||||
packet[1] = convert_channel_8b_scale(RUDDER ,0x00,0x64); // rudder
|
||||
packet[2] = convert_channel_8b_scale(ELEVATOR,0x00,0x64); // elevator
|
||||
packet[3] = convert_channel_8b_scale(AILERON ,0x00,0x64); // aileron
|
||||
=======
|
||||
packet[1] = convert_channel_8b_scale(RUDDER ,0x64,0x00); // rudder
|
||||
packet[2] = convert_channel_8b_scale(ELEVATOR,0x00,0x64); // elevator
|
||||
packet[3] = convert_channel_8b_scale(AILERON ,0x64,0x00); // aileron
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
if(packet_count++ >= 23)
|
||||
{
|
||||
yz_seq_num ++;
|
||||
@ -132,10 +176,14 @@ static void __attribute__((unused)) MT99XX_send_packet()
|
||||
packet[8] = 0xff;
|
||||
}
|
||||
|
||||
<<<<<<< HEAD
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no] + channel_offset);
|
||||
=======
|
||||
if(sub_protocol == LS)
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, 0x2D); // LS always transmits on the same channel
|
||||
else
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no] + channel_offset);
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
|
||||
NRF24L01_FlushTx();
|
||||
XN297_WritePayload(packet, MT99XX_PACKET_SIZE);
|
||||
@ -153,11 +201,16 @@ static void __attribute__((unused)) MT99XX_send_packet()
|
||||
static void __attribute__((unused)) MT99XX_init()
|
||||
{
|
||||
NRF24L01_Initialize();
|
||||
<<<<<<< HEAD
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
NRF24L01_FlushTx();
|
||||
=======
|
||||
if(sub_protocol == YZ)
|
||||
XN297_SetScrambledMode(XN297_UNSCRAMBLED);
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
NRF24L01_FlushTx();
|
||||
XN297_SetTXAddr((uint8_t *)"\xCC\xCC\xCC\xCC\xCC", 5);
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
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
|
||||
@ -169,18 +222,31 @@ static void __attribute__((unused)) MT99XX_init()
|
||||
NRF24L01_SetBitrate(NRF24L01_BR_1M); // 1Mbps
|
||||
NRF24L01_SetPower();
|
||||
|
||||
<<<<<<< HEAD
|
||||
XN297_Configure(BV(NRF24L01_00_EN_CRC) | BV(NRF24L01_00_CRCO) | BV(NRF24L01_00_PWR_UP) | (sub_protocol == YZ ? BV(XN297_UNSCRAMBLED):0) );
|
||||
|
||||
XN297_SetTXAddr((uint8_t *)"\xCC\xCC\xCC\xCC\xCC", 5);
|
||||
=======
|
||||
XN297_Configure(_BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO) | _BV(NRF24L01_00_PWR_UP) );
|
||||
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) MT99XX_initialize_txid()
|
||||
{
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
rx_tx_addr[3] = 0xCC;
|
||||
rx_tx_addr[4] = 0xCC;
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
if(sub_protocol == YZ)
|
||||
{
|
||||
rx_tx_addr[0] = 0x53; // test (SB id)
|
||||
rx_tx_addr[1] = 0x00;
|
||||
<<<<<<< HEAD
|
||||
}
|
||||
checksum_offset = (rx_tx_addr[0] + rx_tx_addr[1]) & 0xff;
|
||||
=======
|
||||
rx_tx_addr[2] = 0x00;
|
||||
}
|
||||
else
|
||||
@ -189,6 +255,7 @@ static void __attribute__((unused)) MT99XX_initialize_txid()
|
||||
else //MT99 & H7
|
||||
rx_tx_addr[2] = 0x00;
|
||||
checksum_offset = rx_tx_addr[0] + rx_tx_addr[1] + rx_tx_addr[2];
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
channel_offset = (((checksum_offset & 0xf0)>>4) + (checksum_offset & 0x0f)) % 8;
|
||||
}
|
||||
|
||||
@ -200,16 +267,26 @@ uint16_t MT99XX_callback()
|
||||
{
|
||||
if (bind_counter == 0)
|
||||
{
|
||||
<<<<<<< HEAD
|
||||
rx_tx_addr[2] = 0x00;
|
||||
rx_tx_addr[3] = 0xCC;
|
||||
rx_tx_addr[4] = 0xCC;
|
||||
=======
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
// set tx address for data packets
|
||||
XN297_SetTXAddr(rx_tx_addr, 5);
|
||||
BIND_DONE;
|
||||
}
|
||||
else
|
||||
{
|
||||
<<<<<<< HEAD
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no]);
|
||||
=======
|
||||
if(sub_protocol == LS)
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, 0x2D); // LS always transmits on the same channel
|
||||
else
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no]);
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
|
||||
NRF24L01_FlushTx();
|
||||
XN297_WritePayload(packet, MT99XX_PACKET_SIZE); // bind packet
|
||||
@ -236,6 +313,25 @@ uint16_t initMT99XX(void)
|
||||
MT99XX_init();
|
||||
|
||||
packet[0] = 0x20;
|
||||
<<<<<<< HEAD
|
||||
if(sub_protocol!=YZ)
|
||||
{ // MT99 & H7
|
||||
packet_period = MT99XX_PACKET_PERIOD_MT;
|
||||
packet[1] = 0x14;
|
||||
packet[2] = 0x03;
|
||||
packet[3] = 0x25;
|
||||
}
|
||||
else
|
||||
{ // YZ
|
||||
packet_period = MT99XX_PACKET_PERIOD_YZ;
|
||||
packet[1] = 0x15;
|
||||
packet[2] = 0x05;
|
||||
packet[3] = 0x06;
|
||||
}
|
||||
packet[4] = rx_tx_addr[0]; // 1st byte for data state tx address
|
||||
packet[5] = rx_tx_addr[1]; // 2nd byte for data state tx address (always 0x00 on Yi Zhan ?)
|
||||
packet[6] = 0x00; // 3rd byte for data state tx address (always 0x00 ?)
|
||||
=======
|
||||
packet_period = MT99XX_PACKET_PERIOD_MT;
|
||||
switch(sub_protocol)
|
||||
{ // MT99 & H7
|
||||
@ -260,6 +356,7 @@ uint16_t initMT99XX(void)
|
||||
packet[4] = rx_tx_addr[0];
|
||||
packet[5] = rx_tx_addr[1];
|
||||
packet[6] = rx_tx_addr[2];
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
packet[7] = checksum_offset; // checksum offset
|
||||
packet[8] = 0xAA; // fixed
|
||||
packet_count=0;
|
||||
|
@ -1,11 +1,17 @@
|
||||
/*********************************************************
|
||||
Multiprotocol Tx code
|
||||
by Midelic and Pascal Langer(hpnuts)
|
||||
http://www.rcgroups.com/forums/showthread.php?t=2165676
|
||||
Multiprotocol Tx code
|
||||
by Midelic and Pascal Langer(hpnuts)
|
||||
fork by Tipouic
|
||||
http://www.rcgroups.com/forums/showthread.php?t=2165676
|
||||
https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/edit/master/README.md
|
||||
|
||||
<<<<<<< HEAD
|
||||
Thanks to PhracturedBlue, Hexfet, Goebish and all protocol developers
|
||||
Ported from deviation firmware
|
||||
=======
|
||||
Thanks to PhracturedBlue, Hexfet, Goebish, Victzh and all protocol developers
|
||||
Ported from deviation firmware
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
|
||||
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
|
||||
@ -22,12 +28,19 @@
|
||||
*/
|
||||
#include <avr/eeprom.h>
|
||||
#include <avr/pgmspace.h>
|
||||
<<<<<<< HEAD
|
||||
#include <util/delay.h>
|
||||
=======
|
||||
//#define DEBUG_TX
|
||||
#include "Pins.h"
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
#include "Multiprotocol.h"
|
||||
|
||||
//Multiprotocol module configuration file
|
||||
#include "_Config.h"
|
||||
<<<<<<< HEAD
|
||||
|
||||
=======
|
||||
#include "TX_Def.h"
|
||||
|
||||
#ifdef XMEGA
|
||||
@ -40,6 +53,7 @@
|
||||
#define DSM_TELEMETRY // Enable DSM telemetry
|
||||
#endif
|
||||
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
//Global constants/variables
|
||||
uint32_t MProtocol_id;//tx id,
|
||||
uint32_t MProtocol_id_master;
|
||||
@ -53,16 +67,40 @@ uint8_t packet[40];
|
||||
// Servo data
|
||||
uint16_t Servo_data[NUM_CHN];
|
||||
uint8_t Servo_AUX;
|
||||
<<<<<<< HEAD
|
||||
const uint8_t ch[]={AILERON, ELEVATOR, THROTTLE, RUDDER, AUX1, AUX2, AUX3, AUX4};
|
||||
|
||||
// Protocol variables
|
||||
uint8_t rx_tx_addr[5];
|
||||
uint8_t phase;
|
||||
=======
|
||||
uint16_t servo_max_100,servo_min_100,servo_max_125,servo_min_125;
|
||||
|
||||
// Protocol variables
|
||||
uint8_t cyrfmfg_id[6];//for dsm2 and devo
|
||||
uint8_t rx_tx_addr[5];
|
||||
uint8_t phase;
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
uint16_t bind_counter;
|
||||
uint8_t bind_phase;
|
||||
uint8_t binding_idx;
|
||||
uint16_t packet_period;
|
||||
<<<<<<< HEAD
|
||||
uint8_t packet_count;
|
||||
uint8_t packet_sent;
|
||||
uint8_t packet_length;
|
||||
uint8_t hopping_frequency[23];
|
||||
uint8_t *hopping_frequency_ptr;
|
||||
uint8_t hopping_frequency_no=0;
|
||||
uint8_t rf_ch_num;
|
||||
uint8_t throttle, rudder, elevator, aileron;
|
||||
uint8_t flags;
|
||||
uint16_t crc;
|
||||
//
|
||||
uint32_t state;
|
||||
uint8_t len;
|
||||
uint8_t RX_num;
|
||||
=======
|
||||
uint8_t packet_count;
|
||||
uint8_t packet_sent;
|
||||
uint8_t packet_length;
|
||||
@ -89,6 +127,7 @@ const uint8_t CH_AETR[]={AILERON, ELEVATOR, THROTTLE, RUDDER, AUX1, AUX2, AUX3,
|
||||
const uint8_t CH_TAER[]={THROTTLE, AILERON, ELEVATOR, RUDDER, AUX1, AUX2, AUX3, AUX4, AUX5, AUX6, AUX7, AUX8};
|
||||
const uint8_t CH_RETA[]={RUDDER, ELEVATOR, THROTTLE, AILERON, AUX1, AUX2, AUX3, AUX4, AUX5, AUX6, AUX7, AUX8};
|
||||
const uint8_t CH_EATR[]={ELEVATOR, AILERON, THROTTLE, RUDDER, AUX1, AUX2, AUX3, AUX4, AUX5, AUX6, AUX7, AUX8};
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
|
||||
// Mode_select variables
|
||||
uint8_t mode_select;
|
||||
@ -97,10 +136,20 @@ uint8_t protocol_flags=0,protocol_flags2=0;
|
||||
// PPM variable
|
||||
volatile uint16_t PPM_data[NUM_CHN];
|
||||
|
||||
<<<<<<< HEAD
|
||||
// Serial variables
|
||||
#define RXBUFFER_SIZE 25
|
||||
#define TXBUFFER_SIZE 12
|
||||
volatile uint8_t rx_buff[RXBUFFER_SIZE];
|
||||
volatile uint8_t rx_ok_buff[RXBUFFER_SIZE];
|
||||
volatile uint8_t tx_buff[TXBUFFER_SIZE];
|
||||
volatile uint8_t idx = 0;
|
||||
=======
|
||||
#ifndef XMEGA
|
||||
//Random variable
|
||||
volatile uint32_t gWDT_entropy=0;
|
||||
#endif
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
|
||||
//Serial protocol
|
||||
uint8_t sub_protocol;
|
||||
@ -143,6 +192,11 @@ volatile uint8_t discard_frame = 0;
|
||||
#define MAX_PKT 27
|
||||
uint8_t pkt[MAX_PKT];//telemetry receiving packets
|
||||
#if defined(TELEMETRY)
|
||||
<<<<<<< HEAD
|
||||
uint8_t pktt[MAX_PKT];//telemetry receiving packets
|
||||
volatile uint8_t tx_head;
|
||||
volatile uint8_t tx_tail;
|
||||
=======
|
||||
#ifdef INVERT_TELEMETRY
|
||||
// enable bit bash for serial
|
||||
#ifndef XMEGA
|
||||
@ -158,6 +212,7 @@ uint8_t pkt[MAX_PKT];//telemetry receiving packets
|
||||
volatile uint8_t tx_head=0;
|
||||
volatile uint8_t tx_tail=0;
|
||||
#endif // BASH_SERIAL
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
uint8_t v_lipo;
|
||||
int16_t RSSI_dBm;
|
||||
//const uint8_t RSSI_offset=72;//69 71.72 values db
|
||||
@ -229,6 +284,19 @@ void setup()
|
||||
#endif
|
||||
|
||||
// Set Chip selects
|
||||
<<<<<<< HEAD
|
||||
CS_on;
|
||||
CC25_CSN_on;
|
||||
NRF_CSN_on;
|
||||
CYRF_CSN_on;
|
||||
// Set SPI lines
|
||||
SDI_on;
|
||||
SCK_off;
|
||||
|
||||
// Timer1 config
|
||||
TCCR1A = 0;
|
||||
TCCR1B = (1 << CS11); //prescaler8, set timer1 to increment every 0.5us(16Mhz) and start timer
|
||||
=======
|
||||
#ifdef A7105_INSTALLED
|
||||
A7105_CSN_on;
|
||||
#endif
|
||||
@ -244,10 +312,42 @@ void setup()
|
||||
// Set SPI lines
|
||||
SDI_on;
|
||||
SCLK_off;
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
|
||||
// Set servos positions
|
||||
for(uint8_t i=0;i<NUM_CHN;i++)
|
||||
Servo_data[i]=1500;
|
||||
<<<<<<< HEAD
|
||||
Servo_data[THROTTLE]=PPM_MIN_100;
|
||||
memcpy((void *)PPM_data,Servo_data, sizeof(Servo_data));
|
||||
|
||||
//Wait for every component to start
|
||||
delay(100);
|
||||
|
||||
// Read status of bind button
|
||||
if( (PINB & _BV(5)) == 0x00 )
|
||||
BIND_BUTTON_FLAG_on; // If bind button pressed save the status for protocol id reset under hubsan
|
||||
|
||||
// Read status of mode select binary switch
|
||||
// after this mode_select will be one of {0000, 0001, ..., 1111}
|
||||
mode_select=0x0F - ( ( (PINB>>2)&0x07 ) | ( (PINC<<3)&0x08) );//encoder dip switches 1,2,4,8=>B2,B3,B4,C0
|
||||
//**********************************
|
||||
//mode_select=1; // here to test PPM
|
||||
//**********************************
|
||||
|
||||
// Update LED
|
||||
LED_OFF;
|
||||
LED_SET_OUTPUT;
|
||||
|
||||
// Read or create protocol id
|
||||
MProtocol_id_master=random_id(10,false);
|
||||
|
||||
//Init RF modules
|
||||
#ifdef CC2500_INSTALLED
|
||||
CC2500_Reset();
|
||||
#endif
|
||||
|
||||
=======
|
||||
Servo_data[THROTTLE]=servo_min_100;
|
||||
#ifdef ENABLE_PPM
|
||||
memcpy((void *)PPM_data,Servo_data, sizeof(Servo_data));
|
||||
@ -288,12 +388,17 @@ void setup()
|
||||
MProtocol_id_master=random_id(10,false);
|
||||
|
||||
#ifdef ENABLE_PPM
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
//Protocol and interrupts initialization
|
||||
if(mode_select != MODE_SERIAL)
|
||||
{ // PPM
|
||||
mode_select--;
|
||||
<<<<<<< HEAD
|
||||
cur_protocol[0] = PPM_prot[mode_select].protocol;
|
||||
=======
|
||||
protocol = PPM_prot[mode_select].protocol;
|
||||
cur_protocol[1] = protocol;
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
sub_protocol = PPM_prot[mode_select].sub_proto;
|
||||
RX_num = PPM_prot[mode_select].rx_num;
|
||||
MProtocol_id = RX_num + MProtocol_id_master;
|
||||
@ -301,6 +406,16 @@ void setup()
|
||||
if(PPM_prot[mode_select].power) POWER_FLAG_on;
|
||||
if(PPM_prot[mode_select].autobind) AUTOBIND_FLAG_on;
|
||||
mode_select++;
|
||||
<<<<<<< HEAD
|
||||
|
||||
protocol_init();
|
||||
|
||||
//Configure PPM interrupt
|
||||
EICRA |=(1<<ISC11); // The rising edge of INT1 pin D3 generates an interrupt request
|
||||
EIMSK |= (1<<INT1); // INT1 interrupt enable
|
||||
#if defined(TELEMETRY)
|
||||
PPM_Telemetry_serial_init(); // Configure serial for telemetry
|
||||
=======
|
||||
servo_max_100=PPM_MAX_100; servo_min_100=PPM_MIN_100;
|
||||
servo_max_125=PPM_MAX_125; servo_min_125=PPM_MIN_125;
|
||||
|
||||
@ -319,6 +434,7 @@ void setup()
|
||||
|
||||
#if defined(TELEMETRY)
|
||||
PPM_Telemetry_serial_init(); // Configure serial for telemetry
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
#endif
|
||||
}
|
||||
else
|
||||
@ -338,6 +454,39 @@ void setup()
|
||||
// Main
|
||||
// Protocol scheduler
|
||||
void loop()
|
||||
<<<<<<< HEAD
|
||||
{
|
||||
if(mode_select==MODE_SERIAL && IS_RX_FLAG_on) // Serial mode and something has been received
|
||||
{
|
||||
update_serial_data(); // Update protocol and data
|
||||
update_aux_flags();
|
||||
if(IS_CHANGE_PROTOCOL_FLAG_on)
|
||||
{ // Protocol needs to be changed
|
||||
LED_OFF; //led off during protocol init
|
||||
module_reset(); //reset previous module
|
||||
protocol_init(); //init new protocol
|
||||
CHANGE_PROTOCOL_FLAG_off; //done
|
||||
}
|
||||
}
|
||||
if(mode_select!=MODE_SERIAL && IS_PPM_FLAG_on) // PPM mode and a full frame has been received
|
||||
{
|
||||
for(uint8_t i=0;i<NUM_CHN;i++)
|
||||
{ // update servo data without interrupts to prevent bad read in protocols
|
||||
cli(); // disable global int
|
||||
Servo_data[i]=PPM_data[i];
|
||||
sei(); // enable global int
|
||||
}
|
||||
update_aux_flags();
|
||||
PPM_FLAG_off; // wait for next frame before update
|
||||
}
|
||||
update_led_status();
|
||||
#if defined(TELEMETRY)
|
||||
if( ((cur_protocol[0]&0x1F)==MODE_FRSKY) || ((cur_protocol[0]&0x1F)==MODE_HUBSAN) || ((cur_protocol[0]&0x1F)==MODE_FRSKYX) )
|
||||
frskyUpdate();
|
||||
#endif
|
||||
if (remote_callback != 0)
|
||||
CheckTimer(remote_callback);
|
||||
=======
|
||||
{
|
||||
uint16_t next_callback,diff=0xFFFF;
|
||||
|
||||
@ -428,6 +577,7 @@ void Update_All()
|
||||
if((protocol==MODE_FRSKYD) || (protocol==MODE_HUBSAN) || (protocol==MODE_FRSKYX) || (protocol==MODE_DSM) )
|
||||
TelemetryUpdate();
|
||||
#endif
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
}
|
||||
|
||||
// Update Servo_AUX flags based on servo AUX positions
|
||||
@ -444,18 +594,64 @@ static void update_led_status(void)
|
||||
{
|
||||
if(blink<millis())
|
||||
{
|
||||
<<<<<<< HEAD
|
||||
if(cur_protocol[0]==0) // No valid serial received at least once
|
||||
blink+=BLINK_SERIAL_TIME; //blink slowly while waiting a valid serial input
|
||||
=======
|
||||
if(cur_protocol[1]==0) //No valid serial received at least once
|
||||
blink+=BLINK_SERIAL_TIME; //blink slowly while waiting a valid serial input
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
else
|
||||
if(remote_callback == 0)
|
||||
{ // Invalid protocol
|
||||
if(IS_LED_on) //flash to indicate invalid protocol
|
||||
blink+=BLINK_BAD_PROTO_TIME_LOW;
|
||||
else
|
||||
blink+=BLINK_BAD_PROTO_TIME_HIGH;
|
||||
}
|
||||
if(IS_LED_on) //flash to indicate invalid protocol
|
||||
blink+=BLINK_BAD_PROTO_TIME_LOW;
|
||||
else
|
||||
blink+=BLINK_BAD_PROTO_TIME_HIGH;
|
||||
}
|
||||
else
|
||||
if(IS_BIND_DONE_on)
|
||||
<<<<<<< HEAD
|
||||
LED_OFF; //bind completed -> led on
|
||||
else
|
||||
blink+=BLINK_BIND_TIME; //blink fastly during binding
|
||||
LED_TOGGLE;
|
||||
}
|
||||
}
|
||||
|
||||
// Protocol scheduler
|
||||
static void CheckTimer(uint16_t (*cb)(void))
|
||||
{
|
||||
uint16_t next_callback;
|
||||
uint32_t prev;
|
||||
if( (TIFR1 & (1<<OCF1A)) != 0)
|
||||
{
|
||||
cli(); // disable global int
|
||||
OCR1A=TCNT1; // Callback should already have been called... Use "now" as new sync point.
|
||||
sei(); // enable global int
|
||||
}
|
||||
else
|
||||
while((TIFR1 & (1<<OCF1A)) == 0); // wait before callback
|
||||
prev=micros();
|
||||
next_callback=cb();
|
||||
if(prev+next_callback+50 > micros())
|
||||
{ // Callback did not took more than requested time for next callback
|
||||
if(next_callback>32000)
|
||||
{ // next_callback should not be more than 32767 so we will wait here...
|
||||
delayMicroseconds(next_callback-2000);
|
||||
cli(); // disable global int
|
||||
OCR1A=TCNT1+4000;
|
||||
sei(); // enable global int
|
||||
}
|
||||
else
|
||||
{
|
||||
cli(); // disable global int
|
||||
OCR1A+=next_callback*2; // set compare A for callback
|
||||
sei(); // enable global int
|
||||
}
|
||||
TIFR1=(1<<OCF1A); // clear compare A=callback flag
|
||||
}
|
||||
=======
|
||||
LED_off; //bind completed -> led on
|
||||
else
|
||||
blink+=BLINK_BIND_TIME; //blink fastly during binding
|
||||
@ -494,6 +690,7 @@ inline void tx_resume()
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
}
|
||||
|
||||
// Protocol start
|
||||
@ -517,10 +714,227 @@ static void protocol_init()
|
||||
if(IS_BIND_BUTTON_FLAG_on)
|
||||
AUTOBIND_FLAG_on;
|
||||
if(IS_AUTOBIND_FLAG_on)
|
||||
BIND_IN_PROGRESS; // Indicates bind in progress for blinking bind led
|
||||
BIND_IN_PROGRESS; // Indicates bind in progress for blinking bind led
|
||||
else
|
||||
BIND_DONE;
|
||||
|
||||
<<<<<<< HEAD
|
||||
CTRL1_on; //NRF24L01 antenna RF3 by default
|
||||
CTRL2_off; //NRF24L01 antenna RF3 by default
|
||||
|
||||
switch(cur_protocol[0]&0x1F) // Init the requested protocol
|
||||
{
|
||||
#if defined(HM830_NRF24L01_INO)
|
||||
case MODE_HM830:
|
||||
next_callback=HM830_setup();
|
||||
remote_callback = HM830_callback;
|
||||
break;
|
||||
#endif
|
||||
#if defined(CFlie_NRF24L01_INO)
|
||||
case MODE_CFLIE:
|
||||
next_callback=Cflie_setup();
|
||||
remote_callback = cflie_callback;
|
||||
break;
|
||||
#endif
|
||||
#if defined(JOYSWAY_A7105_INO)
|
||||
case MODE_JOYSWAY:
|
||||
next_callback=JOYSWAY_Setup();
|
||||
remote_callback = joysway_cb;
|
||||
break;
|
||||
#endif
|
||||
#if defined(H377_NRF24L01_INO)
|
||||
case MODE_H377:
|
||||
next_callback=h377_setup();
|
||||
remote_callback = h377_cb;
|
||||
break;
|
||||
#endif
|
||||
#if defined(J6PRO_CYRF6936_INO)
|
||||
case MODE_J6PRO:
|
||||
next_callback=j6pro_setup();
|
||||
remote_callback = j6pro_cb;
|
||||
break;
|
||||
#endif
|
||||
#if defined(WK2x01_CYRF6936_INO)
|
||||
case MODE_WK2x01:
|
||||
next_callback=wk_setup();
|
||||
remote_callback = wk_cb;
|
||||
break;
|
||||
#endif
|
||||
#if defined(ESKY150_NRF24L01_INO)
|
||||
case MODE_ESKY150:
|
||||
next_callback=esky150_setup();
|
||||
remote_callback = esky150_callback;
|
||||
break;
|
||||
#endif
|
||||
#if defined(BlueFly_NRF24L01_INO)
|
||||
case MODE_BlueFly:
|
||||
next_callback=BlueFly_setup();
|
||||
remote_callback = bluefly_cb;
|
||||
break;
|
||||
#endif
|
||||
#if defined(HonTai_NRF24L01_INO)
|
||||
case MODE_HonTai:
|
||||
next_callback=ht_setup();
|
||||
remote_callback = ht_callback;
|
||||
break;
|
||||
#endif
|
||||
#if defined(UDI_NRF24L01_INO)
|
||||
case MODE_UDI:
|
||||
next_callback=UDI_setup();
|
||||
remote_callback = UDI_callback;
|
||||
break;
|
||||
#endif
|
||||
#if defined(NE260_NRF24L01_INO)
|
||||
case MODE_NE260:
|
||||
next_callback=NE260_setup();
|
||||
remote_callback = ne260_cb;
|
||||
break;
|
||||
#endif
|
||||
#if defined(SKYARTEC_CC2500_INO)
|
||||
case MODE_SKYARTEC:
|
||||
next_callback=skyartec_setup();
|
||||
remote_callback = skyartec_cb;
|
||||
break;
|
||||
#endif
|
||||
#if defined(FBL100_NRF24L01_INO)
|
||||
case MODE_FBL100:
|
||||
next_callback=fbl_setup();
|
||||
remote_callback = ne260_cb;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined(FLYSKY_A7105_INO)
|
||||
case MODE_FLYSKY:
|
||||
CTRL1_off; //antenna RF1
|
||||
next_callback = initFlySky();
|
||||
remote_callback = ReadFlySky;
|
||||
break;
|
||||
#endif
|
||||
#if defined(HUBSAN_A7105_INO)
|
||||
case MODE_HUBSAN:
|
||||
CTRL1_off; //antenna RF1
|
||||
if(IS_BIND_BUTTON_FLAG_on) random_id(10,true); // Generate new ID if bind button is pressed.
|
||||
next_callback = initHubsan();
|
||||
remote_callback = ReadHubsan;
|
||||
break;
|
||||
#endif
|
||||
#if defined(FRSKY_CC2500_INO)
|
||||
case MODE_FRSKY:
|
||||
CTRL1_off; //antenna RF2
|
||||
CTRL2_on;
|
||||
next_callback = initFrSky_2way();
|
||||
remote_callback = ReadFrSky_2way;
|
||||
break;
|
||||
#endif
|
||||
#if defined(FRSKYX_CC2500_INO)
|
||||
case MODE_FRSKYX:
|
||||
CTRL1_off; //antenna RF2
|
||||
CTRL2_on;
|
||||
next_callback = initFrSkyX();
|
||||
remote_callback = ReadFrSkyX;
|
||||
break;
|
||||
#endif
|
||||
#if defined(DSM2_CYRF6936_INO)
|
||||
case MODE_DSM2:
|
||||
CTRL2_on; //antenna RF4
|
||||
next_callback = initDsm2();
|
||||
//Servo_data[2]=1500;//before binding
|
||||
remote_callback = ReadDsm2;
|
||||
break;
|
||||
#endif
|
||||
#if defined(DEVO_CYRF6936_INO)
|
||||
case MODE_DEVO:
|
||||
CTRL2_on; //antenna RF4
|
||||
next_callback = DevoInit();
|
||||
remote_callback = devo_callback;
|
||||
break;
|
||||
#endif
|
||||
#if defined(HISKY_NRF24L01_INO)
|
||||
case MODE_HISKY:
|
||||
next_callback=initHiSky();
|
||||
remote_callback = hisky_cb;
|
||||
break;
|
||||
#endif
|
||||
#if defined(V2X2_NRF24L01_INO)
|
||||
case MODE_V2X2:
|
||||
next_callback = initV2x2();
|
||||
remote_callback = ReadV2x2;
|
||||
break;
|
||||
#endif
|
||||
#if defined(YD717_NRF24L01_INO)
|
||||
case MODE_YD717:
|
||||
next_callback=initYD717();
|
||||
remote_callback = yd717_callback;
|
||||
break;
|
||||
#endif
|
||||
#if defined(KN_NRF24L01_INO)
|
||||
case MODE_KN:
|
||||
next_callback = initKN();
|
||||
remote_callback = kn_callback;
|
||||
break;
|
||||
#endif
|
||||
#if defined(SYMAX_NRF24L01_INO)
|
||||
case MODE_SYMAX:
|
||||
next_callback = initSymax();
|
||||
remote_callback = symax_callback;
|
||||
break;
|
||||
#endif
|
||||
#if defined(SLT_NRF24L01_INO)
|
||||
case MODE_SLT:
|
||||
next_callback=initSLT();
|
||||
remote_callback = SLT_callback;
|
||||
break;
|
||||
#endif
|
||||
#if defined(CX10_NRF24L01_INO)
|
||||
case MODE_CX10:
|
||||
next_callback=initCX10();
|
||||
remote_callback = CX10_callback;
|
||||
break;
|
||||
#endif
|
||||
#if defined(CG023_NRF24L01_INO)
|
||||
case MODE_CG023:
|
||||
next_callback=initCG023();
|
||||
remote_callback = CG023_callback;
|
||||
break;
|
||||
#endif
|
||||
#if defined(BAYANG_NRF24L01_INO)
|
||||
case MODE_BAYANG:
|
||||
next_callback=initBAYANG();
|
||||
remote_callback = BAYANG_callback;
|
||||
break;
|
||||
#endif
|
||||
#if defined(ESKY_NRF24L01_INO)
|
||||
case MODE_ESKY:
|
||||
next_callback=initESKY();
|
||||
remote_callback = ESKY_callback;
|
||||
break;
|
||||
#endif
|
||||
#if defined(MT99XX_NRF24L01_INO)
|
||||
case MODE_MT99XX:
|
||||
next_callback=initMT99XX();
|
||||
remote_callback = MT99XX_callback;
|
||||
break;
|
||||
#endif
|
||||
#if defined(MJXQ_NRF24L01_INO)
|
||||
case MODE_MJXQ:
|
||||
next_callback=initMJXQ();
|
||||
remote_callback = MJXQ_callback;
|
||||
break;
|
||||
#endif
|
||||
#if defined(SHENQI_NRF24L01_INO)
|
||||
case MODE_SHENQI:
|
||||
next_callback=initSHENQI();
|
||||
remote_callback = SHENQI_callback;
|
||||
break;
|
||||
#endif
|
||||
#if defined(FY326_NRF24L01_INO)
|
||||
case MODE_FY326:
|
||||
next_callback=initFY326();
|
||||
remote_callback = FY326_callback;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
=======
|
||||
PE1_on; //NRF24L01 antenna RF3 by default
|
||||
PE2_off; //NRF24L01 antenna RF3 by default
|
||||
|
||||
@ -721,6 +1135,7 @@ static void protocol_init()
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
|
||||
if(next_callback>32000)
|
||||
{ // next_callback should not be more than 32767 so we will wait here...
|
||||
@ -728,15 +1143,39 @@ static void protocol_init()
|
||||
delayMilliseconds(temp);
|
||||
next_callback-=temp<<10; // between 2-3ms left at this stage
|
||||
}
|
||||
<<<<<<< HEAD
|
||||
cli(); // disable global int
|
||||
OCR1A=TCNT1+next_callback*2; // set compare A for callback
|
||||
sei(); // enable global int
|
||||
TIFR1=(1<<OCF1A); // clear compare A flag
|
||||
BIND_BUTTON_FLAG_off; // do not bind/reset id anymore even if protocol change
|
||||
=======
|
||||
cli(); // disable global int
|
||||
OCR1A = TCNT1 + next_callback*2; // set compare A for callback
|
||||
sei(); // enable global int
|
||||
TIFR1 = OCF1A_bm ; // clear compare A flag
|
||||
BIND_BUTTON_FLAG_off; // do not bind/reset id anymore even if protocol change
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
}
|
||||
|
||||
void update_serial_data()
|
||||
{
|
||||
<<<<<<< HEAD
|
||||
if(rx_ok_buff[0]&0x20) //check range
|
||||
RANGE_FLAG_on;
|
||||
else
|
||||
RANGE_FLAG_off;
|
||||
if(rx_ok_buff[0]&0xC0) //check autobind(0x40) & bind(0x80) together
|
||||
AUTOBIND_FLAG_on;
|
||||
else
|
||||
AUTOBIND_FLAG_off;
|
||||
if(rx_ok_buff[1]&0x80) //if rx_ok_buff[1] ==1,power is low ,0-power high
|
||||
POWER_FLAG_off; //power low
|
||||
else
|
||||
POWER_FLAG_on; //power high
|
||||
|
||||
option=rx_ok_buff[2];
|
||||
=======
|
||||
RX_DONOTUPDTAE_on;
|
||||
RX_FLAG_off; //data is being processed
|
||||
if(rx_ok_buff[1]&0x20) //check range
|
||||
@ -751,11 +1190,29 @@ void update_serial_data()
|
||||
POWER_FLAG_off; //power low
|
||||
else
|
||||
POWER_FLAG_on; //power high
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
|
||||
option=rx_ok_buff[3];
|
||||
|
||||
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
|
||||
<<<<<<< HEAD
|
||||
prev_protocol=cur_protocol[0]&0x1F; //store previous protocol so we can reset the module
|
||||
cur_protocol[1] = rx_ok_buff[1]&0x7F; //store current protocol
|
||||
CHANGE_PROTOCOL_FLAG_on; //change protocol
|
||||
sub_protocol=(rx_ok_buff[1]>>4)& 0x07; //subprotocol no (0-7) bits 4-6
|
||||
RX_num=rx_ok_buff[1]& 0x0F;
|
||||
MProtocol_id=MProtocol_id_master+RX_num; //personalized RX bind + rx num // rx_num bits 0---3
|
||||
}
|
||||
else
|
||||
if( ((rx_ok_buff[0]&0x80)!=0) && ((cur_protocol[0]&0x80)==0) ) // Bind flag has been set
|
||||
CHANGE_PROTOCOL_FLAG_on; //restart protocol with bind
|
||||
cur_protocol[0] = rx_ok_buff[0]; //store current protocol
|
||||
|
||||
// decode channel values
|
||||
volatile uint8_t *p=rx_ok_buff+2;
|
||||
uint8_t dec=-3;
|
||||
=======
|
||||
CHANGE_PROTOCOL_FLAG_on; //change protocol
|
||||
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
|
||||
@ -775,11 +1232,46 @@ void update_serial_data()
|
||||
// decode channel values
|
||||
volatile uint8_t *p=rx_ok_buff+3;
|
||||
uint8_t dec=-3;
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
for(uint8_t i=0;i<NUM_CHN;i++)
|
||||
{
|
||||
dec+=3;
|
||||
dec+=3;
|
||||
if(dec>=8)
|
||||
{
|
||||
<<<<<<< HEAD
|
||||
dec-=8;
|
||||
p++;
|
||||
}
|
||||
p++;
|
||||
Servo_data[i]=((((*((uint32_t *)p))>>dec)&0x7FF)*5)/8+860; //value range 860<->2140 -125%<->+125%
|
||||
}
|
||||
RX_FLAG_off; //data has been processed
|
||||
}
|
||||
|
||||
static void module_reset()
|
||||
{
|
||||
if(remote_callback)
|
||||
{ // previous protocol loaded
|
||||
remote_callback = 0;
|
||||
switch(prev_protocol)
|
||||
{
|
||||
case MODE_FLYSKY:
|
||||
case MODE_HUBSAN:
|
||||
A7105_Reset();
|
||||
break;
|
||||
case MODE_FRSKY:
|
||||
case MODE_FRSKYX:
|
||||
CC2500_Reset();
|
||||
break;
|
||||
case MODE_DSM2:
|
||||
case MODE_DEVO:
|
||||
CYRF_Reset();
|
||||
break;
|
||||
default: // MODE_HISKY, MODE_V2X2, MODE_YD717, MODE_KN, MODE_SYMAX, MODE_SLT, MODE_CX10, MODE_CG023, MODE_BAYANG, MODE_ESKY, MODE_MT99XX, MODE_MJXQ, MODE_SHENQI, MODE_FY326
|
||||
NRF24L01_Reset();
|
||||
break;
|
||||
}
|
||||
=======
|
||||
dec-=8;
|
||||
p++;
|
||||
}
|
||||
@ -796,6 +1288,7 @@ void update_serial_data()
|
||||
{ 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;
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
}
|
||||
#ifdef XMEGA
|
||||
sei();
|
||||
@ -862,15 +1355,35 @@ void Mprotocol_serial_init()
|
||||
#if defined(TELEMETRY)
|
||||
void PPM_Telemetry_serial_init()
|
||||
{
|
||||
<<<<<<< HEAD
|
||||
if(Servo_data[ch]>PPM_MAX_100)
|
||||
return PPM_MAX_100;
|
||||
else
|
||||
if (Servo_data[ch]<PPM_MIN_100)
|
||||
return PPM_MIN_100;
|
||||
return Servo_data[ch];
|
||||
=======
|
||||
if( (protocol==MODE_FRSKYD) || (protocol==MODE_HUBSAN))
|
||||
initTXSerial( SPEED_9600 ) ;
|
||||
if(protocol==MODE_FRSKYX)
|
||||
initTXSerial( SPEED_57600 ) ;
|
||||
if(protocol==MODE_DSM)
|
||||
initTXSerial( SPEED_125K ) ;
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
}
|
||||
#endif
|
||||
|
||||
<<<<<<< HEAD
|
||||
#if defined(TELEMETRY)
|
||||
void Serial_write(uint8_t data)
|
||||
{
|
||||
cli(); // disable global int
|
||||
if(++tx_head>=TXBUFFER_SIZE)
|
||||
tx_head=0;
|
||||
tx_buff[tx_head]=data;
|
||||
sei(); // enable global int
|
||||
UCSR0B |= (1<<UDRIE0);//enable UDRE interrupt
|
||||
=======
|
||||
// Convert 32b id to rx_tx_addr
|
||||
static void set_rx_tx_addr(uint32_t id)
|
||||
{ // Used by almost all protocols
|
||||
@ -889,15 +1402,53 @@ static void random_init(void)
|
||||
WDTCSR |= _BV(WDCE); // WDT control register, This sets the Watchdog Change Enable (WDCE) flag, which is needed to set the prescaler
|
||||
WDTCSR = _BV(WDIE); // Watchdog interrupt enable (WDIE)
|
||||
sei(); // Turn interupts on
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
}
|
||||
|
||||
static uint32_t random_value(void)
|
||||
{
|
||||
<<<<<<< HEAD
|
||||
#include <util/setbaud.h>
|
||||
UBRR0H = UBRRH_VALUE;
|
||||
UBRR0L = UBRRL_VALUE;
|
||||
UCSR0A = 0 ; // Clear X2 bit
|
||||
//Set frame format to 8 data bits, even parity, 2 stop bits
|
||||
UCSR0C = (1<<UPM01)|(1<<USBS0)|(1<<UCSZ01)|(1<<UCSZ00);
|
||||
while ( UCSR0A & (1 << RXC0) )//flush receive buffer
|
||||
UDR0;
|
||||
//enable reception and RC complete interrupt
|
||||
UCSR0B = (1<<RXEN0)|(1<<RXCIE0);//rx enable and interrupt
|
||||
UCSR0B |= (1<<TXEN0);//tx enable
|
||||
=======
|
||||
while (!gWDT_entropy);
|
||||
return gWDT_entropy;
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(TELEMETRY)
|
||||
static void PPM_Telemetry_serial_init()
|
||||
{
|
||||
//9600 bauds
|
||||
UBRR0H = 0x00;
|
||||
UBRR0L = 0x67;
|
||||
UCSR0A = 0 ; // Clear X2 bit
|
||||
//Set frame format to 8 data bits, none, 1 stop bit
|
||||
UCSR0C = (1<<UCSZ01)|(1<<UCSZ00);
|
||||
UCSR0B = (1<<TXEN0);//tx enable
|
||||
}
|
||||
#endif
|
||||
|
||||
// Convert 32b id to rx_tx_addr
|
||||
static void set_rx_tx_addr(uint32_t id)
|
||||
{ // Used by almost all protocols
|
||||
rx_tx_addr[0] = (id >> 24) & 0xFF;
|
||||
rx_tx_addr[1] = (id >> 16) & 0xFF;
|
||||
rx_tx_addr[2] = (id >> 8) & 0xFF;
|
||||
rx_tx_addr[3] = (id >> 0) & 0xFF;
|
||||
rx_tx_addr[4] = 0xC1; // for YD717: always uses first data port
|
||||
}
|
||||
|
||||
static uint32_t random_id(uint16_t adress, uint8_t create_new)
|
||||
{
|
||||
uint32_t id;
|
||||
@ -928,6 +1479,13 @@ static uint32_t random_id(uint16_t adress, uint8_t create_new)
|
||||
/**************************/
|
||||
|
||||
//PPM
|
||||
<<<<<<< HEAD
|
||||
ISR(INT1_vect)
|
||||
{ // Interrupt on PPM pin
|
||||
static int8_t chan=-1;
|
||||
static uint16_t Prev_TCNT1=0;
|
||||
uint16_t Cur_TCNT1;
|
||||
=======
|
||||
#ifdef ENABLE_PPM
|
||||
#ifdef XMEGA
|
||||
#if PPM_pin == 2
|
||||
@ -946,6 +1504,7 @@ static uint32_t random_id(uint16_t adress, uint8_t create_new)
|
||||
static int8_t chan=-1;
|
||||
static uint16_t Prev_TCNT1=0;
|
||||
uint16_t Cur_TCNT1;
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
|
||||
Cur_TCNT1 = TCNT1 - Prev_TCNT1 ; // Capture current Timer1 value
|
||||
if(Cur_TCNT1<1000)
|
||||
@ -956,6 +1515,19 @@ static uint32_t random_id(uint16_t adress, uint8_t create_new)
|
||||
chan=0; // start of frame
|
||||
PPM_FLAG_on; // full frame present (even at startup since PPM_data has been initialized)
|
||||
}
|
||||
<<<<<<< HEAD
|
||||
Prev_TCNT1+=Cur_TCNT1;
|
||||
}
|
||||
|
||||
//Serial RX
|
||||
ISR(USART_RX_vect)
|
||||
{ // RX interrupt
|
||||
if((UCSR0A&0x1C)==0) // Check frame error, data overrun and parity error
|
||||
{ // received byte is ok to process
|
||||
if(idx==0)
|
||||
{ // Let's try to sync at this point
|
||||
if(UDR0==0x55) // If 1st byte is 0x55 it looks ok
|
||||
=======
|
||||
else
|
||||
if(chan!=-1) // need to wait for start of frame
|
||||
{ //servo values between 500us and 2420us will end up here
|
||||
@ -1000,6 +1572,7 @@ static uint32_t random_id(uint16_t adress, uint8_t create_new)
|
||||
}
|
||||
}
|
||||
else
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
{
|
||||
rx_buff[idx++]=UDR0; // Store received byte
|
||||
if(idx>=RXBUFFER_SIZE)
|
||||
@ -1070,4 +1643,30 @@ static uint32_t random_id(uint16_t adress, uint8_t create_new)
|
||||
WDTCSR = 0; // Disable Watchdog interrupt
|
||||
}
|
||||
}
|
||||
<<<<<<< HEAD
|
||||
}
|
||||
|
||||
//Serial timer
|
||||
ISR(TIMER1_COMPB_vect)
|
||||
{ // Timer1 compare B interrupt
|
||||
idx=0;
|
||||
}
|
||||
|
||||
#if defined(TELEMETRY)
|
||||
//Serial TX
|
||||
ISR(USART_UDRE_vect)
|
||||
{ // Transmit interrupt
|
||||
uint8_t t = tx_tail;
|
||||
if(tx_head!=t)
|
||||
{
|
||||
if(++t>=TXBUFFER_SIZE)//head
|
||||
t=0;
|
||||
UDR0=tx_buff[t];
|
||||
tx_tail=t;
|
||||
}
|
||||
if (t == tx_head)
|
||||
UCSR0B &= ~(1<<UDRIE0); // Check if all data is transmitted . if yes disable transmitter UDRE interrupt
|
||||
}
|
||||
=======
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
#endif
|
||||
|
@ -234,7 +234,11 @@ uint8_t NRF24L01_packet_ack()
|
||||
|
||||
///////////////
|
||||
// XN297 emulation layer
|
||||
<<<<<<< HEAD
|
||||
uint8_t xn297_scramble_enabled;
|
||||
=======
|
||||
uint8_t xn297_scramble_enabled=XN297_SCRAMBLED; //enabled by default
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
uint8_t xn297_addr_len;
|
||||
uint8_t xn297_tx_addr[5];
|
||||
uint8_t xn297_rx_addr[5];
|
||||
@ -247,6 +251,16 @@ static const uint8_t xn297_scramble[] = {
|
||||
0x1b, 0x5d, 0x19, 0x10, 0x24, 0xd3, 0xdc, 0x3f,
|
||||
0x8e, 0xc5, 0x2f};
|
||||
|
||||
<<<<<<< HEAD
|
||||
const uint16_t PROGMEM xn297_crc_xorout[] = {
|
||||
0x0000, 0x3d5f, 0xa6f1, 0x3a23, 0xaa16, 0x1caf,
|
||||
0x62b2, 0xe0eb, 0x0821, 0xbe07, 0x5f1a, 0xaf15,
|
||||
0x4f0a, 0xad24, 0x5e48, 0xed34, 0x068c, 0xf2c9,
|
||||
0x1852, 0xdf36, 0x129d, 0xb17c, 0xd5f5, 0x70d7,
|
||||
0xb798, 0x5133, 0x67db, 0xd94e};
|
||||
|
||||
=======
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
const uint16_t PROGMEM xn297_crc_xorout_scrambled[] = {
|
||||
0x0000, 0x3448, 0x9BA7, 0x8BBB, 0x85E1, 0x3E8C,
|
||||
0x451E, 0x18E6, 0x6B24, 0xE7AB, 0x3828, 0x814B,
|
||||
@ -320,8 +334,14 @@ void XN297_SetRXAddr(const uint8_t* addr, uint8_t len)
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, buf, 5);
|
||||
}
|
||||
|
||||
void XN297_Configure(uint8_t flags)
|
||||
void XN297_Configure(uint16_t flags)
|
||||
{
|
||||
<<<<<<< HEAD
|
||||
xn297_scramble_enabled = !(flags & BV(XN297_UNSCRAMBLED));
|
||||
xn297_crc = !!(flags & BV(NRF24L01_00_EN_CRC));
|
||||
flags &= ~(BV(NRF24L01_00_EN_CRC) | BV(NRF24L01_00_CRCO));
|
||||
NRF24L01_WriteReg(NRF24L01_00_CONFIG, flags & 0xFF);
|
||||
=======
|
||||
xn297_crc = !!(flags & _BV(NRF24L01_00_EN_CRC));
|
||||
flags &= ~(_BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO));
|
||||
NRF24L01_WriteReg(NRF24L01_00_CONFIG, flags & 0xFF);
|
||||
@ -330,6 +350,7 @@ void XN297_Configure(uint8_t flags)
|
||||
void XN297_SetScrambledMode(const u8 mode)
|
||||
{
|
||||
xn297_scramble_enabled = mode;
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
}
|
||||
|
||||
void XN297_WritePayload(uint8_t* msg, uint8_t len)
|
||||
@ -391,6 +412,32 @@ void XN297_ReadPayload(uint8_t* msg, uint8_t len)
|
||||
// End of XN297 emulation
|
||||
|
||||
///////////////
|
||||
<<<<<<< HEAD
|
||||
// LT8910 emulation layer
|
||||
uint8_t LT8910_buffer[64];
|
||||
uint8_t LT8910_buffer_start;
|
||||
uint16_t LT8910_buffer_overhead_bits;
|
||||
uint8_t LT8910_addr[8];
|
||||
uint8_t LT8910_addr_size;
|
||||
uint8_t LT8910_Preamble_Len;
|
||||
uint8_t LT8910_Tailer_Len;
|
||||
uint8_t LT8910_CRC_Initial_Data;
|
||||
uint8_t LT8910_Flags;
|
||||
#define LT8910_CRC_ON 6
|
||||
#define LT8910_SCRAMBLE_ON 5
|
||||
#define LT8910_PACKET_LENGTH_EN 4
|
||||
#define LT8910_DATA_PACKET_TYPE_1 3
|
||||
#define LT8910_DATA_PACKET_TYPE_0 2
|
||||
#define LT8910_FEC_TYPE_1 1
|
||||
#define LT8910_FEC_TYPE_0 0
|
||||
|
||||
void LT8910_Config(uint8_t preamble_len, uint8_t trailer_len, uint8_t flags, uint8_t crc_init)
|
||||
{
|
||||
//Preamble 1 to 8 bytes
|
||||
LT8910_Preamble_Len=preamble_len;
|
||||
//Trailer 4 to 18 bits
|
||||
LT8910_Tailer_Len=trailer_len;
|
||||
=======
|
||||
// LT8900 emulation layer
|
||||
uint8_t LT8900_buffer[64];
|
||||
uint8_t LT8900_buffer_start;
|
||||
@ -415,23 +462,37 @@ void LT8900_Config(uint8_t preamble_len, uint8_t trailer_len, uint8_t flags, uin
|
||||
LT8900_Preamble_Len=preamble_len;
|
||||
//Trailer 4 to 18 bits
|
||||
LT8900_Tailer_Len=trailer_len;
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
//Flags
|
||||
// CRC_ON: 1 on, 0 off
|
||||
// SCRAMBLE_ON: 1 on, 0 off
|
||||
// PACKET_LENGTH_EN: 1 1st byte of payload is payload size
|
||||
// DATA_PACKET_TYPE: 00 NRZ, 01 Manchester, 10 8bit/10bit line code, 11 interleave data type
|
||||
// FEC_TYPE: 00 No FEC, 01 FEC13, 10 FEC23, 11 reserved
|
||||
<<<<<<< HEAD
|
||||
LT8910_Flags=flags;
|
||||
//CRC init constant
|
||||
LT8910_CRC_Initial_Data=crc_init;
|
||||
}
|
||||
|
||||
void LT8910_SetChannel(uint8_t channel)
|
||||
=======
|
||||
LT8900_Flags=flags;
|
||||
//CRC init constant
|
||||
LT8900_CRC_Initial_Data=crc_init;
|
||||
}
|
||||
|
||||
void LT8900_SetChannel(uint8_t channel)
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
{
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, channel +2); //NRF24L01 is 2400+channel but LT8900 is 2402+channel
|
||||
}
|
||||
|
||||
<<<<<<< HEAD
|
||||
void LT8910_SetTxRxMode(enum TXRX_State mode)
|
||||
=======
|
||||
void LT8900_SetTxRxMode(enum TXRX_State mode)
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
{
|
||||
if(mode == TX_EN)
|
||||
{
|
||||
@ -457,12 +518,35 @@ void LT8900_SetTxRxMode(enum TXRX_State mode)
|
||||
NRF24L01_SetTxRxMode(TXRX_OFF);
|
||||
}
|
||||
|
||||
<<<<<<< HEAD
|
||||
void LT8910_BuildOverhead()
|
||||
=======
|
||||
void LT8900_BuildOverhead()
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
{
|
||||
uint8_t pos;
|
||||
|
||||
//Build overhead
|
||||
//preamble
|
||||
<<<<<<< HEAD
|
||||
memset(LT8910_buffer,LT8910_addr[0]&0x01?0xAA:0x55,LT8910_Preamble_Len-1);
|
||||
pos=LT8910_Preamble_Len-1;
|
||||
//address
|
||||
for(uint8_t i=0;i<LT8910_addr_size;i++)
|
||||
{
|
||||
LT8910_buffer[pos]=bit_reverse(LT8910_addr[i]);
|
||||
pos++;
|
||||
}
|
||||
//trailer
|
||||
memset(LT8910_buffer+pos,(LT8910_buffer[pos-1]&0x01)==0?0xAA:0x55,3);
|
||||
LT8910_buffer_overhead_bits=pos*8+LT8910_Tailer_Len;
|
||||
//nrf address length max is 5
|
||||
pos+=LT8910_Tailer_Len/8;
|
||||
LT8910_buffer_start=pos>5?5:pos;
|
||||
}
|
||||
|
||||
void LT8910_SetAddress(uint8_t *address,uint8_t addr_size)
|
||||
=======
|
||||
memset(LT8900_buffer,LT8900_addr[0]&0x01?0xAA:0x55,LT8900_Preamble_Len-1);
|
||||
pos=LT8900_Preamble_Len-1;
|
||||
//address
|
||||
@ -480,10 +564,33 @@ void LT8900_BuildOverhead()
|
||||
}
|
||||
|
||||
void LT8900_SetAddress(uint8_t *address,uint8_t addr_size)
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
{
|
||||
uint8_t addr[5];
|
||||
|
||||
//Address size (SyncWord) 2 to 8 bytes, 16/32/48/64 bits
|
||||
<<<<<<< HEAD
|
||||
LT8910_addr_size=addr_size;
|
||||
memcpy(LT8910_addr,address,LT8910_addr_size);
|
||||
|
||||
//Build overhead
|
||||
LT8910_BuildOverhead();
|
||||
|
||||
//Set NRF RX&TX address based on overhead content
|
||||
NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, LT8910_buffer_start-2);
|
||||
for(uint8_t i=0;i<LT8910_buffer_start;i++) // reverse bytes order
|
||||
addr[i]=LT8910_buffer[LT8910_buffer_start-i-1];
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, addr,LT8910_buffer_start);
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, addr,LT8910_buffer_start);
|
||||
}
|
||||
|
||||
uint8_t LT8910_ReadPayload(uint8_t* msg, uint8_t len)
|
||||
{
|
||||
uint8_t i,pos=0,shift,end,buffer[32];
|
||||
unsigned int crc=LT8910_CRC_Initial_Data,a;
|
||||
pos=LT8910_buffer_overhead_bits/8-LT8910_buffer_start;
|
||||
end=pos+len+(LT8910_Flags&_BV(LT8910_PACKET_LENGTH_EN)?1:0)+(LT8910_Flags&_BV(LT8910_CRC_ON)?2:0);
|
||||
=======
|
||||
LT8900_addr_size=addr_size;
|
||||
for (uint8_t i = 0; i < addr_size; i++)
|
||||
LT8900_addr[i] = address[addr_size-1-i];
|
||||
@ -505,14 +612,22 @@ uint8_t LT8900_ReadPayload(uint8_t* msg, uint8_t len)
|
||||
unsigned int crc=LT8900_CRC_Initial_Data,a;
|
||||
pos=LT8900_buffer_overhead_bits/8-LT8900_buffer_start;
|
||||
end=pos+len+(LT8900_Flags&_BV(LT8900_PACKET_LENGTH_EN)?1:0)+(LT8900_Flags&_BV(LT8900_CRC_ON)?2:0);
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
//Read payload
|
||||
NRF24L01_ReadPayload(buffer,end+1);
|
||||
//Check address + trail
|
||||
for(i=0;i<pos;i++)
|
||||
<<<<<<< HEAD
|
||||
if(LT8910_buffer[LT8910_buffer_start+i]!=buffer[i])
|
||||
return 0; // wrong address...
|
||||
//Shift buffer to remove trail bits
|
||||
shift=LT8910_buffer_overhead_bits&0x7;
|
||||
=======
|
||||
if(LT8900_buffer[LT8900_buffer_start+i]!=buffer[i])
|
||||
return 0; // wrong address...
|
||||
//Shift buffer to remove trail bits
|
||||
shift=LT8900_buffer_overhead_bits&0x7;
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
for(i=pos;i<end;i++)
|
||||
{
|
||||
a=(buffer[i]<<8)+buffer[i+1];
|
||||
@ -520,7 +635,11 @@ uint8_t LT8900_ReadPayload(uint8_t* msg, uint8_t len)
|
||||
buffer[i]=(a>>8)&0xFF;
|
||||
}
|
||||
//Check len
|
||||
<<<<<<< HEAD
|
||||
if(LT8910_Flags&_BV(LT8910_PACKET_LENGTH_EN))
|
||||
=======
|
||||
if(LT8900_Flags&_BV(LT8900_PACKET_LENGTH_EN))
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
{
|
||||
crc=crc16_update(crc,buffer[pos]);
|
||||
if(bit_reverse(len)!=buffer[pos++])
|
||||
@ -533,7 +652,11 @@ uint8_t LT8900_ReadPayload(uint8_t* msg, uint8_t len)
|
||||
msg[i]=bit_reverse(buffer[pos++]);
|
||||
}
|
||||
//Check CRC
|
||||
<<<<<<< HEAD
|
||||
if(LT8910_Flags&_BV(LT8910_CRC_ON))
|
||||
=======
|
||||
if(LT8900_Flags&_BV(LT8900_CRC_ON))
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
{
|
||||
if(buffer[pos++]!=((crc>>8)&0xFF)) return 0; // wrong CRC...
|
||||
if(buffer[pos]!=(crc&0xFF)) return 0; // wrong CRC...
|
||||
@ -542,12 +665,21 @@ uint8_t LT8900_ReadPayload(uint8_t* msg, uint8_t len)
|
||||
return 1;
|
||||
}
|
||||
|
||||
<<<<<<< HEAD
|
||||
void LT8910_WritePayload(uint8_t* msg, uint8_t len)
|
||||
{
|
||||
unsigned int crc=LT8910_CRC_Initial_Data,a,mask;
|
||||
uint8_t i, pos=0,tmp, buffer[64], pos_final,shift;
|
||||
//Add packet len
|
||||
if(LT8910_Flags&_BV(LT8910_PACKET_LENGTH_EN))
|
||||
=======
|
||||
void LT8900_WritePayload(uint8_t* msg, uint8_t len)
|
||||
{
|
||||
unsigned int crc=LT8900_CRC_Initial_Data,a,mask;
|
||||
uint8_t i, pos=0,tmp, buffer[64], pos_final,shift;
|
||||
//Add packet len
|
||||
if(LT8900_Flags&_BV(LT8900_PACKET_LENGTH_EN))
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
{
|
||||
tmp=bit_reverse(len);
|
||||
buffer[pos++]=tmp;
|
||||
@ -561,12 +693,27 @@ void LT8900_WritePayload(uint8_t* msg, uint8_t len)
|
||||
crc=crc16_update(crc,tmp);
|
||||
}
|
||||
//Add CRC
|
||||
<<<<<<< HEAD
|
||||
if(LT8910_Flags&_BV(LT8910_CRC_ON))
|
||||
=======
|
||||
if(LT8900_Flags&_BV(LT8900_CRC_ON))
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
{
|
||||
buffer[pos++]=crc>>8;
|
||||
buffer[pos++]=crc;
|
||||
}
|
||||
//Shift everything to fit behind the trailer (4 to 18 bits)
|
||||
<<<<<<< HEAD
|
||||
shift=LT8910_buffer_overhead_bits&0x7;
|
||||
pos_final=LT8910_buffer_overhead_bits/8;
|
||||
mask=~(0xFF<<(8-shift));
|
||||
LT8910_buffer[pos_final+pos]=0xFF;
|
||||
for(i=pos-1;i!=0xFF;i--)
|
||||
{
|
||||
a=buffer[i]<<(8-shift);
|
||||
LT8910_buffer[pos_final+i]=(LT8910_buffer[pos_final+i]&mask>>8)|a>>8;
|
||||
LT8910_buffer[pos_final+i+1]=(LT8910_buffer[pos_final+i+1]&mask)|a;
|
||||
=======
|
||||
shift=LT8900_buffer_overhead_bits&0x7;
|
||||
pos_final=LT8900_buffer_overhead_bits/8;
|
||||
mask=~(0xFF<<(8-shift));
|
||||
@ -576,10 +723,17 @@ void LT8900_WritePayload(uint8_t* msg, uint8_t len)
|
||||
a=buffer[i]<<(8-shift);
|
||||
LT8900_buffer[pos_final+i]=(LT8900_buffer[pos_final+i]&mask>>8)|a>>8;
|
||||
LT8900_buffer[pos_final+i+1]=(LT8900_buffer[pos_final+i+1]&mask)|a;
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
}
|
||||
if(shift)
|
||||
pos++;
|
||||
//Send everything
|
||||
<<<<<<< HEAD
|
||||
NRF24L01_WritePayload(LT8910_buffer+LT8910_buffer_start,pos_final+pos-LT8910_buffer_start);
|
||||
}
|
||||
// End of LT8910 emulation
|
||||
=======
|
||||
NRF24L01_WritePayload(LT8900_buffer+LT8900_buffer_start,pos_final+pos-LT8900_buffer_start);
|
||||
}
|
||||
// End of LT8900 emulation
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
|
150
Multiprotocol/Nrf24l01_bluefly.ino
Normal file
150
Multiprotocol/Nrf24l01_bluefly.ino
Normal file
@ -0,0 +1,150 @@
|
||||
/*
|
||||
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.
|
||||
|
||||
Deviation 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 Deviation. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if defined(BlueFly_NRF24L01_INO)
|
||||
#include "iface_nrf24l01.h"
|
||||
|
||||
#define BIND_BlueFly_COUNT 800
|
||||
|
||||
#define TXID_BlueFly_SIZE 5
|
||||
|
||||
#define PAYLOAD_BlueFly_SIZE 12
|
||||
// available frequency must be in between 2402 and 2477
|
||||
static uint8_t hopping_frequency_start;
|
||||
|
||||
static uint8_t bluefly_binding_adr_rf[TXID_BlueFly_SIZE]={0x32,0xaa,0x45,0x45,0x78}; // fixed binding ids for all planes
|
||||
|
||||
static uint8_t bind_payload[PAYLOAD_BlueFly_SIZE];
|
||||
|
||||
static unsigned int ch_data_bluefly[8];
|
||||
|
||||
|
||||
static void bluefly_binding_packet(void)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < TXID_BlueFly_SIZE; ++i)
|
||||
bind_payload[i] = rx_tx_addr[i];
|
||||
bind_payload[i++] = hopping_frequency_start;
|
||||
for (; i < PAYLOAD_BlueFly_SIZE; ++i) bind_payload[i] = 0x55;
|
||||
}
|
||||
|
||||
static void bluefly_init() {
|
||||
NRF24L01_Initialize();
|
||||
|
||||
NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable p0 rx
|
||||
NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknoledgement
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_addr, 5);
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, rx_tx_addr, 5);
|
||||
NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, PAYLOAD_BlueFly_SIZE); // payload size = 12
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, 81); // binding packet must be set in channel 81
|
||||
|
||||
// 2-bytes CRC, radio on
|
||||
NRF24L01_WriteReg(NRF24L01_00_CONFIG, BV(NRF24L01_00_EN_CRC) | BV(NRF24L01_00_CRCO) | BV(NRF24L01_00_PWR_UP));
|
||||
NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x03); // 5-byte RX/TX address (byte -2)
|
||||
NRF24L01_SetBitrate(NRF24L01_BR_250K); // BlueFly - 250kbps
|
||||
NRF24L01_SetPower();
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
|
||||
}
|
||||
|
||||
// HiSky channel sequence: AILE ELEV THRO RUDD GEAR PITCH, channel data value is from 0 to 1000
|
||||
static void bluefly_ch_data() {
|
||||
uint32_t temp;
|
||||
int i;
|
||||
for (i = 0; i< 8; ++i) {
|
||||
temp = (uint32_t)Servo_data[ch[i]] * 300/PPM_MAX + 500; // 200-800 range
|
||||
if (temp < 0)
|
||||
ch_data_bluefly[i] = 0;
|
||||
else if (temp > 1000)
|
||||
ch_data_bluefly[i] = 1000;
|
||||
else
|
||||
ch_data_bluefly[i] = (unsigned int)temp;
|
||||
|
||||
packet[i] = (uint8_t)ch_data_bluefly[i];
|
||||
}
|
||||
|
||||
packet[8] = (uint8_t)((ch_data_bluefly[0]>>8)&0x0003);
|
||||
packet[8] |= (uint8_t)((ch_data_bluefly[1]>>6)&0x000c);
|
||||
packet[8] |= (uint8_t)((ch_data_bluefly[2]>>4)&0x0030);
|
||||
packet[8] |= (uint8_t)((ch_data_bluefly[3]>>2)&0x00c0);
|
||||
|
||||
packet[9] = (uint8_t)((ch_data_bluefly[4]>>8)&0x0003);
|
||||
packet[9] |= (uint8_t)((ch_data_bluefly[5]>>6)&0x000c);
|
||||
packet[9] |= (uint8_t)((ch_data_bluefly[6]>>4)&0x0030);
|
||||
packet[9] |= (uint8_t)((ch_data_bluefly[7]>>2)&0x00c0);
|
||||
|
||||
unsigned char l, h, t;
|
||||
l = h = 0xff;
|
||||
for (int i=0; i<10; ++i) {
|
||||
h ^= packet[i];
|
||||
h ^= h >> 4;
|
||||
t = h;
|
||||
h = l;
|
||||
l = t;
|
||||
t = (l<<4) | (l>>4);
|
||||
h ^= ((t<<2) | (t>>6)) & 0x1f;
|
||||
h ^= t & 0xf0;
|
||||
l ^= ((t<<1) | (t>>7)) & 0xe0;
|
||||
}
|
||||
// Checksum
|
||||
packet[10] = h;
|
||||
packet[11] = l;
|
||||
}
|
||||
|
||||
static uint16_t bluefly_cb() {
|
||||
switch(phase++) {
|
||||
case 0:
|
||||
bluefly_ch_data();
|
||||
break;
|
||||
case 1:
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_addr, 5);
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency_start + hopping_frequency_no*2);
|
||||
hopping_frequency_no++;
|
||||
hopping_frequency_no %= 15;
|
||||
NRF24L01_FlushTx();
|
||||
NRF24L01_WritePayload(packet, PAYLOAD_BlueFly_SIZE);
|
||||
break;
|
||||
case 2:
|
||||
break;
|
||||
case 3:
|
||||
if (bind_phase>0) {
|
||||
bind_phase--;
|
||||
if (! bind_phase) { BIND_DONE; }
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, bluefly_binding_adr_rf, 5);
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, 81);
|
||||
NRF24L01_FlushTx();
|
||||
NRF24L01_WritePayload(bind_payload, PAYLOAD_BlueFly_SIZE);
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
break;
|
||||
case 5:
|
||||
NRF24L01_SetPower();
|
||||
/* FALLTHROUGH */
|
||||
default:
|
||||
phase = 0;
|
||||
break;
|
||||
}
|
||||
return 1000; // send 1 binding packet and 1 data packet per 9ms
|
||||
}
|
||||
|
||||
static uint16_t BlueFly_setup() {
|
||||
hopping_frequency_start = ((MProtocol_id >> 8) % 47) + 2;
|
||||
bluefly_binding_packet();
|
||||
bluefly_init();
|
||||
if(IS_AUTOBIND_FLAG_on) { bind_phase = BIND_BlueFly_COUNT; } else { bind_phase = 0; }
|
||||
|
||||
return 1000;
|
||||
}
|
||||
#endif
|
318
Multiprotocol/Nrf24l01_cflie.ino
Normal file
318
Multiprotocol/Nrf24l01_cflie.ino
Normal file
@ -0,0 +1,318 @@
|
||||
/*
|
||||
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.
|
||||
|
||||
Deviation 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 Deviation. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* NB: Not implemented
|
||||
Uncomment define below to enable telemetry. Also add CFlie protocol to TELEMETRY_SetTypeByProtocol to set type to DSM.
|
||||
#define CFLIE_TELEMETRY
|
||||
*/
|
||||
|
||||
|
||||
#if defined(CFlie_NRF24L01_INO)
|
||||
#include "iface_nrf24l01.h"
|
||||
|
||||
#define BIND_COUNT 60
|
||||
|
||||
// Address size
|
||||
#define TX_ADDR_SIZE 5
|
||||
|
||||
// Timeout for callback in uSec, 10ms=10000us for Crazyflie
|
||||
#define PACKET_PERIOD 10000
|
||||
|
||||
|
||||
// For code readability
|
||||
enum {
|
||||
CHANNEL1 = 0,
|
||||
CHANNEL2,
|
||||
CHANNEL3,
|
||||
CHANNEL4,
|
||||
CHANNEL5,
|
||||
CHANNEL6,
|
||||
CHANNEL7,
|
||||
CHANNEL8,
|
||||
CHANNEL9,
|
||||
CHANNEL10
|
||||
};
|
||||
|
||||
#define PAYLOADSIZE 8 // receive data pipes set to this size, but unused
|
||||
#define MAX_PACKET_SIZE 9 // YD717 packets have 8-byte payload, Syma X4 is 9
|
||||
|
||||
//static uint8_t packet[MAX_PACKET_SIZE];
|
||||
|
||||
static uint8_t data_rate, rf_channel;
|
||||
|
||||
enum {
|
||||
CFLIE_INIT_SEARCH = 0,
|
||||
CFLIE_INIT_DATA,
|
||||
CFLIE_SEARCH,
|
||||
CFLIE_DATA
|
||||
};
|
||||
|
||||
#ifdef CFLIE_TELEMETRY
|
||||
static const char * const cflie_opts[] = {
|
||||
_tr_noop("Telemetry"), _tr_noop("Off"), _tr_noop("On"), NULL,
|
||||
NULL
|
||||
};
|
||||
enum {
|
||||
PROTOOPTS_TELEMETRY = 0,
|
||||
LAST_PROTO_OPT,
|
||||
};
|
||||
ctassert(LAST_PROTO_OPT <= NUM_PROTO_OPTS, too_many_protocol_opts);
|
||||
|
||||
#define TELEM_OFF 0
|
||||
#define TELEM_ON 1
|
||||
#endif
|
||||
|
||||
#define PACKET_CHKTIME 500 // time to wait if packet not yet acknowledged or timed out
|
||||
|
||||
static uint16_t dbg_cnt = 0;
|
||||
static uint8_t packet_ack() {
|
||||
if (++dbg_cnt > 50) { dbg_cnt = 0; }
|
||||
switch (NRF24L01_ReadReg(NRF24L01_07_STATUS) & (BV(NRF24L01_07_TX_DS) | BV(NRF24L01_07_MAX_RT))) {
|
||||
case BV(NRF24L01_07_TX_DS):
|
||||
return PKT_ACKED;
|
||||
case BV(NRF24L01_07_MAX_RT):
|
||||
return PKT_TIMEOUT;
|
||||
}
|
||||
return PKT_PENDING;
|
||||
}
|
||||
|
||||
static void set_rate_channel(uint8_t rate, uint8_t channel) {
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, channel); // Defined by model id
|
||||
NRF24L01_SetBitrate(rate); // Defined by model id
|
||||
}
|
||||
|
||||
static void send_search_packet() {
|
||||
uint8_t buf[1];
|
||||
buf[0] = 0xff;
|
||||
// clear packet status bits and TX FIFO
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, (BV(NRF24L01_07_TX_DS) | BV(NRF24L01_07_MAX_RT)));
|
||||
NRF24L01_FlushTx();
|
||||
|
||||
if (rf_channel++ > 125) {
|
||||
rf_channel = 0;
|
||||
switch(data_rate) {
|
||||
case NRF24L01_BR_250K:
|
||||
data_rate = NRF24L01_BR_1M;
|
||||
break;
|
||||
case NRF24L01_BR_1M:
|
||||
data_rate = NRF24L01_BR_2M;
|
||||
break;
|
||||
case NRF24L01_BR_2M:
|
||||
data_rate = NRF24L01_BR_250K;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
set_rate_channel(data_rate, rf_channel);
|
||||
|
||||
NRF24L01_WritePayload(buf, sizeof(buf));
|
||||
|
||||
++packet_counter;
|
||||
}
|
||||
|
||||
// Frac 16.16
|
||||
#define FRAC_MANTISSA 16
|
||||
#define FRAC_SCALE (1 << FRAC_MANTISSA)
|
||||
|
||||
// Convert fractional 16.16 to float32
|
||||
static void frac2float(uint32_t n, float* res) {
|
||||
if (n == 0) {
|
||||
*res = 0.0;
|
||||
return;
|
||||
}
|
||||
uint32_t m = n < 0 ? -n : n;
|
||||
int i;
|
||||
for (i = (31-FRAC_MANTISSA); (m & 0x80000000) == 0; i--, m <<= 1) ;
|
||||
m <<= 1; // Clear implicit leftmost 1
|
||||
m >>= 9;
|
||||
uint32_t e = 127 + i;
|
||||
if (n < 0) m |= 0x80000000;
|
||||
m |= e << 23;
|
||||
*((uint32_t *) res) = m;
|
||||
}
|
||||
|
||||
static void send_cmd_packet() {
|
||||
// Commander packet, 15 bytes
|
||||
uint8_t buf[15];
|
||||
float x_roll, x_pitch, yaw;
|
||||
|
||||
// Channels in AETR order
|
||||
|
||||
// Roll, aka aileron, float +- 50.0 in degrees
|
||||
// float roll = -(float) Servo_data[AILERON]*50.0/10000;
|
||||
uint32_t f_roll = -Servo_data[AILERON] * FRAC_SCALE / (10000 / 50);
|
||||
|
||||
// Pitch, aka elevator, float +- 50.0 degrees
|
||||
//float pitch = -(float) Servo_data[ELEVATOR]*50.0/10000;
|
||||
uint32_t f_pitch = -Servo_data[ELEVATOR] * FRAC_SCALE / (10000 / 50);
|
||||
|
||||
// Thrust, aka throttle 0..65535, working range 5535..65535
|
||||
// No space for overshoot here, hard limit Channel3 by -10000..10000
|
||||
uint32_t ch = Servo_data[THROTTLE];
|
||||
if (ch < PPM_MIN) {
|
||||
ch = PPM_MIN;
|
||||
} else if (ch > PPM_MAX) {
|
||||
ch = PPM_MAX;
|
||||
}
|
||||
uint16_t thrust = ch*3L + 35535L;
|
||||
|
||||
// Yaw, aka rudder, float +- 400.0 deg/s
|
||||
// float yaw = -(float) Servo_data[RUDDER]*400.0/10000;
|
||||
uint32_t f_yaw = - Servo_data[RUDDER] * FRAC_SCALE / (10000 / 400);
|
||||
frac2float(f_yaw, &yaw);
|
||||
|
||||
// Convert + to X. 181 / 256 = 0.70703125 ~= sqrt(2) / 2
|
||||
uint32_t f_x_roll = (f_roll + f_pitch) * 181 / 256;
|
||||
frac2float(f_x_roll, &x_roll);
|
||||
uint32_t f_x_pitch = (f_pitch - f_roll) * 181 / 256;
|
||||
frac2float(f_x_pitch, &x_pitch);
|
||||
|
||||
int bufptr = 0;
|
||||
buf[bufptr++] = 0x30; // Commander packet to channel 0
|
||||
memcpy(&buf[bufptr], (char*) &x_roll, 4); bufptr += 4;
|
||||
memcpy(&buf[bufptr], (char*) &x_pitch, 4); bufptr += 4;
|
||||
memcpy(&buf[bufptr], (char*) &yaw, 4); bufptr += 4;
|
||||
memcpy(&buf[bufptr], (char*) &thrust, 2); bufptr += 2;
|
||||
|
||||
|
||||
// clear packet status bits and TX FIFO
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, (BV(NRF24L01_07_TX_DS) | BV(NRF24L01_07_MAX_RT)));
|
||||
NRF24L01_FlushTx();
|
||||
|
||||
NRF24L01_WritePayload(buf, sizeof(buf));
|
||||
|
||||
++packet_counter;
|
||||
|
||||
NRF24L01_SetPower();
|
||||
}
|
||||
|
||||
static int cflie_init() {
|
||||
NRF24L01_Initialize();
|
||||
|
||||
// CRC, radio on
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
NRF24L01_WriteReg(NRF24L01_00_CONFIG, BV(NRF24L01_00_EN_CRC) | BV(NRF24L01_00_CRCO) | BV(NRF24L01_00_PWR_UP));
|
||||
// NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknowledgement
|
||||
NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x01); // Auto Acknowledgement for data pipe 0
|
||||
NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0
|
||||
NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, TX_ADDR_SIZE-2); // 5-byte RX/TX address
|
||||
NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0x13); // 3 retransmits, 500us delay
|
||||
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, rf_channel); // Defined by model id
|
||||
NRF24L01_SetBitrate(data_rate); // Defined by model id
|
||||
|
||||
NRF24L01_SetPower();
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
|
||||
|
||||
NRF24L01_WriteReg(NRF24L01_17_FIFO_STATUS, 0x00); // Just in case, no real bits to write here
|
||||
|
||||
// this sequence necessary for module from stock tx
|
||||
NRF24L01_ReadReg(NRF24L01_1D_FEATURE);
|
||||
NRF24L01_Activate(0x73); // Activate feature register
|
||||
NRF24L01_ReadReg(NRF24L01_1D_FEATURE);
|
||||
|
||||
NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 0x01); // Enable Dynamic Payload Length on pipe 0
|
||||
NRF24L01_WriteReg(NRF24L01_1D_FEATURE, 0x06); // Enable Dynamic Payload Length, enable Payload with ACK
|
||||
|
||||
|
||||
// NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, rx_tx_addr, TX_ADDR_SIZE);
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_addr, TX_ADDR_SIZE);
|
||||
|
||||
NRF24L01_Activate(0x53); // switch bank back
|
||||
|
||||
// 50ms delay in callback
|
||||
return 50000;
|
||||
}
|
||||
|
||||
|
||||
#ifdef CFLIE_TELEMETRY
|
||||
static void update_telemetry() {
|
||||
static uint8_t frameloss = 0;
|
||||
|
||||
frameloss += NRF24L01_ReadReg(NRF24L01_08_OBSERVE_TX) >> 4;
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, rf_channel); // reset packet loss counter
|
||||
|
||||
Telemetry.p.dsm.flog.frameloss = frameloss;
|
||||
// Telemetry.p.dsm.flog.volt[0] = read battery voltage from ack payload
|
||||
TELEMETRY_SetUpdated(TELEM_DSM_FLOG_FRAMELOSS);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static uint16_t cflie_callback() {
|
||||
switch (phase) {
|
||||
case CFLIE_INIT_SEARCH:
|
||||
send_search_packet();
|
||||
phase = CFLIE_SEARCH;
|
||||
break;
|
||||
case CFLIE_INIT_DATA:
|
||||
send_cmd_packet();
|
||||
phase = CFLIE_DATA;
|
||||
break;
|
||||
case CFLIE_SEARCH:
|
||||
switch (packet_ack()) {
|
||||
case PKT_PENDING:
|
||||
return PACKET_CHKTIME; // packet send not yet complete
|
||||
case PKT_ACKED:
|
||||
phase = CFLIE_DATA;
|
||||
BIND_DONE;
|
||||
break;
|
||||
case PKT_TIMEOUT:
|
||||
send_search_packet();
|
||||
counter = BIND_COUNT;
|
||||
}
|
||||
break;
|
||||
case CFLIE_DATA:
|
||||
#ifdef CFLIE_TELEMETRY
|
||||
update_telemetry();
|
||||
#endif
|
||||
if (packet_ack() == PKT_PENDING)
|
||||
return PACKET_CHKTIME; // packet send not yet complete
|
||||
send_cmd_packet();
|
||||
break;
|
||||
}
|
||||
return PACKET_PERIOD; // Packet at standard protocol interval
|
||||
}
|
||||
|
||||
|
||||
// Generate address to use from TX id and manufacturer id (STM32 unique id)
|
||||
static uint8_t initialize_rx_tx_addr() {
|
||||
rx_tx_addr[0] =
|
||||
rx_tx_addr[1] =
|
||||
rx_tx_addr[2] =
|
||||
rx_tx_addr[3] =
|
||||
rx_tx_addr[4] = 0xE7; // CFlie uses fixed address
|
||||
|
||||
data_rate = NRF24L01_BR_250K;
|
||||
rf_channel = 0;
|
||||
return CFLIE_INIT_SEARCH;
|
||||
// return CFLIE_INIT_DATA;
|
||||
}
|
||||
|
||||
static uint16_t Cflie_setup() {
|
||||
phase = initialize_rx_tx_addr();
|
||||
packet_counter = 0;
|
||||
|
||||
int delay = cflie_init();
|
||||
|
||||
#ifdef CFLIE_TELEMETRY
|
||||
memset(&Telemetry, 0, sizeof(Telemetry));
|
||||
TELEMETRY_SetType(TELEM_DSM);
|
||||
#endif
|
||||
if (phase == CFLIE_INIT_SEARCH) { BIND_IN_PROGRESS; }
|
||||
return delay;
|
||||
}
|
||||
|
||||
#endif
|
172
Multiprotocol/Nrf24l01_esky150.ino
Normal file
172
Multiprotocol/Nrf24l01_esky150.ino
Normal file
@ -0,0 +1,172 @@
|
||||
/*
|
||||
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.
|
||||
|
||||
Deviation 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 Deviation. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if defined(ESKY150_NRF24L01_INO)
|
||||
#include "iface_nrf24l01.h"
|
||||
|
||||
|
||||
// Timeout for callback in uSec, 4.8ms=4800us for ESky150
|
||||
#define ESKY150_PERIOD 4800
|
||||
#define ESKY150_CHKTIME 100 // Time to wait for packet to be sent (no ACK, so very short)
|
||||
|
||||
#define esky150_PAYLOADSIZE 15
|
||||
#define ADDR_esky150_SIZE 4
|
||||
|
||||
static uint32_t total_packets;
|
||||
enum {
|
||||
ESKY150_INIT2 = 0,
|
||||
ESKY150_DATA
|
||||
};
|
||||
|
||||
|
||||
static uint8_t esky150_packet_ack() {
|
||||
switch (NRF24L01_ReadReg(NRF24L01_07_STATUS) & (BV(NRF24L01_07_TX_DS) | BV(NRF24L01_07_MAX_RT))) {
|
||||
case BV(NRF24L01_07_TX_DS): return PKT_ACKED;
|
||||
case BV(NRF24L01_07_MAX_RT): return PKT_TIMEOUT;
|
||||
}
|
||||
return PKT_PENDING;
|
||||
}
|
||||
|
||||
// 2-bytes CRC
|
||||
#define CRC_CONFIG (BV(NRF24L01_00_EN_CRC) | BV(NRF24L01_00_CRCO))
|
||||
static uint16_t esky150_init() {
|
||||
uint8_t rx_addr[ADDR_esky150_SIZE] = { 0x73, 0x73, 0x74, 0x63 };
|
||||
uint8_t tx_addr[ADDR_esky150_SIZE] = { 0x71, 0x0A, 0x31, 0xF4 };
|
||||
NRF24L01_Initialize();
|
||||
|
||||
NRF24L01_WriteReg(NRF24L01_00_CONFIG, CRC_CONFIG);
|
||||
NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknoledgement
|
||||
NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0
|
||||
NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, ADDR_esky150_SIZE-2); // 4-byte RX/TX address
|
||||
NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0); // Disable retransmit
|
||||
NRF24L01_SetPower();
|
||||
NRF24L01_SetBitrate(NRF24L01_BR_2M);
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, rx_addr, ADDR_esky150_SIZE);
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, tx_addr, ADDR_esky150_SIZE);
|
||||
|
||||
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
|
||||
NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, esky150_PAYLOADSIZE); // bytes of data payload for pipe 0
|
||||
|
||||
|
||||
NRF24L01_Activate(0x73);
|
||||
NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 1); // Dynamic payload for data pipe 0
|
||||
// Enable: Dynamic Payload Length, Payload with ACK , W_TX_PAYLOAD_NOACK
|
||||
NRF24L01_WriteReg(NRF24L01_1D_FEATURE, BV(NRF2401_1D_EN_DPL) | BV(NRF2401_1D_EN_ACK_PAY) | BV(NRF2401_1D_EN_DYN_ACK));
|
||||
|
||||
// Delay 50 ms
|
||||
return 50000;
|
||||
}
|
||||
|
||||
|
||||
static uint16_t esky150_init2() {
|
||||
NRF24L01_FlushTx();
|
||||
NRF24L01_FlushRx();
|
||||
packet_sent = 0;
|
||||
packet_count = 0;
|
||||
rf_ch_num = 0;
|
||||
|
||||
// Turn radio power on
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
NRF24L01_WriteReg(NRF24L01_00_CONFIG, CRC_CONFIG | BV(NRF24L01_00_PWR_UP));
|
||||
// delayMicroseconds(150);
|
||||
return 150;
|
||||
}
|
||||
|
||||
|
||||
static void calc_fh_channels(uint32_t seed) {
|
||||
// Use channels 2..79
|
||||
uint8_t first = seed % 37 + 2;
|
||||
uint8_t second = first + 40;
|
||||
hopping_frequency[0] = first; // 0x22;
|
||||
hopping_frequency[1] = second; // 0x4a;
|
||||
}
|
||||
|
||||
|
||||
static uint8_t convert_channel(uint8_t num) {
|
||||
uint32_t ch = Servo_data[num];
|
||||
if (ch < PPM_MIN) { ch = PPM_MIN; }
|
||||
else if (ch > PPM_MAX) { ch = PPM_MAX; }
|
||||
return (uint8_t) ((ch * 500 / PPM_MAX) + 1500);
|
||||
}
|
||||
static void read_controls(uint8_t* throttle, uint8_t* aileron, uint8_t* elevator, uint8_t* rudder) {
|
||||
*throttle = convert_channel(THROTTLE);
|
||||
*aileron = convert_channel(AILERON);
|
||||
*elevator = convert_channel(ELEVATOR);
|
||||
*rudder = convert_channel(RUDDER);
|
||||
}
|
||||
|
||||
|
||||
static void esky150_send_packet() {
|
||||
uint8_t rf_ch = hopping_frequency[rf_ch_num];
|
||||
rf_ch_num = 1 - rf_ch_num;
|
||||
|
||||
read_controls(&throttle, &aileron, &elevator, &rudder);
|
||||
|
||||
packet[0] = hopping_frequency[0];
|
||||
packet[1] = hopping_frequency[1];
|
||||
packet[2] = (throttle >> 8) & 0xFF;
|
||||
packet[3] = throttle & 0xFF;
|
||||
packet[4] = (aileron >> 8) & 0xFF;
|
||||
packet[5] = aileron & 0xFF;
|
||||
packet[6] = (elevator >> 8) & 0xFF;
|
||||
packet[7] = elevator & 0xFF;
|
||||
packet[8] = (rudder >> 8) & 0xFF;
|
||||
packet[9] = rudder & 0xFF;
|
||||
// Constant values 00 d8 18 f8
|
||||
packet[10] = 0x00;
|
||||
packet[11] = 0xd8;
|
||||
packet[12] = 0x18;
|
||||
packet[13] = 0xf8;
|
||||
uint8_t sum = 0;
|
||||
for (int i = 0; i < 14; ++i) sum += packet[i];
|
||||
packet[14] = sum;
|
||||
|
||||
packet_sent = 0;
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, rf_ch);
|
||||
NRF24L01_FlushTx();
|
||||
NRF24L01_WritePayload(packet, sizeof(packet));
|
||||
++total_packets;
|
||||
packet_sent = 1;
|
||||
}
|
||||
|
||||
static uint16_t esky150_callback() {
|
||||
uint16_t timeout = ESKY150_PERIOD;
|
||||
switch (phase) {
|
||||
case ESKY150_INIT2:
|
||||
timeout = esky150_init2();
|
||||
phase = ESKY150_DATA;
|
||||
break;
|
||||
case ESKY150_DATA:
|
||||
if (packet_count == 4)
|
||||
packet_count = 0;
|
||||
else {
|
||||
if (packet_sent && esky150_packet_ack() != PKT_ACKED) {
|
||||
return ESKY150_CHKTIME;
|
||||
}
|
||||
esky150_send_packet();
|
||||
}
|
||||
break;
|
||||
}
|
||||
return timeout;
|
||||
}
|
||||
|
||||
static uint16_t esky150_setup() {
|
||||
total_packets = 0;
|
||||
uint16_t timeout = esky150_init();
|
||||
|
||||
return timeout;
|
||||
}
|
||||
#endif
|
282
Multiprotocol/Nrf24l01_fbl100.ino
Normal file
282
Multiprotocol/Nrf24l01_fbl100.ino
Normal file
@ -0,0 +1,282 @@
|
||||
/*
|
||||
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.
|
||||
|
||||
Deviation 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 Deviation. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
rewrite v977/v966 protocol to improve reliability
|
||||
*/
|
||||
|
||||
#if defined(FBL100_NRF24L01_INO)
|
||||
#include "iface_nrf24l01.h"
|
||||
|
||||
#define BIND_FBL_COUNT 800
|
||||
#define FBL_SIZE 5
|
||||
#define FREQUENCE_FBL_NUM 20
|
||||
|
||||
static uint8_t binding_fbl_adr_rf[5]; // fixed binding ids for all planes
|
||||
|
||||
static uint8_t bind_fbl_buf_array[4][10];
|
||||
|
||||
static unsigned int fbl_data[8];
|
||||
|
||||
|
||||
// HiSky protocol uses TX id as an address for nRF24L01, and uses frequency hopping sequence
|
||||
// which does not depend on this id and is passed explicitly in binding sequence. So we are free
|
||||
// to generate this sequence as we wish. It should be in the range [02..77]
|
||||
static void calc_fbl_channels() {
|
||||
int idx = 0;
|
||||
uint32_t rnd = MProtocol_id;
|
||||
while (idx < FREQUENCE_FBL_NUM) {
|
||||
int i;
|
||||
int count_2_26 = 0, count_27_50 = 0, count_51_74 = 0;
|
||||
rnd = rnd * 0x0019660D + 0x3C6EF35F; // Randomization
|
||||
|
||||
// Use least-significant byte. 73 is prime, so channels 76..77 are unused
|
||||
uint8_t next_ch = ((rnd >> 8) % 73) + 2;
|
||||
// Keep the distance 2 between the channels - either odd or even
|
||||
if (((next_ch ^ MProtocol_id) & 0x01 )== 0) { continue; }
|
||||
// Check that it's not duplicate and spread uniformly
|
||||
for (i = 0; i < idx; i++) {
|
||||
if(hopping_frequency[i] == next_ch) { break; }
|
||||
if(hopping_frequency[i] <= 26) { count_2_26++; }
|
||||
else if (hopping_frequency[i] <= 50) { count_27_50++; }
|
||||
else { count_51_74++; }
|
||||
}
|
||||
if (i != idx) { continue; }
|
||||
if ((next_ch <= 26 && count_2_26 < 8) ||(next_ch >= 27 && next_ch <= 50 && count_27_50 < 8) ||(next_ch >= 51 && count_51_74 < 8)) {
|
||||
hopping_frequency[idx++] = next_ch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void fbl100_build_binding_packet(void) {
|
||||
uint8_t i;
|
||||
unsigned int sum;
|
||||
uint8_t sum_l,sum_h;
|
||||
|
||||
sum = 0;
|
||||
for(i=0;i<5;i++) { sum += rx_tx_addr[i]; }
|
||||
sum_l = (uint8_t)sum;
|
||||
sum >>= 8;
|
||||
sum_h = (uint8_t)sum;
|
||||
bind_fbl_buf_array[0][0] = 0xff;
|
||||
bind_fbl_buf_array[0][1] = 0xaa;
|
||||
bind_fbl_buf_array[0][2] = 0x55;
|
||||
for(i=3;i<8;i++) { bind_fbl_buf_array[0][i] = rx_tx_addr[i-3]; }
|
||||
|
||||
for(i=1;i<4;i++) {
|
||||
bind_fbl_buf_array[i][0] = sum_l;
|
||||
bind_fbl_buf_array[i][1] = sum_h;
|
||||
bind_fbl_buf_array[i][2] = i-1;
|
||||
}
|
||||
for(i=0;i<7;i++) { bind_fbl_buf_array[1][i+3] = hopping_frequency[i]; }
|
||||
for(i=0;i<7;i++) { bind_fbl_buf_array[2][i+3] = hopping_frequency[i+7]; }
|
||||
for(i=0;i<6;i++) { bind_fbl_buf_array[3][i+3] = hopping_frequency[i+14]; }
|
||||
|
||||
binding_idx = 0;
|
||||
}
|
||||
|
||||
static void hp100_build_binding_packet(void) {
|
||||
memcpy(packet, rx_tx_addr, 5);
|
||||
packet[5] = hopping_frequency[0]; // start address
|
||||
for (uint8_t i = 6; i < 12; i++) { packet[i] = 0x55; }
|
||||
}
|
||||
|
||||
static void config_nrf24l01() {
|
||||
NRF24L01_Initialize();
|
||||
|
||||
NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable p0 rx
|
||||
NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // 0:No Auto Acknoledgement; 1:Auto Acknoledgement
|
||||
NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, packet_length); // fbl100/v922's packet size = 10, hp100 = 12
|
||||
// 2-bytes CRC, radio off
|
||||
NRF24L01_WriteReg(NRF24L01_00_CONFIG, BV(NRF24L01_00_EN_CRC) | BV(NRF24L01_00_CRCO) | BV(NRF24L01_00_PWR_UP));
|
||||
NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x03); // 5-byte RX/TX address (byte -2)
|
||||
NRF24L01_SetBitrate(sub_protocol == HP100? NRF24L01_BR_250K:NRF24L01_BR_1M); //hp100:250kbps; fbl100: 1Mbps
|
||||
NRF24L01_SetPower();
|
||||
|
||||
NRF24L01_FlushTx();
|
||||
NRF24L01_FlushRx();
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
|
||||
}
|
||||
|
||||
// FBL100 channel sequence: AILE ELEV THRO RUDD GEAR PITH, channel data value is from 0 to 1000
|
||||
static void fbl100_build_ch_data() {
|
||||
uint32_t temp;
|
||||
uint8_t i;
|
||||
for (i = 0; i< 8; i++) {
|
||||
temp = (uint32_t)Servo_data[i] * 500/PPM_MAX + 500;
|
||||
if (i == 2) { temp = 1000 -temp; } // It is clear that fbl100's thro stick is made reversely,so I adjust it here on purposely
|
||||
if (temp < 0) { fbl_data[i] = 0; }
|
||||
else if (temp > 1000) { fbl_data[i] = 1000; }
|
||||
else { fbl_data[i] = (unsigned int)temp; }
|
||||
packet[i] = (uint8_t)fbl_data[i];
|
||||
}
|
||||
|
||||
packet[8] = (uint8_t)((fbl_data[0]>>8)&0x0003);
|
||||
packet[8] |= (uint8_t)((fbl_data[1]>>6)&0x000c);
|
||||
packet[8] |= (uint8_t)((fbl_data[2]>>4)&0x0030);
|
||||
packet[8] |= (uint8_t)((fbl_data[3]>>2)&0x00c0);
|
||||
|
||||
packet[9] = (uint8_t)((fbl_data[4]>>8)&0x0003);
|
||||
packet[9] |= (uint8_t)((fbl_data[5]>>6)&0x000c);
|
||||
packet[9] |= (uint8_t)((fbl_data[6]>>4)&0x0030);
|
||||
packet[9] |= (uint8_t)((fbl_data[7]>>2)&0x00c0);
|
||||
}
|
||||
|
||||
static void hp100_build_ch_data() {
|
||||
uint32_t temp;
|
||||
uint8_t i;
|
||||
for (i = 0; i< 8; i++) {
|
||||
temp = (uint32_t)Servo_data[i] * 300/PPM_MAX + 500;
|
||||
if (temp < 0) { temp = 0; }
|
||||
else if (temp > 1000) { temp = 1000; }
|
||||
if (i == 3 || i == 5) { temp = 1000 -temp; } // hp100's rudd and pit channel are made reversely,so I adjust them on purposely
|
||||
|
||||
fbl_data[i] = (unsigned int)temp;
|
||||
packet[i] = (uint8_t)fbl_data[i];
|
||||
}
|
||||
|
||||
packet[8] = (uint8_t)((fbl_data[0]>>8)&0x0003);
|
||||
packet[8] |= (uint8_t)((fbl_data[1]>>6)&0x000c);
|
||||
packet[8] |= (uint8_t)((fbl_data[2]>>4)&0x0030);
|
||||
packet[8] |= (uint8_t)((fbl_data[3]>>2)&0x00c0);
|
||||
|
||||
packet[9] = (uint8_t)((fbl_data[4]>>8)&0x0003);
|
||||
packet[9] |= (uint8_t)((fbl_data[5]>>6)&0x000c);
|
||||
packet[9] |= (uint8_t)((fbl_data[6]>>4)&0x0030);
|
||||
packet[9] |= (uint8_t)((fbl_data[7]>>2)&0x00c0);
|
||||
|
||||
unsigned char l, h, t;
|
||||
l=h=0xff;
|
||||
for(i=0; i<10; i++ ) {
|
||||
h ^= packet[i];
|
||||
h ^= h>>4;
|
||||
t = h;
|
||||
h = l;
|
||||
l = t;
|
||||
t = (l<<4) | (l>>4);
|
||||
h^=((t<<2) | (t>>6)) & 0x1f;
|
||||
h^=t&0xf0;
|
||||
l^=((t<<1) | (t>>7)) & 0xe0;
|
||||
}
|
||||
packet[10] = h;
|
||||
packet[11] = l;
|
||||
}
|
||||
|
||||
|
||||
static uint16_t fbl100_cb() {
|
||||
switch(phase) {
|
||||
case 0:
|
||||
fbl100_build_ch_data();
|
||||
break;
|
||||
case 1:
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_addr, 5);
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no]);
|
||||
hopping_frequency_no++;
|
||||
if (hopping_frequency_no >= FREQUENCE_FBL_NUM) { hopping_frequency_no = 0; }
|
||||
break;
|
||||
case 2:
|
||||
NRF24L01_FlushTx();
|
||||
NRF24L01_WritePayload(packet, packet_length);
|
||||
break;
|
||||
case 3:
|
||||
break;
|
||||
case 4:
|
||||
if (bind_phase>0) {
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, binding_fbl_adr_rf, 5);
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, 81);
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
if (bind_phase >0) {
|
||||
bind_phase--;
|
||||
if (! bind_phase) { BIND_DONE; } // binding finished, change tx add
|
||||
NRF24L01_FlushTx(); // must be invoked before NRF24L01_WritePayload()
|
||||
NRF24L01_WritePayload(bind_fbl_buf_array[binding_idx], packet_length);
|
||||
binding_idx++;
|
||||
if (binding_idx >= 4)
|
||||
binding_idx = 0;
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
break;
|
||||
case 7:
|
||||
NRF24L01_SetPower();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
phase++;
|
||||
if (phase >=9) { phase = 0; } // send 1 binding packet and 1 data packet per 9ms
|
||||
return 1000;
|
||||
}
|
||||
|
||||
static uint16_t hp100_cb() {
|
||||
switch(phase) {
|
||||
case 0:
|
||||
hp100_build_ch_data();
|
||||
break;
|
||||
case 1:
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_addr, 5);
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[0] + hopping_frequency_no*2);
|
||||
hopping_frequency_no++;
|
||||
hopping_frequency_no %= 15;
|
||||
NRF24L01_FlushTx();
|
||||
NRF24L01_WritePayload(packet, packet_length);
|
||||
break;
|
||||
case 2:
|
||||
if(bind_phase>0) { hp100_build_binding_packet(); }
|
||||
break;
|
||||
case 3:
|
||||
if (bind_phase>0) {
|
||||
bind_phase--;
|
||||
if (! bind_phase) { BIND_DONE; }
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, binding_fbl_adr_rf, 5);
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, 81);
|
||||
NRF24L01_FlushTx();
|
||||
NRF24L01_WritePayload(packet, packet_length);
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
break;
|
||||
case 5:
|
||||
NRF24L01_SetPower();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
phase++;
|
||||
if (phase >= 6) { phase = 0; } // send 1 binding packet and 1 data packet per 10ms
|
||||
return 1000;
|
||||
}
|
||||
|
||||
static uint8_t fbl_setup() {
|
||||
calc_fbl_channels();
|
||||
|
||||
printf("FH Seq: ");
|
||||
for (int i = 0; i < FREQUENCE_FBL_NUM; ++i) { printf("%d, ", hopping_frequency[i]); }
|
||||
printf("\r\n");
|
||||
|
||||
// debut init
|
||||
if (sub_protocol == HP100) {
|
||||
packet_length = 12;
|
||||
binding_fbl_adr_rf[0] = 0x32; binding_fbl_adr_rf[1] = 0xaa; binding_fbl_adr_rf[2] = 0x45;
|
||||
binding_fbl_adr_rf[3] = 0x45; binding_fbl_adr_rf[4] = 0x78;
|
||||
} else {
|
||||
packet_length = 10;
|
||||
binding_fbl_adr_rf[0] = 0x12; binding_fbl_adr_rf[1] = 0x23; binding_fbl_adr_rf[2] = 0x23;
|
||||
binding_fbl_adr_rf[3] = 0x45; binding_fbl_adr_rf[4] = 0x78;
|
||||
fbl100_build_binding_packet();
|
||||
}
|
||||
config_nrf24l01();
|
||||
|
||||
if(IS_AUTOBIND_FLAG_on) { bind_phase = BIND_FBL_COUNT; }
|
||||
else { bind_phase = 0; }
|
||||
|
||||
// CLOCK_StartTimer(1000, sub_protocol == HP100?hp100_cb:fbl100_cb);
|
||||
}
|
||||
#endif
|
210
Multiprotocol/Nrf24l01_h377.ino
Normal file
210
Multiprotocol/Nrf24l01_h377.ino
Normal file
@ -0,0 +1,210 @@
|
||||
/*
|
||||
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.
|
||||
|
||||
Deviation 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 Deviation. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if defined (H377_NRF24L01_INO)
|
||||
#include "iface_nrf24l01.h"
|
||||
|
||||
#define BIND_COUNT 800
|
||||
|
||||
|
||||
#define TXID_H377_SIZE 5
|
||||
|
||||
#define FREQUENCE_NUM_H377 20
|
||||
#define SET_NUM_H377 9
|
||||
// available frequency must be in between 2402 and 2477
|
||||
|
||||
static uint8_t binding_ch=0x50;
|
||||
static uint8_t hopping_frequency_data[SET_NUM_H377] = {0x1c,0x1b,0x1d,0x11,0x0e,0x0d,0x01,0x1d,0x15};
|
||||
|
||||
static const uint8_t binding_adr_rf[5]={0x32,0xaa,0x45,0x45,0x78};
|
||||
|
||||
static uint8_t rf_adr_buf[5];
|
||||
static uint8_t rf_adr_buf_data[SET_NUM_H377][5] = {
|
||||
{0xad,0x9a,0xa6,0x69,0xb2},//ansheng
|
||||
{0x92,0x9a,0x9d,0x69,0x99},//dc59
|
||||
{0x92,0xb2,0x9d,0x69,0x9a},//small two
|
||||
{0xad,0x9a,0x5a,0x69,0x96},//james_1
|
||||
{0x95,0x9a,0x52,0x69,0x99},//james_2
|
||||
{0x52,0x52,0x52,0x69,0xb9},//james_3
|
||||
{0x52,0x52,0x52,0x52,0x55},//small two_1
|
||||
{0x92,0xB2,0x9D,0x69,0x9A},//small two_2
|
||||
{0x96,0x9A,0x45,0x69,0xB2}//small two_3
|
||||
};
|
||||
|
||||
static uint8_t bind_buf_array[10];
|
||||
static uint8_t bind_buf_array_data[SET_NUM_H377][4] = {
|
||||
{0xcf,0x1c,0x19,0x1a},
|
||||
{0xff,0x48,0x19,0x19},
|
||||
{0xf3,0x4d,0x19,0x19},
|
||||
{0x9e,0x1f,0x19,0x19},
|
||||
{0x8d,0x3d,0x19,0x19},
|
||||
{0xbd,0x23,0x19,0x19},
|
||||
{0xF3,0x28,0x19,0x19},
|
||||
{0xF3,0x4D,0x19,0x19},
|
||||
{0x82,0x8D,0x19,0x19}
|
||||
};
|
||||
|
||||
|
||||
static unsigned int ch_data[8];
|
||||
static uint8_t payload[10];
|
||||
static uint8_t counter1ms;
|
||||
|
||||
static int select_ch_id = 0;
|
||||
|
||||
static void h377_binding_packet(void) { //bind_buf_array
|
||||
uint8_t i;
|
||||
counter1ms = 0;
|
||||
hopping_frequency_no = 0;
|
||||
|
||||
for(i=0;i<5;i++)
|
||||
bind_buf_array[i] = rf_adr_buf[i];
|
||||
|
||||
bind_buf_array[5] = hopping_frequency[0];
|
||||
|
||||
for(i=0;i<4;i++)
|
||||
bind_buf_array[i+6] = bind_buf_array_data[select_ch_id][i];
|
||||
}
|
||||
|
||||
static void h377_init() {
|
||||
NRF24L01_Initialize();
|
||||
|
||||
NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable p0 rx
|
||||
NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknoledgement
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rf_adr_buf, 5);
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, rf_adr_buf, 5);
|
||||
NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, 10); // payload size = 10
|
||||
//NRF24L01_WriteReg(NRF24L01_05_RF_CH, 81); // binding packet must be set in channel 81
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, binding_ch); // binding packet must be set in channel 81
|
||||
|
||||
// 2-bytes CRC, radio off
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
NRF24L01_WriteReg(NRF24L01_00_CONFIG, BV(NRF24L01_00_EN_CRC) | BV(NRF24L01_00_CRCO) | BV(NRF24L01_00_PWR_UP));
|
||||
NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x03); // 5-byte RX/TX address (byte -2)
|
||||
NRF24L01_SetBitrate(0); // 1Mbps
|
||||
NRF24L01_SetPower();
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
|
||||
}
|
||||
|
||||
// H377 channel sequence: AILE ELEV THRO RUDD GEAR PITH, channel data value is from 0 to 1000
|
||||
static void h377_ch_data() {
|
||||
uint32_t temp;
|
||||
uint8_t i;
|
||||
for (i = 0; i< 8; i++) {
|
||||
temp = (uint32_t)Servo_data[i] * 450/PPM_MAX + 500; // max/min servo range is +-125%
|
||||
if (i == 2) // It is clear that h377's thro stick is made reversely, so I adjust it here on purpose
|
||||
temp = 1000 -temp;
|
||||
//if (i == 0) // It is clear that h377's thro stick is made reversely, so I adjust it here on purpose
|
||||
// temp = 1000 -temp;
|
||||
//if (i == 1) // It is clear that h377's thro stick is made reversely, so I adjust it here on purpose
|
||||
// temp = 1000 -temp;
|
||||
if (temp < 0)
|
||||
ch_data[i] = 0;
|
||||
else if (temp > 1000)
|
||||
ch_data[i] = 1000;
|
||||
else
|
||||
ch_data[i] = (unsigned int)temp;
|
||||
payload[i] = (uint8_t)ch_data[i];
|
||||
}
|
||||
payload[8] = (uint8_t)((ch_data[0]>>8)&0x0003);
|
||||
payload[8] |= (uint8_t)((ch_data[1]>>6)&0x000c);
|
||||
payload[8] |= (uint8_t)((ch_data[2]>>4)&0x0030);
|
||||
payload[8] |= (uint8_t)((ch_data[3]>>2)&0x00c0);
|
||||
|
||||
payload[9] = (uint8_t)((ch_data[4]>>8)&0x0003);
|
||||
payload[9] |= (uint8_t)((ch_data[5]>>6)&0x000c);
|
||||
payload[9] |= (uint8_t)((ch_data[6]>>4)&0x0030);
|
||||
payload[9] |= (uint8_t)((ch_data[7]>>2)&0x00c0);
|
||||
}
|
||||
|
||||
static uint16_t h377_cb() {
|
||||
counter1ms++;
|
||||
if(counter1ms==1) { NRF24L01_FlushTx(); }
|
||||
//-------------------------
|
||||
else if(counter1ms==2) {
|
||||
if (bind_phase>0) {
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, (uint8_t *)binding_adr_rf, 5);
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, binding_ch);
|
||||
}
|
||||
}
|
||||
else if(counter1ms==3) {
|
||||
if (bind_phase >0) {
|
||||
bind_phase--;
|
||||
if (! bind_phase) { BIND_DONE; } // binding finished, change tx add
|
||||
NRF24L01_WritePayload(bind_buf_array,10);
|
||||
}
|
||||
}
|
||||
else if (counter1ms==4) { if (bind_phase > 0) { NRF24L01_FlushTx(); }}
|
||||
//-------------------------
|
||||
else if(counter1ms==5) { NRF24L01_SetPower(); }
|
||||
//-------------------------
|
||||
else if (counter1ms == 6) {
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rf_adr_buf, 5);
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no]);
|
||||
hopping_frequency_no++;
|
||||
if (hopping_frequency_no >= FREQUENCE_NUM_H377) { hopping_frequency_no = 0; }
|
||||
}
|
||||
else if (counter1ms == 7) { h377_ch_data(); }
|
||||
else if(counter1ms>8) {
|
||||
counter1ms = 0;
|
||||
NRF24L01_WritePayload(payload,10);
|
||||
}
|
||||
return 1000; // send 1 binding packet and 1 data packet per 9ms
|
||||
}
|
||||
|
||||
// Linear feedback shift register with 32-bit Xilinx polinomial x^32 + x^22 + x^2 + x + 1
|
||||
static const uint32_t LFSR_FEEDBACK = 0x80200003ul;
|
||||
static const uint32_t LFSR_INTAP = 32-1;
|
||||
|
||||
static void update_lfsr(uint32_t *lfsr, uint8_t b) {
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
*lfsr = (*lfsr >> 1) ^ ((-(*lfsr & 1u) & LFSR_FEEDBACK) ^ ~((uint32_t)(b & 1) << LFSR_INTAP));
|
||||
b >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Generate internal id from TX id and manufacturer id (STM32 unique id)
|
||||
|
||||
|
||||
static void H377_tx_id() {
|
||||
for(int i=0;i<5;i++)
|
||||
rf_adr_buf[i] = rf_adr_buf_data[select_ch_id][i];
|
||||
|
||||
hopping_frequency[0] = hopping_frequency_data[select_ch_id];
|
||||
|
||||
for (int i = 1; i < FREQUENCE_NUM_H377; i++) {
|
||||
hopping_frequency[i] = hopping_frequency[i-1] + 3;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static uint16_t h377_setup() {
|
||||
select_ch_id = MProtocol_id_master%SET_NUM_H377;
|
||||
|
||||
H377_tx_id();//rf_adr_buf hopping_frequency
|
||||
|
||||
h377_binding_packet();//bind_buf_array (rf_adr_buf hopping_frequency)
|
||||
|
||||
h377_init();
|
||||
|
||||
if(IS_AUTOBIND_FLAG_on) {
|
||||
bind_phase = BIND_COUNT;
|
||||
BIND_IN_PROGRESS;
|
||||
}
|
||||
else { bind_phase = 0; }
|
||||
|
||||
return 1000;
|
||||
}
|
||||
#endif
|
267
Multiprotocol/Nrf24l01_hm830.ino
Normal file
267
Multiprotocol/Nrf24l01_hm830.ino
Normal file
@ -0,0 +1,267 @@
|
||||
/*
|
||||
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.
|
||||
Deviation 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 Deviation. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* This protocol is for the HM Hobby HM830 RC Paper Airplane
|
||||
Protocol spec:
|
||||
Channel data:
|
||||
AA BB CC DD EE FF GG
|
||||
AA : Throttle Min=0x00 max =0x64
|
||||
BB :
|
||||
bit 0,1,2: Left/Right magnitude, bit 5 Polarity (set = right)
|
||||
bit 6: Accelerate
|
||||
bit 7: Right button (also the ABC Button)
|
||||
CC : bit 0 seems to be impacted by the Right button
|
||||
DD
|
||||
EE
|
||||
FF : Trim (bit 0-5: Magnitude, bit 6 polarity (set = right)
|
||||
GG : Checksum (CRC8 on bytes AA-FF), init = 0xa5, poly = 0x01
|
||||
*/
|
||||
|
||||
#ifdef HM830_NRF24L01_INO
|
||||
|
||||
#include "iface_nrf24l01.h"
|
||||
|
||||
enum {
|
||||
HM830_BIND1A = 0,
|
||||
HM830_BIND2A,
|
||||
HM830_BIND3A,
|
||||
HM830_BIND4A,
|
||||
HM830_BIND5A,
|
||||
HM830_BIND6A,
|
||||
HM830_BIND7A,
|
||||
HM830_DATA1,
|
||||
HM830_DATA2,
|
||||
HM830_DATA3,
|
||||
HM830_DATA4,
|
||||
HM830_DATA5,
|
||||
HM830_DATA6,
|
||||
HM830_DATA7,
|
||||
HM830_BIND1B = 0x80,
|
||||
HM830_BIND2B,
|
||||
HM830_BIND3B,
|
||||
HM830_BIND4B,
|
||||
HM830_BIND5B,
|
||||
HM830_BIND6B,
|
||||
HM830_BIND7B,
|
||||
};
|
||||
|
||||
static uint8_t init_vals_hm830[][2] = {
|
||||
{NRF24L01_17_FIFO_STATUS, 0x00},
|
||||
{NRF24L01_16_RX_PW_P5, 0x07},
|
||||
{NRF24L01_15_RX_PW_P4, 0x07},
|
||||
{NRF24L01_14_RX_PW_P3, 0x07},
|
||||
{NRF24L01_13_RX_PW_P2, 0x07},
|
||||
{NRF24L01_12_RX_PW_P1, 0x07},
|
||||
{NRF24L01_11_RX_PW_P0, 0x07},
|
||||
{NRF24L01_0F_RX_ADDR_P5, 0xC6},
|
||||
{NRF24L01_0E_RX_ADDR_P4, 0xC5},
|
||||
{NRF24L01_0D_RX_ADDR_P3, 0xC4},
|
||||
{NRF24L01_0C_RX_ADDR_P2, 0xC3},
|
||||
{NRF24L01_09_CD, 0x00},
|
||||
{NRF24L01_08_OBSERVE_TX, 0x00},
|
||||
{NRF24L01_07_STATUS, 0x07},
|
||||
// {NRF24L01_06_RF_SETUP, 0x07},
|
||||
{NRF24L01_05_RF_CH, 0x18},
|
||||
{NRF24L01_04_SETUP_RETR, 0x3F},
|
||||
{NRF24L01_03_SETUP_AW, 0x03},
|
||||
{NRF24L01_02_EN_RXADDR, 0x3F},
|
||||
{NRF24L01_01_EN_AA, 0x3F},
|
||||
{NRF24L01_00_CONFIG, 0x0E},
|
||||
};
|
||||
|
||||
static uint8_t count;
|
||||
static uint8_t rf_ch[] = {0x08, 0x35, 0x12, 0x3f, 0x1c, 0x49, 0x26};
|
||||
static uint8_t bind_addr[] = {0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xc2};
|
||||
|
||||
static uint8_t crc8(uint32_t result, uint8_t *data, int len) {
|
||||
int polynomial = 0x01;
|
||||
for(int i = 0; i < len; i++) {
|
||||
result = result ^ data[i];
|
||||
for(int j = 0; j < 8; j++) {
|
||||
if(result & 0x80) { result = (result << 1) ^ polynomial; }
|
||||
else { result = result << 1; }
|
||||
}
|
||||
}
|
||||
return result & 0xff;
|
||||
}
|
||||
|
||||
static void HM830_init() {
|
||||
NRF24L01_Initialize();
|
||||
for (uint32_t i = 0; i < sizeof(init_vals_hm830) / sizeof(init_vals_hm830[0]); i++) { NRF24L01_WriteReg(init_vals_hm830[i][0], init_vals_hm830[i][1]); }
|
||||
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
NRF24L01_SetBitrate(0);
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, bind_addr, 5);
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_0B_RX_ADDR_P1, bind_addr+1, 5);
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, bind_addr, 5);
|
||||
NRF24L01_Activate(0x73); //Enable FEATURE
|
||||
NRF24L01_WriteReg(NRF24L01_1D_FEATURE, 0x07);
|
||||
NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 0x3F);
|
||||
//NRF24L01_ReadReg(NRF24L01_07_STATUS) ==> 0x07
|
||||
|
||||
NRF24L01_Activate(0x53); // switch bank back
|
||||
|
||||
NRF24L01_FlushTx();
|
||||
//NRF24L01_ReadReg(NRF24L01_07_STATUS) ==> 0x0e
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x0e);
|
||||
//NRF24L01_ReadReg(NRF24L01_00_CONFIG); ==> 0x0e
|
||||
NRF24L01_WriteReg(NRF24L01_00_CONFIG, 0x0e);
|
||||
NRF24L01_ReadReg(NRF24L01_01_EN_AA); // No Auto Acknoledgement
|
||||
}
|
||||
|
||||
static void build_bind_packet_hm830() {
|
||||
for(int i = 0; i < 6; i++) { packet[i] = rx_tx_addr[i]; }
|
||||
packet[6] = crc8(0xa5, packet, 6);
|
||||
}
|
||||
|
||||
static void build_data_packet() {
|
||||
uint8_t ail_sign = 0, trim_sign = 0;
|
||||
|
||||
throttle = (uint32_t)Servo_data[THROTTLE] * 50 / PPM_MAX + 50;
|
||||
if (throttle < 0) { throttle = 0; }
|
||||
|
||||
aileron = (uint32_t)Servo_data[AILERON] * 8 / PPM_MAX;
|
||||
if (aileron < 0) { aileron = -aileron; ail_sign = 1; }
|
||||
if (aileron > 7) { aileron = 7; }
|
||||
|
||||
uint8_t turbo = (uint32_t)Servo_data[ELEVATOR] > 0 ? 1 : 0;
|
||||
|
||||
uint8_t trim = ((uint32_t)Servo_data[RUDDER] * 0x1f / PPM_MAX);
|
||||
if (trim < 0) { trim = -trim; trim_sign = 1; }
|
||||
if (trim > 0x1f) { trim = 0x1f; }
|
||||
|
||||
uint8_t rbutton = (uint32_t)Servo_data[4] > 0 ? 1 : 0;
|
||||
packet[0] = throttle;
|
||||
packet[1] = aileron;
|
||||
if (ail_sign) { packet[1] |= 0x20; }
|
||||
if (turbo) { packet[1] |= 0x40; }
|
||||
if (rbutton) { packet[1] |= 0x80; }
|
||||
packet[5] = trim;
|
||||
if (trim_sign) { packet[5] |= 0x20;}
|
||||
packet[6] = crc8(0xa5, packet, 6);
|
||||
}
|
||||
|
||||
static void send_packet_hm830() {
|
||||
NRF24L01_ReadReg(NRF24L01_17_FIFO_STATUS);
|
||||
NRF24L01_WritePayload(packet, 7);
|
||||
}
|
||||
|
||||
static uint16_t handle_binding() {
|
||||
uint8_t status = NRF24L01_ReadReg(NRF24L01_07_STATUS);
|
||||
if (status & 0x20) {
|
||||
//Binding complete
|
||||
phase = HM830_DATA1 + ((phase&0x7F)-HM830_BIND1A);
|
||||
count = 0;
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, rx_tx_addr, 5);
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_0B_RX_ADDR_P1, rx_tx_addr+1, 5);
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_addr, 5);
|
||||
NRF24L01_FlushTx();
|
||||
build_data_packet();
|
||||
uint8_t rb = NRF24L01_ReadReg(NRF24L01_07_STATUS); //==> 0x0E
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, rb);
|
||||
rb = NRF24L01_ReadReg(NRF24L01_00_CONFIG); //==> 0x0E
|
||||
NRF24L01_WriteReg(NRF24L01_00_CONFIG, rb);
|
||||
send_packet_hm830();
|
||||
return 14000;
|
||||
}
|
||||
switch (phase) {
|
||||
case HM830_BIND1A:
|
||||
//Look for a Rx that is already bound
|
||||
NRF24L01_SetPower();
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, rx_tx_addr, 5);
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_0B_RX_ADDR_P1, rx_tx_addr+1, 5);
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_addr, 5);
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, rf_ch[0]);
|
||||
build_bind_packet_hm830();
|
||||
break;
|
||||
case HM830_BIND1B:
|
||||
//Look for a Rx that is not yet bound
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, bind_addr, 5);
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_0B_RX_ADDR_P1, bind_addr+1, 5);
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, bind_addr, 5);
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, rf_ch[0]);
|
||||
break;
|
||||
case HM830_BIND2A:
|
||||
case HM830_BIND3A:
|
||||
case HM830_BIND4A:
|
||||
case HM830_BIND5A:
|
||||
case HM830_BIND6A:
|
||||
case HM830_BIND7A:
|
||||
case HM830_BIND2B:
|
||||
case HM830_BIND3B:
|
||||
case HM830_BIND4B:
|
||||
case HM830_BIND5B:
|
||||
case HM830_BIND6B:
|
||||
case HM830_BIND7B:
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, rf_ch[(phase&0x7F)-HM830_BIND1A]);
|
||||
break;
|
||||
}
|
||||
NRF24L01_FlushTx();
|
||||
uint8_t rb = NRF24L01_ReadReg(NRF24L01_07_STATUS); //==> 0x0E
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, rb);
|
||||
rb = NRF24L01_ReadReg(NRF24L01_00_CONFIG); //==> 0x0E
|
||||
NRF24L01_WriteReg(NRF24L01_00_CONFIG, rb);
|
||||
send_packet_hm830();
|
||||
phase++;
|
||||
if (phase == HM830_BIND7B+1) { phase = HM830_BIND1A; }
|
||||
else if (phase == HM830_BIND7A+1) { phase = HM830_BIND1B; }
|
||||
return 20000;
|
||||
}
|
||||
|
||||
static uint16_t handle_data() {
|
||||
uint8_t status = NRF24L01_ReadReg(NRF24L01_07_STATUS);
|
||||
if (count <= 0 || !(status & 0x20)) {
|
||||
if(count < 0 || ! (status & 0x20)) {
|
||||
count = 0;
|
||||
//We didn't get a response on this channel, try the next one
|
||||
phase++;
|
||||
if (phase-HM830_DATA1 > 6) { phase = HM830_DATA1; }
|
||||
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, rf_ch[0]);
|
||||
NRF24L01_FlushTx();
|
||||
build_data_packet();
|
||||
uint8_t rb = NRF24L01_ReadReg(NRF24L01_07_STATUS); //==> 0x0E
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, rb);
|
||||
rb = NRF24L01_ReadReg(NRF24L01_00_CONFIG); //==> 0x0E
|
||||
NRF24L01_WriteReg(NRF24L01_00_CONFIG, rb);
|
||||
send_packet_hm830();
|
||||
return 14000;
|
||||
}
|
||||
}
|
||||
build_data_packet();
|
||||
count++;
|
||||
if(count == 98) {
|
||||
count = -1;
|
||||
NRF24L01_SetPower();
|
||||
}
|
||||
uint8_t rb = NRF24L01_ReadReg(NRF24L01_07_STATUS); //==> 0x0E
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, rb);
|
||||
rb = NRF24L01_ReadReg(NRF24L01_00_CONFIG); //==> 0x0E
|
||||
NRF24L01_WriteReg(NRF24L01_00_CONFIG, rb);
|
||||
send_packet_hm830();
|
||||
return 20000;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static uint16_t HM830_callback() {
|
||||
if ((phase & 0x7F) < HM830_DATA1) { return handle_binding(); }
|
||||
else { return handle_data(); }
|
||||
}
|
||||
|
||||
|
||||
static uint32_t HM830_setup(){
|
||||
count = 0;
|
||||
// initialize_tx_id
|
||||
|
||||
rx_tx_addr[4] = 0xee;
|
||||
rx_tx_addr[5] = 0xc2;
|
||||
HM830_init();
|
||||
phase = HM830_BIND1A;
|
||||
|
||||
return 500;
|
||||
}
|
||||
#endif
|
272
Multiprotocol/Nrf24l01_hontai.ino
Normal file
272
Multiprotocol/Nrf24l01_hontai.ino
Normal file
@ -0,0 +1,272 @@
|
||||
/*
|
||||
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.
|
||||
|
||||
Deviation 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 Deviation. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#if defined(HonTai_NRF24L01_INO)
|
||||
#include "iface_nrf24l01.h"
|
||||
|
||||
#define BIND_HT_COUNT 80
|
||||
#define PACKET_HT_PERIOD 13500 // Timeout for callback in uSec
|
||||
//printf inside an interrupt handler is really dangerous
|
||||
//this shouldn't be enabled even in debug builds without explicitly
|
||||
//turning it on
|
||||
#define dbgprintf if(0) printf
|
||||
|
||||
#define INITIAL_HT_WAIT 500
|
||||
#define BIND_HT_PACKET_SIZE 10
|
||||
#define PACKET_HT_SIZE 12
|
||||
#define RF_BIND_HT_CHANNEL 0
|
||||
|
||||
enum {
|
||||
FORMAT_HONTAI = 0,
|
||||
FORMAT_JJRCX1,
|
||||
};
|
||||
|
||||
|
||||
#define CHANNEL_LED AUX1
|
||||
#define CHANNEL_ARM AUX1 // for JJRC X1
|
||||
#define CHANNEL_FLIP AUX2
|
||||
#define CHANNEL_PICTURE AUX3
|
||||
#define CHANNEL_VIDEO AUX4
|
||||
#define CHANNEL_HEADLESS AUX5
|
||||
#define CHANNEL_RTH AUX6
|
||||
#define CHANNEL_CALIBRATE AUX7
|
||||
|
||||
enum {
|
||||
HonTai_INIT1 = 0,
|
||||
HonTai_BIND2,
|
||||
HonTai_DATA
|
||||
};
|
||||
|
||||
static uint8_t ht_txid[5];
|
||||
|
||||
static uint8_t rf_chan = 0;
|
||||
static uint8_t rf_channels[][3] = {{0x05, 0x19, 0x28}, // Hontai
|
||||
{0x0a, 0x1e, 0x2d}}; // JJRC X1
|
||||
static uint8_t rx_tx_ht_addr[] = {0xd2, 0xb5, 0x99, 0xb3, 0x4a};
|
||||
static uint8_t addr_vals[4][16] = {
|
||||
{0x24, 0x26, 0x2a, 0x2c, 0x32, 0x34, 0x36, 0x4a, 0x4c, 0x4e, 0x54, 0x56, 0x5a, 0x64, 0x66, 0x6a},
|
||||
{0x92, 0x94, 0x96, 0x9a, 0xa4, 0xa6, 0xac, 0xb2, 0xb4, 0xb6, 0xca, 0xcc, 0xd2, 0xd4, 0xd6, 0xda},
|
||||
{0x93, 0x95, 0x99, 0x9b, 0xa5, 0xa9, 0xab, 0xad, 0xb3, 0xb5, 0xc9, 0xcb, 0xcd, 0xd3, 0xd5, 0xd9},
|
||||
{0x25, 0x29, 0x2b, 0x2d, 0x33, 0x35, 0x49, 0x4b, 0x4d, 0x59, 0x5b, 0x65, 0x69, 0x6b, 0x6d, 0x6e}};
|
||||
|
||||
// proudly swiped from http://www.drdobbs.com/implementing-the-ccitt-cyclical-redundan/199904926
|
||||
#define POLY 0x8408
|
||||
static uint16_t crc16(uint8_t *data_p, uint32_t length)
|
||||
{
|
||||
uint8_t i;
|
||||
uint32_t data;
|
||||
uint32_t crc;
|
||||
|
||||
crc = 0xffff;
|
||||
|
||||
if (length == 0) return (~crc);
|
||||
|
||||
length -= 2;
|
||||
do {
|
||||
for (i = 0, data = (uint8_t)0xff & *data_p++;
|
||||
i < 8;
|
||||
i++, data >>= 1) {
|
||||
if ((crc & 0x0001) ^ (data & 0x0001))
|
||||
crc = (crc >> 1) ^ POLY;
|
||||
else
|
||||
crc >>= 1;
|
||||
}
|
||||
} while (--length);
|
||||
|
||||
crc = ~crc;
|
||||
data = crc;
|
||||
crc = (crc << 8) | (data >> 8 & 0xFF);
|
||||
*data_p++ = crc >> 8;
|
||||
*data_p = crc & 0xff;
|
||||
return crc;
|
||||
}
|
||||
|
||||
#define CHAN_RANGE (PPM_MAX - PPM_MIN)
|
||||
static uint8_t scale_HT_channel(uint8_t ch, uint8_t start, uint8_t end)
|
||||
{
|
||||
uint32_t range = end - start;
|
||||
uint32_t chanval = Servo_data[ch];
|
||||
|
||||
if (chanval < PPM_MIN) chanval = PPM_MIN;
|
||||
else if (chanval > PPM_MAX) chanval = PPM_MAX;
|
||||
|
||||
uint32_t round = range < 0 ? 0 : CHAN_RANGE / range; // channels round up
|
||||
if (start < 0) round = CHAN_RANGE / range / 2; // trims zero centered around zero
|
||||
return (range * (chanval - PPM_MIN + round)) / CHAN_RANGE + start;
|
||||
}
|
||||
|
||||
#define GET_FLAG(ch, mask) (Servo_data[ch] > 0 ? mask : 0)
|
||||
static void send_HT_packet(uint8_t bind)
|
||||
{
|
||||
if (bind) {
|
||||
memcpy(packet, ht_txid, 5);
|
||||
memset(&packet[5], 0, 3);
|
||||
} else {
|
||||
if (sub_protocol == FORMAT_HONTAI) {
|
||||
packet[0] = 0x0b;
|
||||
} else {
|
||||
packet[0] = GET_FLAG(CHANNEL_ARM, 0x02);
|
||||
}
|
||||
packet[1] = 0x00;
|
||||
packet[2] = 0x00;
|
||||
packet[3] = (scale_HT_channel(THROTTLE, 0, 127) << 1) // throttle
|
||||
| GET_FLAG(CHANNEL_PICTURE, 0x01);
|
||||
packet[4] = scale_HT_channel(AILERON, 63, 0); // aileron
|
||||
if (sub_protocol == FORMAT_HONTAI) {
|
||||
packet[4] |= GET_FLAG(CHANNEL_RTH, 0x80)
|
||||
| GET_FLAG(CHANNEL_HEADLESS, 0x40);
|
||||
} else {
|
||||
packet[4] |= 0x80; // not sure what this bit does
|
||||
}
|
||||
packet[5] = scale_channel(CHANNEL2, 0, 63) // elevator
|
||||
| GET_FLAG(CHANNEL_CALIBRATE, 0x80)
|
||||
| GET_FLAG(CHANNEL_FLIP, 0x40);
|
||||
packet[6] = scale_HT_channel(RUDDER, 0, 63) // rudder
|
||||
| GET_FLAG(CHANNEL_VIDEO, 0x80);
|
||||
packet[7] = scale_HT_channel(AILERON, -16, 16); // aileron trim
|
||||
if (sub_protocol == FORMAT_HONTAI) {
|
||||
packet[8] = scale_HT_channel(RUDDER, -16, 16); // rudder trim
|
||||
} else {
|
||||
packet[8] = 0xc0 // always in expert mode
|
||||
| GET_FLAG(CHANNEL_RTH, 0x02)
|
||||
| GET_FLAG(CHANNEL_HEADLESS, 0x01);
|
||||
}
|
||||
packet[9] = scale_HT_channel(ELEVATOR, -16, 16); // elevator trim
|
||||
}
|
||||
crc16(packet, bind ? BIND_HT_PACKET_SIZE : PACKET_HT_SIZE);
|
||||
|
||||
// Power on, TX mode, 2byte CRC
|
||||
if (sub_protocol == FORMAT_HONTAI) {
|
||||
XN297_Configure(BV(NRF24L01_00_EN_CRC) | BV(NRF24L01_00_CRCO) | BV(NRF24L01_00_PWR_UP));
|
||||
} else {
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
}
|
||||
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, bind ? RF_BIND_HT_CHANNEL : rf_channels[sub_protocol][rf_chan++]);
|
||||
rf_chan %= sizeof(rf_channels);
|
||||
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
|
||||
NRF24L01_FlushTx();
|
||||
|
||||
if (sub_protocol == FORMAT_HONTAI) {
|
||||
XN297_WritePayload(packet, bind ? BIND_HT_PACKET_SIZE : PACKET_HT_SIZE);
|
||||
} else {
|
||||
NRF24L01_WritePayload(packet, bind ? BIND_HT_PACKET_SIZE : PACKET_HT_SIZE);
|
||||
}
|
||||
|
||||
NRF24L01_SetPower();
|
||||
}
|
||||
|
||||
static void ht_init()
|
||||
{
|
||||
NRF24L01_Initialize();
|
||||
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
|
||||
// SPI trace of stock TX has these writes to registers that don't appear in
|
||||
// nRF24L01 or Beken 2421 datasheets. Uncomment if you have an XN297 chip?
|
||||
// NRF24L01_WriteRegisterMulti(0x3f, "\x4c\x84\x67,\x9c,\x20", 5);
|
||||
// NRF24L01_WriteRegisterMulti(0x3e, "\xc9\x9a\xb0,\x61,\xbb,\xab,\x9c", 7);
|
||||
// NRF24L01_WriteRegisterMulti(0x39, "\x0b\xdf\xc4,\xa7,\x03,\xab,\x9c", 7);
|
||||
|
||||
if (sub_protocol == FORMAT_HONTAI) {
|
||||
XN297_SetTXAddr(rx_tx_ht_addr, sizeof(rx_tx_ht_addr));
|
||||
} else {
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_ht_addr, sizeof(rx_tx_ht_addr));
|
||||
}
|
||||
|
||||
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_SetBitrate(NRF24L01_BR_1M); // 1Mbps
|
||||
NRF24L01_SetPower();
|
||||
NRF24L01_Activate(0x73); // Activate feature register
|
||||
if (sub_protocol == FORMAT_HONTAI) {
|
||||
NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0x00); // no retransmits
|
||||
NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 0x00); // Disable dynamic payload length on all pipes
|
||||
NRF24L01_WriteReg(NRF24L01_1D_FEATURE, 0x00);
|
||||
NRF24L01_Activate(0x73); // Deactivate feature register
|
||||
} else {
|
||||
NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0xff); // JJRC uses dynamic payload length
|
||||
NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 0x3f); // match other stock settings even though AA disabled...
|
||||
NRF24L01_WriteReg(NRF24L01_1D_FEATURE, 0x07);
|
||||
}
|
||||
}
|
||||
|
||||
static void ht_init2()
|
||||
{
|
||||
uint8_t data_tx_addr[] = {0x2a, 0xda, 0xa5, 0x25, 0x24};
|
||||
|
||||
data_tx_addr[0] = addr_vals[0][ ht_txid[3] & 0x0f];
|
||||
data_tx_addr[1] = addr_vals[1][(ht_txid[3] >> 4) & 0x0f];
|
||||
data_tx_addr[2] = addr_vals[2][ ht_txid[4] & 0x0f];
|
||||
data_tx_addr[3] = addr_vals[3][(ht_txid[4] >> 4) & 0x0f];
|
||||
|
||||
if (sub_protocol == FORMAT_HONTAI) {
|
||||
XN297_SetTXAddr(data_tx_addr, sizeof(data_tx_addr));
|
||||
} else {
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, data_tx_addr, sizeof(data_tx_addr));
|
||||
}
|
||||
}
|
||||
|
||||
static uint16_t ht_callback()
|
||||
{
|
||||
switch (phase) {
|
||||
case HonTai_INIT1:
|
||||
phase = HonTai_BIND2;
|
||||
break;
|
||||
case HonTai_BIND2:
|
||||
if (counter == 0) {
|
||||
ht_init2();
|
||||
phase = HonTai_DATA;
|
||||
BIND_DONE;
|
||||
} else {
|
||||
send_HT_packet(1);
|
||||
counter -= 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case HonTai_DATA:
|
||||
send_HT_packet(0);
|
||||
break;
|
||||
}
|
||||
return PACKET_HT_PERIOD;
|
||||
}
|
||||
|
||||
static uint16_t ht_setup()
|
||||
{
|
||||
counter = BIND_HT_COUNT;
|
||||
|
||||
if (sub_protocol == FORMAT_HONTAI) {
|
||||
ht_txid[0] = 0x4c; // first three bytes some kind of model id? - set same as stock tx
|
||||
ht_txid[1] = 0x4b;
|
||||
ht_txid[2] = 0x3a;
|
||||
} else {
|
||||
ht_txid[0] = 0x4b; // JJRC X1
|
||||
ht_txid[1] = 0x59;
|
||||
ht_txid[2] = 0x3a;
|
||||
}
|
||||
ht_txid[3] = (MProtocol_id >> 8 ) & 0xff;
|
||||
ht_txid[4] = MProtocol_id & 0xff;
|
||||
|
||||
ht_init();
|
||||
phase = HonTai_INIT1;
|
||||
|
||||
return INITIAL_HT_WAIT;
|
||||
}
|
||||
#endif
|
||||
|
272
Multiprotocol/Nrf24l01_ne260.ino
Normal file
272
Multiprotocol/Nrf24l01_ne260.ino
Normal file
@ -0,0 +1,272 @@
|
||||
/*
|
||||
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.
|
||||
|
||||
Deviation 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 Deviation. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/* This code is based upon code from:
|
||||
http://www.rcgroups.com/forums/showthread.php?t=1564343
|
||||
Author : Ferenc Szili (kile at the rcgroups.net forum)
|
||||
*/
|
||||
|
||||
|
||||
#if defined(NE260_NRF24L01_INO)
|
||||
#include "iface_nrf24l01.h"
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
///////////////////////
|
||||
// register bits
|
||||
///////////////////////
|
||||
|
||||
// CONFIG
|
||||
#define MASK_RX_DR 6
|
||||
#define MASK_TX_DS 5
|
||||
#define MASK_MAX_RT 4
|
||||
#define EN_CRC 3
|
||||
#define CRCO 2
|
||||
#define PWR_UP 1
|
||||
#define PRIM_RX 0
|
||||
|
||||
// EN_AA
|
||||
#define ENAA_P5 5
|
||||
#define ENAA_P4 4
|
||||
#define ENAA_P3 3
|
||||
#define ENAA_P2 2
|
||||
#define ENAA_P1 1
|
||||
#define ENAA_P0 0
|
||||
|
||||
// EN_RXADDR
|
||||
#define ERX_P5 5
|
||||
#define ERX_P4 4
|
||||
#define ERX_P3 3
|
||||
#define ERX_P2 2
|
||||
#define ERX_P1 1
|
||||
#define ERX_P0 0
|
||||
|
||||
// RF_SETUP
|
||||
#define CONT_WAVE 7
|
||||
#define RF_DR_LOW 5
|
||||
#define PLL_LOCK 4
|
||||
#define RF_DR_HIGH 3
|
||||
#define RF_PWR_HIGH 2
|
||||
#define RF_PWR_LOW 1
|
||||
#define LNA_HCURR 0 // obsolete in nRF24L01+
|
||||
|
||||
// STATUS
|
||||
#define RX_DR 6
|
||||
#define TX_DS 5
|
||||
#define MAX_RT 4
|
||||
#define TX_FULL 0
|
||||
|
||||
// FIFO_STATUS
|
||||
#define TX_REUSE 6
|
||||
#define FIFO_TX_FULL 5
|
||||
#define TX_EMPTY 4
|
||||
#define RX_FULL 1
|
||||
#define RX_EMPTY 0
|
||||
|
||||
///////////////////////
|
||||
// register bit values
|
||||
///////////////////////
|
||||
|
||||
// CONFIG
|
||||
#define vMASK_RX_DR (1<<(MASK_RX_DR))
|
||||
#define vMASK_TX_DS (1<<(MASK_TX_DS))
|
||||
#define vMASK_MAX_RT (1<<(MASK_MAX_RT))
|
||||
#define vEN_CRC (1<<(EN_CRC))
|
||||
#define vCRCO (1<<(CRCO))
|
||||
#define vPWR_UP (1<<(PWR_UP))
|
||||
#define vPRIM_RX (1<<(PRIM_RX))
|
||||
|
||||
// EN_AA
|
||||
#define vENAA_P5 (1<<(ENAA_P5))
|
||||
#define vENAA_P4 (1<<(ENAA_P4))
|
||||
#define vENAA_P3 (1<<(ENAA_P3))
|
||||
#define vENAA_P2 (1<<(ENAA_P2))
|
||||
#define vENAA_P1 (1<<(ENAA_P1))
|
||||
#define vENAA_P0 (1<<(ENAA_P0))
|
||||
|
||||
// EN_RXADDR
|
||||
#define vERX_P5 (1<<(ERX_P5))
|
||||
#define vERX_P4 (1<<(ERX_P4))
|
||||
#define vERX_P3 (1<<(ERX_P3))
|
||||
#define vERX_P2 (1<<(ERX_P2))
|
||||
#define vERX_P1 (1<<(ERX_P1))
|
||||
#define vERX_P0 (1<<(ERX_P0))
|
||||
|
||||
// SETUP_AW -- address widths in bytes
|
||||
#define vAW_3 1
|
||||
#define vAW_4 2
|
||||
#define vAW_5 3
|
||||
|
||||
// RF_SETUP
|
||||
#define vCONT_WAVE (1<<(CONT_WAVE))
|
||||
#define vRF_DR_LOW (1<<(RF_DR_LOW))
|
||||
#define vPLL_LOCK (1<<(PLL_LOCK))
|
||||
#define vRF_DR_HIGH (1<<(RF_DR_HIGH))
|
||||
#define vRF_PWR_HIGH (1<<(RF_PWR_HIGH))
|
||||
#define vRF_PWR_LOW (1<<(RF_PWR_LOW))
|
||||
#define vLNA_HCURR (1<<(LNA_HCURR)) // obsolete in nRF24L01+
|
||||
|
||||
#define vRF_DR_1MBPS 0
|
||||
#define vRF_DR_2MBPS (1<<(RF_DR_HIGH))
|
||||
#define vRF_DR_250KBPS (1<<(RF_DR_LOW))
|
||||
|
||||
#define vRF_PWR_M18DBM 0x00
|
||||
#define vRF_PWR_M12DBM 0x02
|
||||
#define vRF_PWR_M6DBM 0x04
|
||||
#define vRF_PWR_0DBM 0x06
|
||||
|
||||
#define vARD_250us 0x00
|
||||
#define vARD_500us 0x10
|
||||
#define vARD_750us 0x20
|
||||
#define vARD_1000us 0x30
|
||||
#define vARD_1250us 0x40
|
||||
#define vARD_1500us 0x50
|
||||
#define vARD_1750us 0x60
|
||||
#define vARD_2000us 0x70
|
||||
#define vARD_2250us 0x80
|
||||
#define vARD_2500us 0x90
|
||||
#define vARD_2750us 0xA0
|
||||
#define vARD_3000us 0xB0
|
||||
#define vARD_3250us 0xC0
|
||||
#define vARD_3500us 0xD0
|
||||
#define vARD_3750us 0xE0
|
||||
#define vARD_4000us 0xF0
|
||||
|
||||
// STATUS
|
||||
#define vRX_DR (1<<(RX_DR))
|
||||
#define vTX_DS (1<<(TX_DS))
|
||||
#define vMAX_RT (1<<(MAX_RT))
|
||||
#define vTX_FULL (1<<(TX_FULL))
|
||||
|
||||
#define RX_P_NO(stat) ((stat >> 1) & 7)
|
||||
#define HAS_RX_PAYLOAD(stat) ((stat & 0b1110) < 0b1100)
|
||||
|
||||
// FIFO_STATUS
|
||||
#define vTX_REUSE (1<<(TX_REUSE))
|
||||
#define vTX_FULL (1<<(TX_FULL))
|
||||
#define vTX_EMPTY (1<<(TX_EMPTY))
|
||||
#define vRX_FULL (1<<(RX_FULL))
|
||||
#define vRX_EMPTY (1<<(RX_EMPTY))
|
||||
////////////////////////////////////////////////////////////
|
||||
uint8_t neChannel = 10;
|
||||
uint8_t neChannelOffset = 0;
|
||||
#define PACKET_NE_LENGTH 7
|
||||
|
||||
static uint16_t model_id = 0xA04A;
|
||||
|
||||
uint8_t NE_ch[]={THROTTLE, RUDDER, ELEVATOR, AILERON, AUX1};
|
||||
uint8_t NEAddr[] = {0x34, 0x43, 0x10, 0x10, 0x01};
|
||||
enum {
|
||||
NE260_BINDTX,
|
||||
NE260_BINDRX,
|
||||
NE260_DATA1,
|
||||
NE260_DATA2,
|
||||
NE260_DATA3,
|
||||
};
|
||||
|
||||
|
||||
static void ne260_init() {
|
||||
NRF24L01_Initialize();
|
||||
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, NEAddr, 5); // write the address
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, NEAddr, 5);
|
||||
|
||||
NRF24L01_WriteReg(NRF24L01_01_EN_AA, vENAA_P0); // enable auto acknoledge
|
||||
NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, vARD_500us); // ARD=500us, ARC=disabled
|
||||
NRF24L01_WriteReg(NRF24L01_06_RF_SETUP, vRF_DR_250KBPS | vLNA_HCURR | vRF_PWR_0DBM); // data rate, output power and noise cancel
|
||||
NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, PACKET_NE_LENGTH); // RX payload length
|
||||
NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, vERX_P0); // enable RX address
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, vRX_DR | vTX_DS | vMAX_RT); // reset the IRQ flags
|
||||
}
|
||||
|
||||
static void send_data_packet() {
|
||||
for(int i = 0; i < 4; i++) {
|
||||
uint32_t value = (uint32_t)Servo_data[NE_ch[i]] * 0x40 / PPM_MAX + 0x40;
|
||||
if (value > 0x7f)
|
||||
value = 0x7f;
|
||||
else if(value < 0)
|
||||
value = 0;
|
||||
packet[i] = value;
|
||||
}
|
||||
packet[4] = 0x55;
|
||||
packet[5] = model_id & 0xff;
|
||||
packet[6] = (model_id >> 8) & 0xff;
|
||||
|
||||
NRF24L01_FlushTx();
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, vMAX_RT);
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, neChannel + neChannelOffset);
|
||||
NRF24L01_WriteReg(NRF24L01_00_CONFIG, vEN_CRC | vCRCO | vPWR_UP);
|
||||
// send a fresh packet to the nRF
|
||||
NRF24L01_WritePayload((uint8_t*) packet, PACKET_NE_LENGTH);
|
||||
}
|
||||
|
||||
static void send_bind_packet() {
|
||||
packet[0] = 0xAA; //throttle
|
||||
packet[1] = 0xAA; //rudder
|
||||
packet[2] = 0xAA; //elevator
|
||||
packet[3] = 0xAA; //aileron
|
||||
packet[4] = 0xAA; //command
|
||||
packet[5] = model_id & 0xff;
|
||||
packet[6] = (model_id >> 8) & 0xff;
|
||||
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, vRX_DR | vTX_DS | vMAX_RT); // reset the status flags
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, neChannel + neChannelOffset);
|
||||
NRF24L01_FlushTx();
|
||||
NRF24L01_WritePayload((uint8_t*) &packet, PACKET_NE_LENGTH); // send the bind packet
|
||||
}
|
||||
|
||||
static uint16_t ne260_cb() {
|
||||
if (state == NE260_BINDTX) {
|
||||
// do we have a packet?
|
||||
if ((NRF24L01_ReadReg(NRF24L01_07_STATUS) & vRX_DR) != 0) {
|
||||
// read the packet contents
|
||||
NRF24L01_ReadPayload(packet, PACKET_NE_LENGTH);
|
||||
|
||||
// is this the bind response packet?
|
||||
if (strncmp("\x55\x55\x55\x55\x55", (char*) (packet + 1), 5) == 0 && *((uint16_t*)(packet + 6)) == model_id) {
|
||||
// exit the bind loop
|
||||
state = NE260_DATA1;
|
||||
NRF24L01_FlushTx();
|
||||
NRF24L01_FlushRx();
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
return 2000;
|
||||
}
|
||||
}
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
send_bind_packet();
|
||||
state = NE260_BINDRX;
|
||||
return 500;
|
||||
} else if (state == NE260_BINDRX) {
|
||||
// switch to RX mode
|
||||
while (!(NRF24L01_ReadReg(NRF24L01_07_STATUS) & (vMAX_RT | vTX_DS))) ;
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, vTX_DS);
|
||||
|
||||
NRF24L01_SetTxRxMode(RX_EN);
|
||||
NRF24L01_FlushRx();
|
||||
state = NE260_BINDTX;
|
||||
return 2000;
|
||||
}
|
||||
else if (state == NE260_DATA1) { neChannel = 10; state = NE260_DATA2; }
|
||||
else if (state == NE260_DATA2) { neChannel = 30; state = NE260_DATA3; }
|
||||
else if (state == NE260_DATA3) { neChannel = 50; state = NE260_DATA1; }
|
||||
send_data_packet();
|
||||
return 2500;
|
||||
}
|
||||
|
||||
static uint16_t NE260_setup() {
|
||||
ne260_init();
|
||||
state = NE260_BINDTX;
|
||||
|
||||
return 10000;
|
||||
}
|
||||
#endif
|
582
Multiprotocol/Nrf24l01_udi.ino
Normal file
582
Multiprotocol/Nrf24l01_udi.ino
Normal file
@ -0,0 +1,582 @@
|
||||
/*
|
||||
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.
|
||||
|
||||
Deviation 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 Deviation. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// Known UDI 2.4GHz protocol variants, all using BK2421
|
||||
// * UDI U819 coaxial 3ch helicoper
|
||||
// * UDI U816/817/818 quadcopters
|
||||
// - "V1" with orange LED on TX, U816 RX labeled '' , U817/U818 RX labeled 'UD-U817B'
|
||||
// - "V2" with red LEDs on TX, U816 RX labeled '', U817/U818 RX labeled 'UD-U817OG'
|
||||
// - "V3" with green LEDs on TX. Did not get my hands on yet.
|
||||
// * U830 mini quadcopter with tilt steering ("Protocol 2014")
|
||||
// * U839 nano quadcopter ("Protocol 2014")
|
||||
|
||||
#if defined(UDI_NRF24L01_INO)
|
||||
#include "iface_nrf24l01.h"
|
||||
|
||||
#define BIND_UDI_COUNT 1000
|
||||
|
||||
// Timeout for callback in uSec, 4ms=4000us for UDI
|
||||
// ???
|
||||
//#define PACKET_UDI_PERIOD 4000
|
||||
|
||||
#define BIND_PACKET_UDI_PERIOD 5000
|
||||
#define PACKET_UDI_PERIOD 15000
|
||||
|
||||
#define BIND_PACKETS_UDI_PER_CHANNEL 11
|
||||
#define PACKETS_UDI_PER_CHANNEL 11
|
||||
|
||||
#define NUM_UDI_RF_CHANNELS 16
|
||||
|
||||
|
||||
#define INITIAL_UDI_WAIT 50000
|
||||
|
||||
#define PACKET_UDI_CHKTIME 100
|
||||
|
||||
// For readability
|
||||
enum {
|
||||
UDI_CAMERA = 1,
|
||||
UDI_VIDEO = 2,
|
||||
UDI_MODE2 = 4,
|
||||
UDI_FLIP360 = 8,
|
||||
UDI_FLIP =16,
|
||||
UDI_LIGHTS =32
|
||||
};
|
||||
|
||||
// This is maximum payload size used in UDI protocols
|
||||
#define UDI_PAYLOADSIZE 16
|
||||
|
||||
|
||||
|
||||
static uint8_t payload_size; // Bytes in payload for selected variant
|
||||
static uint8_t bind_channel;
|
||||
static uint8_t packets_to_hop;
|
||||
static uint8_t packets_to_check; // BIND_RX phase needs to receive/auto-ack more than one packet for RX to switch to next phase, it seems
|
||||
static uint8_t packets_to_send; // Number of packets to send / check for in current bind phase
|
||||
static uint8_t bind_step_success; // Indicates successfull transmission / receive of bind reply during current bind phase
|
||||
static uint8_t tx_id[3];
|
||||
static uint8_t rx_id[3];
|
||||
static uint8_t randoms[3]; // 3 random bytes choosen by TX, sent in BIND packets. Lower nibble of first byte sets index in RF CH table to use for BIND2
|
||||
|
||||
|
||||
//
|
||||
enum {
|
||||
UDI_INIT2 = 0,
|
||||
UDI_INIT2_NO_BIND,
|
||||
UDI_BIND1_TX,
|
||||
UDI_BIND1_RX,
|
||||
UDI_BIND2_TX,
|
||||
UDI_BIND2_RX,
|
||||
UDI_DATA
|
||||
};
|
||||
|
||||
enum {
|
||||
PROTOOPTS_FORMAT = 0,
|
||||
PROTOOPTS_STARTBIND,
|
||||
};
|
||||
enum {
|
||||
STARTBIND_NO = 0,
|
||||
STARTBIND_YES = 1,
|
||||
};
|
||||
|
||||
// This are frequency hopping tables for UDI protocols
|
||||
|
||||
// uint8_t16 V1 (Orange LED) Bind CH 0x07
|
||||
// TX ID 0x57, 0x5A, 0x2D
|
||||
static const uint8_t freq_hopping_uint8_t16_v1[NUM_UDI_RF_CHANNELS] = {
|
||||
0x07, 0x21, 0x49, 0x0B, 0x39, 0x10, 0x25, 0x42,
|
||||
0x1D, 0x31, 0x35, 0x14, 0x28, 0x3D, 0x18, 0x2D
|
||||
};
|
||||
|
||||
// Protocol 2014 (uint8_t30,uint8_t39,...) BIND CH 0x23 (second entry)
|
||||
// DATA: hops ~ every 0.361s (0.350 ... 0.372)
|
||||
static const uint8_t freq_hopping_uint8_t39[NUM_UDI_RF_CHANNELS] = {
|
||||
0x08, 0x23, 0x48, 0x0D, 0x3B, 0x12, 0x27, 0x44,
|
||||
0x1F, 0x33, 0x37, 0x16, 0x2A, 0x3F, 0x1A, 0x2F
|
||||
};
|
||||
|
||||
// Points to proper table
|
||||
static const uint8_t * rf_udi_channels = NULL;
|
||||
|
||||
|
||||
static uint8_t packet_udi_ack()
|
||||
{
|
||||
switch (NRF24L01_ReadReg(NRF24L01_07_STATUS) & (BV(NRF24L01_07_TX_DS) | BV(NRF24L01_07_MAX_RT))) {
|
||||
case BV(NRF24L01_07_TX_DS): return PKT_ACKED;
|
||||
case BV(NRF24L01_07_MAX_RT): return PKT_TIMEOUT;
|
||||
}
|
||||
return PKT_PENDING;
|
||||
}
|
||||
|
||||
static void UDI_init()
|
||||
{
|
||||
NRF24L01_Initialize();
|
||||
//NRF24L01_SetTxRxMode(TX_EN);
|
||||
|
||||
switch (sub_protocol) {
|
||||
case U816_V1:
|
||||
rf_udi_channels = freq_hopping_uint8_t16_v1;
|
||||
payload_size = 8;
|
||||
break;
|
||||
|
||||
case U816_V2:
|
||||
rf_udi_channels = NULL; // NO HOPPING !
|
||||
payload_size = 7;
|
||||
break;
|
||||
|
||||
case U839_2014:
|
||||
// UDI 2014 Protocol (uint8_t30, uint8_t39, all other new products ?)
|
||||
rf_udi_channels = freq_hopping_uint8_t39;
|
||||
payload_size = 8;
|
||||
break;
|
||||
}
|
||||
|
||||
NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, payload_size);
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x07); // Clear status bits
|
||||
|
||||
if ((sub_protocol == U816_V1) || (sub_protocol == U816_V2)) {
|
||||
NRF24L01_WriteReg(NRF24L01_06_RF_SETUP, 0x27); //
|
||||
NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0x3A); //
|
||||
NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x01); // 3 byte address
|
||||
NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0
|
||||
NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x3F); // Auto-acknowledge on all data pipers, same as YD
|
||||
if (sub_protocol == U816_V1) {
|
||||
NRF24L01_WriteReg(NRF24L01_00_CONFIG, 0x7F); //
|
||||
} else {
|
||||
NRF24L01_WriteReg(NRF24L01_00_CONFIG, 0x7A); //
|
||||
}
|
||||
} else
|
||||
if (sub_protocol == U839_2014) {
|
||||
NRF24L01_WriteReg(NRF24L01_06_RF_SETUP, 0x0F); // 2Mbps air rate, 5dBm RF output power, high LNA gain
|
||||
NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0x1A); // 500uS retransmit t/o, 10 tries (same as YD)
|
||||
NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x01); // 3 byte address
|
||||
NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0
|
||||
NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x3F); // Auto-acknowledge on all data pipers, same as YD
|
||||
NRF24L01_WriteReg(NRF24L01_00_CONFIG, 0x0F); // Enable CRC, 2 byte CRC, PWR UP, PRIMARY RX
|
||||
}
|
||||
|
||||
NRF24L01_FlushTx();
|
||||
NRF24L01_FlushRx();
|
||||
uint8_t status = NRF24L01_ReadReg(NRF24L01_07_STATUS);
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, status);
|
||||
|
||||
status = NRF24L01_ReadReg(NRF24L01_07_STATUS);
|
||||
NRF24L01_FlushTx();
|
||||
status = NRF24L01_ReadReg(NRF24L01_07_STATUS);
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, status);
|
||||
|
||||
// Implicit delay in callback
|
||||
// delayMicroseconds(120)
|
||||
}
|
||||
|
||||
static void UDI_init2()
|
||||
{
|
||||
NRF24L01_FlushTx();
|
||||
bind_step_success = 0;
|
||||
packet_sent = 0;
|
||||
|
||||
switch (sub_protocol) {
|
||||
case U816_V1:
|
||||
rf_ch_num = 0;
|
||||
bind_channel = rf_udi_channels[rf_ch_num++];
|
||||
break;
|
||||
case U816_V2:
|
||||
rf_ch_num = 0x07; // This is actual channel. No hopping here
|
||||
bind_channel = 0;
|
||||
break;
|
||||
case U839_2014:
|
||||
rf_ch_num = 1;
|
||||
bind_channel = rf_udi_channels[rf_ch_num++];
|
||||
break;
|
||||
}
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, bind_channel);
|
||||
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, (uint8_t *) "\xe7\x7e\xe7", 3);
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, (uint8_t *) "\xe7\x7e\xe7", 3);
|
||||
|
||||
// Turn radio power on
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
uint8_t config = BV(NRF24L01_00_EN_CRC) | BV(NRF24L01_00_CRCO) | BV(NRF24L01_00_PWR_UP);
|
||||
NRF24L01_WriteReg(NRF24L01_00_CONFIG, config);
|
||||
// Implicit delay in callback
|
||||
// delayMicroseconds(150);
|
||||
}
|
||||
|
||||
static void set_tx_id(uint32_t id)
|
||||
{
|
||||
tx_id[0] = (id >> 16) & 0xFF;
|
||||
tx_id[1] = (id >> 8) & 0xFF;
|
||||
tx_id[2] = (id >> 0) & 0xFF;
|
||||
|
||||
/*
|
||||
uint32_t val = rand32(); randoms[0] = val & 0xff; randoms[1] = (val >> 8 ) & 0xff; randoms[2] = (val >> 16 ) & 0xff;
|
||||
*/
|
||||
// FIXME
|
||||
// This one has been observed, leads to RF CH 0x1F (#08) used for BIND2
|
||||
randoms[0] = 0x98; randoms[1] = 0x80; randoms[2] = 0x5B;
|
||||
}
|
||||
|
||||
static void add_pkt_checksum()
|
||||
{
|
||||
// CHECKSUM was introduced with 2014 protocol
|
||||
if (sub_protocol < U839_2014) return;
|
||||
uint8_t sum = 0;
|
||||
for (uint8_t i = 0; i < payload_size-1; ++i) sum += packet[i];
|
||||
packet[payload_size-1] = sum & 0x3f; // *sick*
|
||||
}
|
||||
|
||||
|
||||
static uint8_t convert_channel(uint8_t num, uint8_t chn_max, uint8_t sign_ofs)
|
||||
{
|
||||
uint32_t ch = Servo_data[num];
|
||||
if (ch < PPM_MIN) {
|
||||
ch = PPM_MIN;
|
||||
} else if (ch > PPM_MAX) {
|
||||
ch = PPM_MAX;
|
||||
}
|
||||
uint32_t chn_val;
|
||||
if (sign_ofs) chn_val = (((ch * chn_max / PPM_MAX) + sign_ofs) >> 1);
|
||||
else chn_val = (ch * chn_max / PPM_MAX);
|
||||
if (chn_val < 0) chn_val = 0;
|
||||
else if (chn_val > chn_max) chn_val = chn_max;
|
||||
return (uint8_t) chn_val;
|
||||
}
|
||||
|
||||
|
||||
static void read_controls(uint8_t* throttle, uint8_t* rudder, uint8_t* elevator, uint8_t* aileron,
|
||||
uint8_t* flags)
|
||||
{
|
||||
// Protocol is registered AETRG, that is
|
||||
// Aileron is channel 0, Elevator - 1, Throttle - 2, Rudder - 3
|
||||
// Sometimes due to imperfect calibration or mixer settings
|
||||
// throttle can be less than PPM_MIN or larger than
|
||||
// PPM_MAX. As we have no space here, we hard-limit
|
||||
// channels values by min..max range
|
||||
|
||||
// Channel 3: throttle is 0-100
|
||||
*throttle = convert_channel(THROTTLE, 0x64, 0);
|
||||
|
||||
// Channel 4
|
||||
*rudder = convert_channel(RUDDER, 0x3f, 0x20);
|
||||
|
||||
// Channel 2
|
||||
*elevator = convert_channel(ELEVATOR, 0x3f, 0x20);
|
||||
|
||||
// Channel 1
|
||||
*aileron = convert_channel(AILERON, 0x3f, 0x20);
|
||||
|
||||
// Channel 5
|
||||
if (Servo_data[AUX1] <= 0) *flags &= ~UDI_FLIP360;
|
||||
else *flags |= UDI_FLIP360;
|
||||
|
||||
// Channel 6
|
||||
if (Servo_data[AUX2] <= 0) *flags &= ~UDI_FLIP;
|
||||
else *flags |= UDI_FLIP;
|
||||
|
||||
// Channel 7
|
||||
if (Servo_data[AUX3] <= 0) *flags &= ~UDI_CAMERA;
|
||||
else *flags |= UDI_CAMERA;
|
||||
|
||||
// Channel 8
|
||||
if (Servo_data[AUX4] <= 0) *flags &= ~UDI_VIDEO;
|
||||
else *flags |= UDI_VIDEO;
|
||||
|
||||
// Channel 9
|
||||
if (Servo_data[AUX5] <= 0) *flags &= ~UDI_LIGHTS;
|
||||
else *flags |= UDI_LIGHTS;
|
||||
|
||||
// Channel 10
|
||||
if (Servo_data[AUX6] <= 0) *flags &= ~UDI_MODE2;
|
||||
else *flags |= UDI_MODE2;
|
||||
}
|
||||
|
||||
static void send_udi_packet(uint8_t bind)
|
||||
{
|
||||
packet[7] = 0x4A;
|
||||
if (bind == 1) {
|
||||
// Bind phase 1
|
||||
// MAGIC
|
||||
packet[0] = 0x5A; // NOTE: Also 0xF3, when RX does not ACK packets (uint8_t39, only TX on) ...
|
||||
// Current Address / TX ID
|
||||
if (sub_protocol == U839_2014) {
|
||||
// uint8_t39: Current RX/TX Addr
|
||||
packet[1] = 0xE7;
|
||||
packet[2] = 0x7E;
|
||||
packet[3] = 0xE7;
|
||||
} else {
|
||||
// uint8_t16: ID Fixed per TX
|
||||
packet[1] = tx_id[0];
|
||||
packet[2] = tx_id[1];
|
||||
packet[3] = tx_id[2];
|
||||
}
|
||||
// Pseudo random values (lower nibble of packet[4] determines index of RF CH used in BIND2)
|
||||
packet[4] = randoms[0];
|
||||
packet[5] = randoms[1];
|
||||
packet[6] = randoms[2];
|
||||
if (sub_protocol == U839_2014) {
|
||||
packet[7] = (packet_counter < 4) ? 0x3f : 0x04; // first four packets use 0x3f here, then 0x04
|
||||
}
|
||||
} else if (bind == 2) {
|
||||
// Bind phase 2
|
||||
// MAGIC
|
||||
packet[0] = 0xAA;
|
||||
// Current Address (RX "ID", pseudorandom again)
|
||||
packet[1] = rx_id[0];
|
||||
packet[2] = rx_id[1];
|
||||
packet[3] = rx_id[2];
|
||||
// Pseudo random values
|
||||
packet[4] = randoms[0];
|
||||
packet[5] = randoms[1];
|
||||
packet[6] = randoms[2];
|
||||
if (sub_protocol == U839_2014) {
|
||||
packet[7] = 0x04;
|
||||
}
|
||||
} else {
|
||||
// regular packet
|
||||
// Read channels (converts to required ranges)
|
||||
read_controls(&throttle, &rudder, &elevator, &aileron, &flags);
|
||||
// MAGIC
|
||||
packet[0] = 0x55;
|
||||
packet[1] = throttle; // throttle is 0-0x64
|
||||
// 3 Channels packed into 2 bytes (5bit per channel)
|
||||
uint16_t encoded = (rudder << 11) | (elevator << 6) | (aileron << 1);
|
||||
packet[2] = (encoded >> 8) & 0xff;
|
||||
packet[3] = encoded & 0xff;
|
||||
// Trims and flags (0x20 = center)
|
||||
packet[4] = 0x20; // rudder trim 6bit
|
||||
packet[5] = 0x20; // elev trim 6bit
|
||||
packet[6] = 0x20; // ail trim 6bit
|
||||
|
||||
if (flags & UDI_FLIP) packet[4] |= 0x80; // "Directional" flip
|
||||
if (flags & UDI_LIGHTS) packet[4] |= 0x40; // Light on/off
|
||||
|
||||
if (flags & UDI_MODE2) packet[5] |= 0x80; // High rate ("Mode2")
|
||||
if (flags & UDI_FLIP360) packet[5] |= 0x40; // 360 degree flip
|
||||
|
||||
if (flags & UDI_VIDEO) packet[6] |= 0x80; // Video recording on/off
|
||||
if (flags & UDI_CAMERA) packet[6] |= 0x40; // Take picture
|
||||
|
||||
// NOTE: Only newer protocols have this (handled by routine)
|
||||
add_pkt_checksum();
|
||||
}
|
||||
|
||||
uint8_t status = NRF24L01_ReadReg(NRF24L01_07_STATUS);
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS,status);
|
||||
|
||||
if (packet_sent && bind && (status & BV(NRF24L01_07_TX_DS))) {
|
||||
bind_step_success = 1;
|
||||
}
|
||||
|
||||
packet_sent = 0;
|
||||
|
||||
// Check if its time to change channel
|
||||
// This seems to be done by measuring time,
|
||||
// not by counting packets, on UDI transmitters
|
||||
// NOTE: Seems even in bind phase channels are changed
|
||||
|
||||
// NOTE: Only hop in TX mode ???
|
||||
if (rf_udi_channels && (bind == 0) && (packets_to_hop-- == 0)) {
|
||||
uint8_t rf_ch = rf_udi_channels[rf_ch_num];
|
||||
rf_ch_num++;
|
||||
rf_ch_num %= NUM_UDI_RF_CHANNELS;
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, rf_ch);
|
||||
|
||||
packets_to_hop = bind ? BIND_PACKETS_UDI_PER_CHANNEL : PACKETS_UDI_PER_CHANNEL;
|
||||
}
|
||||
NRF24L01_FlushTx();
|
||||
NRF24L01_WritePayload(packet, payload_size);
|
||||
++packet_counter;
|
||||
packet_sent = 1;
|
||||
}
|
||||
|
||||
|
||||
static uint16_t UDI_callback() {
|
||||
switch (phase) {
|
||||
case UDI_INIT2:
|
||||
UDI_init2();
|
||||
phase = UDI_BIND1_TX;
|
||||
return 120;
|
||||
break;
|
||||
case UDI_INIT2_NO_BIND:
|
||||
// Do nothing (stay forever)
|
||||
// Cannot re-bind on UDI protocol since IDs are random
|
||||
return 10000; // 10ms
|
||||
break;
|
||||
case UDI_BIND1_TX:
|
||||
if (packet_sent && packet_udi_ack() == PKT_ACKED) { bind_step_success = 1; }
|
||||
if (bind_step_success) {
|
||||
// All fine, wait for reply of receiver
|
||||
phase = UDI_BIND1_RX;
|
||||
|
||||
NRF24L01_SetTxRxMode(RX_EN);
|
||||
NRF24L01_FlushRx();
|
||||
|
||||
NRF24L01_WriteReg(NRF24L01_00_CONFIG, 0x0F);
|
||||
bind_step_success = 0;
|
||||
//packets_to_check = 12; // according to SPI traces on uint8_t17B RX it receives 12 packets (and answers with 5)
|
||||
packets_to_check = 3;
|
||||
} else {
|
||||
send_udi_packet(1);
|
||||
}
|
||||
return BIND_PACKET_UDI_PERIOD;
|
||||
break;
|
||||
case UDI_BIND1_RX:
|
||||
// Check if data has been received
|
||||
if (NRF24L01_ReadReg(NRF24L01_07_STATUS) & BV(NRF24L01_07_RX_DR) ) {
|
||||
uint8_t data[UDI_PAYLOADSIZE];
|
||||
NRF24L01_ReadPayload(data, payload_size);
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x4E); // On original TX this is done on LAST packet check only !
|
||||
NRF24L01_FlushRx();
|
||||
|
||||
// Verify MAGIC and Random ID
|
||||
// (may be reply to bind packet from other TX)
|
||||
if ((data[0] == 0xA5) &&
|
||||
(data[4] == randoms[0]) &&
|
||||
(data[5] == randoms[1]) &&
|
||||
(data[6] == randoms[2]) &&
|
||||
(data[7] == randoms[2])) {
|
||||
rx_id[0] = data[1];
|
||||
rx_id[1] = data[2];
|
||||
rx_id[2] = data[3];
|
||||
if (sub_protocol != U816_V2) {
|
||||
rf_ch_num = randoms[0] & 0x0f;
|
||||
}
|
||||
bind_step_success = 1;
|
||||
}
|
||||
}
|
||||
// RX seems to need more than one ACK
|
||||
if (packets_to_check) packets_to_check--;
|
||||
//NRF24L01_WriteReg(NRF24L01_00_CONFIG, 0x0F);
|
||||
if (bind_step_success && !packets_to_check) {
|
||||
// All fine, switch address and RF channel,
|
||||
// send bind packets with channel hopping now
|
||||
phase = UDI_BIND2_TX;
|
||||
|
||||
packet_sent = 0;
|
||||
packets_to_send = 4;
|
||||
bind_step_success = 0;
|
||||
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, rx_id, 3);
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_id, 3);
|
||||
|
||||
if (sub_protocol != U816_V2) {
|
||||
// Switch RF channel
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, rf_udi_channels[rf_ch_num++]);
|
||||
rf_ch_num %= NUM_UDI_RF_CHANNELS;
|
||||
}
|
||||
|
||||
NRF24L01_FlushTx();
|
||||
NRF24L01_FlushRx();
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x7E);
|
||||
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
//NRF24L01_WriteReg(NRF24L01_00_CONFIG, 0x0E)
|
||||
|
||||
return 10; // 10 µs (start sending immediately)
|
||||
}
|
||||
return BIND_PACKET_UDI_PERIOD;
|
||||
break;
|
||||
|
||||
case UDI_BIND2_TX:
|
||||
if (packet_sent && packet_udi_ack() == PKT_ACKED) {
|
||||
bind_step_success = 1;
|
||||
}
|
||||
send_udi_packet(2);
|
||||
if (packets_to_send) --packets_to_send;
|
||||
if (bind_step_success || !packets_to_send) {
|
||||
// Seems the original TX ignores AACK, too !
|
||||
// U816 V1: 3 packets send, U839: 4 packets send
|
||||
// All fine, wait for reply of receiver
|
||||
phase = UDI_BIND2_RX;
|
||||
|
||||
NRF24L01_SetTxRxMode(RX_EN);
|
||||
NRF24L01_FlushRx();
|
||||
|
||||
NRF24L01_WriteReg(NRF24L01_00_CONFIG, 0x0F);
|
||||
bind_step_success = 0;
|
||||
packets_to_check = 14; // ???
|
||||
}
|
||||
return bind_step_success ? 4000 : 12000; // 4ms if no packed acked yet, 12ms afterwards
|
||||
// return 120; // FIXME: Varies for first three packets !!!
|
||||
|
||||
break;
|
||||
|
||||
case UDI_BIND2_RX:
|
||||
// Check if data has been received
|
||||
if (NRF24L01_ReadReg(NRF24L01_07_STATUS) & BV(NRF24L01_07_RX_DR) ) {
|
||||
uint8_t data[UDI_PAYLOADSIZE];
|
||||
NRF24L01_ReadPayload(data, payload_size);
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x4E);
|
||||
NRF24L01_FlushRx();
|
||||
|
||||
// Verify MAGIC, RX Addr, Random ID
|
||||
// (may be reply to bind packet from other TX)
|
||||
if ((data[0] == 0xDD) &&
|
||||
(data[1] == rx_id[0]) &&
|
||||
(data[2] == rx_id[1]) &&
|
||||
(data[3] == rx_id[2]) &&
|
||||
(data[4] == randoms[0]) &&
|
||||
(data[5] == randoms[1]) &&
|
||||
(data[6] == randoms[2]) &&
|
||||
(data[7] == randoms[2])) {
|
||||
bind_step_success = 1;
|
||||
}
|
||||
}
|
||||
// RX seems to need more than one ACK
|
||||
if (packets_to_check) packets_to_check--;
|
||||
//NRF24L01_WriteReg(NRF24L01_00_CONFIG, 0x0F);
|
||||
if (bind_step_success && !packets_to_check) {
|
||||
phase = UDI_DATA;
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x7E);
|
||||
NRF24L01_WriteReg(NRF24L01_00_CONFIG, 0x0E);
|
||||
NRF24L01_FlushTx();
|
||||
|
||||
// Switch RF channel
|
||||
if (sub_protocol == U816_V2) {
|
||||
// FIXED RF Channel
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, rf_ch_num);
|
||||
} else {
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, rf_udi_channels[rf_ch_num++]);
|
||||
rf_ch_num %= NUM_UDI_RF_CHANNELS;
|
||||
}
|
||||
|
||||
flags = 0;
|
||||
BIND_DONE;
|
||||
}
|
||||
return BIND_PACKET_UDI_PERIOD;
|
||||
break;
|
||||
case UDI_DATA:
|
||||
if (packet_sent && packet_udi_ack() != PKT_ACKED) {
|
||||
return PACKET_UDI_CHKTIME;
|
||||
}
|
||||
send_udi_packet(0);
|
||||
break;
|
||||
}
|
||||
// Packet every 15ms
|
||||
return PACKET_UDI_PERIOD;
|
||||
}
|
||||
|
||||
static uint16_t UDI_setup()
|
||||
{
|
||||
packet_counter = 0;
|
||||
UDI_init();
|
||||
phase = UDI_INIT2;
|
||||
|
||||
// observed on U839 TX
|
||||
set_tx_id(0x457C27);
|
||||
|
||||
return INITIAL_UDI_WAIT;
|
||||
}
|
||||
#endif
|
@ -1,3 +1,5 @@
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
/*
|
||||
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
|
||||
@ -13,6 +15,7 @@
|
||||
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
#if defined(SHENQI_NRF24L01_INO)
|
||||
|
||||
#include "iface_nrf24l01.h"
|
||||
@ -39,10 +42,17 @@ void SHENQI_init()
|
||||
|
||||
NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x03); // 5 bytes rx/tx address
|
||||
|
||||
<<<<<<< HEAD
|
||||
LT8910_Config(4, 8, _BV(LT8910_CRC_ON)|_BV(LT8910_PACKET_LENGTH_EN), 0xAA);
|
||||
LT8910_SetChannel(2);
|
||||
LT8910_SetAddress((uint8_t *)"\x9A\x9A\x9A\x9A",4);
|
||||
LT8910_SetTxRxMode(RX_EN);
|
||||
=======
|
||||
LT8900_Config(4, 8, _BV(LT8900_CRC_ON)|_BV(LT8900_PACKET_LENGTH_EN), 0xAA);
|
||||
LT8900_SetChannel(2);
|
||||
LT8900_SetAddress((uint8_t *)"\x9A\x9A\x9A\x9A",4);
|
||||
LT8900_SetTxRxMode(RX_EN);
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
}
|
||||
|
||||
void SHENQI_send_packet()
|
||||
@ -51,6 +61,16 @@ void SHENQI_send_packet()
|
||||
if(packet_count==0)
|
||||
{
|
||||
uint8_t bind_addr[4];
|
||||
<<<<<<< HEAD
|
||||
bind_addr[0]=0x9A;
|
||||
bind_addr[1]=0x9A;
|
||||
bind_addr[2]=rx_tx_addr[2];
|
||||
bind_addr[3]=rx_tx_addr[3];
|
||||
LT8910_SetAddress(bind_addr,4);
|
||||
LT8910_SetChannel(2);
|
||||
packet[1]=rx_tx_addr[1];
|
||||
packet[2]=rx_tx_addr[0];
|
||||
=======
|
||||
bind_addr[0]=rx_tx_addr[0];
|
||||
bind_addr[1]=rx_tx_addr[1];
|
||||
bind_addr[2]=0x9A;
|
||||
@ -59,24 +79,39 @@ void SHENQI_send_packet()
|
||||
LT8900_SetChannel(2);
|
||||
packet[1]=rx_tx_addr[2];
|
||||
packet[2]=rx_tx_addr[3];
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
packet_period=2508;
|
||||
}
|
||||
else
|
||||
{
|
||||
<<<<<<< HEAD
|
||||
LT8910_SetAddress(rx_tx_addr,4);
|
||||
packet[1]=255-convert_channel_8b(RUDDER);
|
||||
packet[2]=255-convert_channel_8b_scale(THROTTLE,0x60,0xA0);
|
||||
uint8_t freq=pgm_read_byte_near(&SHENQI_Freq[hopping_frequency_no])+(rx_tx_addr[1]&0x0F);
|
||||
LT8910_SetChannel(freq);
|
||||
=======
|
||||
LT8900_SetAddress(rx_tx_addr,4);
|
||||
packet[1]=255-convert_channel_8b(RUDDER);
|
||||
packet[2]=255-convert_channel_8b_scale(THROTTLE,0x60,0xA0);
|
||||
uint8_t freq=pgm_read_byte_near(&SHENQI_Freq[hopping_frequency_no])+(rx_tx_addr[2]&0x0F);
|
||||
LT8900_SetChannel(freq);
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
hopping_frequency_no++;
|
||||
if(hopping_frequency_no==60)
|
||||
hopping_frequency_no=0;
|
||||
packet_period=1750;
|
||||
}
|
||||
// Send packet + 1 retransmit - not sure why but needed (not present on original TX...)
|
||||
<<<<<<< HEAD
|
||||
LT8910_WritePayload(packet,3);
|
||||
while(NRF24L01_packet_ack()!=PKT_ACKED);
|
||||
LT8910_WritePayload(packet,3);
|
||||
=======
|
||||
LT8900_WritePayload(packet,3);
|
||||
while(NRF24L01_packet_ack()!=PKT_ACKED);
|
||||
LT8900_WritePayload(packet,3);
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
|
||||
packet_count++;
|
||||
if(packet_count==7)
|
||||
@ -94,6 +129,16 @@ uint16_t SHENQI_callback()
|
||||
SHENQI_send_packet();
|
||||
else
|
||||
{
|
||||
<<<<<<< HEAD
|
||||
if( NRF24L01_ReadReg(NRF24L01_07_STATUS) & BV(NRF24L01_07_RX_DR))
|
||||
{
|
||||
if(LT8910_ReadPayload(packet, 3))
|
||||
{
|
||||
BIND_DONE;
|
||||
rx_tx_addr[3]=packet[1];
|
||||
rx_tx_addr[2]=packet[2];
|
||||
LT8910_SetTxRxMode(TX_EN);
|
||||
=======
|
||||
if( NRF24L01_ReadReg(NRF24L01_07_STATUS) & _BV(NRF24L01_07_RX_DR))
|
||||
{
|
||||
if(LT8900_ReadPayload(packet, 3))
|
||||
@ -102,6 +147,7 @@ uint16_t SHENQI_callback()
|
||||
rx_tx_addr[0]=packet[1];
|
||||
rx_tx_addr[1]=packet[2];
|
||||
LT8900_SetTxRxMode(TX_EN);
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
packet_period=14000;
|
||||
}
|
||||
NRF24L01_FlushRx();
|
||||
@ -116,7 +162,11 @@ uint16_t initSHENQI()
|
||||
SHENQI_init();
|
||||
hopping_frequency_no = 0;
|
||||
packet_count=0;
|
||||
<<<<<<< HEAD
|
||||
packet_period=100;
|
||||
=======
|
||||
packet_period=500;
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
return 1000;
|
||||
}
|
||||
|
||||
|
@ -1,3 +1,178 @@
|
||||
<<<<<<< HEAD
|
||||
//*************************************
|
||||
// FrSky Telemetry serial code *
|
||||
// By Midelic on RCGroups *
|
||||
//*************************************
|
||||
|
||||
#if defined TELEMETRY
|
||||
#if defined FRSKYX_CC2500_INO
|
||||
#define SPORT_TELEMETRY
|
||||
#endif
|
||||
#if defined FRSKY_CC2500_INO
|
||||
#define HUB_TELEMETRY
|
||||
#endif
|
||||
#if defined SPORT_TELEMETRY
|
||||
#define SPORT_TELEMETRY
|
||||
#define SPORT_TIME 12000
|
||||
uint32_t last=0;
|
||||
uint8_t sport_counter=0;
|
||||
uint8_t RxBt=0;
|
||||
uint8_t rssi;
|
||||
uint8_t ADC2;
|
||||
#endif
|
||||
#if defined HUB_TELEMETRY
|
||||
#define MAX_PKTX 10
|
||||
uint8_t pktx[MAX_PKTX];
|
||||
uint8_t index;
|
||||
uint8_t prev_index;
|
||||
uint8_t pass = 0;
|
||||
#endif
|
||||
#define USER_MAX_BYTES 6
|
||||
uint8_t frame[18];
|
||||
|
||||
void frskySendStuffed()
|
||||
{
|
||||
Serial_write(0x7E);
|
||||
for (uint8_t i = 0; i < 9; i++)
|
||||
{
|
||||
if ((frame[i] == 0x7e) || (frame[i] == 0x7d))
|
||||
{
|
||||
Serial_write(0x7D);
|
||||
frame[i] ^= 0x20;
|
||||
}
|
||||
Serial_write(frame[i]);
|
||||
}
|
||||
Serial_write(0x7E);
|
||||
}
|
||||
|
||||
void compute_RSSIdbm(){
|
||||
|
||||
RSSI_dBm = (((uint16_t)(pktt[len-2])*18)>>5);
|
||||
if(pktt[len-2] >=128)
|
||||
RSSI_dBm -= 82;
|
||||
else
|
||||
RSSI_dBm += 65;
|
||||
}
|
||||
|
||||
void frsky_check_telemetry(uint8_t *pkt,uint8_t len)
|
||||
{
|
||||
if(pkt[1] != rx_tx_addr[3] || pkt[2] != rx_tx_addr[2] || len != pkt[0] + 3)
|
||||
{//only packets with the required id and packet length
|
||||
for(uint8_t i=3;i<6;i++)
|
||||
pktt[i]=0;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (uint8_t i=3;i<len;i++)
|
||||
pktt[i]=pkt[i];
|
||||
telemetry_link=1;
|
||||
if(pktt[6]>0)
|
||||
telemetry_counter=(telemetry_counter+1)%32;
|
||||
}
|
||||
}
|
||||
|
||||
void frsky_link_frame()
|
||||
{
|
||||
frame[0] = 0xFE;
|
||||
if ((cur_protocol[0]&0x1F)==MODE_FRSKY)
|
||||
{
|
||||
compute_RSSIdbm();
|
||||
frame[1] = pktt[3];
|
||||
frame[2] = pktt[4];
|
||||
frame[3] = (uint8_t)RSSI_dBm;
|
||||
frame[4] = pktt[5]*2;
|
||||
}
|
||||
else
|
||||
if ((cur_protocol[0]&0x1F)==MODE_HUBSAN)
|
||||
{
|
||||
frame[1] = v_lipo*2; //v_lipo; common 0x2A=42/10=4.2V
|
||||
frame[2] = frame[1];
|
||||
frame[3] = 0x00;
|
||||
frame[4] = (uint8_t)RSSI_dBm;
|
||||
}
|
||||
frame[5] = frame[6] = frame[7] = frame[8] = 0;
|
||||
frskySendStuffed();
|
||||
}
|
||||
|
||||
#if defined HUB_TELEMETRY
|
||||
void frsky_user_frame()
|
||||
{
|
||||
uint8_t indexx = 0, c=0, j=8, n=0, i;
|
||||
|
||||
if(pktt[6]>0 && pktt[6]<=MAX_PKTX)
|
||||
{//only valid hub frames
|
||||
frame[0] = 0xFD;
|
||||
frame[1] = 0;
|
||||
frame[2] = pktt[7];
|
||||
|
||||
switch(pass)
|
||||
{
|
||||
case 0:
|
||||
indexx=pktt[6];
|
||||
for(i=0;i<indexx;i++)
|
||||
{
|
||||
if(pktt[j]==0x5E)
|
||||
{
|
||||
if(c++)
|
||||
{
|
||||
c=0;
|
||||
n++;
|
||||
j++;
|
||||
}
|
||||
}
|
||||
pktx[i]=pktt[j++];
|
||||
}
|
||||
indexx = indexx-n;
|
||||
pass=1;
|
||||
|
||||
case 1:
|
||||
index=indexx;
|
||||
prev_index = indexx;
|
||||
if(index<USER_MAX_BYTES)
|
||||
{
|
||||
for(i=0;i<index;i++)
|
||||
frame[i+3]=pktx[i];
|
||||
pktt[6]=0;
|
||||
pass=0;
|
||||
}
|
||||
else
|
||||
{
|
||||
index = USER_MAX_BYTES;
|
||||
for(i=0;i<index;i++)
|
||||
frame[i+3]=pktx[i];
|
||||
pass=2;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
index = prev_index - index;
|
||||
prev_index=0;
|
||||
if(index<MAX_PKTX-USER_MAX_BYTES) //10-6=4
|
||||
for(i=0;i<index;i++)
|
||||
frame[i+3]=pktx[USER_MAX_BYTES+i];
|
||||
pass=0;
|
||||
pktt[6]=0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if(!index)
|
||||
return;
|
||||
frame[1] = index;
|
||||
frskySendStuffed();
|
||||
}
|
||||
else
|
||||
pass=0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined SPORT_TELEMETRY
|
||||
|
||||
/* SPORT details serial
|
||||
100K 8E2 normal-multiprotocol
|
||||
-every 12ms-
|
||||
1 2 3 4 5 6 7 8 9 CRC DESCR
|
||||
=======
|
||||
/*
|
||||
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
|
||||
@ -230,6 +405,7 @@ pkt[6]|(counter++)|00 01 02 03 04 05 06 07 08 09
|
||||
100K 8E2 normal-multiprotocol
|
||||
-every 12ms-or multiple of 12; %36
|
||||
1 2 3 4 5 6 7 8 9 CRC DESCR
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
7E 98 10 05 F1 20 23 0F 00 A6 SWR_ID
|
||||
7E 98 10 01 F1 33 00 00 00 C9 RSSI_ID
|
||||
7E 98 10 04 F1 58 00 00 00 A1 BATT_ID
|
||||
@ -241,15 +417,24 @@ pkt[6]|(counter++)|00 01 02 03 04 05 06 07 08 09
|
||||
7E BA 10 03 F1 E2 00 00 00 18 ADC2_ID
|
||||
|
||||
|
||||
<<<<<<< HEAD
|
||||
Telemetry frames(RF) SPORT info 15 bytes
|
||||
SPORT frame 6+3 bytes
|
||||
=======
|
||||
Telemetry frames(RF) SPORT info
|
||||
15 bytes payload
|
||||
SPORT frame valid 6+3 bytes
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
[00] PKLEN 0E 0E 0E 0E
|
||||
[01] TXID1 DD DD DD DD
|
||||
[02] TXID2 6D 6D 6D 6D
|
||||
[03] CONST 02 02 02 02
|
||||
[04] RS/RB 2C D0 2C CE //D0;CE=2*RSSI;....2C = RX battery voltage(5V from Bec)
|
||||
<<<<<<< HEAD
|
||||
[05] ????? 03 10 21 32 //TX/RX telemetry hand-shake bytes
|
||||
=======
|
||||
[05] HD-SK 03 10 21 32 //TX/RX telemetry hand-shake bytes
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
[06] NO.BT 00 00 06 03 //No.of valid SPORT frame bytes in the frame
|
||||
[07] STRM1 00 00 7E 00
|
||||
[08] STRM2 00 00 1A 00
|
||||
@ -257,6 +442,146 @@ pkt[6]|(counter++)|00 01 02 03 04 05 06 07 08 09
|
||||
[10] STRM4 03 03 03 03
|
||||
[11] STRM5 F1 F1 F1 F1
|
||||
[12] STRM6 D1 D1 D0 D0
|
||||
<<<<<<< HEAD
|
||||
[13] CHKSUM1
|
||||
[14] CHKSUM2
|
||||
*/
|
||||
|
||||
|
||||
void sportSend(uint8_t *p)
|
||||
{
|
||||
uint16_t crc_s = 0;
|
||||
Serial_write(0x7e);//+9
|
||||
for (uint8_t i = 0; i < 9; i++)
|
||||
{
|
||||
if (i == 8)
|
||||
p[i] = 0xff - crc_s;
|
||||
if ((p[i] == 0x7e) || (p[i] == 0x7d))
|
||||
{
|
||||
Serial_write(0x7d);
|
||||
Serial_write(0x20 ^ p[i]);
|
||||
}
|
||||
else
|
||||
Serial_write(p[i]);
|
||||
if (i>0)
|
||||
{
|
||||
crc_s += p[i]; //0-1FF
|
||||
crc_s += crc_s >> 8; //0-100
|
||||
crc_s &= 0x00ff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void sportIdle()
|
||||
{
|
||||
Serial_write(0x7e);
|
||||
}
|
||||
|
||||
void sportSendFrame()
|
||||
{
|
||||
//at the moment only SWR RSSI,RxBt and A2.
|
||||
sport_counter = (sport_counter + 1) %9;
|
||||
|
||||
for (uint8_t i=5;i<8;i++)
|
||||
frame[i]=0;
|
||||
|
||||
switch (sport_counter)
|
||||
{
|
||||
case 0: // SWR
|
||||
frame[0] = 0x98;
|
||||
frame[1] = 0x10;
|
||||
frame[2] = 0x05;
|
||||
frame[3] = 0xf1;
|
||||
frame[4] = 0x20;//dummy values if swr 20230f00
|
||||
frame[5] = 0x23;
|
||||
frame[6] = 0x0F;
|
||||
frame[7] = 0x00;
|
||||
break;
|
||||
case 1: // RSSI
|
||||
frame[0] = 0x98;
|
||||
frame[1] = 0x10;
|
||||
frame[2] = 0x01;
|
||||
frame[3] = 0xf1;
|
||||
frame[4] = rssi;
|
||||
break;
|
||||
case 2: //BATT
|
||||
frame[0] = 0x98;
|
||||
frame[1] = 0x10;
|
||||
frame[2] = 0x04;
|
||||
frame[3] = 0xf1;
|
||||
frame[4] = RxBt;//a1;
|
||||
break;
|
||||
case 3: //ADC2(A2)
|
||||
frame[0] = 0x1A;
|
||||
frame[1] = 0x10;
|
||||
frame[2] = 0x03;
|
||||
frame[3] = 0xf1;
|
||||
frame[4] = ADC2;//a2;;
|
||||
break;
|
||||
default:
|
||||
sportIdle();
|
||||
return;
|
||||
}
|
||||
sportSend(frame);
|
||||
}
|
||||
|
||||
void process_sport_data()//only for ADC2
|
||||
{
|
||||
uint8_t j=7;
|
||||
if(pktt[6]>0 && pktt[6]<=USER_MAX_BYTES)
|
||||
{
|
||||
for(uint8_t i=0;i<6;i++)
|
||||
if(pktt[j++]==0x03)
|
||||
if(pktt[j]==0xF1)
|
||||
{
|
||||
ADC2=pktt[j+1];
|
||||
break;
|
||||
}
|
||||
pktt[6]=0;//new frame
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void frskyUpdate()
|
||||
{
|
||||
if(telemetry_link && (cur_protocol[0]&0x1F) != MODE_FRSKYX )
|
||||
{
|
||||
frsky_link_frame();
|
||||
telemetry_link=0;
|
||||
return;
|
||||
}
|
||||
#if defined HUB_TELEMETRY
|
||||
if(!telemetry_link && (cur_protocol[0]&0x1F) != MODE_HUBSAN && (cur_protocol[0]&0x1F) != MODE_FRSKYX)
|
||||
{
|
||||
frsky_user_frame();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#if defined SPORT_TELEMETRY
|
||||
if ((cur_protocol[0]&0x1F)==MODE_FRSKYX)
|
||||
{
|
||||
if(telemetry_link)
|
||||
{
|
||||
process_sport_data();
|
||||
if(pktt[4]>0x36)
|
||||
rssi=pktt[4]/2;
|
||||
else
|
||||
RxBt=pktt[4];
|
||||
telemetry_link=0;
|
||||
}
|
||||
uint32_t now = micros();
|
||||
if ((now - last) > SPORT_TIME)
|
||||
{
|
||||
sportSendFrame();
|
||||
last = now;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
=======
|
||||
[13] CHKSUM1 --|2 CRC bytes sent by RX (calculated on RX side crc16/table)
|
||||
[14] CHKSUM2 --|
|
||||
+2 appended bytes automatically RSSI and LQI/CRC bytes(len=0x0E+3);
|
||||
@ -824,3 +1149,4 @@ ISR(TIMER0_OVF_vect)
|
||||
#endif // BASH_SERIAL
|
||||
|
||||
#endif // TELEMETRY
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
|
@ -34,6 +34,16 @@
|
||||
|
||||
#define YD717_PAYLOADSIZE 8 // receive data pipes set to this size, but unused
|
||||
|
||||
<<<<<<< HEAD
|
||||
enum {
|
||||
YD717_INIT1 = 0,
|
||||
YD717_BIND2,
|
||||
YD717_BIND3,
|
||||
YD717_DATA
|
||||
};
|
||||
|
||||
=======
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
static void __attribute__((unused)) yd717_send_packet(uint8_t bind)
|
||||
{
|
||||
uint8_t rudder_trim, elevator_trim, aileron_trim;
|
||||
@ -139,6 +149,11 @@ static void __attribute__((unused)) yd717_init()
|
||||
NRF24L01_WriteReg(NRF24L01_1D_FEATURE, 0x07); // Set feature bits on
|
||||
NRF24L01_Activate(0x73);
|
||||
|
||||
<<<<<<< HEAD
|
||||
static void __attribute__((unused)) YD717_init1()
|
||||
{
|
||||
=======
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
// for bind packets set address to prearranged value known to receiver
|
||||
uint8_t bind_rx_tx_addr[] = {0x65, 0x65, 0x65, 0x65, 0x65};
|
||||
|
||||
@ -153,6 +168,16 @@ static void __attribute__((unused)) yd717_init()
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, bind_rx_tx_addr, 5);
|
||||
}
|
||||
|
||||
<<<<<<< HEAD
|
||||
static void __attribute__((unused)) YD717_init2()
|
||||
{
|
||||
// set rx/tx address for data phase
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, rx_tx_addr, 5);
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_addr, 5);
|
||||
}
|
||||
|
||||
=======
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
uint16_t yd717_callback()
|
||||
{
|
||||
if(IS_BIND_DONE_on)
|
||||
|
@ -13,6 +13,85 @@
|
||||
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
<<<<<<< HEAD
|
||||
/** Multiprotocol module configuration file ***/
|
||||
|
||||
//Uncomment your TX type
|
||||
#define TARANIS //TARANIS TAER (1100<->1900µs)
|
||||
//#define TX_ER9X //ER9X AETR (988<->2012µs)
|
||||
//#define TX_DEVO7 //DEVO7 EATR (1120<->1920µs)
|
||||
//#define TX_SPEKTRUM //Spektrum TAER (1100<->1900µs)
|
||||
//#define TX_HISKY //HISKY AETR (1100<->1900µs)
|
||||
|
||||
//Uncomment to enable telemetry
|
||||
#define TELEMETRY
|
||||
|
||||
//Comment if a module is not installed
|
||||
#define A7105_INSTALLED
|
||||
#define CYRF6936_INSTALLED
|
||||
//#define CC2500_INSTALLED
|
||||
#define NFR24L01_INSTALLED
|
||||
|
||||
//Comment a protocol to exclude it from compilation
|
||||
#ifdef A7105_INSTALLED
|
||||
#define JOYSWAY_A7105_INO
|
||||
|
||||
#define FLYSKY_A7105_INO
|
||||
#define HUBSAN_A7105_INO
|
||||
#endif
|
||||
#ifdef CYRF6936_INSTALLED
|
||||
#define J6PRO_CYRF6936_INO
|
||||
#define WK2x01_CYRF6936_INO
|
||||
|
||||
#define DEVO_CYRF6936_INO
|
||||
#define DSM2_CYRF6936_INO
|
||||
#endif
|
||||
#ifdef CC2500_INSTALLED
|
||||
#define SKYARTEC_CC2500_INO
|
||||
|
||||
#define FRSKY_CC2500_INO
|
||||
#define FRSKYX_CC2500_INO
|
||||
#endif
|
||||
#ifdef NFR24L01_INSTALLED
|
||||
#define HM830_NRF24L01_INO
|
||||
#define CFlie_NRF24L01_INO
|
||||
#define H377_NRF24L01_INO
|
||||
#define ESKY150_NRF24L01_INO
|
||||
#define HonTai_NRF24L01_INO
|
||||
#define UDI_NRF24L01_INO
|
||||
#define NE260_NRF24L01_INO
|
||||
#define BlueFly_NRF24L01_INO //probleme gene id
|
||||
#define FBL100_NRF24L01_INO // finir id
|
||||
|
||||
#define BAYANG_NRF24L01_INO
|
||||
#define CG023_NRF24L01_INO
|
||||
#define CX10_NRF24L01_INO
|
||||
#define ESKY_NRF24L01_INO
|
||||
#define HISKY_NRF24L01_INO
|
||||
#define KN_NRF24L01_INO
|
||||
#define SLT_NRF24L01_INO
|
||||
#define SYMAX_NRF24L01_INO
|
||||
#define V2X2_NRF24L01_INO
|
||||
#define YD717_NRF24L01_INO
|
||||
#define MT99XX_NRF24L01_INO
|
||||
#define MJXQ_NRF24L01_INO
|
||||
#define SHENQI_NRF24L01_INO
|
||||
#define FY326_NRF24L01_INO
|
||||
#endif
|
||||
|
||||
//Update this table to set which protocol and all associated settings are called for the corresponding dial number
|
||||
const PPM_Parameters PPM_prot[15]= {
|
||||
// Dial Protocol Sub protocol RX_Num Power Auto Bind Option
|
||||
/* 1 */ {MODE_FLYSKY, Flysky , 0 , P_HIGH , AUTOBIND , 0 },
|
||||
/* 2 */ {MODE_HUBSAN, 0 , 0 , P_HIGH , NO_AUTOBIND , 0 },
|
||||
/* 3 */ {MODE_FRSKY , 0 , 0 , P_HIGH , NO_AUTOBIND , 0xD7 }, // D7 fine tuning
|
||||
/* 4 */ {MODE_HISKY , Hisky , 0 , P_HIGH , NO_AUTOBIND , 0 },
|
||||
/* 5 */ {MODE_V2X2 , 0 , 0 , P_HIGH , NO_AUTOBIND , 0 },
|
||||
/* 6 */ {MODE_DSM2 , DSM2 , 0 , P_HIGH , NO_AUTOBIND , 6 }, // 6 channels @ 11ms
|
||||
/* 7 */ {MODE_DEVO , 0 , 0 , P_HIGH , NO_AUTOBIND , 0 },
|
||||
/* 8 */ {MODE_YD717 , YD717 , 0 , P_HIGH , NO_AUTOBIND , 0 },
|
||||
/* 9 */ {MODE_KN , FEILUN , 0 , P_HIGH , AUTOBIND , 0 },
|
||||
=======
|
||||
/**********************************************/
|
||||
/** Multiprotocol module configuration file ***/
|
||||
/**********************************************/
|
||||
@ -155,6 +234,7 @@ const PPM_Parameters PPM_prot[15]= {
|
||||
/* 7 */ {MODE_DEVO , 0 , 0 , P_HIGH , NO_AUTOBIND , 0 },
|
||||
/* 8 */ {MODE_YD717 , YD717 , 0 , P_HIGH , NO_AUTOBIND , 0 },
|
||||
/* 9 */ {MODE_KN , WLTOYS , 0 , P_HIGH , NO_AUTOBIND , 0 },
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
/* 10 */ {MODE_SYMAX , SYMAX , 0 , P_HIGH , NO_AUTOBIND , 0 },
|
||||
/* 11 */ {MODE_SLT , 0 , 0 , P_HIGH , NO_AUTOBIND , 0 },
|
||||
/* 12 */ {MODE_CX10 , CX10_BLUE , 0 , P_HIGH , NO_AUTOBIND , 0 },
|
||||
@ -162,7 +242,11 @@ const PPM_Parameters PPM_prot[15]= {
|
||||
/* 14 */ {MODE_BAYANG, 0 , 0 , P_HIGH , NO_AUTOBIND , 0 },
|
||||
/* 15 */ {MODE_SYMAX , SYMAX5C , 0 , P_HIGH , NO_AUTOBIND , 0 }
|
||||
};
|
||||
<<<<<<< HEAD
|
||||
/* Available protocols and associated sub protocols:
|
||||
=======
|
||||
/* Available protocols and associated sub protocols to pick and choose from
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
MODE_FLYSKY
|
||||
Flysky
|
||||
V9X9
|
||||
@ -170,18 +254,28 @@ const PPM_Parameters PPM_prot[15]= {
|
||||
V912
|
||||
MODE_HUBSAN
|
||||
NONE
|
||||
<<<<<<< HEAD
|
||||
MODE_FRSKY
|
||||
=======
|
||||
MODE_FRSKYD
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
NONE
|
||||
MODE_HISKY
|
||||
Hisky
|
||||
HK310
|
||||
MODE_V2X2
|
||||
NONE
|
||||
<<<<<<< HEAD
|
||||
MODE_DSM2
|
||||
DSM2
|
||||
DSMX
|
||||
=======
|
||||
MODE_DSM
|
||||
DSM2_22
|
||||
DSM2_11
|
||||
DSMX_22
|
||||
DSMX_11
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
MODE_DEVO
|
||||
NONE
|
||||
MODE_YD717
|
||||
@ -214,20 +308,137 @@ const PPM_Parameters PPM_prot[15]= {
|
||||
MODE_BAYANG
|
||||
NONE
|
||||
MODE_FRSKYX
|
||||
<<<<<<< HEAD
|
||||
NONE
|
||||
=======
|
||||
CH_16
|
||||
CH_8
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
MODE_ESKY
|
||||
NONE
|
||||
MODE_MT99XX
|
||||
MT99
|
||||
H7
|
||||
YZ
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
LS
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
MODE_MJXQ
|
||||
WLH08
|
||||
X600
|
||||
X800
|
||||
H26D
|
||||
<<<<<<< HEAD
|
||||
MODE_SHENQI
|
||||
NONE
|
||||
MODE_FY326
|
||||
FY326
|
||||
FY319
|
||||
|
||||
RX_Num value between 0 and 15
|
||||
|
||||
Power P_HIGH or P_LOW
|
||||
|
||||
Auto Bind AUTOBIND or NO_AUTOBIND
|
||||
|
||||
Option value between 0 and 255. 0xD7 or 0x00 for Frsky fine tuning.
|
||||
*/
|
||||
|
||||
//******************
|
||||
//TX definitions with timing endpoints and channels order
|
||||
|
||||
// Turnigy PPM and channels
|
||||
#if defined(TX_ER9X)
|
||||
#define PPM_MAX 2140
|
||||
#define PPM_MIN 860
|
||||
#define PPM_MAX_100 2012
|
||||
#define PPM_MIN_100 988
|
||||
#define AETR
|
||||
#endif
|
||||
|
||||
// Devo PPM and channels
|
||||
#if defined(TX_DEVO7)
|
||||
#define PPM_MAX 2100
|
||||
#define PPM_MIN 900
|
||||
#define PPM_MAX_100 1920
|
||||
#define PPM_MIN_100 1120
|
||||
#define EATR
|
||||
#endif
|
||||
|
||||
// SPEKTRUM PPM and channels
|
||||
#if defined(TX_SPEKTRUM)
|
||||
#define PPM_MAX 2000
|
||||
#define PPM_MIN 1000
|
||||
#define PPM_MAX_100 1900
|
||||
#define PPM_MIN_100 1100
|
||||
#define TAER
|
||||
#endif
|
||||
|
||||
// TARANIS PPM and channels
|
||||
#if defined(TARANIS)
|
||||
#define PPM_MAX 2000
|
||||
#define PPM_MIN 1000
|
||||
#define PPM_MAX_100 1900
|
||||
#define PPM_MIN_100 1100
|
||||
#define EATR
|
||||
#endif
|
||||
|
||||
// HISKY
|
||||
#if defined(TX_HISKY)
|
||||
#define PPM_MAX 2000
|
||||
#define PPM_MIN 1000
|
||||
#define PPM_MAX_100 1900
|
||||
#define PPM_MIN_100 1100
|
||||
#define AETR
|
||||
#endif
|
||||
|
||||
#if defined(EATR)
|
||||
enum chan_order{
|
||||
ELEVATOR=0,
|
||||
AILERON,
|
||||
THROTTLE,
|
||||
RUDDER,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(TAER)
|
||||
enum chan_order{
|
||||
THROTTLE=0,
|
||||
AILERON,
|
||||
ELEVATOR,
|
||||
RUDDER,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(AETR)
|
||||
enum chan_order{
|
||||
AILERON =0,
|
||||
ELEVATOR,
|
||||
THROTTLE,
|
||||
RUDDER,
|
||||
};
|
||||
#endif
|
||||
enum chan_orders{
|
||||
AUX1 =4,
|
||||
AUX2,
|
||||
AUX3,
|
||||
AUX4,
|
||||
AUX5,
|
||||
AUX6,
|
||||
AUX7,
|
||||
AUX8,
|
||||
AUX9
|
||||
};
|
||||
|
||||
#define PPM_MIN_COMMAND 1250
|
||||
#define PPM_SWITCH 1550
|
||||
#define PPM_MAX_COMMAND 1750
|
||||
|
||||
//Uncoment the desired serial speed
|
||||
#define BAUD 100000
|
||||
//#define BAUD 125000
|
||||
=======
|
||||
E010
|
||||
MODE_SHENQI
|
||||
NONE
|
||||
@ -260,4 +471,5 @@ const PPM_Parameters PPM_prot[15]= {
|
||||
// As an exxample, it's usefull for the WLTOYS F929/F939/F949/F959 (all using the Flysky protocol) which requires a bind at each power up.
|
||||
|
||||
// Option: the value is between -127 and +127.
|
||||
// The option value is only valid for some protocols, read this page for more information: https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/blob/master/Protocols_Details.md
|
||||
// The option value is only valid for some protocols, read this page for more information: https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/blob/master/Protocols_Details.md
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
|
@ -103,8 +103,13 @@ enum {
|
||||
//#define NOP 0xFF
|
||||
|
||||
// XN297 emulation layer
|
||||
<<<<<<< HEAD
|
||||
#define XN297_UNSCRAMBLED 8
|
||||
|
||||
=======
|
||||
enum {
|
||||
XN297_UNSCRAMBLED = 0,
|
||||
XN297_SCRAMBLED
|
||||
};
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
#endif
|
94
Multiprotocol/multi.lua
Normal file
94
Multiprotocol/multi.lua
Normal file
@ -0,0 +1,94 @@
|
||||
-- Multiprotocole Midelic et Pascallanger
|
||||
local debut = 0
|
||||
local tps = 0
|
||||
local tpsact = 1024
|
||||
local mix, mixe
|
||||
local channel
|
||||
|
||||
local inp = {
|
||||
{ "Protocole", VALUE, 1, 26, 2 },
|
||||
{ "Switch", SOURCE }
|
||||
}
|
||||
-- 6 7 8 15 16 17 24 25 26
|
||||
-- 4 5 12 13 14 21 22 23
|
||||
-- 1 2 3 9 10 11 18 19 20
|
||||
local out = { "Bind", "Gaz", "Aile", "Prof", "Dir" }
|
||||
|
||||
local function run_func(proto, sw)
|
||||
-- test mixage lua
|
||||
if debut == 0 then
|
||||
-- passage en lua
|
||||
for channel = 0, 3, 1 do
|
||||
local mix = model.getMix(channel, 0)
|
||||
mix_source = mix["source"]
|
||||
if mix_source < 33 or 1 then
|
||||
model.deleteMix(channel, 0)
|
||||
mix["source"] = channel + 34
|
||||
mix["name"] = "Lua "
|
||||
model.insertMix(channel, 0, mix)
|
||||
end
|
||||
end
|
||||
end
|
||||
-- inter install
|
||||
channel = 4
|
||||
mix = { name="Raz Bind", source=33, weight=100, switch=0, multiplex=REPLACE }
|
||||
count = model.getMixesCount(channel + 0)
|
||||
if count == 0 and inter == 1 then
|
||||
model.insertMix(channel + 0, 0, mix)
|
||||
elseif count == 1 and inter == 0 then
|
||||
mixe = model.getMix(channel, 0)
|
||||
if mixe["name"] == mix["name"] then
|
||||
model.deleteMix(channel, 0)
|
||||
end
|
||||
end
|
||||
|
||||
-- delais init
|
||||
if proto ~= debut then
|
||||
tps = getTime() + 250 -- delai pour mini 12 cycle PPM
|
||||
tpsact = 1024
|
||||
debut = proto
|
||||
end
|
||||
|
||||
local gaz = 1024
|
||||
local ail = 0
|
||||
local dir = 0
|
||||
local pro = 0
|
||||
|
||||
if tpsact == 0 and sw < 100 then
|
||||
-- reprise valeur input
|
||||
pro = getValue(1)
|
||||
ail = getValue(2)
|
||||
gaz = getValue(3)
|
||||
dir = getValue(4)
|
||||
elseif tpsact ~= 0 then
|
||||
-- decallage pour position memo (centre)
|
||||
if proto > 4 then proto = proto + 1 end
|
||||
|
||||
-- calcul position
|
||||
-- decallage pour > 18
|
||||
if proto > 18 then
|
||||
ail = 1024
|
||||
proto = proto - 18
|
||||
end
|
||||
-- decallage pour > 9
|
||||
if proto > 9 then
|
||||
ail = -1024
|
||||
proto = proto - 9
|
||||
end
|
||||
|
||||
if proto < 4 then pro = -1024 end
|
||||
if proto > 6 then pro = 1024 end
|
||||
|
||||
if proto % 3 == 1 then dir = -1024 end
|
||||
if proto % 3 == 0 then dir = 1024 end
|
||||
|
||||
if tps < getTime() then
|
||||
tpsact = tpsact - 512
|
||||
if tpsact>-20 then tps = getTime() + 250 end
|
||||
end
|
||||
sw = tpsact
|
||||
end
|
||||
|
||||
return sw, gaz, ail, pro, dir
|
||||
end
|
||||
return { run=run_func, input=inp, output=out}
|
485
Multiprotocol/multiprotocol.h
Normal file
485
Multiprotocol/multiprotocol.h
Normal file
@ -0,0 +1,485 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
|
||||
// Check selected board type
|
||||
#ifndef XMEGA
|
||||
#if not defined(ARDUINO_AVR_PRO) && not defined(ARDUINO_AVR_MINI) && not defined(ARDUINO_AVR_NANO)
|
||||
#error You must select the board type "Arduino Pro or Pro Mini" or "Arduino Mini"
|
||||
#endif
|
||||
#if F_CPU != 16000000L || not defined(__AVR_ATmega328P__)
|
||||
#error You must select the processor type "ATmega328(5V, 16MHz)"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//******************
|
||||
// Protocols
|
||||
//******************
|
||||
enum PROTOCOLS
|
||||
{
|
||||
MODE_SERIAL = 0, // Serial commands
|
||||
MODE_FLYSKY = 1, // =>A7105
|
||||
MODE_HUBSAN = 2, // =>A7105
|
||||
MODE_FRSKYD = 3, // =>CC2500
|
||||
MODE_HISKY = 4, // =>NRF24L01
|
||||
MODE_V2X2 = 5, // =>NRF24L01
|
||||
MODE_DSM = 6, // =>CYRF6936
|
||||
MODE_DEVO = 7, // =>CYRF6936
|
||||
MODE_YD717 = 8, // =>NRF24L01
|
||||
MODE_KN = 9, // =>NRF24L01
|
||||
MODE_SYMAX = 10, // =>NRF24L01
|
||||
MODE_SLT = 11, // =>NRF24L01
|
||||
MODE_CX10 = 12, // =>NRF24L01
|
||||
MODE_CG023 = 13, // =>NRF24L01
|
||||
MODE_BAYANG = 14, // =>NRF24L01
|
||||
MODE_FRSKYX = 15, // =>CC2500
|
||||
MODE_ESKY = 16, // =>NRF24L01
|
||||
MODE_MT99XX = 17, // =>NRF24L01
|
||||
MODE_MJXQ = 18, // =>NRF24L01
|
||||
MODE_SHENQI = 19, // =>NRF24L01
|
||||
MODE_FY326 = 20, // =>NRF24L01
|
||||
MODE_SFHSS = 21, // =>CC2500
|
||||
MODE_J6PRO = 22, // =>CYRF6936
|
||||
MODE_FQ777 = 23, // =>NRF24L01
|
||||
MODE_ASSAN = 24, // =>NRF24L01
|
||||
MODE_FRSKYV = 25, // =>CC2500
|
||||
MODE_HONTAI = 26, // =>NRF24L01
|
||||
MODE_OPENLRS = 27, // =>OpenLRS hardware
|
||||
};
|
||||
|
||||
enum Flysky
|
||||
{
|
||||
Flysky = 0,
|
||||
V9X9 = 1,
|
||||
V6X6 = 2,
|
||||
V912 = 3
|
||||
};
|
||||
enum Hisky
|
||||
{
|
||||
Hisky = 0,
|
||||
HK310 = 1
|
||||
};
|
||||
enum DSM
|
||||
{
|
||||
DSM2_22 = 0,
|
||||
DSM2_11 = 1,
|
||||
DSMX_22 = 2,
|
||||
DSMX_11 = 3,
|
||||
DSM_AUTO = 4
|
||||
};
|
||||
enum YD717
|
||||
{
|
||||
YD717 = 0,
|
||||
SKYWLKR = 1,
|
||||
SYMAX4 = 2,
|
||||
XINXUN = 3,
|
||||
NIHUI = 4
|
||||
};
|
||||
enum KN
|
||||
{
|
||||
WLTOYS = 0,
|
||||
FEILUN = 1
|
||||
};
|
||||
enum SYMAX
|
||||
{
|
||||
SYMAX = 0,
|
||||
SYMAX5C = 1
|
||||
};
|
||||
enum CX10
|
||||
{
|
||||
CX10_GREEN = 0,
|
||||
CX10_BLUE = 1, // also compatible with CX10-A, CX12
|
||||
DM007 = 2,
|
||||
Q282 = 3,
|
||||
JC3015_1 = 4,
|
||||
JC3015_2 = 5,
|
||||
MK33041 = 6,
|
||||
Q242 = 7
|
||||
};
|
||||
enum CG023
|
||||
{
|
||||
CG023 = 0,
|
||||
YD829 = 1,
|
||||
H8_3D = 2
|
||||
};
|
||||
enum MT99XX
|
||||
{
|
||||
MT99 = 0,
|
||||
H7 = 1,
|
||||
YZ = 2,
|
||||
LS = 3
|
||||
};
|
||||
enum MJXQ
|
||||
{
|
||||
WLH08 = 0,
|
||||
X600 = 1,
|
||||
X800 = 2,
|
||||
H26D = 3,
|
||||
E010 = 4
|
||||
};
|
||||
enum FRSKYX
|
||||
{
|
||||
CH_16 = 0,
|
||||
CH_8 = 1,
|
||||
};
|
||||
enum HONTAI
|
||||
{
|
||||
FORMAT_HONTAI = 0,
|
||||
FORMAT_JJRCX1 = 1,
|
||||
FORMAT_X5C1 = 2
|
||||
};
|
||||
|
||||
#define NONE 0
|
||||
#define P_HIGH 1
|
||||
#define P_LOW 0
|
||||
#define AUTOBIND 1
|
||||
#define NO_AUTOBIND 0
|
||||
|
||||
struct PPM_Parameters
|
||||
{
|
||||
uint8_t protocol : 6;
|
||||
uint8_t sub_proto : 3;
|
||||
uint8_t rx_num : 4;
|
||||
uint8_t power : 1;
|
||||
uint8_t autobind : 1;
|
||||
uint8_t option;
|
||||
};
|
||||
|
||||
// Macros
|
||||
#define NOP() __asm__ __volatile__("nop")
|
||||
|
||||
//*******************
|
||||
//*** Timer ***
|
||||
//*******************
|
||||
#ifdef XMEGA
|
||||
#define TIFR1 TCC1.INTFLAGS
|
||||
#define OCF1A_bm TC1_CCAIF_bm
|
||||
#define OCR1A TCC1.CCA
|
||||
#define TCNT1 TCC1.CNT
|
||||
#define UDR0 USARTC0.DATA
|
||||
#define OCF1B_bm TC1_CCBIF_bm
|
||||
#define OCR1B TCC1.CCB
|
||||
#define TIMSK1 TCC1.INTCTRLB
|
||||
#define SET_TIMSK1_OCIE1B TIMSK1 = (TIMSK1 & 0xF3) | 0x04
|
||||
#define CLR_TIMSK1_OCIE1B TIMSK1 &= 0xF3
|
||||
#else
|
||||
#define OCF1A_bm _BV(OCF1A)
|
||||
#define OCF1B_bm _BV(OCF1B)
|
||||
#define SET_TIMSK1_OCIE1B TIMSK1 |= _BV(OCIE1B)
|
||||
#define CLR_TIMSK1_OCIE1B TIMSK1 &=~_BV(OCIE1B)
|
||||
#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)
|
||||
#define IS_CHANGE_PROTOCOL_FLAG_on ( ( protocol_flags & _BV(1) ) !=0 )
|
||||
//
|
||||
#define POWER_FLAG_on protocol_flags |= _BV(2)
|
||||
#define POWER_FLAG_off protocol_flags &= ~_BV(2)
|
||||
#define IS_POWER_FLAG_on ( ( protocol_flags & _BV(2) ) !=0 )
|
||||
//
|
||||
#define RANGE_FLAG_on protocol_flags |= _BV(3)
|
||||
#define RANGE_FLAG_off protocol_flags &= ~_BV(3)
|
||||
#define IS_RANGE_FLAG_on ( ( protocol_flags & _BV(3) ) !=0 )
|
||||
//
|
||||
#define AUTOBIND_FLAG_on protocol_flags |= _BV(4)
|
||||
#define AUTOBIND_FLAG_off protocol_flags &= ~_BV(4)
|
||||
#define IS_AUTOBIND_FLAG_on ( ( protocol_flags & _BV(4) ) !=0 )
|
||||
//
|
||||
#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_on ( ( protocol_flags & _BV(7) ) !=0 )
|
||||
//
|
||||
#define BAD_PROTO_off protocol_flags2 &= ~_BV(0)
|
||||
#define BAD_PROTO_on protocol_flags2 |= _BV(0)
|
||||
#define IS_BAD_PROTO_on ( ( protocol_flags2 & _BV(0) ) !=0 )
|
||||
//
|
||||
#define RX_DONOTUPDTAE_off protocol_flags2 &= ~_BV(1)
|
||||
#define RX_DONOTUPDTAE_on protocol_flags2 |= _BV(1)
|
||||
#define IS_RX_DONOTUPDTAE_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 )
|
||||
|
||||
//********************
|
||||
//*** Blink timing ***
|
||||
//********************
|
||||
#define BLINK_BIND_TIME 100
|
||||
#define BLINK_SERIAL_TIME 500
|
||||
#define BLINK_BAD_PROTO_TIME_LOW 1000
|
||||
#define BLINK_BAD_PROTO_TIME_HIGH 50
|
||||
|
||||
//*******************
|
||||
//*** AUX flags ***
|
||||
//*******************
|
||||
#define GET_FLAG(ch, mask) ( ch ? mask : 0)
|
||||
#define Servo_AUX1 Servo_AUX & _BV(0)
|
||||
#define Servo_AUX2 Servo_AUX & _BV(1)
|
||||
#define Servo_AUX3 Servo_AUX & _BV(2)
|
||||
#define Servo_AUX4 Servo_AUX & _BV(3)
|
||||
#define Servo_AUX5 Servo_AUX & _BV(4)
|
||||
#define Servo_AUX6 Servo_AUX & _BV(5)
|
||||
#define Servo_AUX7 Servo_AUX & _BV(6)
|
||||
#define Servo_AUX8 Servo_AUX & _BV(7)
|
||||
|
||||
//************************
|
||||
//*** 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_2
|
||||
#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_16
|
||||
#define CC2500_LOW_POWER CC2500_POWER_13
|
||||
#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
|
||||
|
||||
//****************************************
|
||||
//*** 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[0] = 0x54 sub_protocol values are 32..63
|
||||
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
|
||||
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
|
||||
sub_protocol==Hisky
|
||||
Hisky 0
|
||||
HK310 1
|
||||
sub_protocol==DSM
|
||||
DSM2_22 0
|
||||
DSM2_11 1
|
||||
DSMX_22 2
|
||||
DSMX_11 3
|
||||
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
|
||||
Q282 3
|
||||
JC3015_1 4
|
||||
JC3015_2 5
|
||||
MK33041 6
|
||||
Q242 7
|
||||
sub_protocol==CG023
|
||||
CG023 0
|
||||
YD829 1
|
||||
H8_3D 2
|
||||
sub_protocol==MT99XX
|
||||
MT99 0
|
||||
H7 1
|
||||
YZ 2
|
||||
LS 3
|
||||
sub_protocol==MJXQ
|
||||
WLH08 0
|
||||
X600 1
|
||||
X800 2
|
||||
H26D 3
|
||||
E010 4
|
||||
sub_protocol==FRSKYX
|
||||
CH_16 0
|
||||
CH_8 1
|
||||
sub_protocol==HONTAI
|
||||
FORMAT_HONTAI 0
|
||||
FORMAT_JJRCX1 1
|
||||
FORMAT_X5C1 2
|
||||
Power value => 0x80 0=High/1=Low
|
||||
Stream[3] = option_protocol;
|
||||
option_protocol value is -127..127
|
||||
Stream[4] to [25] = Channels
|
||||
16 Channels on 11 bits (0..2047)
|
||||
0 -125%
|
||||
204 -100%
|
||||
1024 0%
|
||||
1843 +100%
|
||||
2047 +125%
|
||||
Channels bits are concatenated to fit in 22 bytes like in SBUS protocol
|
||||
*/
|
BIN
Multiprotocol/opentx-multi-2015-24-12.bin
Normal file
BIN
Multiprotocol/opentx-multi-2015-24-12.bin
Normal file
Binary file not shown.
BIN
Multiprotocol/opentx.bin
Normal file
BIN
Multiprotocol/opentx.bin
Normal file
Binary file not shown.
192
README.md
192
README.md
@ -1,8 +1,12 @@
|
||||
<<<<<<< HEAD
|
||||
# DIY-Multiprotocol-TX-Module
|
||||
=======
|
||||
# Overview of the MPTM
|
||||
|
||||
The **Multiprotocol Tx Module** (or **MPTM**) is a 2.4GHz transmitter module which enables almost any TX to control lot of different models available on the market.
|
||||
|
||||
The source code is partly based on the [Deviation TX project](http://www.deviationtx.com), thanks to all the developers for their great job on protocols.
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
|
||||
## Quicklinks
|
||||
* [Download latest releases of the firmware](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/releases)
|
||||
@ -11,6 +15,193 @@ The source code is partly based on the [Deviation TX project](http://www.deviati
|
||||
* [The old documentation](docs/README-old.md)
|
||||
* [Documentation to-do list](docs/Documentation_To_Do_List.md)
|
||||
|
||||
<<<<<<< HEAD
|
||||
Fork du projet https://github.com/pascallanger/DIY-Multiprotocol-TX-Module
|
||||
|
||||
Afin d'ajouter :
|
||||
- Une sélection du protocole via les manches de la radio
|
||||
- Un rebind hardware en PPM
|
||||
- La radio TARANIS (TAERB, B = rebind ;-) ) et redéclaration des radios
|
||||
- Un script "LUA" afin de faciliter la position des manches
|
||||
|
||||
|
||||
|
||||
Programme des évolutions :
|
||||
- Ajout du de la télémetrie TARANIS à l'aide du projet https://github.com/shadow974/TxAdapter
|
||||
|
||||
(Attention, il faut rajouter un transistor afin d'inverser et amplifier le signal)
|
||||
|
||||
|
||||
#Schematic
|
||||

|
||||
|
||||
Notes:
|
||||
- Attention: All modules are 3.3V only, never power them with 5V.
|
||||
- For serial, the dial switch is not needed and the bind button optionnal
|
||||
- Ajout d'un switch + transistor sur le TX
|
||||

|
||||
|
||||
|
||||
#Protocoles ajoutés mais non testés (Issue de Deviation)
|
||||
##CYRF6936 RF Module
|
||||
###J6PRO
|
||||
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12
|
||||
---|---|---|---|---|---|---|---|---|---|---|---
|
||||
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12
|
||||
|
||||
###WK2x01
|
||||
Autobind
|
||||
|
||||
####Sub_protocol WK2401
|
||||
CH1|CH2|CH3|CH4
|
||||
---|---|---|---
|
||||
CH1|CH2|CH3|CH4
|
||||
|
||||
|
||||
####Sub_protocol WK2601
|
||||
Option:
|
||||
|
||||
0 = 5+1
|
||||
2 = 6+1
|
||||
..1 = Hélicoptère (. = autres options pour ce mode)
|
||||
.01 = Hélicoptère normal
|
||||
.11 = Hélicoptère avec pit inversé
|
||||
0.1 = Pitch curve -100
|
||||
1.1 = Pitch curve 100
|
||||
|
||||
CH1|CH2|CH3|CH4|CH5|CH6|CH7
|
||||
---|---|---|---|---|---|---
|
||||
CH1|CH2|CH3|CH4|???|CONF|Gyro & Rudder mix
|
||||
|
||||
CONF: Option 1 = Rate Throtle
|
||||
|
||||
Option 2 = Pitch
|
||||
|
||||
|
||||
####Sub_protocol WK2801
|
||||
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8
|
||||
---|---|---|---|---|---|---|---
|
||||
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8
|
||||
|
||||
|
||||
##A7105 RF Module
|
||||
###Joysway
|
||||
CH1|CH2|CH3|CH4
|
||||
---|---|---|---
|
||||
A|E|T|R
|
||||
|
||||
##CC2500 RF Module
|
||||
###SKYARTEC
|
||||
CH1|CH2|CH3|CH4|CH5|CH6|CH7
|
||||
---|---|---|---|---|---|---
|
||||
? | ? | ? | ? | ? | ? | ?
|
||||
|
||||
##NRF24L01 RF Module
|
||||
###BLUEFLY
|
||||
Autobind
|
||||
|
||||
CH1|CH2|CH3|CH4|CH5|CH6
|
||||
---|---|---|---|---|---
|
||||
A|E|T|R|GEAR|PITCH
|
||||
|
||||
###CFLIE
|
||||
Modele: CrazyFlie Nano quad
|
||||
|
||||
Autobind
|
||||
|
||||
CH1|CH2|CH3|CH4
|
||||
---|---|---|---
|
||||
A|E|T|R
|
||||
|
||||
###ESKY150
|
||||
|
||||
Autobind
|
||||
|
||||
CH1|CH2|CH3|CH4
|
||||
---|---|---|---
|
||||
A|E|T|R
|
||||
|
||||
###FBL100
|
||||
Autobind
|
||||
|
||||
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8
|
||||
---|---|---|---|---|---|---|---
|
||||
? | ? | ? | ? | ? | ? | ? | ?
|
||||
|
||||
####Sub_protocol HP100
|
||||
Same channels assignement as above.
|
||||
|
||||
###Fy326
|
||||
Autobind
|
||||
|
||||
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9
|
||||
---|---|---|---|---|---|---|---|---
|
||||
A|E|T|R|FLIP|HEADLESS|RTH|Calibrate|Expert
|
||||
|
||||
####Sub_protocol FY319
|
||||
Same channels assignement as above.
|
||||
|
||||
###H377
|
||||
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8
|
||||
---|---|---|---|---|---|---|---
|
||||
A|E|T|R|CH5|CH6|CH7|CH8
|
||||
|
||||
###HM830
|
||||
Modele: HM Hobby HM830 RC Paper Airplane
|
||||
|
||||
Autobind
|
||||
|
||||
CH1|CH2|CH3|CH4|CH5
|
||||
---|---|---|---
|
||||
A|Turbo|T|Trim|Bouton
|
||||
|
||||
###HONTAI
|
||||
Autobind
|
||||
|
||||
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11
|
||||
---|---|---|---|---|---|---|---|---|---|---
|
||||
A|E|T|R|LED|FLIP|PICTURE|VIDEO|HEADLESS|RTH|Calibrate
|
||||
|
||||
####Sub_protocol JJRCX1
|
||||
Modele: JJRC X1
|
||||
|
||||
CH5|CH6|CH7|CH8|CH9|CH10|CH11
|
||||
---|---|---|---|---|---|---|---|---|---|---
|
||||
ARM|FLIP|PICTURE|VIDEO|HEADLESS|RTH|Calibrate
|
||||
|
||||
###NE260
|
||||
Modele: Nine Eagles SoloPro
|
||||
|
||||
Autobind
|
||||
|
||||
CH1|CH2|CH3|CH4
|
||||
---|---|---|---
|
||||
A|E|T|R
|
||||
|
||||
###UDI
|
||||
Modele: Known UDI 2.4GHz protocol variants, all using BK2421
|
||||
* UDI U819 coaxial 3ch helicoper
|
||||
* UDI U816/817/818 quadcopters
|
||||
- "V1" with orange LED on TX, U816 RX labeled '' , U817/U818 RX labeled 'UD-U817B'
|
||||
- "V2" with red LEDs on TX, U816 RX labeled '', U817/U818 RX labeled 'UD-U817OG'
|
||||
- "V3" with green LEDs on TX. Did not get my hands on yet.
|
||||
* U830 mini quadcopter with tilt steering ("Protocol 2014")
|
||||
* U839 nano quadcopter ("Protocol 2014")
|
||||
|
||||
Autobind
|
||||
|
||||
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10
|
||||
---|---|---|---|---|---|---|---|---|---
|
||||
A|E|T|R|FLIP 360|FLIP|VIDEO|LED|MODE 2
|
||||
|
||||
####Sub_protocol U816_V1 (orange)
|
||||
####Sub_protocol U816_V2 (red)
|
||||
####Sub_protocol U839_2014
|
||||
Same channels assignement as above.
|
||||
|
||||
|
||||
###D'autres à venir
|
||||
=======
|
||||
## Outline of the documentation
|
||||
1. Introduction (this page)
|
||||
1. [Available protocols](docs/Protocol_Details.md)
|
||||
@ -119,3 +310,4 @@ A very big thanks to all the people who have shared their time so graciously to
|
||||
* hexfet – from Deviation-tx
|
||||
|
||||
Your help would be greatly appreciated. If protocol reverse-engineering and dev is not your thing then any help with testing and contributing to the documentation would be amazing. Given the number of different Tx/module hardware/RF module/protocol/model combinations the process of testing and documenting is a major bottleneck for the developers. Anything you can do to help will free them up to do even greater things.
|
||||
>>>>>>> refs/remotes/pascallanger/master
|
||||
|
BIN
sync.ffs_db
Normal file
BIN
sync.ffs_db
Normal file
Binary file not shown.
BIN
taranis_switches.png
Normal file
BIN
taranis_switches.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 75 KiB |
BIN
telemetryFRSKY.fzz
Normal file
BIN
telemetryFRSKY.fzz
Normal file
Binary file not shown.
BIN
telemetryFRSKY.jpg
Normal file
BIN
telemetryFRSKY.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 77 KiB |
Loading…
x
Reference in New Issue
Block a user