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); 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); ReadRegisterMulti(CYRF_21_RX_BUFFER, dpbuffer, length);
} }
*/
static void CYRF_WriteDataPacketLen(const uint8_t dpbuffer[], uint8_t len) static void CYRF_WriteDataPacketLen(const uint8_t dpbuffer[], uint8_t len)
{ {
CYRF_WriteRegister(CYRF_01_TX_LENGTH, 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, DSM2_CH2_READ_B = BIND_COUNT1 + 10,
}; };
const uint8_t PROGMEM pncodes[5][9][8] = {
const uint8_t pncodes[5][9][8] = {
/* Note these are in order transmitted (LSB 1st) */ /* Note these are in order transmitted (LSB 1st) */
{ /* Row 0 */ { /* Row 0 */
/* Col 0 */ {0x03, 0xBC, 0x6E, 0x8A, 0xEF, 0xBD, 0xFE, 0xF8}, /* 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 chidx;
uint8_t sop_col; uint8_t sop_col;
@ -109,8 +114,6 @@ uint8_t data_col;
uint16_t cyrf_state; uint16_t cyrf_state;
uint8_t crcidx; uint8_t crcidx;
uint8_t binding; uint8_t binding;
uint16_t crc;
/* /*
#ifdef USE_FIXED_MFGID #ifdef USE_FIXED_MFGID
const uint8_t cyrfmfg_id[6] = {0x5e, 0x28, 0xa3, 0x1b, 0x00, 0x00}; //dx8 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() static void __attribute__((unused)) initialize_bind_state()
{ {
const uint8_t pn_bind[] = { 0xc6,0x94,0x22,0xfe,0x48,0xe6,0x57,0x4e }; uint8_t code[32];
uint8_t data_code[32];
CYRF_ConfigRFChannel(BIND_CHANNEL); //This seems to be random? CYRF_ConfigRFChannel(BIND_CHANNEL); //This seems to be random?
uint8_t pn_row = get_pn_row(BIND_CHANNEL); 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); //printf("Ch: %d Row: %d SOP: %d Data: %d\n", BIND_CHANNEL, pn_row, sop_col, data_col);
CYRF_ConfigCRCSeed(crc); CYRF_ConfigCRCSeed(crc);
CYRF_ConfigSOPCode(pncodes[pn_row][sop_col]);
memcpy(data_code, pncodes[pn_row][data_col], 16); read_code(code,pn_row,sop_col,8);
memcpy(data_code + 16, pncodes[0][8], 8); CYRF_ConfigSOPCode(code);
memcpy(data_code + 24, pn_bind, 8); read_code(code,pn_row,data_col,16);
CYRF_ConfigDataCode(data_code, 32); 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(); build_bind_packet();
} }
@ -349,12 +355,17 @@ static void __attribute__((unused)) cyrf_configdata()
static void __attribute__((unused)) set_sop_data_crc() static void __attribute__((unused)) set_sop_data_crc()
{ {
uint8_t code[16];
uint8_t pn_row = get_pn_row(hopping_frequency[chidx]); 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); //printf("Ch: %d Row: %d SOP: %d Data: %d\n", ch[chidx], pn_row, sop_col, data_col);
CYRF_ConfigRFChannel(hopping_frequency[chidx]); CYRF_ConfigRFChannel(hopping_frequency[chidx]);
CYRF_ConfigCRCSeed(crcidx ? ~crc : crc); 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) if(sub_protocol == DSMX)
chidx = (chidx + 1) % 23; chidx = (chidx + 1) % 23;
else else

View File

@ -1,4 +1,7 @@
/*
/* **************************
* By Midelic on RCGroups *
**************************
This project is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
@ -11,11 +14,302 @@
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>. along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
*/ */
#if defined(FRSKYX_CC2500_INO) #if defined(FRSKYX_CC2500_INO)
#include "iface_cc2500.h" #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
};
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);
}
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 #endif

View File

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

View File

@ -37,29 +37,16 @@ enum{
FLAG_MT_FLIP = 0x80, FLAG_MT_FLIP = 0x80,
}; };
enum{
// flags going to ?????? (Yi Zhan i6S)ROLL
BLABLA,
};
enum { enum {
MT99XX_INIT = 0, MT99XX_INIT = 0,
MT99XX_BIND, MT99XX_BIND,
MT99XX_DATA 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 void __attribute__((unused)) MT99XX_send_packet()
{ {
static const uint8_t yz_p4_seq[] = {0xa0, 0x20, 0x60}; const uint8_t yz_p4_seq[] = {0xa0, 0x20, 0x60};
static const uint8_t mys_byte[] = { const uint8_t mys_byte[] = {
0x01, 0x11, 0x02, 0x12, 0x03, 0x13, 0x04, 0x14, 0x01, 0x11, 0x02, 0x12, 0x03, 0x13, 0x04, 0x14,
0x05, 0x15, 0x06, 0x16, 0x07, 0x17, 0x00, 0x10 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[1] = convert_channel_8b_scale(RUDDER ,0x00,0xE1); // rudder
packet[2] = convert_channel_8b_scale(AILERON ,0x00,0xE1); // aileron packet[2] = convert_channel_8b_scale(AILERON ,0x00,0xE1); // aileron
packet[3] = convert_channel_8b_scale(ELEVATOR,0x00,0xE1); // elevator 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[4] = 0x20; // pitch trim (0x3f-0x20-0x00)
packet[5] = convert_channel_8b_scale(AUX6,0x00,0x3F); // roll trim (0x00-0x20-0x3f) packet[5] = 0x20; // roll trim (0x00-0x20-0x3f)
packet[6] = GET_FLAG( Servo_AUX1, FLAG_MT_FLIP ) packet[6] = GET_FLAG( Servo_AUX1, FLAG_MT_FLIP )
| GET_FLAG( Servo_AUX3, FLAG_MT_SNAPSHOT ) | GET_FLAG( Servo_AUX3, FLAG_MT_SNAPSHOT )
| GET_FLAG( Servo_AUX4, FLAG_MT_VIDEO ); | GET_FLAG( Servo_AUX4, FLAG_MT_VIDEO );
@ -84,7 +71,10 @@ static void __attribute__((unused)) MT99XX_send_packet()
// low nibble: index in chan list ? // low nibble: index in chan list ?
// high nibble: 0->start from start of list, 1->start from end of list ? // high nibble: 0->start from start of list, 1->start from end of list ?
packet[7] = mys_byte[hopping_frequency_no]; 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 else
{ // YZ { // YZ
@ -100,8 +90,12 @@ static void __attribute__((unused)) MT99XX_send_packet()
packet_count=0; packet_count=0;
} }
packet[4] = yz_p4_seq[yz_seq_num]; packet[4] = yz_p4_seq[yz_seq_num];
packet[5] = 0x02; // expert ? (0=unarmed, 1=normal) packet[5] = 0x02 // expert ? (0=unarmed, 1=normal)
packet[6] = 0x80; | 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]; packet[7] = packet[0];
for(uint8_t idx = 1; idx < MT99XX_PACKET_SIZE-2; idx++) for(uint8_t idx = 1; idx < MT99XX_PACKET_SIZE-2; idx++)
packet[7] += packet[idx]; packet[7] += packet[idx];
@ -138,7 +132,10 @@ static void __attribute__((unused)) MT99XX_init()
else else
NRF24L01_SetBitrate(NRF24L01_BR_1M); // 1Mbps NRF24L01_SetBitrate(NRF24L01_BR_1M); // 1Mbps
NRF24L01_SetPower(); 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() static void __attribute__((unused)) MT99XX_initialize_txid()
@ -190,7 +187,7 @@ uint16_t initMT99XX(void)
BIND_IN_PROGRESS; // autobind protocol BIND_IN_PROGRESS; // autobind protocol
bind_counter = MT99XX_BIND_COUNT; 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_initialize_txid();
MT99XX_init(); MT99XX_init();
@ -210,9 +207,9 @@ uint16_t initMT99XX(void)
packet[2] = 0x05; packet[2] = 0x05;
packet[3] = 0x06; packet[3] = 0x06;
} }
packet[4] = rx_tx_addr[0]; // 1th byte for data state tx address packet[4] = rx_tx_addr[0]; // 1st 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[5] = rx_tx_addr[1]; // 2nd byte for data state tx address (always 0x00 on Yi Zhan ?)
packet[6] = 0x00; // 3th byte for data state tx address (always 0x00 ?) packet[6] = 0x00; // 3rd byte for data state tx address (always 0x00 ?)
packet[7] = checksum_offset; // checksum offset packet[7] = checksum_offset; // checksum offset
packet[8] = 0xAA; // fixed packet[8] = 0xAA; // fixed
packet_count=0; packet_count=0;

View File

@ -1,6 +1,7 @@
/********************************************************* /*********************************************************
Multiprotocol Tx code Multiprotocol Tx code
by Midelic and Pascal Langer(hpnuts) by Midelic and Pascal Langer(hpnuts)
fork by Tipouic
http://www.rcgroups.com/forums/showthread.php?t=2165676 http://www.rcgroups.com/forums/showthread.php?t=2165676
https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/edit/master/README.md https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/edit/master/README.md
@ -29,7 +30,6 @@
#include "_Config.h" #include "_Config.h"
//Global constants/variables //Global constants/variables
uint32_t MProtocol_id;//tx id, uint32_t MProtocol_id;//tx id,
uint32_t MProtocol_id_master; uint32_t MProtocol_id_master;
uint32_t Model_fixed_id=0; uint32_t Model_fixed_id=0;
@ -48,7 +48,7 @@ uint8_t Servo_AUX;
// PPM variable // PPM variable
volatile uint16_t PPM_data[NUM_CHN]; volatile uint16_t PPM_data[NUM_CHN];
// NRF variables // Protocol variables
uint8_t rx_tx_addr[5]; uint8_t rx_tx_addr[5];
uint8_t phase; uint8_t phase;
uint16_t bind_counter; uint16_t bind_counter;
@ -65,6 +65,7 @@ uint8_t hopping_frequency_no=0;
uint8_t rf_ch_num; uint8_t rf_ch_num;
uint8_t throttle, rudder, elevator, aileron; uint8_t throttle, rudder, elevator, aileron;
uint8_t flags; uint8_t flags;
uint16_t crc;
// //
uint32_t state; uint32_t state;
uint8_t len; uint8_t len;
@ -100,6 +101,7 @@ uint8_t pktt[MAX_PKT];//telemetry receiving packets
int16_t RSSI_dBm; int16_t RSSI_dBm;
//const uint8_t RSSI_offset=72;//69 71.72 values db //const uint8_t RSSI_offset=72;//69 71.72 values db
uint8_t telemetry_link=0; uint8_t telemetry_link=0;
uint8_t telemetry_counter=0;
#endif #endif
// Callback // Callback
@ -313,6 +315,49 @@ static void protocol_init()
switch(cur_protocol[0]&0x1F) // Init the requested protocol 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) #if defined(FLYSKY_A7105_INO)
case MODE_FLYSKY: case MODE_FLYSKY:
CTRL1_off; //antenna RF1 CTRL1_off; //antenna RF1

View File

@ -257,6 +257,7 @@ uint8_t NRF24L01_packet_ack()
/////////////// ///////////////
// XN297 emulation layer // XN297 emulation layer
uint8_t xn297_scramble_enabled;
uint8_t xn297_addr_len; uint8_t xn297_addr_len;
uint8_t xn297_tx_addr[5]; uint8_t xn297_tx_addr[5];
uint8_t xn297_rx_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, 0x1b, 0x5d, 0x19, 0x10, 0x24, 0xd3, 0xdc, 0x3f,
0x8e, 0xc5, 0x2f}; 0x8e, 0xc5, 0x2f};
static const uint16_t xn297_crc_xorout[] = { const uint16_t PROGMEM xn297_crc_xorout[] = {
0x0000, 0x3448, 0x9BA7, 0x8BBB, 0x85E1, 0x3E8C, // 1st entry is missing, probably never needed 0x0000, 0x3d5f, 0xa6f1, 0x3a23, 0xaa16, 0x1caf,
0x451E, 0x18E6, 0x6B24, 0xE7AB, 0x3828, 0x814B, // it's used for 3-byte address w/ 0 byte payload only 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, 0xD461, 0xF494, 0x2503, 0x691D, 0xFE8B, 0x9BA7,
0x8B17, 0x2920, 0x8B5F, 0x61B1, 0xD391, 0x7401, 0x8B17, 0x2920, 0x8B5F, 0x61B1, 0xD391, 0x7401,
0x2138, 0x129F, 0xB3A0, 0x2988}; 0x2138, 0x129F, 0xB3A0, 0x2988};
@ -327,16 +335,21 @@ void XN297_SetRXAddr(const uint8_t* addr, uint8_t len)
memcpy(buf, addr, len); memcpy(buf, addr, len);
memcpy(xn297_rx_addr, addr, len); memcpy(xn297_rx_addr, addr, len);
for (uint8_t i = 0; i < xn297_addr_len; ++i) 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_WriteReg(NRF24L01_03_SETUP_AW, len-2);
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, buf, 5); 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)); xn297_crc = !!(flags & BV(NRF24L01_00_EN_CRC));
flags &= ~(BV(NRF24L01_00_EN_CRC) | BV(NRF24L01_00_CRCO)); 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) 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; buf[last++] = 0x55;
} }
for (uint8_t i = 0; i < xn297_addr_len; ++i) for (uint8_t i = 0; i < xn297_addr_len; ++i)
buf[last++] = xn297_tx_addr[xn297_addr_len-i-1] ^ xn297_scramble[i]; {
buf[last] = xn297_tx_addr[xn297_addr_len-i-1];
for (uint8_t i = 0; i < len; ++i) { if(xn297_scramble_enabled)
buf[last] ^= xn297_scramble[i];
last++;
}
for (uint8_t i = 0; i < len; ++i)
{
// bit-reverse bytes in packet // bit-reverse bytes in packet
uint8_t b_out = bit_reverse(msg[i]); 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) if (xn297_crc)
{ {
@ -365,7 +386,10 @@ void XN297_WritePayload(uint8_t* msg, uint8_t len)
uint16_t crc = 0xb5d2; uint16_t crc = 0xb5d2;
for (uint8_t i = offset; i < last; ++i) for (uint8_t i = offset; i < last; ++i)
crc = crc16_update(crc, buf[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 >> 8;
buf[last++] = crc & 0xff; 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) void XN297_ReadPayload(uint8_t* msg, uint8_t len)
{ {
// TODO: if xn297_crc==1, check CRC before filling *msg
NRF24L01_ReadPayload(msg, len); NRF24L01_ReadPayload(msg, len);
for(uint8_t i=0; i<len; i++) 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 // 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,24 +1,39 @@
//************************************* //*************************************
// FrSky Telemetry serial code * // FrSky Telemetry serial code *
// By Midelic on RCG * // By Midelic on RCGroups *
//************************************* //*************************************
#if defined TELEMETRY #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];
#define USER_MAX_BYTES 6 void frskySendStuffed()
#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); Serial_write(0x7E);
for (uint8_t i = 0; i < 9; i++) for (uint8_t i = 0; i < 9; i++)
{ {
if ((frame[i] == 0x7e) || (frame[i] == 0x7d)) if ((frame[i] == 0x7e) || (frame[i] == 0x7d))
{ {
Serial_write(0x7D); Serial_write(0x7D);
@ -27,18 +42,19 @@ void frskySendStuffed()
Serial_write(frame[i]); Serial_write(frame[i]);
} }
Serial_write(0x7E); Serial_write(0x7E);
} }
void compute_RSSIdbm(){
void compute_RSSIdbm(){
RSSI_dBm = (((uint16_t)(pktt[len-2])*18)>>5); RSSI_dBm = (((uint16_t)(pktt[len-2])*18)>>5);
if(pktt[len-2] >=128) if(pktt[len-2] >=128)
RSSI_dBm -= 82; RSSI_dBm -= 82;
else else
RSSI_dBm += 65; RSSI_dBm += 65;
} }
void frsky_check_telemetry(uint8_t *pkt,uint8_t len) 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) 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 {//only packets with the required id and packet length
for(uint8_t i=3;i<6;i++) for(uint8_t i=3;i<6;i++)
@ -53,10 +69,10 @@ void frsky_check_telemetry(uint8_t *pkt,uint8_t len)
if(pktt[6]>0) if(pktt[6]>0)
telemetry_counter=(telemetry_counter+1)%32; telemetry_counter=(telemetry_counter+1)%32;
} }
} }
void frsky_link_frame() void frsky_link_frame()
{ {
frame[0] = 0xFE; frame[0] = 0xFE;
if ((cur_protocol[0]&0x1F)==MODE_FRSKY) if ((cur_protocol[0]&0x1F)==MODE_FRSKY)
{ {
@ -76,11 +92,11 @@ void frsky_link_frame()
} }
frame[5] = frame[6] = frame[7] = frame[8] = 0; frame[5] = frame[6] = frame[7] = frame[8] = 0;
frskySendStuffed(); frskySendStuffed();
} }
#if defined HUB_TELEMETRY #if defined HUB_TELEMETRY
void frsky_user_frame() void frsky_user_frame()
{ {
uint8_t indexx = 0, c=0, j=8, n=0, i; uint8_t indexx = 0, c=0, j=8, n=0, i;
if(pktt[6]>0 && pktt[6]<=MAX_PKTX) if(pktt[6]>0 && pktt[6]<=MAX_PKTX)
@ -146,21 +162,176 @@ void frsky_user_frame()
} }
else else
pass=0; pass=0;
} }
#endif #endif
void frskyUpdate() #if defined SPORT_TELEMETRY
{
if(telemetry_link) /* 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(); frsky_link_frame();
telemetry_link=0; telemetry_link=0;
return; return;
} }
#if defined HUB_TELEMETRY #if defined HUB_TELEMETRY
if(!telemetry_link && (cur_protocol[0]&0x1F) != MODE_HUBSAN ) if(!telemetry_link && (cur_protocol[0]&0x1F) != MODE_HUBSAN && (cur_protocol[0]&0x1F) != MODE_FRSKYX)
{
frsky_user_frame(); frsky_user_frame();
return;
}
#endif #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 #endif

View File

@ -24,7 +24,6 @@
//Uncomment to enable telemetry //Uncomment to enable telemetry
#define TELEMETRY #define TELEMETRY
#define HUB_TELEMETRY
//Uncomment to enable potar select //Uncomment to enable potar select
@ -34,29 +33,48 @@
#define POTAR_SELECT_M AILERON #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 //Comment a protocol to exclude it from compilation
//A7105 protocols #ifdef A7105_INSTALLED
#define FLYSKY_A7105_INO #define JOYSWAY_A7105_INO
#define HUBSAN_A7105_INO
//CYRF6936 protocols #define FLYSKY_A7105_INO
#define DEVO_CYRF6936_INO #define HUBSAN_A7105_INO
#define DSM2_CYRF6936_INO #endif
//CC2500 protocols #ifdef CYRF6936_INSTALLED
#define FRSKY_CC2500_INO #define J6PRO_CYRF6936_INO
//#define FRSKYX_CC2500_INO // #define WK2x01_CYRF6936_INO
//NFR24L01 protocols
#define BAYANG_NRF24L01_INO #define DEVO_CYRF6936_INO
#define CG023_NRF24L01_INO #define DSM2_CYRF6936_INO
#define CX10_NRF24L01_INO #endif
#define ESKY_NRF24L01_INO #ifdef CC2500_INSTALLED
#define HISKY_NRF24L01_INO #define FRSKY_CC2500_INO
#define KN_NRF24L01_INO #define FRSKYX_CC2500_INO
#define SLT_NRF24L01_INO #endif
#define SYMAX_NRF24L01_INO #ifdef NFR24L01_INSTALLED
#define V2X2_NRF24L01_INO #define HM830_NRF24L01_INO
#define YD717_NRF24L01_INO #define CFlie_NRF24L01_INO
#define MT99XX_NRF24L01_INO #define H377_NRF24L01_INO
#define MJXQ_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 //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]= 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, RUDDER,
}; };
#endif #endif
enum chan_order{ enum chan_orders{
AUX1 =4, AUX1 =4,
AUX2, AUX2,
AUX3, AUX3,

View File

@ -102,18 +102,7 @@ enum {
#define REUSE_TX_PL 0xE3 #define REUSE_TX_PL 0xE3
//#define NOP 0xFF //#define NOP 0xFF
/* // XN297 emulation layer
void NRF24L01_Initialize(); #define XN297_UNSCRAMBLED 8
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);
byte NRF24L01_FlushTx();
byte NRF24L01_FlushRx();
byte NRF24L01_Activate(byte code);
*/
#endif #endif

View File

@ -15,7 +15,7 @@
// Check selected board type // Check selected board type
#ifndef ARDUINO_AVR_PRO #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 #endif
#if F_CPU != 16000000L || not defined(__AVR_ATmega328P__) #if F_CPU != 16000000L || not defined(__AVR_ATmega328P__)
#error You must select the processor type "ATmega328(5V, 16MHz)" #error You must select the processor type "ATmega328(5V, 16MHz)"
@ -26,6 +26,14 @@
//****************** //******************
enum PROTOCOLS 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_SERIAL = 0, // Serial commands
MODE_FLYSKY = 1, // =>A7105 MODE_FLYSKY = 1, // =>A7105
MODE_HUBSAN = 2, // =>A7105 MODE_HUBSAN = 2, // =>A7105
@ -110,6 +118,12 @@ enum MJXQ
X800 = 2, X800 = 2,
H26D = 3 H26D = 3
}; };
enum WK2X01
{
WK2801 = 0,
WK2601 = 1,
WK2401 = 2
};
#define NONE 0 #define NONE 0
#define P_HIGH 1 #define P_HIGH 1

View File

@ -26,3 +26,45 @@ Notes:
- For serial, the dial switch is not needed and the bind button optionnal - For serial, the dial switch is not needed and the bind button optionnal
- Ajout d'un switch + transistor sur le TX - Ajout d'un switch + transistor sur le TX
![Alt text](telemetryFRSKY.jpg) ![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