Ajout de protocol

This commit is contained in:
tipouic 2016-02-13 15:54:15 +01:00
parent eb2e9477b3
commit 1b8f56180d
22 changed files with 2790 additions and 261 deletions

Binary file not shown.

View 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;
counter = 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] = counter == 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] = counter == 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 (counter == 254) {
counter = 0;
A7105_WriteID(0x5475c52a);
ch = 0x0a;
} else if (counter == 2) {
A7105_WriteID(MProtocol_id_master);
ch = 0x30;
} else {
if ((counter & 0x01) ^ EVEN_ODD) {
ch = 0x30;
} else {
ch = next_ch;
}
}
if (! ((counter & 0x01) ^ EVEN_ODD)) {
next_ch++;
if (next_ch == 0x45)
next_ch = 0x30;
}
joysway_build_packet();
A7105_Strobe(A7105_STANDBY);
A7105_WriteData(16, ch);
counter++;
return 6000;
}
static uint16_t JOYSWAY_Setup() {
while(1) {
A7105_Reset();
if (joysway_init())
break;
}
return 2400;
}
#endif

View File

@ -215,11 +215,10 @@ static void CYRF_StartReceive()
CYRF_ReadRegisterMulti(CYRF_21_RX_BUFFER, dpbuffer, 0x10);
}
*/
/*static void CYRF_ReadDataPacketLen(uint8_t dpbuffer[], uint8_t length)
static void CYRF_ReadDataPacketLen(uint8_t dpbuffer[], uint8_t length)
{
ReadRegisterMulti(CYRF_21_RX_BUFFER, dpbuffer, length);
}
*/
static void CYRF_WriteDataPacketLen(const uint8_t dpbuffer[], uint8_t len)
{
CYRF_WriteRegister(CYRF_01_TX_LENGTH, len);

View 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

View 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 u8 *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 (Model.proto_opts[WK2601_OPT_PIT_INV]) { 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 = Model.proto_opts[WK2601_OPT_PIT_LIMIT] * 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 (Model.proto_opts[WK2601_OPT_CHANMODE] == 1) { channels_heli_2601(frame, &v1, &v2); }
else if (Model.proto_opts[WK2601_OPT_CHANMODE] == 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

View File

@ -42,8 +42,7 @@ enum {
DSM2_CH2_READ_B = BIND_COUNT1 + 10,
};
const uint8_t pncodes[5][9][8] = {
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},
@ -102,6 +101,12 @@ const uint8_t pncodes[5][9][8] = {
},
};
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;
@ -109,8 +114,6 @@ uint8_t data_col;
uint16_t cyrf_state;
uint8_t crcidx;
uint8_t binding;
uint16_t crc;
/*
#ifdef USE_FIXED_MFGID
const uint8_t cyrfmfg_id[6] = {0x5e, 0x28, 0xa3, 0x1b, 0x00, 0x00}; //dx8
@ -309,17 +312,20 @@ static void __attribute__((unused)) cyrf_config()
static void __attribute__((unused)) initialize_bind_state()
{
const uint8_t pn_bind[] = { 0xc6,0x94,0x22,0xfe,0x48,0xe6,0x57,0x4e };
uint8_t data_code[32];
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);
CYRF_ConfigSOPCode(pncodes[pn_row][sop_col]);
memcpy(data_code, pncodes[pn_row][data_col], 16);
memcpy(data_code + 16, pncodes[0][8], 8);
memcpy(data_code + 24, pn_bind, 8);
CYRF_ConfigDataCode(data_code, 32);
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();
}
@ -349,12 +355,17 @@ static void __attribute__((unused)) cyrf_configdata()
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);
CYRF_ConfigSOPCode(pncodes[pn_row][sop_col]);
CYRF_ConfigDataCode(pncodes[pn_row][data_col], 16);
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

View File

@ -1,21 +1,315 @@
/*
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/>.
*/
/* **************************
* By Midelic on RCGroups *
**************************
This project is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Multiprotocol is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
*/
#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"
uint8_t hop(uint8_t byte)
{
return pgm_read_byte_near(&hop_data[byte]);
}
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;
}
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;
}
void 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]));
}
void frskyX_init()
{
CC2500_Reset();
cc2500_writeReg(CC2500_02_IOCFG0, 0x06);
cc2500_writeReg(CC2500_00_IOCFG2, 0x06);
cc2500_writeReg(CC2500_17_MCSM1, 0x0C);
cc2500_writeReg(CC2500_18_MCSM0, 0x18);
cc2500_writeReg(CC2500_06_PKTLEN, 0x1E);
cc2500_writeReg(CC2500_07_PKTCTRL1, 0x04);
cc2500_writeReg(CC2500_08_PKTCTRL0, 0x01);
cc2500_writeReg(CC2500_3E_PATABLE, 0xff);
cc2500_writeReg(CC2500_0B_FSCTRL1, 0x0A);
cc2500_writeReg(CC2500_0C_FSCTRL0, 0x00);
cc2500_writeReg(CC2500_0D_FREQ2, 0x5c);
cc2500_writeReg(CC2500_0E_FREQ1, 0x76);
cc2500_writeReg(CC2500_0F_FREQ0, 0x27);
cc2500_writeReg(CC2500_10_MDMCFG4, 0x7B);
cc2500_writeReg(CC2500_11_MDMCFG3, 0x61);
cc2500_writeReg(CC2500_12_MDMCFG2, 0x13);
cc2500_writeReg(CC2500_13_MDMCFG1, 0x23);
cc2500_writeReg(CC2500_14_MDMCFG0, 0x7a);
cc2500_writeReg(CC2500_15_DEVIATN, 0x51);
cc2500_writeReg(CC2500_19_FOCCFG, 0x16);
cc2500_writeReg(CC2500_1A_BSCFG, 0x6c);
cc2500_writeReg(CC2500_1B_AGCCTRL2,0x43);
cc2500_writeReg(CC2500_1C_AGCCTRL1,0x40);
cc2500_writeReg(CC2500_1D_AGCCTRL0,0x91);
cc2500_writeReg(CC2500_21_FREND1, 0x56);
cc2500_writeReg(CC2500_22_FREND0, 0x10);
cc2500_writeReg(CC2500_23_FSCAL3, 0xa9);
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_03_FIFOTHR, 0x07);
cc2500_writeReg(CC2500_09_ADDR, 0x00);
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########
}
void 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);
}
void 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);
//
}
void 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);
}
#endif
uint16_t 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;
}
uint8_t crc_Byte( uint8_t byte )
{
crc = (crc<<8) ^ pgm_read_word(&CRCTable[((uint8_t)(crc>>8) ^ byte) & 0xFF]);
return byte;
}
#endif

