mirror of
https://github.com/pascallanger/DIY-Multiprotocol-TX-Module.git
synced 2025-07-03 03:57:51 +00:00
Ajout de protocol
This commit is contained in:
parent
eb2e9477b3
commit
1b8f56180d
BIN
AVR8_Burn-O-Mat_2_1_2_setup.exe
Normal file
BIN
AVR8_Burn-O-Mat_2_1_2_setup.exe
Normal file
Binary file not shown.
164
Multiprotocol/A7105_joysway.ino
Normal file
164
Multiprotocol/A7105_joysway.ino
Normal file
@ -0,0 +1,164 @@
|
||||
/*
|
||||
This project is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Deviation is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Deviation. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if defined JOYSWAY_A7105_INO
|
||||
#include "iface_a7105.h"
|
||||
|
||||
|
||||
#define EVEN_ODD 0x00
|
||||
//#define EVEN_ODD 0x01
|
||||
static const uint8_t A7105_regs[] = {
|
||||
0x00, 0x62, -1, 0x0f, 0x00, -1 , -1 , 0x00, 0x00, 0x05, 0x00, 0x01, 0x00, 0xf5, 0x00, 0x15,
|
||||
0x9e, 0x4b, 0x00, 0x03, 0x56, 0x2b, 0x12, 0x4a, 0x02, 0x80, 0x80, 0x00, 0x0e, 0x91, 0x03, 0x0f,
|
||||
0x16, 0x2a, 0x00, -1, -1, -1, 0x3a, 0x06, 0x1f, 0x47, 0x80, 0x01, 0x05, 0x45, 0x18, 0x00,
|
||||
0x01, 0x0f, 0x00
|
||||
};
|
||||
|
||||
static uint8_t next_ch;
|
||||
|
||||
static int joysway_init()
|
||||
{
|
||||
int i;
|
||||
uint8_t if_calibration1;
|
||||
//uint8_t vco_calibration0;
|
||||
//uint8_t vco_calibration1;
|
||||
|
||||
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
|
@ -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);
|
||||
|
277
Multiprotocol/CYRF6936_j6pro.ino
Normal file
277
Multiprotocol/CYRF6936_j6pro.ino
Normal file
@ -0,0 +1,277 @@
|
||||
/*
|
||||
This project is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Deviation is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Deviation. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if defined(J6PRO_CYRF6936_INO)
|
||||
#include "iface_cyrf6936.h"
|
||||
|
||||
#define NUM_WAIT_LOOPS (100 / 5) //each loop is ~5us. Do not wait more than 100us
|
||||
|
||||
//For Debug
|
||||
//#define NO_SCRAMBLE
|
||||
|
||||
enum J6ProState {
|
||||
J6PRO_BIND,
|
||||
J6PRO_BIND_01,
|
||||
J6PRO_BIND_03_START,
|
||||
J6PRO_BIND_03_CHECK,
|
||||
J6PRO_BIND_05_1,
|
||||
J6PRO_BIND_05_2,
|
||||
J6PRO_BIND_05_3,
|
||||
J6PRO_BIND_05_4,
|
||||
J6PRO_BIND_05_5,
|
||||
J6PRO_BIND_05_6,
|
||||
J6PRO_CHANSEL,
|
||||
J6PRO_CHAN_1,
|
||||
J6PRO_CHAN_2,
|
||||
J6PRO_CHAN_3,
|
||||
J6PRO_CHAN_4,
|
||||
};
|
||||
|
||||
static const uint8_t J6Pro_sopcodes[][8] = {
|
||||
/* Note these are in order transmitted (LSB 1st) */
|
||||
{0x3C, 0x37, 0xCC, 0x91, 0xE2, 0xF8, 0xCC, 0x91},
|
||||
{0x9B, 0xC5, 0xA1, 0x0F, 0xAD, 0x39, 0xA2, 0x0F},
|
||||
{0xEF, 0x64, 0xB0, 0x2A, 0xD2, 0x8F, 0xB1, 0x2A},
|
||||
{0x66, 0xCD, 0x7C, 0x50, 0xDD, 0x26, 0x7C, 0x50},
|
||||
{0x5C, 0xE1, 0xF6, 0x44, 0xAD, 0x16, 0xF6, 0x44},
|
||||
{0x5A, 0xCC, 0xAE, 0x46, 0xB6, 0x31, 0xAE, 0x46},
|
||||
{0xA1, 0x78, 0xDC, 0x3C, 0x9E, 0x82, 0xDC, 0x3C},
|
||||
{0xB9, 0x8E, 0x19, 0x74, 0x6F, 0x65, 0x18, 0x74},
|
||||
{0xDF, 0xB1, 0xC0, 0x49, 0x62, 0xDF, 0xC1, 0x49},
|
||||
{0x97, 0xE5, 0x14, 0x72, 0x7F, 0x1A, 0x14, 0x72},
|
||||
{0x82, 0xC7, 0x90, 0x36, 0x21, 0x03, 0xFF, 0x17},
|
||||
{0xE2, 0xF8, 0xCC, 0x91, 0x3C, 0x37, 0xCC, 0x91}, //Note: the '03' was '9E' in the Cypress recommended table
|
||||
{0xAD, 0x39, 0xA2, 0x0F, 0x9B, 0xC5, 0xA1, 0x0F}, //The following are the same as the 1st 8 above,
|
||||
{0xD2, 0x8F, 0xB1, 0x2A, 0xEF, 0x64, 0xB0, 0x2A}, //but with the upper and lower word swapped
|
||||
{0xDD, 0x26, 0x7C, 0x50, 0x66, 0xCD, 0x7C, 0x50},
|
||||
{0xAD, 0x16, 0xF6, 0x44, 0x5C, 0xE1, 0xF6, 0x44},
|
||||
{0xB6, 0x31, 0xAE, 0x46, 0x5A, 0xCC, 0xAE, 0x46},
|
||||
{0x9E, 0x82, 0xDC, 0x3C, 0xA1, 0x78, 0xDC, 0x3C},
|
||||
{0x6F, 0x65, 0x18, 0x74, 0xB9, 0x8E, 0x19, 0x74},
|
||||
};
|
||||
const uint8_t bind_sop_code[] = {0x62, 0xdf, 0xc1, 0x49, 0xdf, 0xb1, 0xc0, 0x49};
|
||||
const uint8_t data_code[] = {0x02, 0xf9, 0x93, 0x97, 0x02, 0xfa, 0x5c, 0xe3, 0x01, 0x2b, 0xf1, 0xdb, 0x01, 0x32, 0xbe, 0x6f};
|
||||
|
||||
static uint8_t stateJ6P;
|
||||
static uint8_t radio_ch[4];
|
||||
static uint8_t num_channels;
|
||||
|
||||
void J6Pro_build_bind_packet()
|
||||
{
|
||||
packet[0] = 0x01; //Packet type
|
||||
packet[1] = 0x01; //FIXME: What is this? Model number maybe?
|
||||
packet[2] = 0x56; //FIXME: What is this?
|
||||
packet[3] = cyrfmfg_id[0];
|
||||
packet[4] = cyrfmfg_id[1];
|
||||
packet[5] = cyrfmfg_id[2];
|
||||
packet[6] = cyrfmfg_id[3];
|
||||
packet[7] = cyrfmfg_id[4];
|
||||
packet[8] = cyrfmfg_id[5];
|
||||
}
|
||||
void J6Pro_build_data_packet()
|
||||
{
|
||||
uint8_t i;
|
||||
uint32_t upperbits = 0;
|
||||
packet[0] = 0xaa; //FIXME what is this?
|
||||
for (i = 0; i < 12; i++) {
|
||||
if (i >= num_channels) {
|
||||
packet[i+1] = 0xff;
|
||||
continue;
|
||||
}
|
||||
uint32_t value = (uint32_t)Servo_data[i] * 0x200 / PPM_MAX + 0x200;
|
||||
if (value < 0)
|
||||
value = 0;
|
||||
if (value > 0x3ff)
|
||||
value = 0x3ff;
|
||||
packet[i+1] = value & 0xff;
|
||||
upperbits |= (value >> 8) << (i * 2);
|
||||
}
|
||||
packet[13] = upperbits & 0xff;
|
||||
packet[14] = (upperbits >> 8) & 0xff;
|
||||
packet[15] = (upperbits >> 16) & 0xff;
|
||||
}
|
||||
|
||||
static void J6Pro_cyrf_init()
|
||||
{
|
||||
/* Initialise CYRF chip */
|
||||
CYRF_WriteRegister(CYRF_28_CLK_EN, 0x02);
|
||||
CYRF_WriteRegister(CYRF_32_AUTO_CAL_TIME, 0x3c);
|
||||
CYRF_WriteRegister(CYRF_35_AUTOCAL_OFFSET, 0x14);
|
||||
CYRF_WriteRegister(CYRF_1C_TX_OFFSET_MSB, 0x05);
|
||||
CYRF_WriteRegister(CYRF_1B_TX_OFFSET_LSB, 0x55);
|
||||
CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x25);
|
||||
CYRF_WriteRegister(CYRF_03_TX_CFG, 0x05 | CYRF_BIND_POWER);
|
||||
CYRF_WriteRegister(CYRF_06_RX_CFG, 0x8a);
|
||||
CYRF_WriteRegister(CYRF_03_TX_CFG, 0x28 | CYRF_BIND_POWER);
|
||||
CYRF_WriteRegister(CYRF_12_DATA64_THOLD, 0x0e);
|
||||
CYRF_WriteRegister(CYRF_10_FRAMING_CFG, 0xee);
|
||||
CYRF_WriteRegister(CYRF_1F_TX_OVERRIDE, 0x00);
|
||||
CYRF_WriteRegister(CYRF_1E_RX_OVERRIDE, 0x00);
|
||||
CYRF_ConfigDataCode(data_code, 16);
|
||||
CYRF_WritePreamble(0x023333);
|
||||
}
|
||||
static void J6Pro_cyrf_bindinit()
|
||||
{
|
||||
/* Use when binding */
|
||||
//0.060470# 03 2f
|
||||
CYRF_WriteRegister(CYRF_03_TX_CFG, 0x28 | 0x07); //Use max power for binding in case there is no telem module
|
||||
|
||||
CYRF_ConfigRFChannel(0x52);
|
||||
CYRF_ConfigSOPCode(bind_sop_code);
|
||||
CYRF_ConfigCRCSeed(0x0000);
|
||||
CYRF_WriteRegister(CYRF_06_RX_CFG, 0x4a);
|
||||
CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x83);
|
||||
//0.061511# 13 20
|
||||
|
||||
CYRF_ConfigRFChannel(0x52);
|
||||
//0.062684# 0f 05
|
||||
CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x25);
|
||||
//0.062792# 0f 05
|
||||
CYRF_WriteRegister(CYRF_02_TX_CTRL, 0x40);
|
||||
J6Pro_build_bind_packet(); //01 01 e9 49 ec a9 c4 c1 ff
|
||||
//CYRF_WriteDataPacketLen(packet, 0x09);
|
||||
}
|
||||
static void J6Pro_cyrf_datainit()
|
||||
{
|
||||
/* Use when already bound */
|
||||
//0.094007# 0f 05
|
||||
uint8_t sop_idx = (0xff & (cyrfmfg_id[0] + cyrfmfg_id[1] + cyrfmfg_id[2] + cyrfmfg_id[3] - cyrfmfg_id[5])) % 19;
|
||||
uint16_t crc = (0xff & (cyrfmfg_id[1] - cyrfmfg_id[4] + cyrfmfg_id[5])) |
|
||||
((0xff & (cyrfmfg_id[2] + cyrfmfg_id[3] - cyrfmfg_id[4] + cyrfmfg_id[5])) << 8);
|
||||
CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x25);
|
||||
CYRF_ConfigSOPCode(J6Pro_sopcodes[sop_idx]);
|
||||
CYRF_ConfigCRCSeed(crc);
|
||||
}
|
||||
|
||||
static void J6Pro_set_radio_channels()
|
||||
{
|
||||
//FIXME: Query free channels
|
||||
//lowest channel is 0x08, upper channel is 0x4d?
|
||||
CYRF_FindBestChannels(radio_ch, 3, 5, 8, 77);
|
||||
radio_ch[3] = radio_ch[0];
|
||||
}
|
||||
|
||||
static uint16_t j6pro_cb()
|
||||
{
|
||||
switch(stateJ6P) {
|
||||
case J6PRO_BIND:
|
||||
J6Pro_cyrf_bindinit();
|
||||
stateJ6P = J6PRO_BIND_01;
|
||||
//no break because we want to send the 1st bind packet now
|
||||
case J6PRO_BIND_01:
|
||||
CYRF_ConfigRFChannel(0x52);
|
||||
CYRF_SetTxRxMode(TX_EN);
|
||||
//0.062684# 0f 05
|
||||
CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x25);
|
||||
//0.062684# 0f 05
|
||||
CYRF_WriteDataPacketLen(packet, 0x09);
|
||||
stateJ6P = J6PRO_BIND_03_START;
|
||||
return 3000; //3msec
|
||||
case J6PRO_BIND_03_START:
|
||||
{
|
||||
int i = 0;
|
||||
while (! (CYRF_ReadRegister(0x04) & 0x06))
|
||||
if(++i > NUM_WAIT_LOOPS)
|
||||
break;
|
||||
}
|
||||
CYRF_ConfigRFChannel(0x53);
|
||||
CYRF_SetTxRxMode(RX_EN);
|
||||
CYRF_WriteRegister(CYRF_06_RX_CFG, 0x4a);
|
||||
CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x83);
|
||||
stateJ6P = J6PRO_BIND_03_CHECK;
|
||||
return 30000; //30msec
|
||||
case J6PRO_BIND_03_CHECK:
|
||||
{
|
||||
uint8_t rx = CYRF_ReadRegister(CYRF_07_RX_IRQ_STATUS);
|
||||
if((rx & 0x1a) == 0x1a) {
|
||||
rx = CYRF_ReadRegister(CYRF_0A_RX_LENGTH);
|
||||
if(rx == 0x0f) {
|
||||
rx = CYRF_ReadRegister(CYRF_09_RX_COUNT);
|
||||
if(rx == 0x0f) {
|
||||
//Expected and actual length are both 15
|
||||
CYRF_ReadDataPacketLen(packet, rx);
|
||||
if (packet[0] == 0x03 &&
|
||||
packet[3] == cyrfmfg_id[0] &&
|
||||
packet[4] == cyrfmfg_id[1] &&
|
||||
packet[5] == cyrfmfg_id[2] &&
|
||||
packet[6] == cyrfmfg_id[3] &&
|
||||
packet[7] == cyrfmfg_id[4] &&
|
||||
packet[8] == cyrfmfg_id[5])
|
||||
{
|
||||
//Send back Ack
|
||||
packet[0] = 0x05;
|
||||
CYRF_ConfigRFChannel(0x54);
|
||||
CYRF_SetTxRxMode(TX_EN);
|
||||
stateJ6P = J6PRO_BIND_05_1;
|
||||
return 2000; //2msec
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
stateJ6P = J6PRO_BIND_01;
|
||||
return 500;
|
||||
}
|
||||
case J6PRO_BIND_05_1:
|
||||
case J6PRO_BIND_05_2:
|
||||
case J6PRO_BIND_05_3:
|
||||
case J6PRO_BIND_05_4:
|
||||
case J6PRO_BIND_05_5:
|
||||
case J6PRO_BIND_05_6:
|
||||
CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x25);
|
||||
CYRF_WriteDataPacketLen(packet, 0x0f);
|
||||
stateJ6P = stateJ6P + 1;
|
||||
return 4600; //4.6msec
|
||||
case J6PRO_CHANSEL:
|
||||
BIND_DONE;
|
||||
J6Pro_set_radio_channels();
|
||||
J6Pro_cyrf_datainit();
|
||||
stateJ6P = J6PRO_CHAN_1;
|
||||
case J6PRO_CHAN_1:
|
||||
//Keep transmit power updated
|
||||
CYRF_SetPower(CYRF_HIGH_POWER);
|
||||
J6Pro_build_data_packet();
|
||||
//return 3400;
|
||||
case J6PRO_CHAN_2:
|
||||
//return 3500;
|
||||
case J6PRO_CHAN_3:
|
||||
//return 3750
|
||||
case J6PRO_CHAN_4:
|
||||
CYRF_ConfigRFChannel(radio_ch[stateJ6P - J6PRO_CHAN_1]);
|
||||
CYRF_SetTxRxMode(TX_EN);
|
||||
CYRF_WriteDataPacket(packet);
|
||||
if (stateJ6P == J6PRO_CHAN_4) {
|
||||
stateJ6P = J6PRO_CHAN_1;
|
||||
return 13900;
|
||||
}
|
||||
stateJ6P = stateJ6P + 1;
|
||||
return 3550;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint16_t j6pro_setup()
|
||||
{
|
||||
CYRF_Reset();
|
||||
J6Pro_cyrf_init();
|
||||
num_channels = 8;
|
||||
if (IS_AUTOBIND_FLAG_on) {
|
||||
stateJ6P = J6PRO_BIND;
|
||||
BIND_IN_PROGRESS;
|
||||
} else {
|
||||
stateJ6P = J6PRO_CHANSEL;
|
||||
}
|
||||
return 2400;
|
||||
}
|
||||
#endif
|
449
Multiprotocol/Cyrf6936_wk2x01.ino
Normal file
449
Multiprotocol/Cyrf6936_wk2x01.ino
Normal file
@ -0,0 +1,449 @@
|
||||
/*
|
||||
This project is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
Deviation is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License along with Deviation. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#if defined(WK2x01_CYRF6936_INO)
|
||||
#include "iface_cyrf6936.h"
|
||||
|
||||
#define PKTS_PER_CHANNEL 4
|
||||
|
||||
//Fewer bind packets in the emulator so we can get right to the important bits
|
||||
#define WK_BIND_COUNT 2980
|
||||
|
||||
#define NUM_WAIT_LOOPS (100 / 5) //each loop is ~5us. Do not wait more than 100us
|
||||
|
||||
|
||||
#define WK_BIND 0
|
||||
#define WK_BOUND_1 1
|
||||
#define WK_BOUND_2 2
|
||||
#define WK_BOUND_3 3
|
||||
#define WK_BOUND_4 4
|
||||
#define WK_BOUND_5 5
|
||||
#define WK_BOUND_6 6
|
||||
#define WK_BOUND_7 7
|
||||
#define WK_BOUND_8 8
|
||||
|
||||
static const uint8_t sopcode[8] = {
|
||||
/* Note these are in order transmitted (LSB 1st) */
|
||||
0xDF,0xB1,0xC0,0x49,0x62,0xDF,0xC1,0x49 //0x49C1DF6249C0B1DF
|
||||
};
|
||||
static const uint8_t fail_map[8] = {2, 1, 0, 3, 4, 5, 6, 7};
|
||||
|
||||
static uint8_t wk_pkt_num;
|
||||
static 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
|
@ -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
|
||||
|
@ -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
|
@ -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;
|
||||
//
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
318
Multiprotocol/Nrf24l01_cflie.ino
Normal file
318
Multiprotocol/Nrf24l01_cflie.ino
Normal file
@ -0,0 +1,318 @@
|
||||
/*
|
||||
This project is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Deviation is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Deviation. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* NB: Not implemented
|
||||
Uncomment define below to enable telemetry. Also add CFlie protocol to TELEMETRY_SetTypeByProtocol to set type to DSM.
|
||||
#define CFLIE_TELEMETRY
|
||||
*/
|
||||
|
||||
|
||||
#if defined(CFlie_NRF24L01_INO)
|
||||
#include "iface_nrf24l01.h"
|
||||
|
||||
#define BIND_COUNT 60
|
||||
|
||||
// Address size
|
||||
#define TX_ADDR_SIZE 5
|
||||
|
||||
// Timeout for callback in uSec, 10ms=10000us for Crazyflie
|
||||
#define PACKET_PERIOD 10000
|
||||
|
||||
|
||||
// For code readability
|
||||
enum {
|
||||
CHANNEL1 = 0,
|
||||
CHANNEL2,
|
||||
CHANNEL3,
|
||||
CHANNEL4,
|
||||
CHANNEL5,
|
||||
CHANNEL6,
|
||||
CHANNEL7,
|
||||
CHANNEL8,
|
||||
CHANNEL9,
|
||||
CHANNEL10
|
||||
};
|
||||
|
||||
#define PAYLOADSIZE 8 // receive data pipes set to this size, but unused
|
||||
#define MAX_PACKET_SIZE 9 // YD717 packets have 8-byte payload, Syma X4 is 9
|
||||
|
||||
//static uint8_t packet[MAX_PACKET_SIZE];
|
||||
|
||||
static uint8_t data_rate, rf_channel;
|
||||
|
||||
enum {
|
||||
CFLIE_INIT_SEARCH = 0,
|
||||
CFLIE_INIT_DATA,
|
||||
CFLIE_SEARCH,
|
||||
CFLIE_DATA
|
||||
};
|
||||
|
||||
#ifdef CFLIE_TELEMETRY
|
||||
static const char * const cflie_opts[] = {
|
||||
_tr_noop("Telemetry"), _tr_noop("Off"), _tr_noop("On"), NULL,
|
||||
NULL
|
||||
};
|
||||
enum {
|
||||
PROTOOPTS_TELEMETRY = 0,
|
||||
LAST_PROTO_OPT,
|
||||
};
|
||||
ctassert(LAST_PROTO_OPT <= NUM_PROTO_OPTS, too_many_protocol_opts);
|
||||
|
||||
#define TELEM_OFF 0
|
||||
#define TELEM_ON 1
|
||||
#endif
|
||||
|
||||
#define PACKET_CHKTIME 500 // time to wait if packet not yet acknowledged or timed out
|
||||
|
||||
static uint16_t dbg_cnt = 0;
|
||||
static uint8_t packet_ack() {
|
||||
if (++dbg_cnt > 50) { dbg_cnt = 0; }
|
||||
switch (NRF24L01_ReadReg(NRF24L01_07_STATUS) & (BV(NRF24L01_07_TX_DS) | BV(NRF24L01_07_MAX_RT))) {
|
||||
case BV(NRF24L01_07_TX_DS):
|
||||
return PKT_ACKED;
|
||||
case BV(NRF24L01_07_MAX_RT):
|
||||
return PKT_TIMEOUT;
|
||||
}
|
||||
return PKT_PENDING;
|
||||
}
|
||||
|
||||
static void set_rate_channel(uint8_t rate, uint8_t channel) {
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, channel); // Defined by model id
|
||||
NRF24L01_SetBitrate(rate); // Defined by model id
|
||||
}
|
||||
|
||||
static void send_search_packet() {
|
||||
uint8_t buf[1];
|
||||
buf[0] = 0xff;
|
||||
// clear packet status bits and TX FIFO
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, (BV(NRF24L01_07_TX_DS) | BV(NRF24L01_07_MAX_RT)));
|
||||
NRF24L01_FlushTx();
|
||||
|
||||
if (rf_channel++ > 125) {
|
||||
rf_channel = 0;
|
||||
switch(data_rate) {
|
||||
case NRF24L01_BR_250K:
|
||||
data_rate = NRF24L01_BR_1M;
|
||||
break;
|
||||
case NRF24L01_BR_1M:
|
||||
data_rate = NRF24L01_BR_2M;
|
||||
break;
|
||||
case NRF24L01_BR_2M:
|
||||
data_rate = NRF24L01_BR_250K;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
set_rate_channel(data_rate, rf_channel);
|
||||
|
||||
NRF24L01_WritePayload(buf, sizeof(buf));
|
||||
|
||||
++packet_counter;
|
||||
}
|
||||
|
||||
// Frac 16.16
|
||||
#define FRAC_MANTISSA 16
|
||||
#define FRAC_SCALE (1 << FRAC_MANTISSA)
|
||||
|
||||
// Convert fractional 16.16 to float32
|
||||
static void frac2float(uint32_t n, float* res) {
|
||||
if (n == 0) {
|
||||
*res = 0.0;
|
||||
return;
|
||||
}
|
||||
uint32_t m = n < 0 ? -n : n;
|
||||
int i;
|
||||
for (i = (31-FRAC_MANTISSA); (m & 0x80000000) == 0; i--, m <<= 1) ;
|
||||
m <<= 1; // Clear implicit leftmost 1
|
||||
m >>= 9;
|
||||
uint32_t e = 127 + i;
|
||||
if (n < 0) m |= 0x80000000;
|
||||
m |= e << 23;
|
||||
*((uint32_t *) res) = m;
|
||||
}
|
||||
|
||||
static void send_cmd_packet() {
|
||||
// Commander packet, 15 bytes
|
||||
uint8_t buf[15];
|
||||
float x_roll, x_pitch, yaw;
|
||||
|
||||
// Channels in AETR order
|
||||
|
||||
// Roll, aka aileron, float +- 50.0 in degrees
|
||||
// float roll = -(float) Servo_data[AILERON]*50.0/10000;
|
||||
uint32_t f_roll = -Servo_data[AILERON] * FRAC_SCALE / (10000 / 50);
|
||||
|
||||
// Pitch, aka elevator, float +- 50.0 degrees
|
||||
//float pitch = -(float) Servo_data[ELEVATOR]*50.0/10000;
|
||||
uint32_t f_pitch = -Servo_data[ELEVATOR] * FRAC_SCALE / (10000 / 50);
|
||||
|
||||
// Thrust, aka throttle 0..65535, working range 5535..65535
|
||||
// No space for overshoot here, hard limit Channel3 by -10000..10000
|
||||
uint32_t ch = Servo_data[THROTTLE];
|
||||
if (ch < PPM_MIN) {
|
||||
ch = PPM_MIN;
|
||||
} else if (ch > PPM_MAX) {
|
||||
ch = PPM_MAX;
|
||||
}
|
||||
uint16_t thrust = ch*3L + 35535L;
|
||||
|
||||
// Yaw, aka rudder, float +- 400.0 deg/s
|
||||
// float yaw = -(float) Servo_data[RUDDER]*400.0/10000;
|
||||
uint32_t f_yaw = - Servo_data[RUDDER] * FRAC_SCALE / (10000 / 400);
|
||||
frac2float(f_yaw, &yaw);
|
||||
|
||||
// Convert + to X. 181 / 256 = 0.70703125 ~= sqrt(2) / 2
|
||||
uint32_t f_x_roll = (f_roll + f_pitch) * 181 / 256;
|
||||
frac2float(f_x_roll, &x_roll);
|
||||
uint32_t f_x_pitch = (f_pitch - f_roll) * 181 / 256;
|
||||
frac2float(f_x_pitch, &x_pitch);
|
||||
|
||||
int bufptr = 0;
|
||||
buf[bufptr++] = 0x30; // Commander packet to channel 0
|
||||
memcpy(&buf[bufptr], (char*) &x_roll, 4); bufptr += 4;
|
||||
memcpy(&buf[bufptr], (char*) &x_pitch, 4); bufptr += 4;
|
||||
memcpy(&buf[bufptr], (char*) &yaw, 4); bufptr += 4;
|
||||
memcpy(&buf[bufptr], (char*) &thrust, 2); bufptr += 2;
|
||||
|
||||
|
||||
// clear packet status bits and TX FIFO
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, (BV(NRF24L01_07_TX_DS) | BV(NRF24L01_07_MAX_RT)));
|
||||
NRF24L01_FlushTx();
|
||||
|
||||
NRF24L01_WritePayload(buf, sizeof(buf));
|
||||
|
||||
++packet_counter;
|
||||
|
||||
NRF24L01_SetPower();
|
||||
}
|
||||
|
||||
static int cflie_init() {
|
||||
NRF24L01_Initialize();
|
||||
|
||||
// CRC, radio on
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
NRF24L01_WriteReg(NRF24L01_00_CONFIG, BV(NRF24L01_00_EN_CRC) | BV(NRF24L01_00_CRCO) | BV(NRF24L01_00_PWR_UP));
|
||||
// NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknowledgement
|
||||
NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x01); // Auto Acknowledgement for data pipe 0
|
||||
NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0
|
||||
NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, TX_ADDR_SIZE-2); // 5-byte RX/TX address
|
||||
NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0x13); // 3 retransmits, 500us delay
|
||||
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, rf_channel); // Defined by model id
|
||||
NRF24L01_SetBitrate(data_rate); // Defined by model id
|
||||
|
||||
NRF24L01_SetPower();
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
|
||||
|
||||
NRF24L01_WriteReg(NRF24L01_17_FIFO_STATUS, 0x00); // Just in case, no real bits to write here
|
||||
|
||||
// this sequence necessary for module from stock tx
|
||||
NRF24L01_ReadReg(NRF24L01_1D_FEATURE);
|
||||
NRF24L01_Activate(0x73); // Activate feature register
|
||||
NRF24L01_ReadReg(NRF24L01_1D_FEATURE);
|
||||
|
||||
NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 0x01); // Enable Dynamic Payload Length on pipe 0
|
||||
NRF24L01_WriteReg(NRF24L01_1D_FEATURE, 0x06); // Enable Dynamic Payload Length, enable Payload with ACK
|
||||
|
||||
|
||||
// NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, rx_tx_addr, TX_ADDR_SIZE);
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_addr, TX_ADDR_SIZE);
|
||||
|
||||
NRF24L01_Activate(0x53); // switch bank back
|
||||
|
||||
// 50ms delay in callback
|
||||
return 50000;
|
||||
}
|
||||
|
||||
|
||||
#ifdef CFLIE_TELEMETRY
|
||||
static void update_telemetry() {
|
||||
static uint8_t frameloss = 0;
|
||||
|
||||
frameloss += NRF24L01_ReadReg(NRF24L01_08_OBSERVE_TX) >> 4;
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, rf_channel); // reset packet loss counter
|
||||
|
||||
Telemetry.p.dsm.flog.frameloss = frameloss;
|
||||
// Telemetry.p.dsm.flog.volt[0] = read battery voltage from ack payload
|
||||
TELEMETRY_SetUpdated(TELEM_DSM_FLOG_FRAMELOSS);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static uint16_t cflie_callback() {
|
||||
switch (phase) {
|
||||
case CFLIE_INIT_SEARCH:
|
||||
send_search_packet();
|
||||
phase = CFLIE_SEARCH;
|
||||
break;
|
||||
case CFLIE_INIT_DATA:
|
||||
send_cmd_packet();
|
||||
phase = CFLIE_DATA;
|
||||
break;
|
||||
case CFLIE_SEARCH:
|
||||
switch (packet_ack()) {
|
||||
case PKT_PENDING:
|
||||
return PACKET_CHKTIME; // packet send not yet complete
|
||||
case PKT_ACKED:
|
||||
phase = CFLIE_DATA;
|
||||
BIND_DONE;
|
||||
break;
|
||||
case PKT_TIMEOUT:
|
||||
send_search_packet();
|
||||
counter = BIND_COUNT;
|
||||
}
|
||||
break;
|
||||
case CFLIE_DATA:
|
||||
#ifdef CFLIE_TELEMETRY
|
||||
update_telemetry();
|
||||
#endif
|
||||
if (packet_ack() == PKT_PENDING)
|
||||
return PACKET_CHKTIME; // packet send not yet complete
|
||||
send_cmd_packet();
|
||||
break;
|
||||
}
|
||||
return PACKET_PERIOD; // Packet at standard protocol interval
|
||||
}
|
||||
|
||||
|
||||
// Generate address to use from TX id and manufacturer id (STM32 unique id)
|
||||
static uint8_t initialize_rx_tx_addr() {
|
||||
rx_tx_addr[0] =
|
||||
rx_tx_addr[1] =
|
||||
rx_tx_addr[2] =
|
||||
rx_tx_addr[3] =
|
||||
rx_tx_addr[4] = 0xE7; // CFlie uses fixed address
|
||||
|
||||
data_rate = NRF24L01_BR_250K;
|
||||
rf_channel = 0;
|
||||
return CFLIE_INIT_SEARCH;
|
||||
// return CFLIE_INIT_DATA;
|
||||
}
|
||||
|
||||
static uint16_t Cflie_setup() {
|
||||
phase = initialize_rx_tx_addr();
|
||||
packet_counter = 0;
|
||||
|
||||
int delay = cflie_init();
|
||||
|
||||
#ifdef CFLIE_TELEMETRY
|
||||
memset(&Telemetry, 0, sizeof(Telemetry));
|
||||
TELEMETRY_SetType(TELEM_DSM);
|
||||
#endif
|
||||
if (phase == CFLIE_INIT_SEARCH) { BIND_IN_PROGRESS; }
|
||||
return delay;
|
||||
}
|
||||
|
||||
#endif
|
234
Multiprotocol/Nrf24l01_fy326.ino
Normal file
234
Multiprotocol/Nrf24l01_fy326.ino
Normal 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
|
210
Multiprotocol/Nrf24l01_h377.ino
Normal file
210
Multiprotocol/Nrf24l01_h377.ino
Normal file
@ -0,0 +1,210 @@
|
||||
/*
|
||||
This project is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Deviation is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Deviation. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if defined (H377_NRF24L01_INO)
|
||||
#include "iface_nrf24l01.h"
|
||||
|
||||
#define BIND_COUNT 800
|
||||
|
||||
|
||||
#define TXID_H377_SIZE 5
|
||||
|
||||
#define FREQUENCE_NUM_H377 20
|
||||
#define SET_NUM_H377 9
|
||||
// available frequency must be in between 2402 and 2477
|
||||
|
||||
static uint8_t binding_ch=0x50;
|
||||
static uint8_t hopping_frequency_data[SET_NUM_H377] = {0x1c,0x1b,0x1d,0x11,0x0e,0x0d,0x01,0x1d,0x15};
|
||||
|
||||
static const uint8_t binding_adr_rf[5]={0x32,0xaa,0x45,0x45,0x78};
|
||||
|
||||
static uint8_t rf_adr_buf[5];
|
||||
static uint8_t rf_adr_buf_data[SET_NUM_H377][5] = {
|
||||
{0xad,0x9a,0xa6,0x69,0xb2},//ansheng
|
||||
{0x92,0x9a,0x9d,0x69,0x99},//dc59
|
||||
{0x92,0xb2,0x9d,0x69,0x9a},//small two
|
||||
{0xad,0x9a,0x5a,0x69,0x96},//james_1
|
||||
{0x95,0x9a,0x52,0x69,0x99},//james_2
|
||||
{0x52,0x52,0x52,0x69,0xb9},//james_3
|
||||
{0x52,0x52,0x52,0x52,0x55},//small two_1
|
||||
{0x92,0xB2,0x9D,0x69,0x9A},//small two_2
|
||||
{0x96,0x9A,0x45,0x69,0xB2}//small two_3
|
||||
};
|
||||
|
||||
static uint8_t bind_buf_array[10];
|
||||
static uint8_t bind_buf_array_data[SET_NUM_H377][4] = {
|
||||
{0xcf,0x1c,0x19,0x1a},
|
||||
{0xff,0x48,0x19,0x19},
|
||||
{0xf3,0x4d,0x19,0x19},
|
||||
{0x9e,0x1f,0x19,0x19},
|
||||
{0x8d,0x3d,0x19,0x19},
|
||||
{0xbd,0x23,0x19,0x19},
|
||||
{0xF3,0x28,0x19,0x19},
|
||||
{0xF3,0x4D,0x19,0x19},
|
||||
{0x82,0x8D,0x19,0x19}
|
||||
};
|
||||
|
||||
|
||||
static unsigned int ch_data[8];
|
||||
static uint8_t payload[10];
|
||||
static uint8_t counter1ms;
|
||||
|
||||
static int select_ch_id = 0;
|
||||
|
||||
static void h377_binding_packet(void) { //bind_buf_array
|
||||
uint8_t i;
|
||||
counter1ms = 0;
|
||||
hopping_frequency_no = 0;
|
||||
|
||||
for(i=0;i<5;i++)
|
||||
bind_buf_array[i] = rf_adr_buf[i];
|
||||
|
||||
bind_buf_array[5] = hopping_frequency[0];
|
||||
|
||||
for(i=0;i<4;i++)
|
||||
bind_buf_array[i+6] = bind_buf_array_data[select_ch_id][i];
|
||||
}
|
||||
|
||||
static void h377_init() {
|
||||
NRF24L01_Initialize();
|
||||
|
||||
NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable p0 rx
|
||||
NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknoledgement
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rf_adr_buf, 5);
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, rf_adr_buf, 5);
|
||||
NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, 10); // payload size = 10
|
||||
//NRF24L01_WriteReg(NRF24L01_05_RF_CH, 81); // binding packet must be set in channel 81
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, binding_ch); // binding packet must be set in channel 81
|
||||
|
||||
// 2-bytes CRC, radio off
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
NRF24L01_WriteReg(NRF24L01_00_CONFIG, BV(NRF24L01_00_EN_CRC) | BV(NRF24L01_00_CRCO) | BV(NRF24L01_00_PWR_UP));
|
||||
NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x03); // 5-byte RX/TX address (byte -2)
|
||||
NRF24L01_SetBitrate(0); // 1Mbps
|
||||
NRF24L01_SetPower();
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
|
||||
}
|
||||
|
||||
// H377 channel sequence: AILE ELEV THRO RUDD GEAR PITH, channel data value is from 0 to 1000
|
||||
static void h377_ch_data() {
|
||||
uint32_t temp;
|
||||
uint8_t i;
|
||||
for (i = 0; i< 8; i++) {
|
||||
temp = (uint32_t)Servo_data[i] * 450/PPM_MAX + 500; // max/min servo range is +-125%
|
||||
if (i == 2) // It is clear that h377's thro stick is made reversely, so I adjust it here on purpose
|
||||
temp = 1000 -temp;
|
||||
//if (i == 0) // It is clear that h377's thro stick is made reversely, so I adjust it here on purpose
|
||||
// temp = 1000 -temp;
|
||||
//if (i == 1) // It is clear that h377's thro stick is made reversely, so I adjust it here on purpose
|
||||
// temp = 1000 -temp;
|
||||
if (temp < 0)
|
||||
ch_data[i] = 0;
|
||||
else if (temp > 1000)
|
||||
ch_data[i] = 1000;
|
||||
else
|
||||
ch_data[i] = (unsigned int)temp;
|
||||
payload[i] = (uint8_t)ch_data[i];
|
||||
}
|
||||
payload[8] = (uint8_t)((ch_data[0]>>8)&0x0003);
|
||||
payload[8] |= (uint8_t)((ch_data[1]>>6)&0x000c);
|
||||
payload[8] |= (uint8_t)((ch_data[2]>>4)&0x0030);
|
||||
payload[8] |= (uint8_t)((ch_data[3]>>2)&0x00c0);
|
||||
|
||||
payload[9] = (uint8_t)((ch_data[4]>>8)&0x0003);
|
||||
payload[9] |= (uint8_t)((ch_data[5]>>6)&0x000c);
|
||||
payload[9] |= (uint8_t)((ch_data[6]>>4)&0x0030);
|
||||
payload[9] |= (uint8_t)((ch_data[7]>>2)&0x00c0);
|
||||
}
|
||||
|
||||
static uint16_t h377_cb() {
|
||||
counter1ms++;
|
||||
if(counter1ms==1) { NRF24L01_FlushTx(); }
|
||||
//-------------------------
|
||||
else if(counter1ms==2) {
|
||||
if (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
|
267
Multiprotocol/Nrf24l01_hm830.ino
Normal file
267
Multiprotocol/Nrf24l01_hm830.ino
Normal file
@ -0,0 +1,267 @@
|
||||
/*
|
||||
This project is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
Deviation is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License along with Deviation. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* This protocol is for the HM Hobby HM830 RC Paper Airplane
|
||||
Protocol spec:
|
||||
Channel data:
|
||||
AA BB CC DD EE FF GG
|
||||
AA : Throttle Min=0x00 max =0x64
|
||||
BB :
|
||||
bit 0,1,2: Left/Right magnitude, bit 5 Polarity (set = right)
|
||||
bit 6: Accelerate
|
||||
bit 7: Right button (also the ABC Button)
|
||||
CC : bit 0 seems to be impacted by the Right button
|
||||
DD
|
||||
EE
|
||||
FF : Trim (bit 0-5: Magnitude, bit 6 polarity (set = right)
|
||||
GG : Checksum (CRC8 on bytes AA-FF), init = 0xa5, poly = 0x01
|
||||
*/
|
||||
|
||||
#ifdef HM830_NRF24L01_INO
|
||||
|
||||
#include "iface_nrf24l01.h"
|
||||
|
||||
enum {
|
||||
HM830_BIND1A = 0,
|
||||
HM830_BIND2A,
|
||||
HM830_BIND3A,
|
||||
HM830_BIND4A,
|
||||
HM830_BIND5A,
|
||||
HM830_BIND6A,
|
||||
HM830_BIND7A,
|
||||
HM830_DATA1,
|
||||
HM830_DATA2,
|
||||
HM830_DATA3,
|
||||
HM830_DATA4,
|
||||
HM830_DATA5,
|
||||
HM830_DATA6,
|
||||
HM830_DATA7,
|
||||
HM830_BIND1B = 0x80,
|
||||
HM830_BIND2B,
|
||||
HM830_BIND3B,
|
||||
HM830_BIND4B,
|
||||
HM830_BIND5B,
|
||||
HM830_BIND6B,
|
||||
HM830_BIND7B,
|
||||
};
|
||||
|
||||
static uint8_t init_vals_hm830[][2] = {
|
||||
{NRF24L01_17_FIFO_STATUS, 0x00},
|
||||
{NRF24L01_16_RX_PW_P5, 0x07},
|
||||
{NRF24L01_15_RX_PW_P4, 0x07},
|
||||
{NRF24L01_14_RX_PW_P3, 0x07},
|
||||
{NRF24L01_13_RX_PW_P2, 0x07},
|
||||
{NRF24L01_12_RX_PW_P1, 0x07},
|
||||
{NRF24L01_11_RX_PW_P0, 0x07},
|
||||
{NRF24L01_0F_RX_ADDR_P5, 0xC6},
|
||||
{NRF24L01_0E_RX_ADDR_P4, 0xC5},
|
||||
{NRF24L01_0D_RX_ADDR_P3, 0xC4},
|
||||
{NRF24L01_0C_RX_ADDR_P2, 0xC3},
|
||||
{NRF24L01_09_CD, 0x00},
|
||||
{NRF24L01_08_OBSERVE_TX, 0x00},
|
||||
{NRF24L01_07_STATUS, 0x07},
|
||||
// {NRF24L01_06_RF_SETUP, 0x07},
|
||||
{NRF24L01_05_RF_CH, 0x18},
|
||||
{NRF24L01_04_SETUP_RETR, 0x3F},
|
||||
{NRF24L01_03_SETUP_AW, 0x03},
|
||||
{NRF24L01_02_EN_RXADDR, 0x3F},
|
||||
{NRF24L01_01_EN_AA, 0x3F},
|
||||
{NRF24L01_00_CONFIG, 0x0E},
|
||||
};
|
||||
|
||||
static uint8_t count;
|
||||
static uint8_t rf_ch[] = {0x08, 0x35, 0x12, 0x3f, 0x1c, 0x49, 0x26};
|
||||
static uint8_t bind_addr[] = {0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xc2};
|
||||
|
||||
static uint8_t crc8(uint32_t result, uint8_t *data, int len) {
|
||||
int polynomial = 0x01;
|
||||
for(int i = 0; i < len; i++) {
|
||||
result = result ^ data[i];
|
||||
for(int j = 0; j < 8; j++) {
|
||||
if(result & 0x80) { result = (result << 1) ^ polynomial; }
|
||||
else { result = result << 1; }
|
||||
}
|
||||
}
|
||||
return result & 0xff;
|
||||
}
|
||||
|
||||
static void HM830_init() {
|
||||
NRF24L01_Initialize();
|
||||
for (uint32_t i = 0; i < sizeof(init_vals_hm830) / sizeof(init_vals_hm830[0]); i++) { NRF24L01_WriteReg(init_vals_hm830[i][0], init_vals_hm830[i][1]); }
|
||||
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
NRF24L01_SetBitrate(0);
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, bind_addr, 5);
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_0B_RX_ADDR_P1, bind_addr+1, 5);
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, bind_addr, 5);
|
||||
NRF24L01_Activate(0x73); //Enable FEATURE
|
||||
NRF24L01_WriteReg(NRF24L01_1D_FEATURE, 0x07);
|
||||
NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 0x3F);
|
||||
//NRF24L01_ReadReg(NRF24L01_07_STATUS) ==> 0x07
|
||||
|
||||
NRF24L01_Activate(0x53); // switch bank back
|
||||
|
||||
NRF24L01_FlushTx();
|
||||
//NRF24L01_ReadReg(NRF24L01_07_STATUS) ==> 0x0e
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x0e);
|
||||
//NRF24L01_ReadReg(NRF24L01_00_CONFIG); ==> 0x0e
|
||||
NRF24L01_WriteReg(NRF24L01_00_CONFIG, 0x0e);
|
||||
NRF24L01_ReadReg(NRF24L01_01_EN_AA); // No Auto Acknoledgement
|
||||
}
|
||||
|
||||
static void build_bind_packet_hm830() {
|
||||
for(int i = 0; i < 6; i++) { packet[i] = rx_tx_addr[i]; }
|
||||
packet[6] = crc8(0xa5, packet, 6);
|
||||
}
|
||||
|
||||
static void build_data_packet() {
|
||||
uint8_t ail_sign = 0, trim_sign = 0;
|
||||
|
||||
throttle = (uint32_t)Servo_data[THROTTLE] * 50 / PPM_MAX + 50;
|
||||
if (throttle < 0) { throttle = 0; }
|
||||
|
||||
aileron = (uint32_t)Servo_data[AILERON] * 8 / PPM_MAX;
|
||||
if (aileron < 0) { aileron = -aileron; ail_sign = 1; }
|
||||
if (aileron > 7) { aileron = 7; }
|
||||
|
||||
uint8_t turbo = (uint32_t)Servo_data[ELEVATOR] > 0 ? 1 : 0;
|
||||
|
||||
uint8_t trim = ((uint32_t)Servo_data[RUDDER] * 0x1f / PPM_MAX);
|
||||
if (trim < 0) { trim = -trim; trim_sign = 1; }
|
||||
if (trim > 0x1f) { trim = 0x1f; }
|
||||
|
||||
uint8_t rbutton = (uint32_t)Servo_data[4] > 0 ? 1 : 0;
|
||||
packet[0] = throttle;
|
||||
packet[1] = aileron;
|
||||
if (ail_sign) { packet[1] |= 0x20; }
|
||||
if (turbo) { packet[1] |= 0x40; }
|
||||
if (rbutton) { packet[1] |= 0x80; }
|
||||
packet[5] = trim;
|
||||
if (trim_sign) { packet[5] |= 0x20;}
|
||||
packet[6] = crc8(0xa5, packet, 6);
|
||||
}
|
||||
|
||||
static void send_packet_hm830() {
|
||||
NRF24L01_ReadReg(NRF24L01_17_FIFO_STATUS);
|
||||
NRF24L01_WritePayload(packet, 7);
|
||||
}
|
||||
|
||||
static uint16_t handle_binding() {
|
||||
uint8_t status = NRF24L01_ReadReg(NRF24L01_07_STATUS);
|
||||
if (status & 0x20) {
|
||||
//Binding complete
|
||||
phase = HM830_DATA1 + ((phase&0x7F)-HM830_BIND1A);
|
||||
count = 0;
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, rx_tx_addr, 5);
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_0B_RX_ADDR_P1, rx_tx_addr+1, 5);
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_addr, 5);
|
||||
NRF24L01_FlushTx();
|
||||
build_data_packet();
|
||||
uint8_t rb = NRF24L01_ReadReg(NRF24L01_07_STATUS); //==> 0x0E
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, rb);
|
||||
rb = NRF24L01_ReadReg(NRF24L01_00_CONFIG); //==> 0x0E
|
||||
NRF24L01_WriteReg(NRF24L01_00_CONFIG, rb);
|
||||
send_packet_hm830();
|
||||
return 14000;
|
||||
}
|
||||
switch (phase) {
|
||||
case HM830_BIND1A:
|
||||
//Look for a Rx that is already bound
|
||||
NRF24L01_SetPower();
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, rx_tx_addr, 5);
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_0B_RX_ADDR_P1, rx_tx_addr+1, 5);
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_addr, 5);
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, rf_ch[0]);
|
||||
build_bind_packet_hm830();
|
||||
break;
|
||||
case HM830_BIND1B:
|
||||
//Look for a Rx that is not yet bound
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, bind_addr, 5);
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_0B_RX_ADDR_P1, bind_addr+1, 5);
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, bind_addr, 5);
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, rf_ch[0]);
|
||||
break;
|
||||
case HM830_BIND2A:
|
||||
case HM830_BIND3A:
|
||||
case HM830_BIND4A:
|
||||
case HM830_BIND5A:
|
||||
case HM830_BIND6A:
|
||||
case HM830_BIND7A:
|
||||
case HM830_BIND2B:
|
||||
case HM830_BIND3B:
|
||||
case HM830_BIND4B:
|
||||
case HM830_BIND5B:
|
||||
case HM830_BIND6B:
|
||||
case HM830_BIND7B:
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, rf_ch[(phase&0x7F)-HM830_BIND1A]);
|
||||
break;
|
||||
}
|
||||
NRF24L01_FlushTx();
|
||||
uint8_t rb = NRF24L01_ReadReg(NRF24L01_07_STATUS); //==> 0x0E
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, rb);
|
||||
rb = NRF24L01_ReadReg(NRF24L01_00_CONFIG); //==> 0x0E
|
||||
NRF24L01_WriteReg(NRF24L01_00_CONFIG, rb);
|
||||
send_packet_hm830();
|
||||
phase++;
|
||||
if (phase == HM830_BIND7B+1) { phase = HM830_BIND1A; }
|
||||
else if (phase == HM830_BIND7A+1) { phase = HM830_BIND1B; }
|
||||
return 20000;
|
||||
}
|
||||
|
||||
static uint16_t handle_data() {
|
||||
uint8_t status = NRF24L01_ReadReg(NRF24L01_07_STATUS);
|
||||
if (count <= 0 || !(status & 0x20)) {
|
||||
if(count < 0 || ! (status & 0x20)) {
|
||||
count = 0;
|
||||
//We didn't get a response on this channel, try the next one
|
||||
phase++;
|
||||
if (phase-HM830_DATA1 > 6) { phase = HM830_DATA1; }
|
||||
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, rf_ch[0]);
|
||||
NRF24L01_FlushTx();
|
||||
build_data_packet();
|
||||
uint8_t rb = NRF24L01_ReadReg(NRF24L01_07_STATUS); //==> 0x0E
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, rb);
|
||||
rb = NRF24L01_ReadReg(NRF24L01_00_CONFIG); //==> 0x0E
|
||||
NRF24L01_WriteReg(NRF24L01_00_CONFIG, rb);
|
||||
send_packet_hm830();
|
||||
return 14000;
|
||||
}
|
||||
}
|
||||
build_data_packet();
|
||||
count++;
|
||||
if(count == 98) {
|
||||
count = -1;
|
||||
NRF24L01_SetPower();
|
||||
}
|
||||
uint8_t rb = NRF24L01_ReadReg(NRF24L01_07_STATUS); //==> 0x0E
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, rb);
|
||||
rb = NRF24L01_ReadReg(NRF24L01_00_CONFIG); //==> 0x0E
|
||||
NRF24L01_WriteReg(NRF24L01_00_CONFIG, rb);
|
||||
send_packet_hm830();
|
||||
return 20000;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static uint16_t HM830_callback() {
|
||||
if ((phase & 0x7F) < HM830_DATA1) { return handle_binding(); }
|
||||
else { return handle_data(); }
|
||||
}
|
||||
|
||||
|
||||
static uint32_t HM830_setup(){
|
||||
count = 0;
|
||||
// initialize_tx_id
|
||||
|
||||
rx_tx_addr[4] = 0xee;
|
||||
rx_tx_addr[5] = 0xc2;
|
||||
HM830_init();
|
||||
phase = HM830_BIND1A;
|
||||
|
||||
return 500;
|
||||
}
|
||||
#endif
|
@ -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
|
@ -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,
|
||||
|
@ -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
|
@ -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
|
||||
|
42
README.md
42
README.md
@ -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
|
||||

|
||||
|
||||
|
||||
#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 ???
|
||||
|
||||
|
BIN
sync.ffs_db
BIN
sync.ffs_db
Binary file not shown.
BIN
taranis_switches.png
Normal file
BIN
taranis_switches.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 75 KiB |
Loading…
x
Reference in New Issue
Block a user