View File

@ -20,7 +20,6 @@
//##########Variables########
//uint32_t state;
//uint8_t len;
uint8_t telemetry_counter=0;
/*
enum {
@ -128,8 +127,6 @@ static void __attribute__((unused)) frsky2way_build_bind_packet()
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
@ -138,7 +135,11 @@ static void __attribute__((unused)) frsky2way_data_frame()
packet[1] = rx_tx_addr[3];
packet[2] = rx_tx_addr[2];
packet[3] = counter;//
packet[4]=telemetry_counter;
#if defined TELEMETRY
packet[4] = telemetry_counter;
#else
packet[4] = 0x00;
#endif
packet[5] = 0x01;
//

View File

@ -37,29 +37,16 @@ enum{
FLAG_MT_FLIP = 0x80,
};
enum{
// flags going to ?????? (Yi Zhan i6S)ROLL
BLABLA,
};
enum {
MT99XX_INIT = 0,
MT99XX_BIND,
MT99XX_DATA
};
static uint8_t __attribute__((unused)) MT99XX_calcChecksum()
{
uint8_t result=checksum_offset;
for(uint8_t i=0; i<8; i++)
result += packet[i];
return result;
}
static void __attribute__((unused)) MT99XX_send_packet()
{
static const uint8_t yz_p4_seq[] = {0xa0, 0x20, 0x60};
static const uint8_t mys_byte[] = {
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
};
@ -71,8 +58,8 @@ static void __attribute__((unused)) MT99XX_send_packet()
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] = convert_channel_8b_scale(AUX5,0x00,0x3F); // pitch trim (0x3f-0x20-0x00)
packet[5] = convert_channel_8b_scale(AUX6,0x00,0x3F); // roll trim (0x00-0x20-0x3f)
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 );
@ -84,7 +71,10 @@ static void __attribute__((unused)) MT99XX_send_packet()
// 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];
packet[8] = MT99XX_calcChecksum();
uint8_t result=checksum_offset;
for(uint8_t i=0; i<8; i++)
result += packet[i];
packet[8] = result;
}
else
{ // YZ
@ -100,8 +90,12 @@ static void __attribute__((unused)) MT99XX_send_packet()
packet_count=0;
}
packet[4] = yz_p4_seq[yz_seq_num];
packet[5] = 0x02; // expert ? (0=unarmed, 1=normal)
packet[6] = 0x80;
packet[5] = 0x02 // expert ? (0=unarmed, 1=normal)
| GET_FLAG(Servo_AUX4, 0x10) //VIDEO
| GET_FLAG(Servo_AUX1, 0x80) //FLIP
| GET_FLAG(Servo_AUX5, 0x04) //HEADLESS
| GET_FLAG(Servo_AUX3, 0x20); //SNAPSHOT
packet[6] = GET_FLAG(Servo_AUX2, 0x80); //LED
packet[7] = packet[0];
for(uint8_t idx = 1; idx < MT99XX_PACKET_SIZE-2; idx++)
packet[7] += packet[idx];
@ -138,7 +132,10 @@ static void __attribute__((unused)) MT99XX_init()
else
NRF24L01_SetBitrate(NRF24L01_BR_1M); // 1Mbps
NRF24L01_SetPower();
XN297_SetTXAddr((uint8_t *)"\0xCC\0xCC\0xCC\0xCC\0xCC", 5);
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);
}
static void __attribute__((unused)) MT99XX_initialize_txid()
@ -190,7 +187,7 @@ uint16_t initMT99XX(void)
BIND_IN_PROGRESS; // autobind protocol
bind_counter = MT99XX_BIND_COUNT;
memcpy(hopping_frequency,"\0x02\0x48\0x0C\0x3e\0x16\0x34\0x20\0x2A,\0x2A\0x20\0x34\0x16\0x3e\0x0c\0x48\0x02",16);
memcpy(hopping_frequency,"\x02\x48\x0C\x3e\x16\x34\x20\x2A\x2A\x20\x34\x16\x3e\x0c\x48\x02",16);
MT99XX_initialize_txid();
MT99XX_init();
@ -210,11 +207,11 @@ uint16_t initMT99XX(void)
packet[2] = 0x05;
packet[3] = 0x06;
}
packet[4] = rx_tx_addr[0]; // 1th byte for data state tx address
packet[5] = rx_tx_addr[1]; // 2th byte for data state tx address (always 0x00 on Yi Zhan ?)
packet[6] = 0x00; // 3th byte for data state tx address (always 0x00 ?)
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[7] = checksum_offset; // checksum offset
packet[8] = 0xAA; // fixed
packet[8] = 0xAA; // fixed
packet_count=0;
return MT99XX_INITIAL_WAIT+MT99XX_PACKET_PERIOD_MT;
}

View File

@ -1,6 +1,7 @@
/*********************************************************
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
@ -29,7 +30,6 @@
#include "_Config.h"
//Global constants/variables
uint32_t MProtocol_id;//tx id,
uint32_t MProtocol_id_master;
uint32_t Model_fixed_id=0;
@ -48,7 +48,7 @@ uint8_t Servo_AUX;
// PPM variable
volatile uint16_t PPM_data[NUM_CHN];
// NRF variables
// Protocol variables
uint8_t rx_tx_addr[5];
uint8_t phase;
uint16_t bind_counter;
@ -65,6 +65,7 @@ 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;
@ -100,6 +101,7 @@ uint8_t pktt[MAX_PKT];//telemetry receiving packets
int16_t RSSI_dBm;
//const uint8_t RSSI_offset=72;//69 71.72 values db
uint8_t telemetry_link=0;
uint8_t telemetry_counter=0;
#endif
// Callback
@ -313,6 +315,49 @@ static void protocol_init()
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(FY326_NRF24L01_INO)
case MODE_FY326:
next_callback=FY326_setup();
remote_callback = fy326_callback;
break;
#endif
#if defined(FLYSKY_A7105_INO)
case MODE_FLYSKY:
CTRL1_off; //antenna RF1

View File

@ -257,6 +257,7 @@ uint8_t NRF24L01_packet_ack()
///////////////
// XN297 emulation layer
uint8_t xn297_scramble_enabled;
uint8_t xn297_addr_len;
uint8_t xn297_tx_addr[5];
uint8_t xn297_rx_addr[5];
@ -269,9 +270,16 @@ static const uint8_t xn297_scramble[] = {
0x1b, 0x5d, 0x19, 0x10, 0x24, 0xd3, 0xdc, 0x3f,
0x8e, 0xc5, 0x2f};
static const uint16_t xn297_crc_xorout[] = {
0x0000, 0x3448, 0x9BA7, 0x8BBB, 0x85E1, 0x3E8C, // 1st entry is missing, probably never needed
0x451E, 0x18E6, 0x6B24, 0xE7AB, 0x3828, 0x814B, // it's used for 3-byte address w/ 0 byte payload only
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};
const uint16_t PROGMEM xn297_crc_xorout_scrambled[] = {
0x0000, 0x3448, 0x9BA7, 0x8BBB, 0x85E1, 0x3E8C,
0x451E, 0x18E6, 0x6B24, 0xE7AB, 0x3828, 0x814B,
0xD461, 0xF494, 0x2503, 0x691D, 0xFE8B, 0x9BA7,
0x8B17, 0x2920, 0x8B5F, 0x61B1, 0xD391, 0x7401,
0x2138, 0x129F, 0xB3A0, 0x2988};
@ -327,16 +335,21 @@ void XN297_SetRXAddr(const uint8_t* addr, uint8_t len)
memcpy(buf, addr, len);
memcpy(xn297_rx_addr, addr, len);
for (uint8_t i = 0; i < xn297_addr_len; ++i)
buf[i] = xn297_rx_addr[i] ^ xn297_scramble[xn297_addr_len-i-1];
{
buf[i] = xn297_rx_addr[i];
if(xn297_scramble_enabled)
buf[i] ^= xn297_scramble[xn297_addr_len-i-1];
}
NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, len-2);
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, buf, 5);
}
void XN297_Configure(uint8_t flags)
void XN297_Configure(uint16_t flags)
{
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);
NRF24L01_WriteReg(NRF24L01_00_CONFIG, flags & 0xFF);
}
void XN297_WritePayload(uint8_t* msg, uint8_t len)
@ -352,12 +365,20 @@ void XN297_WritePayload(uint8_t* msg, uint8_t len)
buf[last++] = 0x55;
}
for (uint8_t i = 0; i < xn297_addr_len; ++i)
buf[last++] = xn297_tx_addr[xn297_addr_len-i-1] ^ xn297_scramble[i];
for (uint8_t i = 0; i < len; ++i) {
{
buf[last] = xn297_tx_addr[xn297_addr_len-i-1];
if(xn297_scramble_enabled)
buf[last] ^= xn297_scramble[i];
last++;
}
for (uint8_t i = 0; i < len; ++i)
{
// bit-reverse bytes in packet
uint8_t b_out = bit_reverse(msg[i]);
buf[last++] = b_out ^ xn297_scramble[xn297_addr_len+i];
buf[last] = b_out;
if(xn297_scramble_enabled)
buf[last] ^= xn297_scramble[xn297_addr_len+i];
last++;
}
if (xn297_crc)
{
@ -365,7 +386,10 @@ void XN297_WritePayload(uint8_t* msg, uint8_t len)
uint16_t crc = 0xb5d2;
for (uint8_t i = offset; i < last; ++i)
crc = crc16_update(crc, buf[i]);
crc ^= xn297_crc_xorout[xn297_addr_len - 3 + len];
if(xn297_scramble_enabled)
crc ^= pgm_read_word(&xn297_crc_xorout_scrambled[xn297_addr_len - 3 + len]);
else
crc ^= pgm_read_word(&xn297_crc_xorout[xn297_addr_len - 3 + len]);
buf[last++] = crc >> 8;
buf[last++] = crc & 0xff;
}
@ -374,9 +398,14 @@ void XN297_WritePayload(uint8_t* msg, uint8_t len)
void XN297_ReadPayload(uint8_t* msg, uint8_t len)
{
// TODO: if xn297_crc==1, check CRC before filling *msg
NRF24L01_ReadPayload(msg, len);
for(uint8_t i=0; i<len; i++)
msg[i] = bit_reverse(msg[i]) ^ bit_reverse(xn297_scramble[i+xn297_addr_len]);
{
msg[i] = bit_reverse(msg[i]);
if(xn297_scramble_enabled)
msg[i] ^= bit_reverse(xn297_scramble[i+xn297_addr_len]);
}
}
// End of XN297 emulation

View 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

View File

@ -0,0 +1,234 @@
/*
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(FY326_NRF24L01_INO)
#include "iface_nrf24l01.h"
#define INITIAL_WAIT 500
#define FY326_PERIOD 1500 // Timeout for callback in uSec
#define FY326_CHKTIME 300 // Time to wait if packet not yet received or sent
#define FY326_SIZE 15
#define FY326_BIND_COUNT 16
static const char * const fy326_opts[] = {
_tr_noop("Expert"), _tr_noop("On"), _tr_noop("Off"), NULL,
NULL
};
#define EXPERT_ON 0
#define EXPERT_OFF 1
#define CHANNEL_FLIP AUX1
#define CHANNEL_HEADLESS AUX2
#define CHANNEL_RTH AUX3
#define CHANNEL_CALIBRATE AUX4
static uint8_t tx_power;
static uint8_t packet[FY326_SIZE];
// frequency channel management
#define RF_BIND_CHANNEL 0x17
#define NUM_RF_CHANNELS 5
static uint8_t current_chan;
static uint8_t rf_chans[NUM_RF_CHANNELS];
static uint8_t txid[5];
static uint8_t rxid;
enum {
FY326_INIT1 = 0,
FY326_BIND1,
FY326_BIND2,
FY326_DATA
};
// Bit vector from bit position
#define BV(bit) (1 << bit)
#define CHAN_RANGE (CHAN_MAX_VALUE - CHAN_MIN_VALUE)
static uint8_t scale_channel(uint8_t ch, uint8_t destMin, uint8_t destMax)
{
uint32_t chanval = Channels[ch];
uint32_t range = destMax - destMin;
if (chanval < CHAN_MIN_VALUE) chanval = CHAN_MIN_VALUE;
else if (chanval > CHAN_MAX_VALUE) chanval = CHAN_MAX_VALUE;
return (range * (chanval - CHAN_MIN_VALUE)) / CHAN_RANGE + destMin;
}
#define GET_FLAG(ch, mask) (Channels[ch] > 0 ? mask : 0)
#define CHAN_TO_TRIM(chanval) ((uint8_t)(((uint16_t)chanval/10)-10)) // scale to [-10,10]. [-20,20] caused problems.
static void send_packet(uint8_t bind)
{
packet[0] = txid[3];
if (bind) {
packet[1] = 0x55;
} else {
packet[1] = GET_FLAG(CHANNEL_HEADLESS, 0x80)
| GET_FLAG(CHANNEL_RTH, 0x40)
| GET_FLAG(CHANNEL_FLIP, 0x02)
| GET_FLAG(CHANNEL_CALIBRATE, 0x01)
| (Model.proto_opts[PROTOOPTS_EXPERT] == EXPERT_ON ? 4 : 0);
}
packet[2] = 200 - scale_channel(AILERON, 0, 200); // aileron
packet[3] = scale_channel(ELEVATOR, 0, 200); // elevator
packet[4] = 200 - scale_channel(RUDDER, 0, 200); // rudder
packet[5] = scale_channel(THROTTLE, 0, 200); // throttle
packet[6] = txid[0];
packet[7] = txid[1];
packet[8] = txid[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[14] = txid[4];
if (bind) {
NRF24L01_WriteReg(NRF24L01_05_RF_CH, RF_BIND_CHANNEL);
} else {
NRF24L01_WriteReg(NRF24L01_05_RF_CH, rf_chans[current_chan++]);
current_chan %= NUM_RF_CHANNELS;
}
// clear packet status bits and TX FIFO
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
NRF24L01_FlushTx();
NRF24L01_WritePayload(packet, FY326_SIZE);
// Check and adjust transmission power. We do this after
// transmission to not bother with timeout after power
// settings change - we have plenty of time until next
// packet.
if (tx_power != Model.tx_power) {
//Keep transmit power updated
tx_power = Model.tx_power;
NRF24L01_SetPower(tx_power);
}
}
static void fy326_init()
{
const uint8_t rx_tx_addr[] = {0x15, 0x59, 0x23, 0xc6, 0x29};
NRF24L01_Initialize();
NRF24L01_SetTxRxMode(TX_EN);
NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x01); // Three-byte rx/tx address
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_addr, sizeof(rx_tx_addr));
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, rx_tx_addr, sizeof(rx_tx_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_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0 only
NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, FY326_SIZE);
NRF24L01_WriteReg(NRF24L01_05_RF_CH, RF_BIND_CHANNEL);
NRF24L01_SetBitrate(NRF24L01_BR_250K);
NRF24L01_SetPower(Model.tx_power);
NRF24L01_Activate(0x73);
NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 0x3f);
NRF24L01_WriteReg(NRF24L01_1D_FEATURE, 0x07);
}
static uint16_t fy326_callback()
{
switch (phase) {
case FY326_INIT1:
MUSIC_Play(MUSIC_TELEMALARM1);
bind_counter = FY326_BIND_COUNT;
phase = FY326_BIND2;
send_packet(1);
return FY326_CHKTIME;
break;
case FY326_BIND1:
#ifdef EMULATOR
if (1) {
packet[13] = 0x7e;
#else
if( NRF24L01_ReadReg(NRF24L01_07_STATUS) & BV(NRF24L01_07_RX_DR)) { // RX fifo data ready
NRF24L01_ReadPayload(packet, FY326_SIZE);
#endif
rxid = packet[13];
txid[0] = 0xaa;
NRF24L01_SetTxRxMode(TXRX_OFF);
NRF24L01_SetTxRxMode(TX_EN);
PROTOCOL_SetBindState(0);
MUSIC_Play(MUSIC_DONE_BINDING);
phase = FY326_DATA;
} else if (bind_counter-- == 0) {
bind_counter = FY326_BIND_COUNT;
NRF24L01_SetTxRxMode(TXRX_OFF);
NRF24L01_SetTxRxMode(TX_EN);
send_packet(1);
phase = FY326_BIND2;
return FY326_CHKTIME;
}
break;
case FY326_BIND2:
#ifdef EMULATOR
if (1) {
#else
if( NRF24L01_ReadReg(NRF24L01_07_STATUS) & BV(NRF24L01_07_TX_DS)) { // TX data sent
#endif
// switch to RX mode
NRF24L01_SetTxRxMode(TXRX_OFF);
NRF24L01_FlushRx();
NRF24L01_SetTxRxMode(RX_EN);
phase = FY326_BIND1;
} else {
return FY326_CHKTIME;
}
break;
case FY326_DATA:
send_packet(0);
break;
}
return FY326_PERIOD;
}
// Generate address to use from TX id and manufacturer id (STM32 unique id)
static void fy_txid()
{
txid[0] = (MProtocol_id_master >> 24) & 0xFF;
txid[1] = ((MProtocol_id_master >> 16) & 0xFF);
txid[2] = (MProtocol_id_master >> 8) & 0xFF;
txid[3] = MProtocol_id_master & 0xFF;
for (uint8_t i = 0; i < sizeof(MProtocol_id_master); ++i) rand32_r(&MProtocol_id_master, 0);
txid[4] = MProtocol_id_master & 0xFF;
rf_chans[0] = txid[0] & 0x0F;
rf_chans[1] = 0x10 + (txid[0] >> 4);
rf_chans[2] = 0x20 + (txid[1] & 0x0F);
rf_chans[3] = 0x30 + (txid[1] >> 4);
rf_chans[4] = 0x40 + (txid[2] >> 4);
}
static uint16_t FY326_setup()
{
BIND_IN_PROGRESS;
tx_power = Model.tx_power;
rxid = 0xaa;
phase = FY326_INIT1;
bind_counter = FY326_BIND_COUNT;
fy_txid();
fy326_init();
return INITIAL_WAIT;
}
#endif

View 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 (counter>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 (counter >0) {
counter--;
if (! counter) { BIND_DONE; } // binding finished, change tx add
NRF24L01_WritePayload(bind_buf_array,10);
}
}
else if (counter1ms==4) { if (counter > 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) {
counter = BIND_COUNT;
BIND_IN_PROGRESS;
}
else { counter = 0; }
return 1000;
}
#endif

View 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

View File

@ -1,166 +1,337 @@
//*************************************
// FrSky Telemetry serial code *
// By Midelic on RCG *
// By Midelic on RCGroups *
//*************************************
#if defined TELEMETRY
#define USER_MAX_BYTES 6
#define MAX_PKTX 10
uint8_t frame[18];
uint8_t pass = 0;
uint8_t index;
uint8_t prev_index;
uint8_t pktx[MAX_PKTX];
void frskySendStuffed()
{
Serial_write(0x7E);
for (uint8_t i = 0; i < 9; i++)
#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()
{
if ((frame[i] == 0x7e) || (frame[i] == 0x7d))
Serial_write(0x7E);
for (uint8_t i = 0; i < 9; i++)
{
Serial_write(0x7D);
frame[i] ^= 0x20;
if ((frame[i] == 0x7e) || (frame[i] == 0x7d))
{
Serial_write(0x7D);
frame[i] ^= 0x20;
}
Serial_write(frame[i]);
}
Serial_write(frame[i]);
Serial_write(0x7E);
}
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];
void compute_RSSIdbm(){
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)
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;
frame[1] = index;
}
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();
}
else
pass=0;
}
#endif
void frskyUpdate()
{
if(telemetry_link)
{
frsky_link_frame();
telemetry_link=0;
return;
}
#if defined HUB_TELEMETRY
if(!telemetry_link && (cur_protocol[0]&0x1F) != MODE_HUBSAN )
frsky_user_frame();
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
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
7E BA 10 03 F1 E2 00 00 00 18 ADC2_ID
7E BA 10 03 F1 E2 00 00 00 18 ADC2_ID
7E BA 10 03 F1 E2 00 00 00 18 ADC2_ID
7E BA 10 03 F1 E2 00 00 00 18 ADC2_ID
7E BA 10 03 F1 E2 00 00 00 18 ADC2_ID
7E BA 10 03 F1 E2 00 00 00 18 ADC2_ID
Telemetry frames(RF) SPORT info 15 bytes
SPORT frame 6+3 bytes
[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)
[05] ????? 03 10 21 32 //TX/RX telemetry hand-shake bytes
[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
[09] STRM3 00 00 10 00
[10] STRM4 03 03 03 03
[11] STRM5 F1 F1 F1 F1
[12] STRM6 D1 D1 D0 D0
[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

View File

@ -24,7 +24,6 @@
//Uncomment to enable telemetry
#define TELEMETRY
#define HUB_TELEMETRY
//Uncomment to enable potar select
@ -34,29 +33,48 @@
#define POTAR_SELECT_M AILERON
//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
//A7105 protocols
#define FLYSKY_A7105_INO
#define HUBSAN_A7105_INO
//CYRF6936 protocols
#define DEVO_CYRF6936_INO
#define DSM2_CYRF6936_INO
//CC2500 protocols
#define FRSKY_CC2500_INO
//#define FRSKYX_CC2500_INO
//NFR24L01 protocols
#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
#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 FRSKY_CC2500_INO
#define FRSKYX_CC2500_INO
#endif
#ifdef NFR24L01_INSTALLED
#define HM830_NRF24L01_INO
#define CFlie_NRF24L01_INO
#define H377_NRF24L01_INO
#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
#endif
//Update this table to set which protocol and all associated settings are called for the corresponding dial number
static const PPM_Parameters PPM_prot[15]=
@ -215,7 +233,7 @@ Option value between 0 and 255. 0xD7 or 0x00 for Frsky fine tuning.
RUDDER,
};
#endif
enum chan_order{
enum chan_orders{
AUX1 =4,
AUX2,
AUX3,

View File

@ -102,18 +102,7 @@ enum {
#define REUSE_TX_PL 0xE3
//#define NOP 0xFF
/*
void NRF24L01_Initialize();
byte NRF24L01_WriteReg(byte reg, byte data);
byte NRF24L01_WriteRegisterMulti(byte reg, byte data[], byte length);
byte NRF24L01_WritePayload(byte *data, byte len);
byte NRF24L01_ReadReg(byte reg);
byte NRF24L01_ReadRegisterMulti(byte reg, byte data[], byte length);
byte NRF24L01_ReadPayload(byte *data, byte len);
// XN297 emulation layer
#define XN297_UNSCRAMBLED 8
byte NRF24L01_FlushTx();
byte NRF24L01_FlushRx();
byte NRF24L01_Activate(byte code);
*/
#endif

View File

@ -15,7 +15,7 @@
// Check selected board type
#ifndef ARDUINO_AVR_PRO
#error You must select the board type "Arduino Pro or Pro Mini"
// #error You must select the board type "Arduino Pro or Pro Mini"
#endif
#if F_CPU != 16000000L || not defined(__AVR_ATmega328P__)
#error You must select the processor type "ATmega328(5V, 16MHz)"
@ -26,6 +26,14 @@
//******************
enum PROTOCOLS
{
MODE_HM830=40, // =>NRF24L01
MODE_CFLIE=41, // =>NRF24L01
MODE_JOYSWAY = 42, // =>A7105
MODE_J6PRO = 43, // =>CYRF6936
MODE_H377=44, // =>NRF24L01
MODE_WK2x01 = 45, // =>CYRF6936
MODE_FY326=46, // =>NRF24L01
MODE_SERIAL = 0, // Serial commands
MODE_FLYSKY = 1, // =>A7105
MODE_HUBSAN = 2, // =>A7105
@ -110,6 +118,12 @@ enum MJXQ
X800 = 2,
H26D = 3
};
enum WK2X01
{
WK2801 = 0,
WK2601 = 1,
WK2401 = 2
};
#define NONE 0
#define P_HIGH 1

View File

@ -26,3 +26,45 @@ Notes:
- For serial, the dial switch is not needed and the bind button optionnal
- Ajout d'un switch + transistor sur le TX
![Alt text](telemetryFRSKY.jpg)
#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
En cours ...
##A7105 RF Module
###Joysway
CH1|CH2|CH3|CH4
---|---|---|---
A|E|T|R
##NRF24L01 RF Module
###CFLIE
Modele: CrazyFlie Nano quad
CH1|CH2|CH3|CH4
---|---|---|---
A|E|T|R
###Fy326
Autobind
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8
---|---|---|---|---|---|---|---
A|E|T|R|FLIP|HEADLESS|RTH|Calibrate
###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
CH1|CH2|CH3|CH4|CH5
---|---|---|---
A|Turbo|T|Trim|Bouton ???

Binary file not shown.

BIN
taranis_switches.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB