diff --git a/AVR8_Burn-O-Mat_2_1_2_setup.exe b/AVR8_Burn-O-Mat_2_1_2_setup.exe new file mode 100644 index 0000000..5f9e431 Binary files /dev/null and b/AVR8_Burn-O-Mat_2_1_2_setup.exe differ diff --git a/Multiprotocol/A7105_joysway.ino b/Multiprotocol/A7105_joysway.ino new file mode 100644 index 0000000..1aed90d --- /dev/null +++ b/Multiprotocol/A7105_joysway.ino @@ -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 . + */ + +#if defined JOYSWAY_A7105_INO +#include "iface_a7105.h" + + +#define EVEN_ODD 0x00 +//#define EVEN_ODD 0x01 +static const uint8_t A7105_regs[] = { + 0x00, 0x62, -1, 0x0f, 0x00, -1 , -1 , 0x00, 0x00, 0x05, 0x00, 0x01, 0x00, 0xf5, 0x00, 0x15, + 0x9e, 0x4b, 0x00, 0x03, 0x56, 0x2b, 0x12, 0x4a, 0x02, 0x80, 0x80, 0x00, 0x0e, 0x91, 0x03, 0x0f, + 0x16, 0x2a, 0x00, -1, -1, -1, 0x3a, 0x06, 0x1f, 0x47, 0x80, 0x01, 0x05, 0x45, 0x18, 0x00, + 0x01, 0x0f, 0x00 +}; + +static uint8_t next_ch; + +static int joysway_init() +{ + int i; + uint8_t if_calibration1; + //uint8_t vco_calibration0; + //uint8_t vco_calibration1; + + phase = 0; + next_ch = 0x30; + + for (i = 0; i < 0x33; i++) + if((uint8_t)A7105_regs[i] != -1) + A7105_WriteReg(i, A7105_regs[i]); + A7105_WriteID(0x5475c52a); + + A7105_Strobe(A7105_PLL); + + //IF Filter Bank Calibration + A7105_WriteReg(0x02, 1); + A7105_ReadReg(0x02); + uint32_t ms = micros(); + while(micros() - ms < 500) { + if(! A7105_ReadReg(0x02)) + break; + } + if (micros() - ms >= 500) + return 0; + A7105_Strobe(A7105_STANDBY); + if_calibration1 = A7105_ReadReg(0x22); + if(if_calibration1 & A7105_MASK_FBCF) { + //Calibration failed...what do we do? + return 0; + } + + //VCO Current Calibration + A7105_WriteReg(0x24, 0x13); //Recomended calibration from A7105 Datasheet + A7105_WriteReg(0x25, 0x09); //Recomended calibration from A7105 Datasheet + + A7105_WriteID(MProtocol_id_master); + A7105_Strobe(A7105_PLL); + A7105_WriteReg(0x02, 1); + ms = micros(); + while(micros() - ms < 500) { + if(! A7105_ReadReg(0x02)) + break; + } + if (micros() - ms >= 500) + return 0; + A7105_Strobe(A7105_STANDBY); + if_calibration1 = A7105_ReadReg(0x22); + if(if_calibration1 & A7105_MASK_FBCF) { + //Calibration failed...what do we do? + return 0; + } + A7105_WriteReg(0x24, 0x13); //Recomended calibration from A7105 Datasheet + A7105_WriteReg(0x25, 0x09); //Recomended calibration from A7105 Datasheet + + A7105_SetTxRxMode(TX_EN); + A7105_SetPower(); + + A7105_Strobe(A7105_STANDBY); + return 1; +} + +static void joysway_build_packet() +{ + int i; + //-100% =~ 0x03e8 + //+100% =~ 0x07ca + //Calculate: + //Center = 0x5d9 + //1 % = 5 + packet[0] = phase == 0 ? 0xdd : 0xff; + packet[1] = (MProtocol_id_master >> 24) & 0xff; + packet[2] = (MProtocol_id_master >> 16) & 0xff; + packet[3] = (MProtocol_id_master >> 8) & 0xff; + packet[4] = (MProtocol_id_master >> 0) & 0xff; + packet[5] = 0x00; + static const int chmap[4] = {6, 7, 10, 11}; + for (i = 0; i < 4; i++) { +// if (i >= Model.num_channels) { packet[chmap[i]] = 0x64; continue; } + uint32_t value = (uint32_t)Servo_data[i] * 0x66 / PPM_MAX + 0x66; + if (value < 0) { value = 0; } + if (value > 0xff) { value = 0xff; } + packet[chmap[i]] = value; + } + packet[8] = 0x64; + packet[9] = 0x64; + packet[12] = 0x64; + packet[13] = 0x64; + packet[14] = phase == 0 ? 0x30 : 0xaa; + uint8_t value = 0; + for (int i = 0; i < 15; i++) { value += packet[i]; } + packet[15] = value; +} + +static uint16_t joysway_cb() +{ + uint8_t ch; + if (phase == 254) { + phase = 0; + A7105_WriteID(0x5475c52a); + ch = 0x0a; + } else if (phase == 2) { + A7105_WriteID(MProtocol_id_master); + ch = 0x30; + } else { + if ((phase & 0x01) ^ EVEN_ODD) { + ch = 0x30; + } else { + ch = next_ch; + } + } + if (! ((phase & 0x01) ^ EVEN_ODD)) { + next_ch++; + if (next_ch == 0x45) + next_ch = 0x30; + } + joysway_build_packet(); + A7105_Strobe(A7105_STANDBY); + A7105_WriteData(16, ch); + phase++; + return 6000; +} + +static uint16_t JOYSWAY_Setup() { + while(1) { + A7105_Reset(); + if (joysway_init()) + break; + } + return 2400; +} +#endif diff --git a/Multiprotocol/CX10_nrf24l01.ino b/Multiprotocol/CX10_nrf24l01.ino index f836e02..adc7279 100644 --- a/Multiprotocol/CX10_nrf24l01.ino +++ b/Multiprotocol/CX10_nrf24l01.ino @@ -25,6 +25,10 @@ #define Q282_PACKET_SIZE 21 #define CX10_PACKET_PERIOD 1316 // Timeout for callback in uSec #define CX10A_PACKET_PERIOD 6000 +<<<<<<< HEAD +#define CX10A_BIND_COUNT 400 // 2 seconds +======= +>>>>>>> refs/remotes/pascallanger/master #define CX10_INITIAL_WAIT 500 @@ -197,15 +201,30 @@ uint16_t CX10_callback() } break; case CX10_BIND2: +<<<<<<< HEAD + bind_counter--; + if(bind_counter==0) + { // Needed for some CX-10A to properly finish the bind + CX10_init(); + bind_counter=CX10A_BIND_COUNT; + } + if( NRF24L01_ReadReg(NRF24L01_07_STATUS) & BV(NRF24L01_07_RX_DR)) +======= if( NRF24L01_ReadReg(NRF24L01_07_STATUS) & _BV(NRF24L01_07_RX_DR)) +>>>>>>> refs/remotes/pascallanger/master { // RX fifo data ready XN297_ReadPayload(packet, packet_length); NRF24L01_SetTxRxMode(TXRX_OFF); NRF24L01_SetTxRxMode(TX_EN); if(packet[9] == 1) { +<<<<<<< HEAD + phase = CX10_BIND1; + bind_counter=0; +======= BIND_DONE; phase = CX10_DATA; +>>>>>>> refs/remotes/pascallanger/master } } else @@ -215,7 +234,11 @@ uint16_t CX10_callback() NRF24L01_FlushTx(); NRF24L01_SetTxRxMode(TX_EN); CX10_Write_Packet(1); +<<<<<<< HEAD + delayMicroseconds(400); // 300µs in deviation but not working so using 400µs instead +======= delayMicroseconds(400); +>>>>>>> refs/remotes/pascallanger/master // switch to RX mode NRF24L01_SetTxRxMode(TXRX_OFF); NRF24L01_FlushRx(); @@ -265,6 +288,10 @@ uint16_t initCX10(void) packet_period = CX10A_PACKET_PERIOD; phase = CX10_BIND2; +<<<<<<< HEAD + bind_counter=CX10A_BIND_COUNT; +======= +>>>>>>> refs/remotes/pascallanger/master for(uint8_t i=0; i<4; i++) packet[5+i] = 0xff; // clear aircraft id diff --git a/Multiprotocol/CYRF6936_SPI.ino b/Multiprotocol/CYRF6936_SPI.ino index 2b2d52a..6a3bae6 100644 --- a/Multiprotocol/CYRF6936_SPI.ino +++ b/Multiprotocol/CYRF6936_SPI.ino @@ -192,11 +192,18 @@ static void CYRF_StartReceive() CYRF_ReadRegisterMulti(CYRF_21_RX_BUFFER, dpbuffer, 0x10); } */ +<<<<<<< HEAD +static void CYRF_ReadDataPacketLen(uint8_t dpbuffer[], uint8_t length) +======= void CYRF_ReadDataPacketLen(uint8_t dpbuffer[], uint8_t length) +>>>>>>> refs/remotes/pascallanger/master { CYRF_ReadRegisterMulti(CYRF_21_RX_BUFFER, dpbuffer, length); } +<<<<<<< HEAD +======= +>>>>>>> refs/remotes/pascallanger/master static void CYRF_WriteDataPacketLen(const uint8_t dpbuffer[], uint8_t len) { CYRF_WriteRegister(CYRF_01_TX_LENGTH, len); diff --git a/Multiprotocol/CYRF6936_j6pro.ino b/Multiprotocol/CYRF6936_j6pro.ino new file mode 100644 index 0000000..623ae5f --- /dev/null +++ b/Multiprotocol/CYRF6936_j6pro.ino @@ -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 . + */ + +#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 diff --git a/Multiprotocol/Cc2500_skyartec.ino b/Multiprotocol/Cc2500_skyartec.ino new file mode 100644 index 0000000..7f3a932 --- /dev/null +++ b/Multiprotocol/Cc2500_skyartec.ino @@ -0,0 +1,183 @@ +/* + This project is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Deviation is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Deviation. If not, see . + */ + +#if defined(SKYARTEC_CC2500_INO) +#include "iface_cc2500.h" + +#define TX_ADDR ((binding_idx >> 16) & 0xff) +#define TX_CHANNEL ((binding_idx >> 24) & 0xff) + +enum { + SKYARTEC_PKT1 = 0, + SKYARTEC_SLEEP1, + SKYARTEC_PKT2, + SKYARTEC_SLEEP2, + SKYARTEC_PKT3, + SKYARTEC_SLEEP3, + SKYARTEC_PKT4, + SKYARTEC_SLEEP4, + SKYARTEC_PKT5, + SKYARTEC_SLEEP5, + SKYARTEC_PKT6, + SKYARTEC_LAST, +}; + +static void skyartec_init() { + CC2500_Reset(); + + cc2500_writeReg(CC2500_16_MCSM2, 0x07); + cc2500_writeReg(CC2500_17_MCSM1, 0x30); + cc2500_writeReg(CC2500_1E_WOREVT1, 0x87); + cc2500_writeReg(CC2500_1F_WOREVT0, 0x6b); + cc2500_writeReg(CC2500_20_WORCTRL, 0xf8); + cc2500_writeReg(CC2500_2A_PTEST, 0x7f); + cc2500_writeReg(CC2500_2B_AGCTEST, 0x3f); + cc2500_writeReg(CC2500_0B_FSCTRL1, 0x09); + cc2500_writeReg(CC2500_0C_FSCTRL0, 0x00); + cc2500_writeReg(CC2500_0D_FREQ2, 0x5d); + cc2500_writeReg(CC2500_0E_FREQ1, 0x93); + cc2500_writeReg(CC2500_0F_FREQ0, 0xb1); + cc2500_writeReg(CC2500_10_MDMCFG4, 0x2d); + cc2500_writeReg(CC2500_11_MDMCFG3, 0x20); + cc2500_writeReg(CC2500_12_MDMCFG2, 0x73); + cc2500_writeReg(CC2500_13_MDMCFG1, 0x22); + cc2500_writeReg(CC2500_14_MDMCFG0, 0xf8); + cc2500_writeReg(CC2500_0A_CHANNR, 0xcd); + cc2500_writeReg(CC2500_15_DEVIATN, 0x50); + cc2500_writeReg(CC2500_21_FREND1, 0xb6); + cc2500_writeReg(CC2500_22_FREND0, 0x10); + cc2500_writeReg(CC2500_18_MCSM0, 0x18); + cc2500_writeReg(CC2500_19_FOCCFG, 0x1d); + cc2500_writeReg(CC2500_1A_BSCFG, 0x1c); + cc2500_writeReg(CC2500_1B_AGCCTRL2, 0xc7); + cc2500_writeReg(CC2500_1C_AGCCTRL1, 0x00); + cc2500_writeReg(CC2500_1D_AGCCTRL0, 0xb2); + cc2500_writeReg(CC2500_23_FSCAL3, 0xea); + cc2500_writeReg(CC2500_24_FSCAL2, 0x0a); + cc2500_writeReg(CC2500_25_FSCAL1, 0x00); + cc2500_writeReg(CC2500_26_FSCAL0, 0x11); + cc2500_writeReg(CC2500_29_FSTEST, 0x59); + cc2500_writeReg(CC2500_2C_TEST2, 0x88); + cc2500_writeReg(CC2500_2D_TEST1, 0x31); + cc2500_writeReg(CC2500_2E_TEST0, 0x0b); + cc2500_writeReg(CC2500_07_PKTCTRL1, 0x05); + cc2500_writeReg(CC2500_08_PKTCTRL0, 0x05); + cc2500_writeReg(CC2500_09_ADDR, 0x43); + cc2500_writeReg(CC2500_06_PKTLEN, 0xff); + cc2500_writeReg(CC2500_04_SYNC1, 0x13); + cc2500_writeReg(CC2500_05_SYNC0, 0x18); + CC2500_SetTxRxMode(TX_EN); + CC2500_SetPower(); + cc2500_strobe(CC2500_SFTX); + cc2500_strobe(CC2500_SFRX); + cc2500_strobe(CC2500_SXOFF); + cc2500_strobe(CC2500_SIDLE); +} + +static void add_pkt_suffix() { + int xor1 = 0; + int xor2 = 0; + for(int i = 3; i <= 16; i++) { xor1 ^= packet[i]; } + for(int i = 3; i <= 14; i++) { xor2 ^= packet[i]; } + + int sum = packet[3] + packet[5] + packet[7] + packet[9] + packet[11] + packet[13]; + packet[17] = xor1; + packet[18] = xor2; + packet[19] = sum & 0xff; +} + +static void send_data_packet() { + //13 c5 01 0259 0168 0000 0259 030c 021a 0489 f3 7e 0a + packet[0] = 0x13; //Length + packet[1] = TX_ADDR; //Tx Addr? + packet[2] = 0x01; //??? + for(int i = 0; i < 7; i++) { + uint32_t value = (uint32_t)Servo_data[i] * 0x280 / PPM_MAX + 0x280; + if(value < 0) { value = 0; } + if(value > 0x500) { value = 0x500; } + packet[3+2*i] = value >> 8; + packet[4+2*i] = value & 0xff; + } + add_pkt_suffix(); + //for(int i = 0; i < 20; i++) printf("%02x ", packet[i]); printf("\n"); + cc2500_writeReg(CC2500_04_SYNC1, ((binding_idx >> 0) & 0xff)); + cc2500_writeReg(CC2500_05_SYNC0, ((binding_idx >> 8) & 0xff)); + cc2500_writeReg(CC2500_09_ADDR, TX_ADDR); + cc2500_writeReg(CC2500_0A_CHANNR, TX_CHANNEL); + cc2500_writeFifo(packet, 20); +} + +static void send_bind_packet() { + //0b 7d 01 01 b2 c5 4a 2f 00 00 c5 d6 + packet[0] = 0x0b; //Length + packet[1] = 0x7d; + packet[2] = 0x01; + packet[3] = 0x01; + packet[4] = (binding_idx >> 24) & 0xff; + packet[5] = (binding_idx >> 16) & 0xff; + packet[6] = (binding_idx >> 8) & 0xff; + packet[7] = (binding_idx >> 0) & 0xff; + packet[8] = 0x00; + packet[9] = 0x00; + packet[10] = TX_ADDR; + uint8_t xore = 0; + for(int i = 3; i < 11; i++) { xore ^= packet[i]; } + packet[11] = xore; + cc2500_writeReg(CC2500_04_SYNC1, 0x7d); + cc2500_writeReg(CC2500_05_SYNC0, 0x7d); + cc2500_writeReg(CC2500_09_ADDR, 0x7d); + cc2500_writeReg(CC2500_0A_CHANNR, 0x7d); + cc2500_writeFifo(packet, 12); +} + +static uint16_t skyartec_cb() { + if (state & 0x01) { + cc2500_strobe(CC2500_SIDLE); + if (state == SKYARTEC_LAST) { CC2500_SetPower(); state = SKYARTEC_PKT1; } + else { state++; } + return 3000; + } + if (state == SKYARTEC_PKT1 && bind_phase) { + send_bind_packet(); + bind_phase--; + if(bind_phase == 0) { printf("Done binding\n"); } + } else { send_data_packet(); } + state++; + return 3000; +} + +static uint8_t skyartec_setup() { + skyartec_init(); +/* binding_idx = 0xb2c54a2f; + if (Model.fixed_id) { + binding_idx ^= Model.binding_idx + (Model.fixed_id << 16); + } else { + int partnum = CC2500_ReadReg(0xF0); + int vernum = CC2500_ReadReg(0xF1); + binding_idx ^= partnum << 24; + binding_idx ^= vernum << 16; + binding_idx ^= (vernum << 4 | partnum >> 4) << 8; + binding_idx ^= (partnum << 4 | vernum >> 4) << 8; + } +*/ + binding_idx = MProtocol_id; + if (0 == (binding_idx & 0xff000000)) { binding_idx |= 0xb2; } + if (0 == (binding_idx & 0x00ff0000)) { binding_idx |= 0xc5; } + if (0 == (binding_idx & 0x0000ff00)) { binding_idx |= 0x4a; } + if (0 == (binding_idx & 0x000000ff)) { binding_idx |= 0x2f; } + bind_phase = 10000; + state = SKYARTEC_PKT1; +} +#endif \ No newline at end of file diff --git a/Multiprotocol/Cyrf6936_wk2x01.ino b/Multiprotocol/Cyrf6936_wk2x01.ino new file mode 100644 index 0000000..58e866a --- /dev/null +++ b/Multiprotocol/Cyrf6936_wk2x01.ino @@ -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 . + */ +#if defined(WK2x01_CYRF6936_INO) +#include "iface_cyrf6936.h" + +#define PKTS_PER_CHANNEL 4 + +//Fewer bind packets in the emulator so we can get right to the important bits +#define WK_BIND_COUNT 2980 + +#define NUM_WAIT_LOOPS (100 / 5) //each loop is ~5us. Do not wait more than 100us + + +#define WK_BIND 0 +#define WK_BOUND_1 1 +#define WK_BOUND_2 2 +#define WK_BOUND_3 3 +#define WK_BOUND_4 4 +#define WK_BOUND_5 5 +#define WK_BOUND_6 6 +#define WK_BOUND_7 7 +#define WK_BOUND_8 8 + +static const uint8_t sopcode[8] = { + /* Note these are in order transmitted (LSB 1st) */ + 0xDF,0xB1,0xC0,0x49,0x62,0xDF,0xC1,0x49 //0x49C1DF6249C0B1DF +}; +static const uint8_t fail_map[8] = {2, 1, 0, 3, 4, 5, 6, 7}; + +static uint8_t wk_pkt_num; +static uint8_t *radio_ch_ptr; +static uint16_t WK_BIND_COUNTer; +static uint8_t last_beacon; +/* +static const char * const wk2601_opts[] = { + _tr_noop("Chan mode"), _tr_noop("5+1"), _tr_noop("Heli"), _tr_noop("6+1"), NULL, + _tr_noop("COL Inv"), _tr_noop("Normal"), _tr_noop("Inverted"), NULL, + _tr_noop("COL Limit"), "-100", "100", NULL, + NULL +}; +#define WK2601_OPT_CHANMODE 0 +#define WK2601_OPT_PIT_INV 1 +#define WK2601_OPT_PIT_LIMIT 2 +#define LAST_PROTO_OPT 3 +*/ + +static void add_pkt_crc(uint8_t init) { + uint8_t add = init; + uint8_t xou = init; + int i; + for (i = 0; i < 14; i++) { add += packet[i]; xou ^= packet[i]; } + packet[14] = xou; + packet[15] = add & 0xff; +} +static const char init_2801[] = {0xc5, 0x34, 0x60, 0x00, 0x25}; +static const char init_2601[] = {0xb9, 0x45, 0xb0, 0xf1, 0x3a}; +static const char init_2401[] = {0xa5, 0x23, 0xd0, 0xf0, 0x00}; +static void build_bind_pkt(const char *init) { + packet[0] = init[0]; + packet[1] = init[1]; + packet[2] = rx_tx_addr[0]; + packet[3] = rx_tx_addr[1]; + packet[4] = init[2]; + packet[5] = rx_tx_addr[2]; + packet[6] = 0xff; + packet[7] = 0x00; + packet[8] = 0x00; + packet[9] = 0x32; + if (sub_protocol == WK2401) { packet[10] = 0x10 | ((fixed_id >> 0) & 0x0e); } + else { packet[10] = (fixed_id >> 0) & 0xff; } + packet[11] = (fixed_id >> 8) & 0xff; + packet[12] = ((fixed_id >> 12) & 0xf0) | wk_pkt_num; + packet[13] = init[3]; + add_pkt_crc(init[4]); +} + +static uint16_t get_channel(uint8_t ch, uint32_t scale, uint32_t center, uint32_t range) { + uint32_t value = (uint32_t)Servo_data[ch] * scale / PPM_MAX + center; + if (value < center - range) { value = center - range; } + if (value > center + range) { value = center + range; } + return value; +} + +static void build_data_pkt_2401() { + uint8_t i; + uint16_t msb = 0; + uint8_t offset = 0; + for (i = 0; i < 4; i++) { + if (i == 2) { offset = 1; } + uint16_t value = get_channel(i, 0x800, 0, 0xA00); //12 bits, allow value to go to 125% + uint16_t base = abs(value) >> 2; //10 bits is the base value + uint16_t trim = abs(value) & 0x03; //lowest 2 bits represent trim + if (base >= 0x200) { //if value is > 100%, remainder goes to trim + trim = 4 *(base - 0x200); + base = 0x1ff; + } + base = (value >= 0) ? 0x200 + base : 0x200 - base; + trim = (value >= 0) ? 0x200 + trim : 0x200 - trim; + + packet[2*i+offset] = base & 0xff; + packet[2*i+offset+1] = trim & 0xff; + msb = (msb << 4) | ((base >> 6) & 0x0c) | ((trim >> 8) & 0x03); + } + packet[4] = msb >> 8; //Ele/Ail MSB + packet[9] = msb & 0xff; //Thr/Rud MSB + packet[10] = 0xe0 | ((fixed_id >> 0) & 0x0e); + packet[11] = (fixed_id >> 8) & 0xff; + packet[12] = ((fixed_id >> 12) & 0xf0) | wk_pkt_num; + packet[13] = 0xf0; //FIXME - What is this? + add_pkt_crc(0x00); +} + +#define PCT(pct, max) (((max) * (pct) + 1L) / 1000) +#define MAXTHR 426 //Measured to provide equal value at +/-0 +static void channels_6plus1_2601(int frame, int *_v1, int *_v2) { + uint16_t thr = get_channel(2, 1000, 0, 1000); + int v1; + int thr_rev = 0, pitch_rev = 0; + if(thr > 0) { + if(thr >= 780) { //78% + v1 = 0; //thr = 60% * (x - 78%) / 22% + 40% + thr = PCT(1000-MAXTHR,512) * (thr-PCT(780,1000)) / PCT(220,1000) + PCT(MAXTHR,512); + } else { + v1 = 1023 - 1023 * thr / 780; + thr = PCT(MAXTHR, 512); //40% + } + } + else { + thr = -thr; + thr_rev = 1; + if(thr >= 780) { //78% + v1 = 1023; //thr = 60% * (x - 78%) / 22% + 40% + thr = PCT(1000-MAXTHR,512) * (thr-PCT(780,1000)) / PCT(220,1000) + PCT(MAXTHR,512); + if (thr >= 512) { thr = 511; } + } + else { + v1 = 1023 * thr / 780; + thr = PCT(MAXTHR, 512); //40% + } + } + if (thr >= 512) { thr = 511; } + packet[2] = thr & 0xff; + packet[4] = (packet[4] & 0xF3) | ((thr >> 6) & 0x04); + + uint16_t pitch= get_channel(5, 0x400, 0, 0x400); + if (pitch < 0) { + pitch_rev = 1; + pitch = -pitch; + } + if (frame == 1) { + //Pitch curve and range + if (thr > PCT(MAXTHR, 512)) { *_v2 = pitch - pitch * 16 * (thr - PCT(MAXTHR, 512)) / PCT(1000 - MAXTHR, 512) / 100; } + else { *_v2 = pitch; } + *_v1 = 0; + } + else if (frame == 2) { + //Throttle curve & Expo + *_v1 = v1; + *_v2 = 512; + } + packet[7] = (thr_rev << 5) | (pitch_rev << 2); //reverse bits + packet[8] = 0; +} + +static void channels_5plus1_2601(int frame, int *v1, int *v2) { + (void)v1; + //Zero out pitch, provide ail, ele, thr, rud, gyr + gear + if (frame == 1) { *v2 = 0; } //Pitch curve and range + packet[7] = 0; + packet[8] = 0; +} +static void channels_heli_2601(int frame, int *v1, int *v2) { + (void)frame; + //pitch is controlled by rx + //we can only control fmode, pit-reverse and pit/thr rate + int pit_rev = 0; + if ((option/10)%10) { pit_rev = 1; } + uint16_t pit_rate = get_channel(5, 0x400, 0, 0x400); + int fmode = 1; + if (pit_rate < 0) { pit_rate = -pit_rate; fmode = 0; } + if (frame == 1) { + //Pitch curve and range + *v1 = pit_rate; + *v2 = ((option/100) ? -100 : 100) * 0x400 / 100 + 0x400; + } + packet[7] = (pit_rev << 2); //reverse bits + packet[8] = fmode ? 0x02 : 0x00; +} + +static void build_data_pkt_2601() { + uint8_t i; + uint8_t msb = 0; + uint8_t frame = (wk_pkt_num % 3); + for (i = 0; i < 4; i++) { + uint16_t value = get_channel(i, 0x190, 0, 0x1FF); + uint16_t mag = value < 0 ? -value : value; + packet[i] = mag & 0xff; + msb = (msb << 2) | ((mag >> 8) & 0x01) | (value < 0 ? 0x02 : 0x00); + } + packet[4] = msb; + int v1 = 0x200, v2 = 0x200; + if (frame == 0) { + //Gyro & Rudder mix + v1 = get_channel(6, 0x200, 0x200, 0x200); + v2 = 0; + } + if (option%10 == 1) { channels_heli_2601(frame, &v1, &v2); } + else if (option%10 == 2) { channels_6plus1_2601(frame, &v1, &v2); } + else { channels_5plus1_2601(frame, &v1, &v2); } + if (v1 > 1023) { v1 = 1023; } + if (v2 > 1023) { v2 = 1023; } + packet[5] = v2 & 0xff; + packet[6] = v1 & 0xff; + //packet[7] handled by channel code + packet[8] |= (get_channel(4, 0x190, 0, 0x1FF) > 0 ? 1 : 0); + packet[9] = ((v1 >> 4) & 0x30) | ((v2 >> 2) & 0xc0) | 0x04 | frame; + packet[10] = (fixed_id >> 0) & 0xff; + packet[11] = (fixed_id >> 8) & 0xff; + packet[12] = ((fixed_id >> 12) & 0xf0) | wk_pkt_num; + packet[13] = 0xff; + + add_pkt_crc(0x3A); +} + +static void build_data_pkt_2801() { + uint8_t i; + uint16_t msb = 0; + uint8_t offset = 0; + uint8_t sign = 0; + for (i = 0; i < 8; i++) { + if (i == 4) { offset = 1; } + uint16_t value = get_channel(i, 0x190, 0, 0x3FF); + uint16_t mag = value < 0 ? -value : value; + packet[i+offset] = mag & 0xff; + msb = (msb << 2) | ((mag >> 8) & 0x03); + if (value < 0) { sign |= 1 << i; } + } + packet[4] = msb >> 8; + packet[9] = msb & 0xff; + packet[10] = (fixed_id >> 0) & 0xff; + packet[11] = (fixed_id >> 8) & 0xff; + packet[12] = ((fixed_id >> 12) & 0xf0) | wk_pkt_num; + packet[13] = sign; + add_pkt_crc(0x25); +} + +static void build_beacon_pkt_2801() { + last_beacon ^= 1; + uint8_t i; + uint8_t en = 0; + uint8_t bind_state; + if (WK_BIND_COUNTer) { bind_state = 0xe4; } + else { bind_state = 0x1b; } + for (i = 0; i < 4; i++) { +/* if (Model.limits[fail_map[i + last_beacon * 4]].flags & CH_FAILSAFE_EN) { + uint32_t value = Model.limits[fail_map[i + last_beacon * 4]].failsafe + 128; + if (value > 255) { value = 255; } + if (value < 0) { value = 0; } + packet[i+1] = value; + en |= 1 << i; + } else +*/ { packet[i+1] = 0; } + } + packet[0] = en; + packet[5] = packet[4]; + packet[4] = last_beacon << 6; + packet[6] = rx_tx_addr[0]; + packet[7] = rx_tx_addr[1]; + packet[8] = rx_tx_addr[2]; + packet[9] = bind_state; + packet[10] = (fixed_id >> 0) & 0xff; + packet[11] = (fixed_id >> 8) & 0xff; + packet[12] = ((fixed_id >> 12) & 0xf0) | wk_pkt_num; + packet[13] = 0x00; //Does this matter? in the docs it is the same as the data packet + add_pkt_crc(0x1C); +} + +static void wk2x01_cyrf_init() { + /* Initialise CYRF chip */ + CYRF_WriteRegister(CYRF_03_TX_CFG, 0x28 | CYRF_HIGH_POWER); + CYRF_WriteRegister(CYRF_06_RX_CFG, 0x4A); + CYRF_WriteRegister(CYRF_0B_PWR_CTRL, 0x00); + CYRF_WriteRegister(CYRF_0C_XTAL_CTRL, 0xC0); + CYRF_WriteRegister(CYRF_0D_IO_CFG, 0x04); + CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x2C); + CYRF_WriteRegister(CYRF_10_FRAMING_CFG, 0xEE); + CYRF_WriteRegister(CYRF_1B_TX_OFFSET_LSB, 0x55); + CYRF_WriteRegister(CYRF_1C_TX_OFFSET_MSB, 0x05); + CYRF_WriteRegister(CYRF_1D_MODE_OVERRIDE, 0x18); + CYRF_WriteRegister(CYRF_32_AUTO_CAL_TIME, 0x3C); + CYRF_WriteRegister(CYRF_35_AUTOCAL_OFFSET, 0x14); + CYRF_WriteRegister(CYRF_1E_RX_OVERRIDE, 0x90); + CYRF_WriteRegister(CYRF_1F_TX_OVERRIDE, 0x00); + CYRF_WriteRegister(CYRF_01_TX_LENGTH, 0x10); + CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x2C); + CYRF_WriteRegister(CYRF_28_CLK_EN, 0x02); + CYRF_WriteRegister(CYRF_27_CLK_OVERRIDE, 0x02); + CYRF_ConfigSOPCode(sopcode); + CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x28); + CYRF_WriteRegister(CYRF_1E_RX_OVERRIDE, 0x10); + CYRF_WriteRegister(CYRF_0E_GPIO_CTRL, 0x20); + CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x2C); +} + +void WK_BuildPacket_2801() { + switch(phase) { + case WK_BIND: + build_bind_pkt(init_2801); +// if ((--WK_BIND_COUNTer == 0) || PROTOCOL_SticksMoved(0)) { + if ((--WK_BIND_COUNTer == 0)) { + WK_BIND_COUNTer = 0; + BIND_DONE; + phase = WK_BOUND_1; + } + break; + case WK_BOUND_1: + case WK_BOUND_2: + case WK_BOUND_3: + case WK_BOUND_4: + case WK_BOUND_5: + case WK_BOUND_6: + case WK_BOUND_7: + build_data_pkt_2801(); + phase++; + break; + case WK_BOUND_8: + build_beacon_pkt_2801(); + phase = WK_BOUND_1; + if (WK_BIND_COUNTer) { + WK_BIND_COUNTer--; + if (WK_BIND_COUNTer == 0) { BIND_DONE; } + } + break; + } + wk_pkt_num = (wk_pkt_num + 1) % 12; +} + +void WK_BuildPacket_2601() { + if (WK_BIND_COUNTer) { + WK_BIND_COUNTer--; + build_bind_pkt(init_2601); + if ((WK_BIND_COUNTer == 0)) { + WK_BIND_COUNTer = 0; + BIND_DONE; + } + } + else { build_data_pkt_2601(); } + wk_pkt_num = (wk_pkt_num + 1) % 12; +} + +void WK_BuildPacket_2401() { + if (WK_BIND_COUNTer) { + WK_BIND_COUNTer--; + build_bind_pkt(init_2401); + if ((WK_BIND_COUNTer == 0)) { + WK_BIND_COUNTer = 0; + BIND_DONE; + } + } + else { build_data_pkt_2401(); } + wk_pkt_num = (wk_pkt_num + 1) % 12; +} + +static uint16_t wk_cb() { + if (packet_sent == 0) { + packet_sent = 1; + if(sub_protocol == WK2801) { WK_BuildPacket_2801(); } + else if(sub_protocol == WK2601) { WK_BuildPacket_2601(); } + else if(sub_protocol == WK2401) { WK_BuildPacket_2401(); } + CYRF_WriteDataPacket(packet); + return 1600; + } + packet_sent = 0; + int i = 0; + while (! (CYRF_ReadRegister(0x04) & 0x02)) { if(++i > NUM_WAIT_LOOPS) { break; } } + if((wk_pkt_num & 0x03) == 0) { + radio_ch_ptr = radio_ch_ptr == &rx_tx_addr[2] ? rx_tx_addr : radio_ch_ptr + 1; + CYRF_ConfigRFChannel(*radio_ch_ptr); + //Keep transmit power updated + CYRF_WriteRegister(CYRF_03_TX_CFG, 0x28 | CYRF_HIGH_POWER); + } + return 1200; +} + +static void wk_bind() { + if((sub_protocol != WK2801)) { return; } + fixed_id = ((MProtocol_id_master << 2) & 0x0ffc00) | ((MProtocol_id_master >> 10) & 0x000300) | ((MProtocol_id_master) & 0x0000ff); + WK_BIND_COUNTer = WK_BIND_COUNT / 8 + 1; + BIND_IN_PROGRESS; +} + +static uint16_t wk_setup() { + CYRF_Reset(); + wk2x01_cyrf_init(); + CYRF_SetTxRxMode(TX_EN); + CYRF_FindBestChannels(rx_tx_addr, 3, 4, 4, 80); + + radio_ch_ptr = rx_tx_addr; + CYRF_ConfigRFChannel(*radio_ch_ptr); + + wk_pkt_num = 0; + packet_sent = 0; + last_beacon = 0; + fixed_id = ((MProtocol_id_master << 2) & 0x0ffc00) | ((MProtocol_id_master >> 10) & 0x000300) | ((MProtocol_id_master) & 0x0000ff); + if (sub_protocol == WK2401) { fixed_id |= 0x01; } //Fixed ID must be odd for 2401 + if(sub_protocol != WK2801) { + WK_BIND_COUNTer = WK_BIND_COUNT; + phase = WK_BIND; + BIND_IN_PROGRESS; + } + else { + phase = WK_BOUND_1; + WK_BIND_COUNTer = 0; + } + CYRF_ConfigRFChannel(*radio_ch_ptr); + return 2800; +} +/* +const void *WK2x01_Cmds(enum ProtoCmds cmd) { + switch(cmd) { + case PROTOCMD_INIT: initialize(); return 0; + case PROTOCMD_DEINIT: return 0; + case PROTOCMD_CHECK_AUTOBIND: + return (Model.protocol == WK2801 && Model.fixed_id) ? 0 : (void *)1L; + case PROTOCMD_BIND: wk_bind(); return 0; + case PROTOCMD_DEFAULT_NUMCHAN: return (Model.protocol == WK2801) + ? (void *)8L + : (Model.protocol == WK2601) + ? (void *)6L + : (void *)4L; + case PROTOCMD_NUMCHAN: return (Model.protocol == WK2801) + ? (void *)8L + : (Model.protocol == WK2601) + ? (void *)7L + : (void *)4L; + case PROTOCMD_GETOPTIONS: + if(Model.protocol == WK2601) + return wk2601_opts; + break; + case PROTOCMD_TELEMETRYSTATE: return (void *)(long)PROTO_TELEM_UNSUPPORTED; + default: break; + } + return 0; +} +*/ +#endif diff --git a/Multiprotocol/DSM2_cyrf6936.ino b/Multiprotocol/DSM2_cyrf6936.ino new file mode 100644 index 0000000..19a969e --- /dev/null +++ b/Multiprotocol/DSM2_cyrf6936.ino @@ -0,0 +1,538 @@ +/* + This project is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Multiprotocol is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Multiprotocol. If not, see . + */ + +#if defined(DSM2_CYRF6936_INO) + +#include "iface_cyrf6936.h" + +#define RANDOM_CHANNELS 0 // disabled +//#define RANDOM_CHANNELS 1 // enabled +#define BIND_CHANNEL 0x0d //13 This can be any odd channel +#define NUM_WAIT_LOOPS (100 / 5) //each loop is ~5us. Do not wait more than 100us + +//During binding we will send BIND_COUNT/2 packets +//One packet each 10msec +#define BIND_COUNT1 600 + +enum { + DSM2_BIND = 0, + DSM2_CHANSEL = BIND_COUNT1 + 0, + DSM2_CH1_WRITE_A = BIND_COUNT1 + 1, + DSM2_CH1_CHECK_A = BIND_COUNT1 + 2, + DSM2_CH2_WRITE_A = BIND_COUNT1 + 3, + DSM2_CH2_CHECK_A = BIND_COUNT1 + 4, + DSM2_CH2_READ_A = BIND_COUNT1 + 5, + DSM2_CH1_WRITE_B = BIND_COUNT1 + 6, + DSM2_CH1_CHECK_B = BIND_COUNT1 + 7, + DSM2_CH2_WRITE_B = BIND_COUNT1 + 8, + DSM2_CH2_CHECK_B = BIND_COUNT1 + 9, + DSM2_CH2_READ_B = BIND_COUNT1 + 10, +}; + +const uint8_t PROGMEM pncodes[5][9][8] = { + /* Note these are in order transmitted (LSB 1st) */ + { /* Row 0 */ + /* Col 0 */ {0x03, 0xBC, 0x6E, 0x8A, 0xEF, 0xBD, 0xFE, 0xF8}, + /* Col 1 */ {0x88, 0x17, 0x13, 0x3B, 0x2D, 0xBF, 0x06, 0xD6}, + /* Col 2 */ {0xF1, 0x94, 0x30, 0x21, 0xA1, 0x1C, 0x88, 0xA9}, + /* Col 3 */ {0xD0, 0xD2, 0x8E, 0xBC, 0x82, 0x2F, 0xE3, 0xB4}, + /* Col 4 */ {0x8C, 0xFA, 0x47, 0x9B, 0x83, 0xA5, 0x66, 0xD0}, + /* Col 5 */ {0x07, 0xBD, 0x9F, 0x26, 0xC8, 0x31, 0x0F, 0xB8}, + /* Col 6 */ {0xEF, 0x03, 0x95, 0x89, 0xB4, 0x71, 0x61, 0x9D}, + /* Col 7 */ {0x40, 0xBA, 0x97, 0xD5, 0x86, 0x4F, 0xCC, 0xD1}, + /* Col 8 */ {0xD7, 0xA1, 0x54, 0xB1, 0x5E, 0x89, 0xAE, 0x86} + }, + { /* Row 1 */ + /* Col 0 */ {0x83, 0xF7, 0xA8, 0x2D, 0x7A, 0x44, 0x64, 0xD3}, + /* Col 1 */ {0x3F, 0x2C, 0x4E, 0xAA, 0x71, 0x48, 0x7A, 0xC9}, + /* Col 2 */ {0x17, 0xFF, 0x9E, 0x21, 0x36, 0x90, 0xC7, 0x82}, + /* Col 3 */ {0xBC, 0x5D, 0x9A, 0x5B, 0xEE, 0x7F, 0x42, 0xEB}, + /* Col 4 */ {0x24, 0xF5, 0xDD, 0xF8, 0x7A, 0x77, 0x74, 0xE7}, + /* Col 5 */ {0x3D, 0x70, 0x7C, 0x94, 0xDC, 0x84, 0xAD, 0x95}, + /* Col 6 */ {0x1E, 0x6A, 0xF0, 0x37, 0x52, 0x7B, 0x11, 0xD4}, + /* Col 7 */ {0x62, 0xF5, 0x2B, 0xAA, 0xFC, 0x33, 0xBF, 0xAF}, + /* Col 8 */ {0x40, 0x56, 0x32, 0xD9, 0x0F, 0xD9, 0x5D, 0x97} + }, + { /* Row 2 */ + /* Col 0 */ {0x40, 0x56, 0x32, 0xD9, 0x0F, 0xD9, 0x5D, 0x97}, + /* Col 1 */ {0x8E, 0x4A, 0xD0, 0xA9, 0xA7, 0xFF, 0x20, 0xCA}, + /* Col 2 */ {0x4C, 0x97, 0x9D, 0xBF, 0xB8, 0x3D, 0xB5, 0xBE}, + /* Col 3 */ {0x0C, 0x5D, 0x24, 0x30, 0x9F, 0xCA, 0x6D, 0xBD}, + /* Col 4 */ {0x50, 0x14, 0x33, 0xDE, 0xF1, 0x78, 0x95, 0xAD}, + /* Col 5 */ {0x0C, 0x3C, 0xFA, 0xF9, 0xF0, 0xF2, 0x10, 0xC9}, + /* Col 6 */ {0xF4, 0xDA, 0x06, 0xDB, 0xBF, 0x4E, 0x6F, 0xB3}, + /* Col 7 */ {0x9E, 0x08, 0xD1, 0xAE, 0x59, 0x5E, 0xE8, 0xF0}, + /* Col 8 */ {0xC0, 0x90, 0x8F, 0xBB, 0x7C, 0x8E, 0x2B, 0x8E} + }, + { /* Row 3 */ + /* Col 0 */ {0xC0, 0x90, 0x8F, 0xBB, 0x7C, 0x8E, 0x2B, 0x8E}, + /* Col 1 */ {0x80, 0x69, 0x26, 0x80, 0x08, 0xF8, 0x49, 0xE7}, + /* Col 2 */ {0x7D, 0x2D, 0x49, 0x54, 0xD0, 0x80, 0x40, 0xC1}, + /* Col 3 */ {0xB6, 0xF2, 0xE6, 0x1B, 0x80, 0x5A, 0x36, 0xB4}, + /* Col 4 */ {0x42, 0xAE, 0x9C, 0x1C, 0xDA, 0x67, 0x05, 0xF6}, + /* Col 5 */ {0x9B, 0x75, 0xF7, 0xE0, 0x14, 0x8D, 0xB5, 0x80}, + /* Col 6 */ {0xBF, 0x54, 0x98, 0xB9, 0xB7, 0x30, 0x5A, 0x88}, + /* Col 7 */ {0x35, 0xD1, 0xFC, 0x97, 0x23, 0xD4, 0xC9, 0x88}, + /* Col 8 */ {0x88, 0xE1, 0xD6, 0x31, 0x26, 0x5F, 0xBD, 0x40} + }, + { /* Row 4 */ + /* Col 0 */ {0xE1, 0xD6, 0x31, 0x26, 0x5F, 0xBD, 0x40, 0x93}, + /* Col 1 */ {0xDC, 0x68, 0x08, 0x99, 0x97, 0xAE, 0xAF, 0x8C}, + /* Col 2 */ {0xC3, 0x0E, 0x01, 0x16, 0x0E, 0x32, 0x06, 0xBA}, + /* Col 3 */ {0xE0, 0x83, 0x01, 0xFA, 0xAB, 0x3E, 0x8F, 0xAC}, + /* Col 4 */ {0x5C, 0xD5, 0x9C, 0xB8, 0x46, 0x9C, 0x7D, 0x84}, + /* Col 5 */ {0xF1, 0xC6, 0xFE, 0x5C, 0x9D, 0xA5, 0x4F, 0xB7}, + /* Col 6 */ {0x58, 0xB5, 0xB3, 0xDD, 0x0E, 0x28, 0xF1, 0xB0}, + /* Col 7 */ {0x5F, 0x30, 0x3B, 0x56, 0x96, 0x45, 0xF4, 0xA1}, + /* Col 8 */ {0x03, 0xBC, 0x6E, 0x8A, 0xEF, 0xBD, 0xFE, 0xF8} + }, +}; + +static void __attribute__((unused)) read_code(uint8_t *buf, uint8_t row, uint8_t col, uint8_t len) +{ + for(uint8_t i=0;i> 8; + packet[1] = crc & 0xff; + packet[2] = 0xff ^ cyrfmfg_id[2]; + packet[3] = (0xff ^ cyrfmfg_id[3]) + RX_num; + packet[4] = packet[0]; + packet[5] = packet[1]; + packet[6] = packet[2]; + packet[7] = packet[3]; + for(i = 0; i < 8; i++) + sum += packet[i]; + packet[8] = sum >> 8; + packet[9] = sum & 0xff; + packet[10] = 0x01; //??? + packet[11] = option>3?option:option+4; + if(sub_protocol==DSMX) //DSMX type + packet[12] = 0xb2; // Telemetry off: packet[12] = num_channels < 8 && Model.proto_opts[PROTOOPTS_TELEMETRY] == TELEM_OFF ? 0xa2 : 0xb2; + else + packet[12] = option<8?0x01:0x02; + packet[13] = 0x00; //??? + for(i = 8; i < 14; i++) + sum += packet[i]; + packet[14] = sum >> 8; + packet[15] = sum & 0xff; +} + +static uint8_t __attribute__((unused)) PROTOCOL_SticksMoved(uint8_t init) +{ +#define STICK_MOVEMENT 15*(PPM_MAX-PPM_MIN)/100 // defines when the bind dialog should be interrupted (stick movement STICK_MOVEMENT %) + static uint16_t ele_start, ail_start; + uint16_t ele = Servo_data[ELEVATOR];//CHAN_ReadInput(MIXER_MapChannel(INP_ELEVATOR)); + uint16_t ail = Servo_data[AILERON];//CHAN_ReadInput(MIXER_MapChannel(INP_AILERON)); + if(init) { + ele_start = ele; + ail_start = ail; + return 0; + } + uint16_t ele_diff = ele_start - ele;//abs(ele_start - ele); + uint16_t ail_diff = ail_start - ail;//abs(ail_start - ail); + return ((ele_diff + ail_diff) > STICK_MOVEMENT);// +} + +static void __attribute__((unused)) build_data_packet(uint8_t upper)// +{ + uint8_t i; + uint8_t bits; + + uint8_t ch_map[] = {3, 2, 1, 5, 0, 4, 6, 7, 8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; //9 Channels - DM9 TX + switch(option>3?option:option+4) // Create channel map based on number of channels + { + case 12: + ch_map[11]=11; // 12 channels + case 11: + ch_map[10]=10; // 11 channels + case 10: + ch_map[9]=9; // 10 channels + break; + case 8: + memcpy(ch_map,"\x01\x05\x02\x03\x06\xFF\xFF\x04\x00\x07",10); // 8 channels - DX8 TX + break; + case 7: + memcpy(ch_map,"\x01\x05\x02\x04\x03\x06\x00",7); // 7 channels - DX6i TX + break; + case 6: + memcpy(ch_map,"\x01\x05\x02\x03\x00\x04\xFF",7); // 6 channels - HP6DSM TX + break; + case 4: + case 5: + memcpy(ch_map,"\x00\x01\x02\x03\xFF\xFF\xFF",7); // 4 channels - Guess + if(option&0x01) + ch_map[4]=4; // 5 channels - Guess + break; + } + // + if( binding && PROTOCOL_SticksMoved(0) ) + binding = 0; + if (sub_protocol==DSMX) + { + packet[0] = cyrfmfg_id[2]; + packet[1] = cyrfmfg_id[3] + RX_num; + bits=11; + } + else + { + packet[0] = (0xff ^ cyrfmfg_id[2]); + packet[1] = (0xff ^ cyrfmfg_id[3]) + RX_num; + bits=10; + } + // + uint16_t max = 1 << bits;//max=2048 for DSMX & 1024 for DSM2 less than 8 ch and 2048 otherwise + //uint16_t pct_100 = (uint32_t)max * 100 / 150;//682 1024*100/150 + // + for (i = 0; i < 7; i++) + { + uint8_t idx = ch_map[upper * 7 + i];//1,5,2,3,0,4 + uint16_t value; + if (idx == 0xff) + value = 0xffff; + else + { + if (binding) + { // Failsafe position during binding + value=max/2; //all channels to middle + if(idx==0) + value=1; //except throttle + } + else + { + switch(idx) + { + case 0: + value=Servo_data[THROTTLE];//85.75-938.25=125%//171-853=100% + break; + case 1: + value=Servo_data[AILERON]; + break; + case 2: + value=Servo_data[ELEVATOR]; + break; + case 3: + value=Servo_data[RUDDER]; + break; + case 4: + value=Servo_data[AUX1]; + break; + case 5: + value=Servo_data[AUX2]; + break; + case 6: + value=Servo_data[AUX3]; + break; + case 7: + value=Servo_data[AUX4]; + break; + } + value=map(value,PPM_MIN,PPM_MAX,0,max-1); + } + value |= (upper && i == 0 ? 0x8000 : 0) | (idx << bits); + } + packet[i*2+2] = (value >> 8) & 0xff; + packet[i*2+3] = (value >> 0) & 0xff; + } +} + +static uint8_t __attribute__((unused)) get_pn_row(uint8_t channel) +{ + return (sub_protocol == DSMX ? (channel - 2) % 5 : channel % 5); +} + +const uint8_t init_vals[][2] = { + {CYRF_02_TX_CTRL, 0x00}, + {CYRF_05_RX_CTRL, 0x00}, + {CYRF_28_CLK_EN, 0x02}, + {CYRF_32_AUTO_CAL_TIME, 0x3c}, + {CYRF_35_AUTOCAL_OFFSET, 0x14}, + {CYRF_06_RX_CFG, 0x4A}, + {CYRF_1B_TX_OFFSET_LSB, 0x55}, + {CYRF_1C_TX_OFFSET_MSB, 0x05}, + {CYRF_0F_XACT_CFG, 0x24}, // Force Idle + {CYRF_03_TX_CFG, 0x38 | CYRF_BIND_POWER}, //Set 64chip, SDR mode + {CYRF_12_DATA64_THOLD, 0x0a}, + {CYRF_0F_XACT_CFG, 0x04}, // Idle + {CYRF_39_ANALOG_CTRL, 0x01}, + {CYRF_0F_XACT_CFG, 0x24}, //Force IDLE + {CYRF_29_RX_ABORT, 0x00}, //Clear RX abort + {CYRF_12_DATA64_THOLD, 0x0a}, //set pn correlation threshold + {CYRF_10_FRAMING_CFG, 0x4a}, //set sop len and threshold + {CYRF_29_RX_ABORT, 0x0f}, //Clear RX abort? + {CYRF_03_TX_CFG, 0x38 | CYRF_BIND_POWER}, //Set 64chip, SDR mode + {CYRF_10_FRAMING_CFG, 0x4a}, //set sop len and threshold + {CYRF_1F_TX_OVERRIDE, 0x04}, //disable tx CRC + {CYRF_1E_RX_OVERRIDE, 0x14}, //disable rx crc + {CYRF_14_EOP_CTRL, 0x02}, //set EOP sync == 2 + {CYRF_01_TX_LENGTH, 0x10}, //16byte packet +}; + +static void __attribute__((unused)) cyrf_config() +{ + for(uint8_t i = 0; i < sizeof(init_vals) / 2; i++) + CYRF_WriteRegister(init_vals[i][0], init_vals[i][1]); + CYRF_WritePreamble(0x333304); + CYRF_ConfigRFChannel(0x61); +} + +static void __attribute__((unused)) initialize_bind_state() +{ + uint8_t code[32]; + + CYRF_ConfigRFChannel(BIND_CHANNEL); //This seems to be random? + uint8_t pn_row = get_pn_row(BIND_CHANNEL); + //printf("Ch: %d Row: %d SOP: %d Data: %d\n", BIND_CHANNEL, pn_row, sop_col, data_col); + CYRF_ConfigCRCSeed(crc); + + read_code(code,pn_row,sop_col,8); + CYRF_ConfigSOPCode(code); + read_code(code,pn_row,data_col,16); + read_code(code+16,0,8,8); + memcpy(code + 24, "\xc6\x94\x22\xfe\x48\xe6\x57\x4e", 8); + CYRF_ConfigDataCode(code, 32); + + build_bind_packet(); +} + +const uint8_t data_vals[][2] = { + {CYRF_05_RX_CTRL, 0x83}, //Initialize for reading RSSI + {CYRF_29_RX_ABORT, 0x20}, + {CYRF_0F_XACT_CFG, 0x24}, + {CYRF_29_RX_ABORT, 0x00}, + {CYRF_03_TX_CFG, 0x08 | CYRF_HIGH_POWER}, + {CYRF_10_FRAMING_CFG, 0xea}, + {CYRF_1F_TX_OVERRIDE, 0x00}, + {CYRF_1E_RX_OVERRIDE, 0x00}, + {CYRF_03_TX_CFG, 0x28 | CYRF_HIGH_POWER}, + {CYRF_12_DATA64_THOLD, 0x3f}, + {CYRF_10_FRAMING_CFG, 0xff}, + {CYRF_0F_XACT_CFG, 0x24}, //Switch from reading RSSI to Writing + {CYRF_29_RX_ABORT, 0x00}, + {CYRF_12_DATA64_THOLD, 0x0a}, + {CYRF_10_FRAMING_CFG, 0xea}, +}; + +static void __attribute__((unused)) cyrf_configdata() +{ + for(uint8_t i = 0; i < sizeof(data_vals) / 2; i++) + CYRF_WriteRegister(data_vals[i][0], data_vals[i][1]); +} + +static void __attribute__((unused)) set_sop_data_crc() +{ + uint8_t code[16]; + uint8_t pn_row = get_pn_row(hopping_frequency[chidx]); + //printf("Ch: %d Row: %d SOP: %d Data: %d\n", ch[chidx], pn_row, sop_col, data_col); + CYRF_ConfigRFChannel(hopping_frequency[chidx]); + CYRF_ConfigCRCSeed(crcidx ? ~crc : crc); + + read_code(code,pn_row,sop_col,8); + CYRF_ConfigSOPCode(code); + read_code(code,pn_row,data_col,16); + CYRF_ConfigDataCode(code, 16); + + if(sub_protocol == DSMX) + chidx = (chidx + 1) % 23; + else + chidx = (chidx + 1) % 2; + crcidx = !crcidx; +} + +static void __attribute__((unused)) calc_dsmx_channel() +{ + uint8_t idx = 0; + uint32_t id = ~(((uint32_t)cyrfmfg_id[0] << 24) | ((uint32_t)cyrfmfg_id[1] << 16) | ((uint32_t)cyrfmfg_id[2] << 8) | (cyrfmfg_id[3] << 0)); + uint32_t id_tmp = id; + while(idx < 23) + { + uint8_t i; + uint8_t count_3_27 = 0, count_28_51 = 0, count_52_76 = 0; + id_tmp = id_tmp * 0x0019660D + 0x3C6EF35F; // Randomization + uint8_t next_ch = ((id_tmp >> 8) % 0x49) + 3; // Use least-significant byte and must be larger than 3 + if (((next_ch ^ id) & 0x01 )== 0) + continue; + for (i = 0; i < idx; i++) + { + if(hopping_frequency[i] == next_ch) + break; + if(hopping_frequency[i] <= 27) + count_3_27++; + else + if (hopping_frequency[i] <= 51) + count_28_51++; + else + count_52_76++; + } + if (i != idx) + continue; + if ((next_ch < 28 && count_3_27 < 8) + ||(next_ch >= 28 && next_ch < 52 && count_28_51 < 7) + ||(next_ch >= 52 && count_52_76 < 8)) + hopping_frequency[idx++] = next_ch; + } +} + +uint16_t ReadDsm2() +{ +#define CH1_CH2_DELAY 4010 // Time between write of channel 1 and channel 2 +#define WRITE_DELAY 1650 // 1550 original, Time after write to verify write complete +#define READ_DELAY 400 // Time before write to check read state, and switch channels + uint8_t i = 0; + + switch(cyrf_state) + { + default: + //Binding + cyrf_state++; + if(cyrf_state & 1) + { + //Send packet on even states + //Note state has already incremented, + // so this is actually 'even' state + CYRF_WriteDataPacket(packet); + return 8500; + } + else + { + //Check status on odd states + CYRF_ReadRegister(CYRF_04_TX_IRQ_STATUS); + return 1500; + } + case DSM2_CHANSEL: + BIND_DONE; + //Select channels and configure for writing data + //CYRF_FindBestChannels(ch, 2, 10, 1, 79); + cyrf_configdata(); + CYRF_SetTxRxMode(TX_EN); + chidx = 0; + crcidx = 0; + cyrf_state = DSM2_CH1_WRITE_A; // in fact cyrf_state++ + set_sop_data_crc(); + return 10000; + case DSM2_CH1_WRITE_A: + case DSM2_CH1_WRITE_B: + build_data_packet(cyrf_state == DSM2_CH1_WRITE_B);//compare state and DSM2_CH1_WRITE_B return 0 or 1 + case DSM2_CH2_WRITE_A: + case DSM2_CH2_WRITE_B: + CYRF_WriteDataPacket(packet); + cyrf_state++; // change from WRITE to CHECK mode + return WRITE_DELAY; + case DSM2_CH1_CHECK_A: + case DSM2_CH1_CHECK_B: + while (! (CYRF_ReadRegister(CYRF_04_TX_IRQ_STATUS) & 0x02)) + if(++i > NUM_WAIT_LOOPS) + break; + set_sop_data_crc(); + cyrf_state++; // change from CH1_CHECK to CH2_WRITE + return CH1_CH2_DELAY - WRITE_DELAY; + case DSM2_CH2_CHECK_A: + case DSM2_CH2_CHECK_B: + while (! (CYRF_ReadRegister(CYRF_04_TX_IRQ_STATUS) & 0x02)) + if(++i > NUM_WAIT_LOOPS) + break; + if (cyrf_state == DSM2_CH2_CHECK_A) + CYRF_SetPower(0x28); //Keep transmit power in sync + // No telemetry... + set_sop_data_crc(); + if (cyrf_state == DSM2_CH2_CHECK_A) + { + if(option < 8) + { + cyrf_state = DSM2_CH1_WRITE_A; // change from CH2_CHECK_A to CH1_WRITE_A (ie no upper) + if(option>3) + return 11000 - CH1_CH2_DELAY - WRITE_DELAY ; // force 11ms if option>3 ie 4,5,6,7 channels @11ms + else + return 22000 - CH1_CH2_DELAY - WRITE_DELAY ; // normal 22ms mode if option<=3 ie 4,5,6,7 channels @22ms + } + else + cyrf_state = DSM2_CH1_WRITE_B; // change from CH2_CHECK_A to CH1_WRITE_A (to transmit upper) + } + else + cyrf_state = DSM2_CH1_WRITE_A; // change from CH2_CHECK_B to CH1_WRITE_A (upper already transmitted so transmit lower) + return 11000 - CH1_CH2_DELAY - WRITE_DELAY; + } + return 0; +} + +uint16_t initDsm2() +{ + CYRF_Reset(); + CYRF_GetMfgData(cyrfmfg_id);// + + cyrf_config(); + + if (sub_protocol ==DSMX) + calc_dsmx_channel(); + else + { +#if RANDOM_CHANNELS == 1 + uint8_t tmpch[10]; + CYRF_FindBestChannels(tmpch, 10, 5, 3, 75); + // + randomSeed((uint32_t)analogRead(A6)<<10|analogRead(A7));//seed + uint8_t idx = random(0xfefefefe) % 10; + hopping_frequency[0] = tmpch[idx]; + while(1) + { + idx = random(0xfefefefe) % 10; + if (tmpch[idx] != hopping_frequency[0]) + break; + } + hopping_frequency[1] = tmpch[idx]; +#else + hopping_frequency[0] = (cyrfmfg_id[0] + cyrfmfg_id[2] + cyrfmfg_id[4]) % 39 + 1; + hopping_frequency[1] = (cyrfmfg_id[1] + cyrfmfg_id[3] + cyrfmfg_id[5]) % 40 + 40; +#endif + } + + ///} + crc = ~((cyrfmfg_id[0] << 8) + cyrfmfg_id[1]); //The crc for channel 'a' is NOT(mfgid[1] << 8 + mfgid[0]) + crcidx = 0;//The crc for channel 'b' is (mfgid[1] << 8 + mfgid[0]) + // + sop_col = (cyrfmfg_id[0] + cyrfmfg_id[1] + cyrfmfg_id[2] + 2) & 0x07;//Ok + data_col = 7 - sop_col;//ok + + CYRF_SetTxRxMode(TX_EN); + // + if(IS_AUTOBIND_FLAG_on) + { + cyrf_state = DSM2_BIND; + PROTOCOL_SticksMoved(1); //Initialize Stick position + initialize_bind_state(); + binding = 1; + } + else + { + cyrf_state = DSM2_CHANSEL;// + binding = 0; + } + return 10000; +} + +#endif diff --git a/Multiprotocol/Devo_cyrf6936.ino b/Multiprotocol/Devo_cyrf6936.ino index a677de9..91d752e 100644 --- a/Multiprotocol/Devo_cyrf6936.ino +++ b/Multiprotocol/Devo_cyrf6936.ino @@ -43,7 +43,31 @@ enum { DEVO_BOUND_10, }; +<<<<<<< HEAD +const uint8_t sopcodes[][8] = { + /* Note these are in order transmitted (LSB 1st) */ + /* 0 */ {0x3C,0x37,0xCC,0x91,0xE2,0xF8,0xCC,0x91}, //0x91CCF8E291CC373C + /* 1 */ {0x9B,0xC5,0xA1,0x0F,0xAD,0x39,0xA2,0x0F}, //0x0FA239AD0FA1C59B + /* 2 */ {0xEF,0x64,0xB0,0x2A,0xD2,0x8F,0xB1,0x2A}, //0x2AB18FD22AB064EF + /* 3 */ {0x66,0xCD,0x7C,0x50,0xDD,0x26,0x7C,0x50}, //0x507C26DD507CCD66 + /* 4 */ {0x5C,0xE1,0xF6,0x44,0xAD,0x16,0xF6,0x44}, //0x44F616AD44F6E15C + /* 5 */ {0x5A,0xCC,0xAE,0x46,0xB6,0x31,0xAE,0x46}, //0x46AE31B646AECC5A + /* 6 */ {0xA1,0x78,0xDC,0x3C,0x9E,0x82,0xDC,0x3C}, //0x3CDC829E3CDC78A1 + /* 7 */ {0xB9,0x8E,0x19,0x74,0x6F,0x65,0x18,0x74}, //0x7418656F74198EB9 + /* 8 */ {0xDF,0xB1,0xC0,0x49,0x62,0xDF,0xC1,0x49}, //0x49C1DF6249C0B1DF + /* 9 */ {0x97,0xE5,0x14,0x72,0x7F,0x1A,0x14,0x72}, //0x72141A7F7214E597 +}; + +uint8_t txState; +uint8_t pkt_num; +uint8_t ch_idx; +uint8_t use_fixed_id; +uint8_t failsafe_pkt; + +static void __attribute__((unused)) scramble_pkt() +======= static void __attribute__((unused)) DEVO_scramble_pkt() +>>>>>>> refs/remotes/pascallanger/master { #ifdef NO_SCRAMBLE return; @@ -53,7 +77,11 @@ static void __attribute__((unused)) DEVO_scramble_pkt() #endif } +<<<<<<< HEAD +static void __attribute__((unused)) add_pkt_suffix() +======= static void __attribute__((unused)) DEVO_add_pkt_suffix() +>>>>>>> refs/remotes/pascallanger/master { uint8_t bind_state; #ifdef ENABLE_PPM @@ -91,7 +119,11 @@ static void __attribute__((unused)) DEVO_add_pkt_suffix() packet[15] = (MProtocol_id >> 16) & 0xff; } +<<<<<<< HEAD +static void __attribute__((unused)) build_beacon_pkt(uint8_t upper) +======= static void __attribute__((unused)) DEVO_build_beacon_pkt(uint8_t upper) +>>>>>>> refs/remotes/pascallanger/master { packet[0] = (DEVO_NUM_CHANNELS << 4) | 0x07; uint8_t max = 8; @@ -106,7 +138,11 @@ static void __attribute__((unused)) DEVO_build_beacon_pkt(uint8_t upper) DEVO_add_pkt_suffix(); } +<<<<<<< HEAD +static void __attribute__((unused)) build_bind_pkt() +======= static void __attribute__((unused)) DEVO_build_bind_pkt() +>>>>>>> refs/remotes/pascallanger/master { packet[0] = (DEVO_NUM_CHANNELS << 4) | 0x0a; packet[1] = bind_counter & 0xff; @@ -126,7 +162,11 @@ static void __attribute__((unused)) DEVO_build_bind_pkt() packet[15] ^= cyrfmfg_id[2]; } +<<<<<<< HEAD +static void __attribute__((unused)) build_data_pkt() +======= static void __attribute__((unused)) DEVO_build_data_pkt() +>>>>>>> refs/remotes/pascallanger/master { static uint8_t ch_idx=0; @@ -150,7 +190,11 @@ static void __attribute__((unused)) DEVO_build_data_pkt() DEVO_add_pkt_suffix(); } +<<<<<<< HEAD +static void __attribute__((unused)) cyrf_set_bound_sop_code() +======= static void __attribute__((unused)) DEVO_cyrf_set_bound_sop_code() +>>>>>>> refs/remotes/pascallanger/master { /* crc == 0 isn't allowed, so use 1 if the math results in 0 */ uint8_t crc = (cyrfmfg_id[0] + (cyrfmfg_id[1] >> 6) + cyrfmfg_id[2]); @@ -163,6 +207,9 @@ static void __attribute__((unused)) DEVO_cyrf_set_bound_sop_code() CYRF_SetPower(0x08); } +<<<<<<< HEAD +static void __attribute__((unused)) cyrf_init() +======= const uint8_t PROGMEM DEVO_init_vals[][2] = { { CYRF_1D_MODE_OVERRIDE, 0x38 }, { CYRF_03_TX_CFG, 0x08 }, @@ -186,13 +233,18 @@ const uint8_t PROGMEM DEVO_init_vals[][2] = { }; static void __attribute__((unused)) DEVO_cyrf_init() +>>>>>>> refs/remotes/pascallanger/master { /* Initialise CYRF chip */ for(uint8_t i = 0; i < sizeof(DEVO_init_vals) / 2; i++) CYRF_WriteRegister(pgm_read_byte( &DEVO_init_vals[i][0]), pgm_read_byte( &DEVO_init_vals[i][1]) ); } +<<<<<<< HEAD +static void __attribute__((unused)) set_radio_channels() +======= static void __attribute__((unused)) DEVO_set_radio_channels() +>>>>>>> refs/remotes/pascallanger/master { CYRF_FindBestChannels(hopping_frequency, 3, 4, 4, 80); hopping_frequency[3] = hopping_frequency[0]; @@ -285,6 +337,35 @@ uint16_t devo_callback() return 1200; } +<<<<<<< HEAD +/*static void __attribute__((unused)) devo_bind() +{ + fixed_id = Model_fixed_id; + bind_counter = DEVO_BIND_COUNT; + use_fixed_id = 1; + //PROTOCOL_SetBindState(0x1388 * 2400 / 1000); //msecs 12000ms +} + + +static void __attribute__((unused)) generate_fixed_id_bind(){ +if(BIND_0){ +//randomSeed((uint32_t)analogRead(A6)<<10|analogRead(A7));//seed +uint8_t txid[4]; +//Model_fixed_id = random(0xfefefefe) + ((uint32_t)random(0xfefefefe) << 16); +Model_fixed_id=0x332211; +txid[0]= (id &0xFF); +txid[1] = ((id >> 8) & 0xFF); +txid[2] = ((id >> 16) & 0xFF); +//txid[3] = ((id >> 24) & 0xFF); +eeprom_write_block((const void*)txid,(void*)40,3); +devo_bind(); +} +} +*/ + + +======= +>>>>>>> refs/remotes/pascallanger/master uint16_t DevoInit() { DEVO_cyrf_init(); diff --git a/Multiprotocol/FY326_nrf24l01.ino b/Multiprotocol/FY326_nrf24l01.ino index 41837d8..670103f 100644 --- a/Multiprotocol/FY326_nrf24l01.ino +++ b/Multiprotocol/FY326_nrf24l01.ino @@ -15,21 +15,38 @@ // Last sync with hexfet new_protocols/fy326_nrf24l01.c dated 2015-07-29 #if defined(FY326_NRF24L01_INO) +<<<<<<< HEAD +======= +>>>>>>> refs/remotes/pascallanger/master #include "iface_nrf24l01.h" #define FY326_INITIAL_WAIT 500 #define FY326_PACKET_PERIOD 1500 #define FY326_PACKET_CHKTIME 300 #define FY326_PACKET_SIZE 15 +<<<<<<< HEAD +#define FY326_BIND_COUNT 16 +======= #define FY326_BIND_COUNT 16 +>>>>>>> refs/remotes/pascallanger/master #define FY326_RF_BIND_CHANNEL 0x17 #define FY326_NUM_RF_CHANNELS 5 enum { +<<<<<<< HEAD + FY326_INIT1 = 0, + FY326_BIND1, + FY326_BIND2, + FY326_DATA, + FY319_INIT1, + FY319_BIND1, + FY319_BIND2, +======= FY326_BIND1=0, FY326_BIND2, FY326_DATA +>>>>>>> refs/remotes/pascallanger/master }; #define rxid channel @@ -39,7 +56,11 @@ static void __attribute__((unused)) FY326_send_packet(uint8_t bind) { packet[0] = rx_tx_addr[3]; if(bind) +<<<<<<< HEAD + packet[1] = 0x55; +======= packet[1] = 0x55; +>>>>>>> refs/remotes/pascallanger/master else packet[1] = GET_FLAG(Servo_AUX3, 0x80) // Headless | GET_FLAG(Servo_AUX2, 0x40) // RTH @@ -50,6 +71,23 @@ static void __attribute__((unused)) FY326_send_packet(uint8_t bind) packet[3] = convert_channel_8b_scale(ELEVATOR, 0, 200); // elevator packet[4] = 200 - convert_channel_8b_scale(RUDDER, 0, 200); // rudder packet[5] = convert_channel_8b_scale(THROTTLE, 0, 200); // throttle +<<<<<<< HEAD + if(sub_protocol == FY319) { + packet[6] = 255 - scale_channel(AILERON, 0, 255); + packet[7] = scale_channel(ELEVATOR, 0, 255); + packet[8] = 255 - scale_channel(RUDDER, 0, 255); + } + else { + packet[6] = rx_tx_addr[0]; + packet[7] = rx_tx_addr[1]; + packet[8] = rx_tx_addr[2]; + } + packet[9] = CHAN_TO_TRIM(packet[2]); // aileron_trim; + packet[10] = CHAN_TO_TRIM(packet[3]); // elevator_trim; + packet[11] = CHAN_TO_TRIM(packet[4]); // rudder_trim; + packet[12] = 0; // throttle_trim; + packet[13] = rxid; +======= packet[6] = rx_tx_addr[0]; packet[7] = rx_tx_addr[1]; packet[8] = rx_tx_addr[2]; @@ -58,6 +96,7 @@ static void __attribute__((unused)) FY326_send_packet(uint8_t bind) packet[11] = CHAN_TO_TRIM(packet[4]); // rudder_trim; packet[12] = 0; // throttle_trim; packet[13] = rxid; +>>>>>>> refs/remotes/pascallanger/master packet[14] = rx_tx_addr[4]; if (bind) @@ -66,11 +105,20 @@ static void __attribute__((unused)) FY326_send_packet(uint8_t bind) { NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no++]); hopping_frequency_no %= FY326_NUM_RF_CHANNELS; +<<<<<<< HEAD + + } + + // clear packet status bits and TX FIFO + NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); + NRF24L01_FlushTx(); +======= } // clear packet status bits and TX FIFO NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); NRF24L01_FlushTx(); +>>>>>>> refs/remotes/pascallanger/master NRF24L01_WritePayload(packet, FY326_PACKET_SIZE); @@ -79,9 +127,18 @@ static void __attribute__((unused)) FY326_send_packet(uint8_t bind) static void __attribute__((unused)) FY326_init() { +<<<<<<< HEAD + NRF24L01_Initialize(); + NRF24L01_SetTxRxMode(TX_EN); + if(sub_protocol == FY319) + NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x03); // Five-byte rx/tx address + else + NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x01); // Three-byte rx/tx address +======= NRF24L01_Initialize(); NRF24L01_SetTxRxMode(TX_EN); NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x01); // Three-byte rx/tx address +>>>>>>> refs/remotes/pascallanger/master NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, (uint8_t *)"\x15\x59\x23\xc6\x29", 5); NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, (uint8_t *)"\x15\x59\x23\xc6\x29", 5); NRF24L01_FlushTx(); @@ -93,13 +150,112 @@ static void __attribute__((unused)) FY326_init() NRF24L01_WriteReg(NRF24L01_05_RF_CH, FY326_RF_BIND_CHANNEL); NRF24L01_SetBitrate(NRF24L01_BR_250K); NRF24L01_SetPower(); +<<<<<<< HEAD + + NRF24L01_Activate(0x73); +======= NRF24L01_Activate(0x73); +>>>>>>> refs/remotes/pascallanger/master NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 0x3f); NRF24L01_WriteReg(NRF24L01_1D_FEATURE, 0x07); NRF24L01_Activate(0x73); } +<<<<<<< HEAD +uint16_t fy326_callback() +{ + uint8_t i; + switch (phase) { + case FY319_INIT1: + NRF24L01_SetTxRxMode(TXRX_OFF); + NRF24L01_FlushRx(); + NRF24L01_SetTxRxMode(RX_EN); + NRF24L01_WriteReg(NRF24L01_05_RF_CH, RF_BIND_CHANNEL); + phase = FY319_BIND1; + BIND_IN_PROGRESS; + return FY326_CHKTIME; + break; + + case FY319_BIND1: + if(NRF24L01_ReadReg(NRF24L01_07_STATUS) & BV(NRF24L01_07_RX_DR)) { + NRF24L01_ReadPayload(packet, FY326_SIZE); + rxid = packet[13]; + packet[0] = txid[3]; + packet[1] = 0x80; + packet[14]= txid[4]; + bind_counter = FY326_BIND_COUNT; + NRF24L01_SetTxRxMode(TXRX_OFF); + NRF24L01_SetTxRxMode(TX_EN); + NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); + NRF24L01_FlushTx(); + bind_counter = 255; + for(i=2; i<6; i++) + packet[i] = rf_chans[0]; + phase = FY319_BIND2; + } + return FY326_CHKTIME; + break; + + case FY319_BIND2: + NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); + NRF24L01_FlushTx(); + NRF24L01_WritePayload(packet, FY326_SIZE); + if(bind_counter == 250) + packet[1] = 0x40; + if(--bind_counter == 0) { + BIND_DONE; + phase = FY326_DATA; + } + break; + + case FY326_INIT1: + bind_counter = FY326_BIND_COUNT; + phase = FY326_BIND2; + send_packet(1); + return FY326_CHKTIME; + break; + + case FY326_BIND1: + if( NRF24L01_ReadReg(NRF24L01_07_STATUS) & BV(NRF24L01_07_RX_DR)) + { // RX fifo data ready + NRF24L01_ReadPayload(packet, FY326_PACKET_SIZE); + rxid = packet[13]; + rx_tx_addr[0] = 0xAA; + NRF24L01_SetTxRxMode(TXRX_OFF); + NRF24L01_SetTxRxMode(TX_EN); + BIND_DONE; + phase = FY326_DATA; + } + else + if (bind_counter-- == 0) + { + bind_counter = FY326_BIND_COUNT; + NRF24L01_SetTxRxMode(TXRX_OFF); + NRF24L01_SetTxRxMode(TX_EN); + FY326_send_packet(1); + phase = FY326_BIND2; + return FY326_PACKET_CHKTIME; + } + break; + + case FY326_BIND2: + if( NRF24L01_ReadReg(NRF24L01_07_STATUS) & BV(NRF24L01_07_TX_DS)) + { // TX data sent -> switch to RX mode + NRF24L01_SetTxRxMode(TXRX_OFF); + NRF24L01_FlushRx(); + NRF24L01_SetTxRxMode(RX_EN); + phase = FY326_BIND1; + } + else + return FY326_PACKET_CHKTIME; + break; + + case FY326_DATA: + FY326_send_packet(0); + break; + } +======= uint16_t FY326_callback() { switch (phase) @@ -141,26 +297,54 @@ uint16_t FY326_callback() FY326_send_packet(0); break; } +>>>>>>> refs/remotes/pascallanger/master return FY326_PACKET_PERIOD; } static void __attribute__((unused)) FY326_initialize_txid() { +<<<<<<< HEAD + if(sub_protocol == FY319) { + hopping_frequency[0] = (rx_tx_addr[0]&0x0f) & ~0x80; + hopping_frequency[1] = (rx_tx_addr[0] >> 4) & ~0x80; + hopping_frequency[2] = (rx_tx_addr[1]&0x0f) & ~0x80; + hopping_frequency[3] = (rx_tx_addr[1] >> 4) & ~0x80; + hopping_frequency[4] = (rx_tx_addr[2] >> 4) & ~0x80; + } else { + hopping_frequency[0] = (rx_tx_addr[0]&0x0f); + hopping_frequency[1] = 0x10 + (rx_tx_addr[0] >> 4); + hopping_frequency[2] = 0x20 + (rx_tx_addr[1]&0x0f); + hopping_frequency[3] = 0x30 + (rx_tx_addr[1] >> 4); + hopping_frequency[4] = 0x40 + (rx_tx_addr[2] >> 4); + } +======= hopping_frequency[0] = (rx_tx_addr[0]&0x0f); hopping_frequency[1] = 0x10 + (rx_tx_addr[0] >> 4); hopping_frequency[2] = 0x20 + (rx_tx_addr[1]&0x0f); hopping_frequency[3] = 0x30 + (rx_tx_addr[1] >> 4); hopping_frequency[4] = 0x40 + (rx_tx_addr[2] >> 4); +>>>>>>> refs/remotes/pascallanger/master } uint16_t initFY326(void) { BIND_IN_PROGRESS; // autobind protocol +<<<<<<< HEAD + rxid = 0xaa; + bind_counter = 0; + FY326_initialize_txid(); + fy326_init(); + if(sub_protocol == FY319) + phase = FY319_INIT1; + else + phase = FY326_INIT1; +======= rxid = 0xAA; bind_counter = 0; FY326_initialize_txid(); FY326_init(); phase=FY326_BIND1; +>>>>>>> refs/remotes/pascallanger/master return FY326_INITIAL_WAIT; } diff --git a/Multiprotocol/FlySky_a7105.ino b/Multiprotocol/FlySky_a7105.ino index 43ccffd..1165aea 100644 --- a/Multiprotocol/FlySky_a7105.ino +++ b/Multiprotocol/FlySky_a7105.ino @@ -21,6 +21,34 @@ //FlySky constants & variables #define FLYSKY_BIND_COUNT 2500 +<<<<<<< HEAD +const uint8_t PROGMEM tx_channels[] = { + 0x0a, 0x5a, 0x14, 0x64, 0x1e, 0x6e, 0x28, 0x78, 0x32, 0x82, 0x3c, 0x8c, 0x46, 0x96, 0x50, 0xa0, + 0xa0, 0x50, 0x96, 0x46, 0x8c, 0x3c, 0x82, 0x32, 0x78, 0x28, 0x6e, 0x1e, 0x64, 0x14, 0x5a, 0x0a, + 0x0a, 0x5a, 0x50, 0xa0, 0x14, 0x64, 0x46, 0x96, 0x1e, 0x6e, 0x3c, 0x8c, 0x28, 0x78, 0x32, 0x82, + 0x82, 0x32, 0x78, 0x28, 0x8c, 0x3c, 0x6e, 0x1e, 0x96, 0x46, 0x64, 0x14, 0xa0, 0x50, 0x5a, 0x0a, + 0x28, 0x78, 0x0a, 0x5a, 0x50, 0xa0, 0x14, 0x64, 0x1e, 0x6e, 0x3c, 0x8c, 0x32, 0x82, 0x46, 0x96, + 0x96, 0x46, 0x82, 0x32, 0x8c, 0x3c, 0x6e, 0x1e, 0x64, 0x14, 0xa0, 0x50, 0x5a, 0x0a, 0x78, 0x28, + 0x50, 0xa0, 0x28, 0x78, 0x0a, 0x5a, 0x1e, 0x6e, 0x3c, 0x8c, 0x32, 0x82, 0x46, 0x96, 0x14, 0x64, + 0x64, 0x14, 0x96, 0x46, 0x82, 0x32, 0x8c, 0x3c, 0x6e, 0x1e, 0x5a, 0x0a, 0x78, 0x28, 0xa0, 0x50, + 0x50, 0xa0, 0x46, 0x96, 0x3c, 0x8c, 0x28, 0x78, 0x0a, 0x5a, 0x32, 0x82, 0x1e, 0x6e, 0x14, 0x64, + 0x64, 0x14, 0x6e, 0x1e, 0x82, 0x32, 0x5a, 0x0a, 0x78, 0x28, 0x8c, 0x3c, 0x96, 0x46, 0xa0, 0x50, + 0x46, 0x96, 0x3c, 0x8c, 0x50, 0xa0, 0x28, 0x78, 0x0a, 0x5a, 0x1e, 0x6e, 0x32, 0x82, 0x14, 0x64, + 0x64, 0x14, 0x82, 0x32, 0x6e, 0x1e, 0x5a, 0x0a, 0x78, 0x28, 0xa0, 0x50, 0x8c, 0x3c, 0x96, 0x46, + 0x46, 0x96, 0x0a, 0x5a, 0x3c, 0x8c, 0x14, 0x64, 0x50, 0xa0, 0x28, 0x78, 0x1e, 0x6e, 0x32, 0x82, + 0x82, 0x32, 0x6e, 0x1e, 0x78, 0x28, 0xa0, 0x50, 0x64, 0x14, 0x8c, 0x3c, 0x5a, 0x0a, 0x96, 0x46, + 0x46, 0x96, 0x0a, 0x5a, 0x50, 0xa0, 0x3c, 0x8c, 0x28, 0x78, 0x1e, 0x6e, 0x32, 0x82, 0x14, 0x64, + 0x64, 0x14, 0x82, 0x32, 0x6e, 0x1e, 0x78, 0x28, 0x8c, 0x3c, 0xa0, 0x50, 0x5a, 0x0a, 0x96, 0x46 +}; + +enum { + // flags going to byte 10 + FLAG_V9X9_VIDEO = 0x40, + FLAG_V9X9_CAMERA= 0x80, + // flags going to byte 12 + FLAG_V9X9_FLIP = 0x10, + FLAG_V9X9_LED = 0x20, +======= enum { // flags going to byte 10 FLAG_V9X9_VIDEO = 0x40, @@ -28,26 +56,27 @@ enum { // flags going to byte 12 FLAG_V9X9_FLIP = 0x10, FLAG_V9X9_LED = 0x20, +>>>>>>> refs/remotes/pascallanger/master }; enum { - // flags going to byte 13 - FLAG_V6X6_HLESS1= 0x80, - // flags going to byte 14 - FLAG_V6X6_VIDEO = 0x01, - FLAG_V6X6_YCAL = 0x02, - FLAG_V6X6_XCAL = 0x04, - FLAG_V6X6_RTH = 0x08, - FLAG_V6X6_CAMERA= 0x10, - FLAG_V6X6_HLESS2= 0x20, - FLAG_V6X6_LED = 0x40, - FLAG_V6X6_FLIP = 0x80, + // flags going to byte 13 + FLAG_V6X6_HLESS1= 0x80, + // flags going to byte 14 + FLAG_V6X6_VIDEO = 0x01, + FLAG_V6X6_YCAL = 0x02, + FLAG_V6X6_XCAL = 0x04, + FLAG_V6X6_RTH = 0x08, + FLAG_V6X6_CAMERA= 0x10, + FLAG_V6X6_HLESS2= 0x20, + FLAG_V6X6_LED = 0x40, + FLAG_V6X6_FLIP = 0x80, }; enum { - // flags going to byte 14 - FLAG_V912_TOPBTN= 0x40, - FLAG_V912_BTMBTN= 0x80, + // flags going to byte 14 + FLAG_V912_TOPBTN= 0x40, + FLAG_V912_BTMBTN= 0x80, }; const uint8_t PROGMEM V912_X17_SEQ[10] = { 0x14, 0x31, 0x40, 0x49, 0x49, // sometime first byte is 0x15 ? @@ -55,6 +84,79 @@ const uint8_t PROGMEM V912_X17_SEQ[10] = { 0x14, 0x31, 0x40, 0x49, 0x49, // static void __attribute__((unused)) flysky_apply_extension_flags() { +<<<<<<< HEAD + const uint8_t V912_X17_SEQ[10] = { 0x14, 0x31, 0x40, 0x49, 0x49, // sometime first byte is 0x15 ? + 0x49, 0x49, 0x49, 0x49, 0x49, }; + static uint8_t seq_counter; + switch(sub_protocol) + { + case V9X9: + if(Servo_AUX1) + packet[12] |= FLAG_V9X9_FLIP; + if(Servo_AUX2) + packet[12] |= FLAG_V9X9_LED; + if(Servo_AUX3) + packet[10] |= FLAG_V9X9_CAMERA; + if(Servo_AUX4) + packet[10] |= FLAG_V9X9_VIDEO; + break; + + case V6X6: + packet[13] = 0x03; // 3 = 100% rate (0=40%, 1=60%, 2=80%) + packet[14] = 0x00; + if(Servo_AUX1) + packet[14] |= FLAG_V6X6_FLIP; + if(Servo_AUX2) + packet[14] |= FLAG_V6X6_LED; + if(Servo_AUX3) + packet[14] |= FLAG_V6X6_CAMERA; + if(Servo_AUX4) + packet[14] |= FLAG_V6X6_VIDEO; + if(Servo_AUX5) + { + packet[13] |= FLAG_V6X6_HLESS1; + packet[14] |= FLAG_V6X6_HLESS2; + } + if(Servo_AUX6) //use option to manipulate these bytes + packet[14] |= FLAG_V6X6_RTH; + if(Servo_AUX7) + packet[14] |= FLAG_V6X6_XCAL; + if(Servo_AUX8) + packet[14] |= FLAG_V6X6_YCAL; + packet[15] = 0x10; // unknown + packet[16] = 0x10; // unknown + packet[17] = 0xAA; // unknown + packet[18] = 0xAA; // unknown + packet[19] = 0x60; // unknown, changes at irregular interval in stock TX + packet[20] = 0x02; // unknown + break; + + case V912: + seq_counter++; + if( seq_counter > 9) + seq_counter = 0; + packet[12] |= 0x20; // bit 6 is always set ? + packet[13] = 0x00; // unknown + packet[14] = 0x00; + if(Servo_AUX1) + packet[14] = FLAG_V912_BTMBTN; + if(Servo_AUX2) + packet[14] |= FLAG_V912_TOPBTN; + packet[15] = 0x27; // [15] and [16] apparently hold an analog channel with a value lower than 1000 + packet[16] = 0x03; // maybe it's there for a pitch channel for a CP copter ? + packet[17] = V912_X17_SEQ[seq_counter]; // not sure what [17] & [18] are for + if(seq_counter == 0) // V912 Rx does not even read those bytes... [17-20] + packet[18] = 0x02; + else + packet[18] = 0x00; + packet[19] = 0x00; // unknown + packet[20] = 0x00; // unknown + break; + + default: + break; + } +======= static uint8_t seq_counter; switch(sub_protocol) { @@ -124,39 +226,78 @@ static void __attribute__((unused)) flysky_apply_extension_flags() default: break; } +>>>>>>> refs/remotes/pascallanger/master } static void __attribute__((unused)) flysky_build_packet(uint8_t init) { uint8_t i; - //servodata timing range for flysky. - ////-100% =~ 0x03e8//=1000us(min) - //+100% =~ 0x07ca//=1994us(max) - //Center = 0x5d9//=1497us(center) - //channel order AIL;ELE;THR;RUD;AUX1;AUX2;AUX3;AUX4 + //servodata timing range for flysky. + ////-100% =~ 0x03e8//=1000us(min) + //+100% =~ 0x07ca//=1994us(max) + //Center = 0x5d9//=1497us(center) + //channel order AIL;ELE;THR;RUD;AUX1;AUX2;AUX3;AUX4 packet[0] = init ? 0xaa : 0x55; packet[1] = rx_tx_addr[3]; packet[2] = rx_tx_addr[2]; packet[3] = rx_tx_addr[1]; packet[4] = rx_tx_addr[0]; +<<<<<<< HEAD + const uint8_t ch[]={AILERON, ELEVATOR, THROTTLE, RUDDER, AUX1, AUX2, AUX3, AUX4}; + for(i = 0; i < 8; i++) + { + packet[5+2*i]=lowByte(Servo_data[ch[i]]); //low byte of servo timing(1000-2000us) + packet[6+2*i]=highByte(Servo_data[ch[i]]); //high byte of servo timing(1000-2000us) + } +======= for(i = 0; i < 8; i++) { packet[5 + i*2]=Servo_data[CH_AETR[i]]&0xFF; //low byte of servo timing(1000-2000us) packet[6 + i*2]=(Servo_data[CH_AETR[i]]>>8)&0xFF; //high byte of servo timing(1000-2000us) } +>>>>>>> refs/remotes/pascallanger/master flysky_apply_extension_flags(); } uint16_t ReadFlySky() { if (bind_counter) - { + { flysky_build_packet(1); A7105_WriteData(21, 1); bind_counter--; if (! bind_counter) BIND_DONE; } +<<<<<<< HEAD + else + { + flysky_build_packet(0); + A7105_WriteData(21, pgm_read_byte_near(&tx_channels[chanrow*16+chancol])-chanoffset); + chancol = (chancol + 1) % 16; + if (! chancol) //Keep transmit power updated + A7105_SetPower(); + } + return 1460; +} + +uint16_t initFlySky() { + //A7105_Reset(); + A7105_Init(INIT_FLYSKY); //flysky_init(); + + if (rx_tx_addr[3] > 0x90) // limit offset to 9 as higher values don't work with some RX (ie V912) + rx_tx_addr[3] = rx_tx_addr[3] - 0x70; + chanrow=rx_tx_addr[3] % 16; + chancol=0; + chanoffset=rx_tx_addr[3] / 16; + + + if(IS_AUTOBIND_FLAG_on) + bind_counter = FLYSKY_BIND_COUNT; + else + bind_counter = 0; + return 2400; +======= else { flysky_build_packet(0); @@ -211,5 +352,7 @@ uint16_t initFlySky() else bind_counter = 0; return 2400; +>>>>>>> refs/remotes/pascallanger/master } #endif + diff --git a/Multiprotocol/FrSkyX_cc2500.ino b/Multiprotocol/FrSkyX_cc2500.ino index be159b3..5f5f6ba 100644 --- a/Multiprotocol/FrSkyX_cc2500.ino +++ b/Multiprotocol/FrSkyX_cc2500.ino @@ -17,9 +17,297 @@ */ #if defined(FRSKYX_CC2500_INO) + + #include "iface_cc2500.h" + + uint8_t chanskip; + uint8_t calData[48][3]; + uint8_t channr; + uint8_t pass_ = 1 ; + uint8_t counter_rst; + uint8_t ctr; + uint8_t FS_flag=0; + // uint8_t ptr[4]={0x01,0x12,0x23,0x30}; + //uint8_t ptr[4]={0x00,0x11,0x22,0x33}; + + const PROGMEM uint8_t hop_data[]={ + 0x02, 0xD4, 0xBB, 0xA2, 0x89, + 0x70, 0x57, 0x3E, 0x25, 0x0C, + 0xDE, 0xC5, 0xAC, 0x93, 0x7A, + 0x61, 0x48, 0x2F, 0x16, 0xE8, + 0xCF, 0xB6, 0x9D, 0x84, 0x6B, + 0x52, 0x39, 0x20, 0x07, 0xD9, + 0xC0, 0xA7, 0x8E, 0x75, 0x5C, + 0x43, 0x2A, 0x11, 0xE3, 0xCA, + 0xB1, 0x98, 0x7F, 0x66, 0x4D, + 0x34, 0x1B, 0x00, 0x1D, 0x03 + }; -#include "iface_cc2500.h" + static uint8_t __attribute__((unused)) hop(uint8_t byte) + { + return pgm_read_byte_near(&hop_data[byte]); + } + static void __attribute__((unused)) set_start(uint8_t ch ) + { + cc2500_strobe(CC2500_SIDLE); + cc2500_writeReg(CC2500_23_FSCAL3, calData[ch][0]); + cc2500_writeReg(CC2500_24_FSCAL2, calData[ch][1]); + cc2500_writeReg(CC2500_25_FSCAL1, calData[ch][2]); + cc2500_writeReg(CC2500_0A_CHANNR, ch==47?0:pgm_read_word(&hop_data[ch])); + } + + static void __attribute__((unused)) frskyX_init() + { + CC2500_Reset(); + + for(uint8_t i=0;i<36;i++) + { + uint8_t reg=pgm_read_byte_near(&cc2500_conf[i][0]); + uint8_t val=pgm_read_byte_near(&cc2500_conf[i][1]); + + if(reg==CC2500_06_PKTLEN) + val=0x1E; + else + if(reg==CC2500_08_PKTCTRL0) + val=0x01; + else + if(reg==CC2500_0B_FSCTRL1) + val=0x0A; + else + if(reg==CC2500_10_MDMCFG4) + val=0x7B; + else + if(reg==CC2500_11_MDMCFG3) + val=0x61; + else + if(reg==CC2500_12_MDMCFG2) + val=0x13; + else + if(reg==CC2500_15_DEVIATN) + val=0x51; + + cc2500_writeReg(reg,val); + } + + cc2500_writeReg(CC2500_07_PKTCTRL1, 0x04); + cc2500_writeReg(CC2500_0C_FSCTRL0, option); + cc2500_strobe(CC2500_SIDLE); + // + for(uint8_t c=0;c < 47;c++){//calibrate hop channels + cc2500_strobe(CC2500_SIDLE); + cc2500_writeReg(CC2500_0A_CHANNR,pgm_read_word(&hop_data[c])); + cc2500_strobe(CC2500_SCAL); + delayMicroseconds(900);// + calData[c][0] = cc2500_readReg(CC2500_23_FSCAL3); + calData[c][1] = cc2500_readReg(CC2500_24_FSCAL2); + calData[c][2] = cc2500_readReg(CC2500_25_FSCAL1); + } + cc2500_strobe(CC2500_SIDLE); + cc2500_writeReg(CC2500_0A_CHANNR,0x00); + cc2500_strobe(CC2500_SCAL); + delayMicroseconds(900); + calData[47][0] = cc2500_readReg(CC2500_23_FSCAL3); + calData[47][1] = cc2500_readReg(CC2500_24_FSCAL2); + calData[47][2] = cc2500_readReg(CC2500_25_FSCAL1); + //#######END INIT######## + } + + static void __attribute__((unused)) initialize_data(uint8_t adr) + { + cc2500_writeReg(CC2500_0C_FSCTRL0,option); // Frequency offset hack + cc2500_writeReg(CC2500_18_MCSM0, 0x8); + cc2500_writeReg(CC2500_09_ADDR, adr ? 0x03 : rx_tx_addr[3]); + cc2500_writeReg(CC2500_07_PKTCTRL1,0x05); + } + + static uint8_t __attribute__((unused)) crc_Byte( uint8_t byte ) + { + crc = (crc<<8) ^ pgm_read_word(&CRCTable[((uint8_t)(crc>>8) ^ byte) & 0xFF]); + return byte; + } + + static uint16_t __attribute__((unused)) scaleForPXX( uint8_t i ) + { //mapped 860,2140(125%) range to 64,1984(PXX values); + return (uint16_t)(((Servo_data[i]-PPM_MIN)*3)>>1)+64; + } + + static void __attribute__((unused)) frskyX_build_bind_packet() + { + crc=0; + packet[0] = 0x1D; + packet[1] = 0x03; + packet[2] = 0x01; + // + packet[3] = crc_Byte(rx_tx_addr[3]); + packet[4] = crc_Byte(rx_tx_addr[2]); + int idx = ((state -FRSKY_BIND) % 10) * 5; + packet[5] = crc_Byte(idx); + packet[6] = crc_Byte(pgm_read_word(&hop_data[idx++])); + packet[7] = crc_Byte(pgm_read_word(&hop_data[idx++])); + packet[8] = crc_Byte(pgm_read_word(&hop_data[idx++])); + packet[9] = crc_Byte(pgm_read_word(&hop_data[idx++])); + packet[10] = crc_Byte(pgm_read_word(&hop_data[idx++])); + packet[11] = crc_Byte(0x02); + packet[12] = crc_Byte(RX_num); + // + for(uint8_t i=13;i<28;i++) + packet[i]=crc_Byte(0); + // + packet[28]=highByte(crc); + packet[29]=lowByte(crc); + // + } + + static void __attribute__((unused)) frskyX_data_frame() + { + //0x1D 0xB3 0xFD 0x02 0x56 0x07 0x15 0x00 0x00 0x00 0x04 0x40 0x00 0x04 0x40 0x00 0x04 0x40 0x00 0x04 0x40 0x08 0x00 0x00 0x00 0x00 0x00 0x00 0x96 0x12 + // + uint8_t lpass = pass_ ; + uint16_t chan_0 ; + uint16_t chan_1 ; + uint8_t flag2 = 0; + uint8_t startChan = 0; + crc = 0; + //static uint8_t p = 0; + // + packet[0] = 0x1D; + packet[1] = rx_tx_addr[3]; + packet[2] = rx_tx_addr[2]; + packet[3] = crc_Byte(0x02); + // + packet[4] = crc_Byte((ctr<<6)+channr); //*64 + packet[5] = crc_Byte(counter_rst); + packet[6] = crc_Byte(RX_num); + // FLAGS 00 - standard packet + //10, 12, 14, 16, 18, 1A, 1C, 1E - failsafe packet + //20 - range check packet + packet[7] = crc_Byte(FS_flag); + packet[8] = crc_Byte(flag2); + // + if ( lpass & 1 ) + startChan += 8 ; + + for(uint8_t i = 0; i <12 ; i+=3) + {//12 bytes + chan_0 = scaleForPXX(startChan); + if(lpass & 1 ) + chan_0+=2048; + + packet[9+i] = crc_Byte(lowByte(chan_0));//3 bytes*4 + startChan++; + chan_1 = scaleForPXX(startChan); + if(lpass & 1 ) + chan_1+= 2048; + + startChan++; + packet[9+i+1]=crc_Byte((((chan_0>>8) & 0x0F)|(chan_1 << 4))); + packet[9+i+2]=crc_Byte(chan_1>>4); + } + //packet[21]=crc_Byte(0x08);//first + packet[21]=crc_Byte(0x80);//??? when received first telemetry frame is changed to 0x80 + //packet[21]=crc_Byte(ptr[p]);//??? + //p=(p+1)%4;//repeating 4 bytes sequence pattern every 4th frame. + + pass_=lpass+1; + + for (uint8_t i=22;i<28;i++) + packet[i]=crc_Byte(0); + + packet[28]=highByte(crc); + packet[29]=lowByte(crc); + } + +<<<<<<< HEAD + uint16_t ReadFrSkyX() + { + switch(state) + { + default: + set_start(47); + CC2500_SetPower(); + cc2500_strobe(CC2500_SFRX); + // + frskyX_build_bind_packet(); + cc2500_strobe(CC2500_SIDLE); + cc2500_writeFifo(packet, packet[0]+1); + state++; + return 9000; + case FRSKY_BIND_DONE: + initialize_data(0); + channr=0; + BIND_DONE; + state++; + break; + case FRSKY_DATA1: + LED_ON; + CC2500_SetTxRxMode(TX_EN); + set_start(channr); + CC2500_SetPower(); + cc2500_strobe(CC2500_SFRX); + channr = (channr+chanskip)%47; + cc2500_strobe(CC2500_SIDLE); + cc2500_writeFifo(packet, packet[0]+1); + // + frskyX_data_frame(); + state++; + return 5500; + case FRSKY_DATA2: + CC2500_SetTxRxMode(RX_EN); + cc2500_strobe(CC2500_SIDLE); + state++; + return 200; + case FRSKY_DATA3: + cc2500_strobe(CC2500_SRX); + state++; + return 3000; + case FRSKY_DATA4: + len = cc2500_readReg(CC2500_3B_RXBYTES | CC2500_READ_BURST) & 0x7F; + if (len &&(len>2; + //for test*************** + //rx_tx_addr[3]=0xB3; + //rx_tx_addr[2]=0xFD; + //************************ + frskyX_init(); + // + if(IS_AUTOBIND_FLAG_on) + { + state = FRSKY_BIND; + initialize_data(1); + } + else + { + state = FRSKY_DATA1; + initialize_data(0); + } + return 10000; + } +======= uint8_t chanskip; uint8_t counter_rst; uint8_t ctr; @@ -329,4 +617,5 @@ uint16_t initFrSkyX() seq_last_rcvd = 8; return 10000; } +>>>>>>> refs/remotes/pascallanger/master #endif \ No newline at end of file diff --git a/Multiprotocol/FrSky_cc2500.ino b/Multiprotocol/FrSky_cc2500.ino new file mode 100644 index 0000000..ec17450 --- /dev/null +++ b/Multiprotocol/FrSky_cc2500.ino @@ -0,0 +1,219 @@ +/* + This project is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Multiprotocol is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Multiprotocol. If not, see . + */ + +#if defined(FRSKY_CC2500_INO) + +#include "iface_cc2500.h" + +//##########Variables######## +//uint32_t state; +//uint8_t len; + +/* +enum { + FRSKY_BIND = 0, + FRSKY_BIND_DONE = 1000, + FRSKY_DATA1, + FRSKY_DATA2, + FRSKY_DATA3, + FRSKY_DATA4, + FRSKY_DATA5 +}; +*/ + +static void __attribute__((unused)) frsky2way_init(uint8_t bind) +{ + // Configure cc2500 for tx mode + CC2500_Reset(); + // + for(uint8_t i=0;i<36;i++) + { + uint8_t reg=pgm_read_byte_near(&cc2500_conf[i][0]); + uint8_t val=pgm_read_byte_near(&cc2500_conf[i][1]); + + if(reg==CC2500_0C_FSCTRL0) + val=option; + else + if(reg==CC2500_1B_AGCCTRL2) + val=bind ? 0x43 : 0x03; + cc2500_writeReg(reg,val); + } + + CC2500_SetTxRxMode(TX_EN); + CC2500_SetPower(); + + cc2500_strobe(CC2500_SIDLE); + + cc2500_writeReg(CC2500_09_ADDR, bind ? 0x03 : rx_tx_addr[3]); + cc2500_writeReg(CC2500_07_PKTCTRL1, 0x05); + cc2500_strobe(CC2500_SIDLE); // Go to idle... + // + cc2500_writeReg(CC2500_0A_CHANNR, 0x00); + cc2500_writeReg(CC2500_23_FSCAL3, 0x89); + cc2500_strobe(CC2500_SFRX); + //#######END INIT######## +} + +static uint8_t __attribute__((unused)) get_chan_num(uint16_t idx) +{ + uint8_t ret = (idx * 0x1e) % 0xeb; + if(idx == 3 || idx == 23 || idx == 47) + ret++; + if(idx > 47) + return 0; + return ret; +} + +static void __attribute__((unused)) frsky2way_build_bind_packet() +{ + //11 03 01 d7 2d 00 00 1e 3c 5b 78 00 00 00 00 00 00 01 + //11 03 01 19 3e 00 02 8e 2f bb 5c 00 00 00 00 00 00 01 + packet[0] = 0x11; + packet[1] = 0x03; + packet[2] = 0x01; + packet[3] = rx_tx_addr[3]; + packet[4] = rx_tx_addr[2]; + uint16_t idx = ((state -FRSKY_BIND) % 10) * 5; + packet[5] = idx; + packet[6] = get_chan_num(idx++); + packet[7] = get_chan_num(idx++); + packet[8] = get_chan_num(idx++); + packet[9] = get_chan_num(idx++); + packet[10] = get_chan_num(idx++); + packet[11] = 0x00; + packet[12] = 0x00; + packet[13] = 0x00; + packet[14] = 0x00; + packet[15] = 0x00; + packet[16] = 0x00; + packet[17] = 0x01; +} + +static void __attribute__((unused)) frsky2way_data_frame() +{//pachet[4] is telemetry user frame counter(hub) + //11 d7 2d 22 00 01 c9 c9 ca ca 88 88 ca ca c9 ca 88 88 + //11 57 12 00 00 01 f2 f2 f2 f2 06 06 ca ca ca ca 18 18 + packet[0] = 0x11; //Length + packet[1] = rx_tx_addr[3]; + packet[2] = rx_tx_addr[2]; + packet[3] = counter;// + #if defined TELEMETRY + packet[4] = telemetry_counter; + #else + packet[4] = 0x00; + #endif + + packet[5] = 0x01; + // + packet[10] = 0; + packet[11] = 0; + packet[16] = 0; + packet[17] = 0; + for(uint8_t i = 0; i < 8; i++) + { + uint16_t value; + value = convert_channel_frsky(i); + if(i < 4) + { + packet[6+i] = value & 0xff; + packet[10+(i>>1)] |= ((value >> 8) & 0x0f) << (4 *(i & 0x01)); + } + else + { + packet[8+i] = value & 0xff; + packet[16+((i-4)>>1)] |= ((value >> 8) & 0x0f) << (4 * ((i-4) & 0x01)); + } + } +} + +uint16_t initFrSky_2way() +{ + if(IS_AUTOBIND_FLAG_on) + { + frsky2way_init(1); + state = FRSKY_BIND;// + } + else + { + frsky2way_init(0); + state = FRSKY_DATA2; + } + return 10000; +} + +uint16_t ReadFrSky_2way() +{ + if (state < FRSKY_BIND_DONE) + { + frsky2way_build_bind_packet(); + cc2500_strobe(CC2500_SIDLE); + cc2500_writeReg(CC2500_0A_CHANNR, 0x00); + cc2500_writeReg(CC2500_23_FSCAL3, 0x89); + cc2500_strobe(CC2500_SFRX);//0x3A + cc2500_writeFifo(packet, packet[0]+1); + state++; + return 9000; + } + if (state == FRSKY_BIND_DONE) + { + state = FRSKY_DATA2; + frsky2way_init(0); + counter = 0; + BIND_DONE; + } + else + if (state == FRSKY_DATA5) + { + cc2500_strobe(CC2500_SRX);//0x34 RX enable + state = FRSKY_DATA1; + return 9200; + } + counter = (counter + 1) % 188; + if (state == FRSKY_DATA4) + { //telemetry receive + CC2500_SetTxRxMode(RX_EN); + cc2500_strobe(CC2500_SIDLE); + cc2500_writeReg(CC2500_0A_CHANNR, get_chan_num(counter % 47)); + cc2500_writeReg(CC2500_23_FSCAL3, 0x89); + state++; + return 1300; + } + else + { + if (state == FRSKY_DATA1) + { + len = cc2500_readReg(CC2500_3B_RXBYTES | CC2500_READ_BURST) & 0x7F; + if (len<=MAX_PKT)//27 bytes + { + cc2500_readFifo(pkt, len); //received telemetry packets + #if defined(TELEMETRY) + //parse telemetry packet here + frsky_check_telemetry(pkt,len); //check if valid telemetry packets and buffer them. + #endif + } + CC2500_SetTxRxMode(TX_EN); + CC2500_SetPower(); // Set tx_power + } + cc2500_strobe(CC2500_SIDLE); + cc2500_writeReg(CC2500_0A_CHANNR, get_chan_num(counter % 47)); + cc2500_writeReg(CC2500_23_FSCAL3, 0x89); + cc2500_strobe(CC2500_SFRX); + frsky2way_data_frame(); + cc2500_writeFifo(packet, packet[0]+1); + state++; + } + return state == FRSKY_DATA4 ? 7500 : 9000; +} +#endif diff --git a/Multiprotocol/KN_nrf24l01.ino b/Multiprotocol/KN_nrf24l01.ino index 14e9566..5675181 100644 --- a/Multiprotocol/KN_nrf24l01.ino +++ b/Multiprotocol/KN_nrf24l01.ino @@ -246,7 +246,11 @@ static void __attribute__((unused)) kn_init() NRF24L01_Initialize(); +<<<<<<< HEAD + NRF24L01_WriteReg(NRF24L01_00_CONFIG, BV(NRF24L01_00_EN_CRC) | BV(NRF24L01_00_CRCO)); +======= NRF24L01_WriteReg(NRF24L01_00_CONFIG, _BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO)); +>>>>>>> refs/remotes/pascallanger/master NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknoledgement NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0 NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x03); // 5-byte RX/TX address @@ -259,7 +263,11 @@ static void __attribute__((unused)) kn_init() NRF24L01_Activate(0x73); NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 1); // Dynamic payload for data pipe 0 // Enable: Dynamic Payload Length to enable PCF +<<<<<<< HEAD + NRF24L01_WriteReg(NRF24L01_1D_FEATURE, BV(NRF2401_1D_EN_DPL)); +======= NRF24L01_WriteReg(NRF24L01_1D_FEATURE, _BV(NRF2401_1D_EN_DPL)); +>>>>>>> refs/remotes/pascallanger/master NRF24L01_SetPower(); diff --git a/Multiprotocol/MJXQ_nrf24l01.ino b/Multiprotocol/MJXQ_nrf24l01.ino index ae95060..a1cb14a 100644 --- a/Multiprotocol/MJXQ_nrf24l01.ino +++ b/Multiprotocol/MJXQ_nrf24l01.ino @@ -12,7 +12,11 @@ You should have received a copy of the GNU General Public License along with Multiprotocol. If not, see . */ +<<<<<<< HEAD +// compatible with MJX WLH08, X600, X800, H26D +======= // compatible with MJX WLH08, X600, X800, H26D, Eachine E010 +>>>>>>> refs/remotes/pascallanger/master // Last sync with hexfet new_protocols/mjxq_nrf24l01.c dated 2016-01-17 #if defined(MJXQ_NRF24L01_INO) @@ -26,6 +30,8 @@ #define MJXQ_RF_NUM_CHANNELS 4 #define MJXQ_ADDRESS_LENGTH 5 +<<<<<<< HEAD +======= // haven't figured out txid<-->rf channel mapping for MJX models const uint8_t PROGMEM MJXQ_map_rfchan[][4] = { {0x0A, 0x46, 0x3A, 0x42}, @@ -37,6 +43,7 @@ const uint8_t PROGMEM MJXQ_map_txid[][3] = { {0x48, 0x6A, 0x40} }; +>>>>>>> refs/remotes/pascallanger/master #define MJXQ_PAN_TILT_COUNT 16 // for H26D - match stock tx timing #define MJXQ_PAN_DOWN 0x08 #define MJXQ_PAN_UP 0x04 @@ -50,6 +57,16 @@ static uint8_t __attribute__((unused)) MJXQ_pan_tilt_value() packet_count++; if(packet_count & MJXQ_PAN_TILT_COUNT) { +<<<<<<< HEAD + if(Servo_AUX8) + pan=MJXQ_PAN_UP; + if(Servo_data[AUX8]PPM_MIN_COMMAND) + pan=MJXQ_TILT_UP; + if(Servo_data[AUX9]PPM_MAX_COMMAND) pan=MJXQ_PAN_UP; if(Servo_data[AUX8]>>>>>> refs/remotes/pascallanger/master } return pan; } @@ -68,10 +86,17 @@ static void __attribute__((unused)) MJXQ_send_packet(uint8_t bind) packet[0] = convert_channel_8b(THROTTLE); packet[1] = convert_channel_s8b(RUDDER); packet[4] = 0x40; // rudder does not work well with dyntrim +<<<<<<< HEAD + packet[2] = convert_channel_s8b(ELEVATOR); + packet[5] = MJXQ_CHAN2TRIM(packet[2]); // trim elevator + packet[3] = convert_channel_s8b(AILERON); + packet[6] = MJXQ_CHAN2TRIM(packet[3]); // trim aileron +======= packet[2] = 0x80 ^ convert_channel_s8b(ELEVATOR); packet[5] = GET_FLAG(Servo_AUX5, 1) ? 0x40 : MJXQ_CHAN2TRIM(packet[2]); // trim elevator packet[3] = convert_channel_s8b(AILERON); packet[6] = GET_FLAG(Servo_AUX5, 1) ? 0x40 : MJXQ_CHAN2TRIM(packet[3]); // trim aileron +>>>>>>> refs/remotes/pascallanger/master packet[7] = rx_tx_addr[0]; packet[8] = rx_tx_addr[1]; packet[9] = rx_tx_addr[2]; @@ -96,7 +121,10 @@ static void __attribute__((unused)) MJXQ_send_packet(uint8_t bind) packet[10]=MJXQ_pan_tilt_value(); // fall through on purpose - no break case WLH08: +<<<<<<< HEAD +======= case E010: +>>>>>>> refs/remotes/pascallanger/master packet[10] += GET_FLAG(Servo_AUX6, 0x02) //RTH | GET_FLAG(Servo_AUX5, 0x01); //HEADLESS if (!bind) @@ -109,6 +137,14 @@ static void __attribute__((unused)) MJXQ_send_packet(uint8_t bind) } break; case X600: +<<<<<<< HEAD + if(Servo_AUX5) //HEADLESS + { // driven trims cause issues when headless is enabled + packet[5] = 0x40; + packet[6] = 0x40; + } +======= +>>>>>>> refs/remotes/pascallanger/master packet[10] = GET_FLAG(!Servo_AUX2, 0x02); //LED packet[11] = GET_FLAG(Servo_AUX6, 0x01); //RTH if (!bind) @@ -142,7 +178,11 @@ static void __attribute__((unused)) MJXQ_send_packet(uint8_t bind) if (sub_protocol == H26D) NRF24L01_SetTxRxMode(TX_EN); else +<<<<<<< HEAD + XN297_Configure(BV(NRF24L01_00_EN_CRC) | BV(NRF24L01_00_CRCO) | BV(NRF24L01_00_PWR_UP)); +======= XN297_Configure(_BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO) | _BV(NRF24L01_00_PWR_UP)); +>>>>>>> refs/remotes/pascallanger/master NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no++ / 2]); hopping_frequency_no %= 2 * MJXQ_RF_NUM_CHANNELS; // channels repeated @@ -165,12 +205,20 @@ static void __attribute__((unused)) MJXQ_init() if (sub_protocol == WLH08) memcpy(hopping_frequency, "\x12\x22\x32\x42", MJXQ_RF_NUM_CHANNELS); else +<<<<<<< HEAD + if (sub_protocol == H26D) +======= if (sub_protocol == H26D || sub_protocol == E010) +>>>>>>> refs/remotes/pascallanger/master memcpy(hopping_frequency, "\x36\x3e\x46\x2e", MJXQ_RF_NUM_CHANNELS); else { memcpy(hopping_frequency, "\x0a\x35\x42\x3d", MJXQ_RF_NUM_CHANNELS); +<<<<<<< HEAD + memcpy(addr, "\x6d\x6a\x73\x73\x73", MJXQ_RF_NUM_CHANNELS); +======= memcpy(addr, "\x6d\x6a\x73\x73\x73", MJXQ_ADDRESS_LENGTH); +>>>>>>> refs/remotes/pascallanger/master } @@ -189,25 +237,53 @@ static void __attribute__((unused)) MJXQ_init() NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0 only NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0x00); // no retransmits NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, MJXQ_PACKET_SIZE); // rx pipe 0 (used only for blue board) +<<<<<<< HEAD + NRF24L01_SetBitrate(NRF24L01_BR_1M); // 1Mbps +======= if (sub_protocol == E010) NRF24L01_SetBitrate(NRF24L01_BR_250K); // 250K else NRF24L01_SetBitrate(NRF24L01_BR_1M); // 1Mbps +>>>>>>> refs/remotes/pascallanger/master NRF24L01_SetPower(); } static void __attribute__((unused)) MJXQ_init2() { +<<<<<<< HEAD + // haven't figured out txid<-->rf channel mapping for MJX models + static const uint8_t rf_map[][4] = { + {0x0A, 0x46, 0x3A, 0x42}, + {0x0A, 0x3C, 0x36, 0x3F}, + {0x0A, 0x43, 0x36, 0x3F} }; + if (sub_protocol == H26D) + memcpy(hopping_frequency, "\x32\x3e\x42\x4e", MJXQ_RF_NUM_CHANNELS); + else + if (sub_protocol == WLH08) + memcpy(hopping_frequency, rf_map[rx_tx_addr[0]%3], MJXQ_RF_NUM_CHANNELS); +======= if (sub_protocol == H26D) memcpy(hopping_frequency, "\x32\x3e\x42\x4e", MJXQ_RF_NUM_CHANNELS); else if (sub_protocol != WLH08 && sub_protocol != E010) for(uint8_t i=0;i>>>>>> refs/remotes/pascallanger/master } static void __attribute__((unused)) MJXQ_initialize_txid() { +<<<<<<< HEAD + // haven't figured out txid<-->rf channel mapping for MJX models + static const uint8_t tx_map[][3]={ + {0xF8, 0x4F, 0x1C}, + {0xC8, 0x6E, 0x02}, + {0x48, 0x6A, 0x40} }; + if (sub_protocol == WLH08) + rx_tx_addr[0]&=0xF8; // txid must be multiple of 8 + else + memcpy(rx_tx_addr,tx_map[rx_tx_addr[0]%3],3); +======= rx_tx_addr[0]&=0xF8; if (sub_protocol == E010) { @@ -217,6 +293,7 @@ static void __attribute__((unused)) MJXQ_initialize_txid() else for(uint8_t i=0;i<3;i++) rx_tx_addr[i]=pgm_read_byte_near( &MJXQ_map_txid[rx_tx_addr[4]%3][i] ); +>>>>>>> refs/remotes/pascallanger/master } uint16_t MJXQ_callback() diff --git a/Multiprotocol/MT99xx_nrf24l01.ino b/Multiprotocol/MT99xx_nrf24l01.ino index 4fb2d65..dff51d7 100644 --- a/Multiprotocol/MT99xx_nrf24l01.ino +++ b/Multiprotocol/MT99xx_nrf24l01.ino @@ -12,7 +12,11 @@ You should have received a copy of the GNU General Public License along with Multiprotocol. If not, see . */ +<<<<<<< HEAD +// compatible with MT99xx, Eachine H7, Yi Zhan i6S +======= // compatible with MT99xx, Eachine H7, Yi Zhan i6S and LS114/124 +>>>>>>> refs/remotes/pascallanger/master // Last sync with Goebish mt99xx_nrf24l01.c dated 2016-01-29 #if defined(MT99XX_NRF24L01_INO) @@ -37,6 +41,8 @@ enum{ FLAG_MT_FLIP = 0x80, }; +<<<<<<< HEAD +======= enum{ // flags going to packet[6] (LS) FLAG_LS_INVERT = 0x01, @@ -47,12 +53,43 @@ enum{ FLAG_LS_FLIP = 0x80, }; +>>>>>>> refs/remotes/pascallanger/master enum { MT99XX_INIT = 0, MT99XX_BIND, MT99XX_DATA }; +<<<<<<< HEAD +static void __attribute__((unused)) MT99XX_send_packet() +{ + const uint8_t yz_p4_seq[] = {0xa0, 0x20, 0x60}; + const uint8_t mys_byte[] = { + 0x01, 0x11, 0x02, 0x12, 0x03, 0x13, 0x04, 0x14, + 0x05, 0x15, 0x06, 0x16, 0x07, 0x17, 0x00, 0x10 + }; + static uint8_t yz_seq_num=0; + + if(sub_protocol != YZ) + { // MT99XX & H7 + packet[0] = convert_channel_8b_scale(THROTTLE,0x00,0xE1); // throttle + packet[1] = convert_channel_8b_scale(RUDDER ,0x00,0xE1); // rudder + packet[2] = convert_channel_8b_scale(AILERON ,0x00,0xE1); // aileron + packet[3] = convert_channel_8b_scale(ELEVATOR,0x00,0xE1); // elevator + packet[4] = 0x20; // pitch trim (0x3f-0x20-0x00) + packet[5] = 0x20; // roll trim (0x00-0x20-0x3f) + packet[6] = GET_FLAG( Servo_AUX1, FLAG_MT_FLIP ) + | GET_FLAG( Servo_AUX3, FLAG_MT_SNAPSHOT ) + | GET_FLAG( Servo_AUX4, FLAG_MT_VIDEO ); + if(sub_protocol==MT99) + packet[6] |= 0x40 | FLAG_MT_RATE2; + else + packet[6] |= FLAG_MT_RATE1; // max rate on H7 + // todo: mys_byte = next channel index ? + // low nibble: index in chan list ? + // high nibble: 0->start from start of list, 1->start from end of list ? + packet[7] = mys_byte[hopping_frequency_no]; +======= const uint8_t h7_mys_byte[] = { 0x01, 0x11, 0x02, 0x12, 0x03, 0x13, 0x04, 0x14, 0x05, 0x15, 0x06, 0x16, 0x07, 0x17, 0x00, 0x10 @@ -101,6 +138,7 @@ static void __attribute__((unused)) MT99XX_send_packet() ls_counter=0; } +>>>>>>> refs/remotes/pascallanger/master uint8_t result=checksum_offset; for(uint8_t i=0; i<8; i++) result += packet[i]; @@ -109,9 +147,15 @@ static void __attribute__((unused)) MT99XX_send_packet() else { // YZ packet[0] = convert_channel_8b_scale(THROTTLE,0x00,0x64); // throttle +<<<<<<< HEAD + packet[1] = convert_channel_8b_scale(RUDDER ,0x00,0x64); // rudder + packet[2] = convert_channel_8b_scale(ELEVATOR,0x00,0x64); // elevator + packet[3] = convert_channel_8b_scale(AILERON ,0x00,0x64); // aileron +======= packet[1] = convert_channel_8b_scale(RUDDER ,0x64,0x00); // rudder packet[2] = convert_channel_8b_scale(ELEVATOR,0x00,0x64); // elevator packet[3] = convert_channel_8b_scale(AILERON ,0x64,0x00); // aileron +>>>>>>> refs/remotes/pascallanger/master if(packet_count++ >= 23) { yz_seq_num ++; @@ -132,10 +176,14 @@ static void __attribute__((unused)) MT99XX_send_packet() packet[8] = 0xff; } +<<<<<<< HEAD + NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no] + channel_offset); +======= if(sub_protocol == LS) NRF24L01_WriteReg(NRF24L01_05_RF_CH, 0x2D); // LS always transmits on the same channel else NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no] + channel_offset); +>>>>>>> refs/remotes/pascallanger/master NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); NRF24L01_FlushTx(); XN297_WritePayload(packet, MT99XX_PACKET_SIZE); @@ -153,11 +201,16 @@ static void __attribute__((unused)) MT99XX_send_packet() static void __attribute__((unused)) MT99XX_init() { NRF24L01_Initialize(); +<<<<<<< HEAD + NRF24L01_SetTxRxMode(TX_EN); + NRF24L01_FlushTx(); +======= if(sub_protocol == YZ) XN297_SetScrambledMode(XN297_UNSCRAMBLED); NRF24L01_SetTxRxMode(TX_EN); NRF24L01_FlushTx(); XN297_SetTXAddr((uint8_t *)"\xCC\xCC\xCC\xCC\xCC", 5); +>>>>>>> refs/remotes/pascallanger/master NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknowldgement on all data pipes NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0 only @@ -169,18 +222,31 @@ static void __attribute__((unused)) MT99XX_init() NRF24L01_SetBitrate(NRF24L01_BR_1M); // 1Mbps NRF24L01_SetPower(); +<<<<<<< HEAD + XN297_Configure(BV(NRF24L01_00_EN_CRC) | BV(NRF24L01_00_CRCO) | BV(NRF24L01_00_PWR_UP) | (sub_protocol == YZ ? BV(XN297_UNSCRAMBLED):0) ); + + XN297_SetTXAddr((uint8_t *)"\xCC\xCC\xCC\xCC\xCC", 5); +======= XN297_Configure(_BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO) | _BV(NRF24L01_00_PWR_UP) ); +>>>>>>> refs/remotes/pascallanger/master } static void __attribute__((unused)) MT99XX_initialize_txid() { +<<<<<<< HEAD +======= rx_tx_addr[3] = 0xCC; rx_tx_addr[4] = 0xCC; +>>>>>>> refs/remotes/pascallanger/master if(sub_protocol == YZ) { rx_tx_addr[0] = 0x53; // test (SB id) rx_tx_addr[1] = 0x00; +<<<<<<< HEAD + } + checksum_offset = (rx_tx_addr[0] + rx_tx_addr[1]) & 0xff; +======= rx_tx_addr[2] = 0x00; } else @@ -189,6 +255,7 @@ static void __attribute__((unused)) MT99XX_initialize_txid() else //MT99 & H7 rx_tx_addr[2] = 0x00; checksum_offset = rx_tx_addr[0] + rx_tx_addr[1] + rx_tx_addr[2]; +>>>>>>> refs/remotes/pascallanger/master channel_offset = (((checksum_offset & 0xf0)>>4) + (checksum_offset & 0x0f)) % 8; } @@ -200,16 +267,26 @@ uint16_t MT99XX_callback() { if (bind_counter == 0) { +<<<<<<< HEAD + rx_tx_addr[2] = 0x00; + rx_tx_addr[3] = 0xCC; + rx_tx_addr[4] = 0xCC; +======= +>>>>>>> refs/remotes/pascallanger/master // set tx address for data packets XN297_SetTXAddr(rx_tx_addr, 5); BIND_DONE; } else { +<<<<<<< HEAD + NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no]); +======= if(sub_protocol == LS) NRF24L01_WriteReg(NRF24L01_05_RF_CH, 0x2D); // LS always transmits on the same channel else NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no]); +>>>>>>> refs/remotes/pascallanger/master NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); NRF24L01_FlushTx(); XN297_WritePayload(packet, MT99XX_PACKET_SIZE); // bind packet @@ -236,6 +313,25 @@ uint16_t initMT99XX(void) MT99XX_init(); packet[0] = 0x20; +<<<<<<< HEAD + if(sub_protocol!=YZ) + { // MT99 & H7 + packet_period = MT99XX_PACKET_PERIOD_MT; + packet[1] = 0x14; + packet[2] = 0x03; + packet[3] = 0x25; + } + else + { // YZ + packet_period = MT99XX_PACKET_PERIOD_YZ; + packet[1] = 0x15; + packet[2] = 0x05; + packet[3] = 0x06; + } + packet[4] = rx_tx_addr[0]; // 1st byte for data state tx address + packet[5] = rx_tx_addr[1]; // 2nd byte for data state tx address (always 0x00 on Yi Zhan ?) + packet[6] = 0x00; // 3rd byte for data state tx address (always 0x00 ?) +======= packet_period = MT99XX_PACKET_PERIOD_MT; switch(sub_protocol) { // MT99 & H7 @@ -260,6 +356,7 @@ uint16_t initMT99XX(void) packet[4] = rx_tx_addr[0]; packet[5] = rx_tx_addr[1]; packet[6] = rx_tx_addr[2]; +>>>>>>> refs/remotes/pascallanger/master packet[7] = checksum_offset; // checksum offset packet[8] = 0xAA; // fixed packet_count=0; diff --git a/Multiprotocol/Multiprotocol.ino b/Multiprotocol/Multiprotocol.ino index fc3c097..fe73f45 100644 --- a/Multiprotocol/Multiprotocol.ino +++ b/Multiprotocol/Multiprotocol.ino @@ -1,11 +1,17 @@ /********************************************************* - Multiprotocol Tx code - by Midelic and Pascal Langer(hpnuts) - http://www.rcgroups.com/forums/showthread.php?t=2165676 + Multiprotocol Tx code + by Midelic and Pascal Langer(hpnuts) + fork by Tipouic + http://www.rcgroups.com/forums/showthread.php?t=2165676 https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/edit/master/README.md +<<<<<<< HEAD + Thanks to PhracturedBlue, Hexfet, Goebish and all protocol developers + Ported from deviation firmware +======= Thanks to PhracturedBlue, Hexfet, Goebish, Victzh and all protocol developers Ported from deviation firmware +>>>>>>> refs/remotes/pascallanger/master This project is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -22,12 +28,19 @@ */ #include #include +<<<<<<< HEAD +#include +======= //#define DEBUG_TX #include "Pins.h" +>>>>>>> refs/remotes/pascallanger/master #include "Multiprotocol.h" //Multiprotocol module configuration file #include "_Config.h" +<<<<<<< HEAD + +======= #include "TX_Def.h" #ifdef XMEGA @@ -40,6 +53,7 @@ #define DSM_TELEMETRY // Enable DSM telemetry #endif +>>>>>>> refs/remotes/pascallanger/master //Global constants/variables uint32_t MProtocol_id;//tx id, uint32_t MProtocol_id_master; @@ -53,16 +67,40 @@ uint8_t packet[40]; // Servo data uint16_t Servo_data[NUM_CHN]; uint8_t Servo_AUX; +<<<<<<< HEAD +const uint8_t ch[]={AILERON, ELEVATOR, THROTTLE, RUDDER, AUX1, AUX2, AUX3, AUX4}; + +// Protocol variables +uint8_t rx_tx_addr[5]; +uint8_t phase; +======= uint16_t servo_max_100,servo_min_100,servo_max_125,servo_min_125; // Protocol variables uint8_t cyrfmfg_id[6];//for dsm2 and devo uint8_t rx_tx_addr[5]; uint8_t phase; +>>>>>>> refs/remotes/pascallanger/master uint16_t bind_counter; uint8_t bind_phase; uint8_t binding_idx; uint16_t packet_period; +<<<<<<< HEAD +uint8_t packet_count; +uint8_t packet_sent; +uint8_t packet_length; +uint8_t hopping_frequency[23]; +uint8_t *hopping_frequency_ptr; +uint8_t hopping_frequency_no=0; +uint8_t rf_ch_num; +uint8_t throttle, rudder, elevator, aileron; +uint8_t flags; +uint16_t crc; +// +uint32_t state; +uint8_t len; +uint8_t RX_num; +======= uint8_t packet_count; uint8_t packet_sent; uint8_t packet_length; @@ -89,6 +127,7 @@ const uint8_t CH_AETR[]={AILERON, ELEVATOR, THROTTLE, RUDDER, AUX1, AUX2, AUX3, const uint8_t CH_TAER[]={THROTTLE, AILERON, ELEVATOR, RUDDER, AUX1, AUX2, AUX3, AUX4, AUX5, AUX6, AUX7, AUX8}; const uint8_t CH_RETA[]={RUDDER, ELEVATOR, THROTTLE, AILERON, AUX1, AUX2, AUX3, AUX4, AUX5, AUX6, AUX7, AUX8}; const uint8_t CH_EATR[]={ELEVATOR, AILERON, THROTTLE, RUDDER, AUX1, AUX2, AUX3, AUX4, AUX5, AUX6, AUX7, AUX8}; +>>>>>>> refs/remotes/pascallanger/master // Mode_select variables uint8_t mode_select; @@ -97,10 +136,20 @@ uint8_t protocol_flags=0,protocol_flags2=0; // PPM variable volatile uint16_t PPM_data[NUM_CHN]; +<<<<<<< HEAD +// Serial variables +#define RXBUFFER_SIZE 25 +#define TXBUFFER_SIZE 12 +volatile uint8_t rx_buff[RXBUFFER_SIZE]; +volatile uint8_t rx_ok_buff[RXBUFFER_SIZE]; +volatile uint8_t tx_buff[TXBUFFER_SIZE]; +volatile uint8_t idx = 0; +======= #ifndef XMEGA //Random variable volatile uint32_t gWDT_entropy=0; #endif +>>>>>>> refs/remotes/pascallanger/master //Serial protocol uint8_t sub_protocol; @@ -143,6 +192,11 @@ volatile uint8_t discard_frame = 0; #define MAX_PKT 27 uint8_t pkt[MAX_PKT];//telemetry receiving packets #if defined(TELEMETRY) +<<<<<<< HEAD +uint8_t pktt[MAX_PKT];//telemetry receiving packets + volatile uint8_t tx_head; + volatile uint8_t tx_tail; +======= #ifdef INVERT_TELEMETRY // enable bit bash for serial #ifndef XMEGA @@ -158,6 +212,7 @@ uint8_t pkt[MAX_PKT];//telemetry receiving packets volatile uint8_t tx_head=0; volatile uint8_t tx_tail=0; #endif // BASH_SERIAL +>>>>>>> refs/remotes/pascallanger/master uint8_t v_lipo; int16_t RSSI_dBm; //const uint8_t RSSI_offset=72;//69 71.72 values db @@ -229,6 +284,19 @@ void setup() #endif // Set Chip selects +<<<<<<< HEAD + CS_on; + CC25_CSN_on; + NRF_CSN_on; + CYRF_CSN_on; + // Set SPI lines + SDI_on; + SCK_off; + + // Timer1 config + TCCR1A = 0; + TCCR1B = (1 << CS11); //prescaler8, set timer1 to increment every 0.5us(16Mhz) and start timer +======= #ifdef A7105_INSTALLED A7105_CSN_on; #endif @@ -244,10 +312,42 @@ void setup() // Set SPI lines SDI_on; SCLK_off; +>>>>>>> refs/remotes/pascallanger/master // Set servos positions for(uint8_t i=0;i>2)&0x07 ) | ( (PINC<<3)&0x08) );//encoder dip switches 1,2,4,8=>B2,B3,B4,C0 + //********************************** +//mode_select=1; // here to test PPM + //********************************** + + // Update LED + LED_OFF; + LED_SET_OUTPUT; + + // Read or create protocol id + MProtocol_id_master=random_id(10,false); + + //Init RF modules + #ifdef CC2500_INSTALLED + CC2500_Reset(); + #endif + +======= Servo_data[THROTTLE]=servo_min_100; #ifdef ENABLE_PPM memcpy((void *)PPM_data,Servo_data, sizeof(Servo_data)); @@ -288,12 +388,17 @@ void setup() MProtocol_id_master=random_id(10,false); #ifdef ENABLE_PPM +>>>>>>> refs/remotes/pascallanger/master //Protocol and interrupts initialization if(mode_select != MODE_SERIAL) { // PPM mode_select--; +<<<<<<< HEAD + cur_protocol[0] = PPM_prot[mode_select].protocol; +======= protocol = PPM_prot[mode_select].protocol; cur_protocol[1] = protocol; +>>>>>>> refs/remotes/pascallanger/master sub_protocol = PPM_prot[mode_select].sub_proto; RX_num = PPM_prot[mode_select].rx_num; MProtocol_id = RX_num + MProtocol_id_master; @@ -301,6 +406,16 @@ void setup() if(PPM_prot[mode_select].power) POWER_FLAG_on; if(PPM_prot[mode_select].autobind) AUTOBIND_FLAG_on; mode_select++; +<<<<<<< HEAD + + protocol_init(); + + //Configure PPM interrupt + EICRA |=(1<>>>>>> refs/remotes/pascallanger/master #endif } else @@ -338,6 +454,39 @@ void setup() // Main // Protocol scheduler void loop() +<<<<<<< HEAD +{ + if(mode_select==MODE_SERIAL && IS_RX_FLAG_on) // Serial mode and something has been received + { + update_serial_data(); // Update protocol and data + update_aux_flags(); + if(IS_CHANGE_PROTOCOL_FLAG_on) + { // Protocol needs to be changed + LED_OFF; //led off during protocol init + module_reset(); //reset previous module + protocol_init(); //init new protocol + CHANGE_PROTOCOL_FLAG_off; //done + } + } + if(mode_select!=MODE_SERIAL && IS_PPM_FLAG_on) // PPM mode and a full frame has been received + { + for(uint8_t i=0;i>>>>>> refs/remotes/pascallanger/master } // Update Servo_AUX flags based on servo AUX positions @@ -444,18 +594,64 @@ static void update_led_status(void) { if(blink>>>>>> refs/remotes/pascallanger/master else if(remote_callback == 0) { // Invalid protocol - if(IS_LED_on) //flash to indicate invalid protocol - blink+=BLINK_BAD_PROTO_TIME_LOW; - else - blink+=BLINK_BAD_PROTO_TIME_HIGH; - } + if(IS_LED_on) //flash to indicate invalid protocol + blink+=BLINK_BAD_PROTO_TIME_LOW; + else + blink+=BLINK_BAD_PROTO_TIME_HIGH; + } else if(IS_BIND_DONE_on) +<<<<<<< HEAD + LED_OFF; //bind completed -> led on + else + blink+=BLINK_BIND_TIME; //blink fastly during binding + LED_TOGGLE; + } +} + +// Protocol scheduler +static void CheckTimer(uint16_t (*cb)(void)) +{ + uint16_t next_callback; + uint32_t prev; + if( (TIFR1 & (1< micros()) + { // Callback did not took more than requested time for next callback + if(next_callback>32000) + { // next_callback should not be more than 32767 so we will wait here... + delayMicroseconds(next_callback-2000); + cli(); // disable global int + OCR1A=TCNT1+4000; + sei(); // enable global int + } + else + { + cli(); // disable global int + OCR1A+=next_callback*2; // set compare A for callback + sei(); // enable global int + } + TIFR1=(1< led on else blink+=BLINK_BIND_TIME; //blink fastly during binding @@ -494,6 +690,7 @@ inline void tx_resume() #endif } #endif +>>>>>>> refs/remotes/pascallanger/master } // Protocol start @@ -517,10 +714,227 @@ static void protocol_init() if(IS_BIND_BUTTON_FLAG_on) AUTOBIND_FLAG_on; if(IS_AUTOBIND_FLAG_on) - BIND_IN_PROGRESS; // Indicates bind in progress for blinking bind led + BIND_IN_PROGRESS; // Indicates bind in progress for blinking bind led else BIND_DONE; +<<<<<<< HEAD + CTRL1_on; //NRF24L01 antenna RF3 by default + CTRL2_off; //NRF24L01 antenna RF3 by default + + switch(cur_protocol[0]&0x1F) // Init the requested protocol + { +#if defined(HM830_NRF24L01_INO) + case MODE_HM830: + next_callback=HM830_setup(); + remote_callback = HM830_callback; + break; +#endif +#if defined(CFlie_NRF24L01_INO) + case MODE_CFLIE: + next_callback=Cflie_setup(); + remote_callback = cflie_callback; + break; +#endif +#if defined(JOYSWAY_A7105_INO) + case MODE_JOYSWAY: + next_callback=JOYSWAY_Setup(); + remote_callback = joysway_cb; + break; +#endif +#if defined(H377_NRF24L01_INO) + case MODE_H377: + next_callback=h377_setup(); + remote_callback = h377_cb; + break; +#endif +#if defined(J6PRO_CYRF6936_INO) + case MODE_J6PRO: + next_callback=j6pro_setup(); + remote_callback = j6pro_cb; + break; +#endif +#if defined(WK2x01_CYRF6936_INO) + case MODE_WK2x01: + next_callback=wk_setup(); + remote_callback = wk_cb; + break; +#endif +#if defined(ESKY150_NRF24L01_INO) + case MODE_ESKY150: + next_callback=esky150_setup(); + remote_callback = esky150_callback; + break; +#endif +#if defined(BlueFly_NRF24L01_INO) + case MODE_BlueFly: + next_callback=BlueFly_setup(); + remote_callback = bluefly_cb; + break; +#endif +#if defined(HonTai_NRF24L01_INO) + case MODE_HonTai: + next_callback=ht_setup(); + remote_callback = ht_callback; + break; +#endif +#if defined(UDI_NRF24L01_INO) + case MODE_UDI: + next_callback=UDI_setup(); + remote_callback = UDI_callback; + break; +#endif +#if defined(NE260_NRF24L01_INO) + case MODE_NE260: + next_callback=NE260_setup(); + remote_callback = ne260_cb; + break; +#endif +#if defined(SKYARTEC_CC2500_INO) + case MODE_SKYARTEC: + next_callback=skyartec_setup(); + remote_callback = skyartec_cb; + break; +#endif +#if defined(FBL100_NRF24L01_INO) + case MODE_FBL100: + next_callback=fbl_setup(); + remote_callback = ne260_cb; + break; +#endif + +#if defined(FLYSKY_A7105_INO) + case MODE_FLYSKY: + CTRL1_off; //antenna RF1 + next_callback = initFlySky(); + remote_callback = ReadFlySky; + break; +#endif +#if defined(HUBSAN_A7105_INO) + case MODE_HUBSAN: + CTRL1_off; //antenna RF1 + if(IS_BIND_BUTTON_FLAG_on) random_id(10,true); // Generate new ID if bind button is pressed. + next_callback = initHubsan(); + remote_callback = ReadHubsan; + break; +#endif +#if defined(FRSKY_CC2500_INO) + case MODE_FRSKY: + CTRL1_off; //antenna RF2 + CTRL2_on; + next_callback = initFrSky_2way(); + remote_callback = ReadFrSky_2way; + break; +#endif +#if defined(FRSKYX_CC2500_INO) + case MODE_FRSKYX: + CTRL1_off; //antenna RF2 + CTRL2_on; + next_callback = initFrSkyX(); + remote_callback = ReadFrSkyX; + break; +#endif +#if defined(DSM2_CYRF6936_INO) + case MODE_DSM2: + CTRL2_on; //antenna RF4 + next_callback = initDsm2(); + //Servo_data[2]=1500;//before binding + remote_callback = ReadDsm2; + break; +#endif +#if defined(DEVO_CYRF6936_INO) + case MODE_DEVO: + CTRL2_on; //antenna RF4 + next_callback = DevoInit(); + remote_callback = devo_callback; + break; +#endif +#if defined(HISKY_NRF24L01_INO) + case MODE_HISKY: + next_callback=initHiSky(); + remote_callback = hisky_cb; + break; +#endif +#if defined(V2X2_NRF24L01_INO) + case MODE_V2X2: + next_callback = initV2x2(); + remote_callback = ReadV2x2; + break; +#endif +#if defined(YD717_NRF24L01_INO) + case MODE_YD717: + next_callback=initYD717(); + remote_callback = yd717_callback; + break; +#endif +#if defined(KN_NRF24L01_INO) + case MODE_KN: + next_callback = initKN(); + remote_callback = kn_callback; + break; +#endif +#if defined(SYMAX_NRF24L01_INO) + case MODE_SYMAX: + next_callback = initSymax(); + remote_callback = symax_callback; + break; +#endif +#if defined(SLT_NRF24L01_INO) + case MODE_SLT: + next_callback=initSLT(); + remote_callback = SLT_callback; + break; +#endif +#if defined(CX10_NRF24L01_INO) + case MODE_CX10: + next_callback=initCX10(); + remote_callback = CX10_callback; + break; +#endif +#if defined(CG023_NRF24L01_INO) + case MODE_CG023: + next_callback=initCG023(); + remote_callback = CG023_callback; + break; +#endif +#if defined(BAYANG_NRF24L01_INO) + case MODE_BAYANG: + next_callback=initBAYANG(); + remote_callback = BAYANG_callback; + break; +#endif +#if defined(ESKY_NRF24L01_INO) + case MODE_ESKY: + next_callback=initESKY(); + remote_callback = ESKY_callback; + break; +#endif +#if defined(MT99XX_NRF24L01_INO) + case MODE_MT99XX: + next_callback=initMT99XX(); + remote_callback = MT99XX_callback; + break; +#endif +#if defined(MJXQ_NRF24L01_INO) + case MODE_MJXQ: + next_callback=initMJXQ(); + remote_callback = MJXQ_callback; + break; +#endif +#if defined(SHENQI_NRF24L01_INO) + case MODE_SHENQI: + next_callback=initSHENQI(); + remote_callback = SHENQI_callback; + break; +#endif +#if defined(FY326_NRF24L01_INO) + case MODE_FY326: + next_callback=initFY326(); + remote_callback = FY326_callback; + break; +#endif + } +======= PE1_on; //NRF24L01 antenna RF3 by default PE2_off; //NRF24L01 antenna RF3 by default @@ -721,6 +1135,7 @@ static void protocol_init() #endif #endif } +>>>>>>> refs/remotes/pascallanger/master if(next_callback>32000) { // next_callback should not be more than 32767 so we will wait here... @@ -728,15 +1143,39 @@ static void protocol_init() delayMilliseconds(temp); next_callback-=temp<<10; // between 2-3ms left at this stage } +<<<<<<< HEAD + cli(); // disable global int + OCR1A=TCNT1+next_callback*2; // set compare A for callback + sei(); // enable global int + TIFR1=(1<>>>>>> refs/remotes/pascallanger/master } void update_serial_data() { +<<<<<<< HEAD + if(rx_ok_buff[0]&0x20) //check range + RANGE_FLAG_on; + else + RANGE_FLAG_off; + if(rx_ok_buff[0]&0xC0) //check autobind(0x40) & bind(0x80) together + AUTOBIND_FLAG_on; + else + AUTOBIND_FLAG_off; + if(rx_ok_buff[1]&0x80) //if rx_ok_buff[1] ==1,power is low ,0-power high + POWER_FLAG_off; //power low + else + POWER_FLAG_on; //power high + + option=rx_ok_buff[2]; +======= RX_DONOTUPDTAE_on; RX_FLAG_off; //data is being processed if(rx_ok_buff[1]&0x20) //check range @@ -751,11 +1190,29 @@ void update_serial_data() POWER_FLAG_off; //power low else POWER_FLAG_on; //power high +>>>>>>> refs/remotes/pascallanger/master option=rx_ok_buff[3]; if( (rx_ok_buff[0] != cur_protocol[0]) || ((rx_ok_buff[1]&0x5F) != (cur_protocol[1]&0x5F)) || ( (rx_ok_buff[2]&0x7F) != (cur_protocol[2]&0x7F) ) ) { // New model has been selected +<<<<<<< HEAD + prev_protocol=cur_protocol[0]&0x1F; //store previous protocol so we can reset the module + cur_protocol[1] = rx_ok_buff[1]&0x7F; //store current protocol + CHANGE_PROTOCOL_FLAG_on; //change protocol + sub_protocol=(rx_ok_buff[1]>>4)& 0x07; //subprotocol no (0-7) bits 4-6 + RX_num=rx_ok_buff[1]& 0x0F; + MProtocol_id=MProtocol_id_master+RX_num; //personalized RX bind + rx num // rx_num bits 0---3 + } + else + if( ((rx_ok_buff[0]&0x80)!=0) && ((cur_protocol[0]&0x80)==0) ) // Bind flag has been set + CHANGE_PROTOCOL_FLAG_on; //restart protocol with bind + cur_protocol[0] = rx_ok_buff[0]; //store current protocol + +// decode channel values + volatile uint8_t *p=rx_ok_buff+2; + uint8_t dec=-3; +======= CHANGE_PROTOCOL_FLAG_on; //change protocol protocol=(rx_ok_buff[0]==0x55?0:32) + (rx_ok_buff[1]&0x1F); //protocol no (0-63) bits 4-6 of buff[1] and bit 0 of buf[0] sub_protocol=(rx_ok_buff[2]>>4)& 0x07; //subprotocol no (0-7) bits 4-6 @@ -775,11 +1232,46 @@ void update_serial_data() // decode channel values volatile uint8_t *p=rx_ok_buff+3; uint8_t dec=-3; +>>>>>>> refs/remotes/pascallanger/master for(uint8_t i=0;i=8) { +<<<<<<< HEAD + dec-=8; + p++; + } + p++; + Servo_data[i]=((((*((uint32_t *)p))>>dec)&0x7FF)*5)/8+860; //value range 860<->2140 -125%<->+125% + } + RX_FLAG_off; //data has been processed +} + +static void module_reset() +{ + if(remote_callback) + { // previous protocol loaded + remote_callback = 0; + switch(prev_protocol) + { + case MODE_FLYSKY: + case MODE_HUBSAN: + A7105_Reset(); + break; + case MODE_FRSKY: + case MODE_FRSKYX: + CC2500_Reset(); + break; + case MODE_DSM2: + case MODE_DEVO: + CYRF_Reset(); + break; + default: // MODE_HISKY, MODE_V2X2, MODE_YD717, MODE_KN, MODE_SYMAX, MODE_SLT, MODE_CX10, MODE_CG023, MODE_BAYANG, MODE_ESKY, MODE_MT99XX, MODE_MJXQ, MODE_SHENQI, MODE_FY326 + NRF24L01_Reset(); + break; + } +======= dec-=8; p++; } @@ -796,6 +1288,7 @@ void update_serial_data() { memcpy((void*)rx_ok_buff,(const void*)rx_buff,RXBUFFER_SIZE);// Duplicate the buffer RX_FLAG_on; // data to be processed next time... RX_MISSED_BUFF_off; +>>>>>>> refs/remotes/pascallanger/master } #ifdef XMEGA sei(); @@ -862,15 +1355,35 @@ void Mprotocol_serial_init() #if defined(TELEMETRY) void PPM_Telemetry_serial_init() { +<<<<<<< HEAD + if(Servo_data[ch]>PPM_MAX_100) + return PPM_MAX_100; + else + if (Servo_data[ch]>>>>>> refs/remotes/pascallanger/master } #endif +<<<<<<< HEAD +#if defined(TELEMETRY) +void Serial_write(uint8_t data) +{ + cli(); // disable global int + if(++tx_head>=TXBUFFER_SIZE) + tx_head=0; + tx_buff[tx_head]=data; + sei(); // enable global int + UCSR0B |= (1<>>>>>> refs/remotes/pascallanger/master } static uint32_t random_value(void) { +<<<<<<< HEAD + #include + UBRR0H = UBRRH_VALUE; + UBRR0L = UBRRL_VALUE; + UCSR0A = 0 ; // Clear X2 bit + //Set frame format to 8 data bits, even parity, 2 stop bits + UCSR0C = (1<>>>>>> refs/remotes/pascallanger/master } #endif +#if defined(TELEMETRY) +static void PPM_Telemetry_serial_init() +{ + //9600 bauds + UBRR0H = 0x00; + UBRR0L = 0x67; + UCSR0A = 0 ; // Clear X2 bit + //Set frame format to 8 data bits, none, 1 stop bit + UCSR0C = (1<> 24) & 0xFF; + rx_tx_addr[1] = (id >> 16) & 0xFF; + rx_tx_addr[2] = (id >> 8) & 0xFF; + rx_tx_addr[3] = (id >> 0) & 0xFF; + rx_tx_addr[4] = 0xC1; // for YD717: always uses first data port +} + static uint32_t random_id(uint16_t adress, uint8_t create_new) { uint32_t id; @@ -928,6 +1479,13 @@ static uint32_t random_id(uint16_t adress, uint8_t create_new) /**************************/ //PPM +<<<<<<< HEAD +ISR(INT1_vect) +{ // Interrupt on PPM pin + static int8_t chan=-1; + static uint16_t Prev_TCNT1=0; + uint16_t Cur_TCNT1; +======= #ifdef ENABLE_PPM #ifdef XMEGA #if PPM_pin == 2 @@ -946,6 +1504,7 @@ static uint32_t random_id(uint16_t adress, uint8_t create_new) static int8_t chan=-1; static uint16_t Prev_TCNT1=0; uint16_t Cur_TCNT1; +>>>>>>> refs/remotes/pascallanger/master Cur_TCNT1 = TCNT1 - Prev_TCNT1 ; // Capture current Timer1 value if(Cur_TCNT1<1000) @@ -956,6 +1515,19 @@ static uint32_t random_id(uint16_t adress, uint8_t create_new) chan=0; // start of frame PPM_FLAG_on; // full frame present (even at startup since PPM_data has been initialized) } +<<<<<<< HEAD + Prev_TCNT1+=Cur_TCNT1; +} + +//Serial RX +ISR(USART_RX_vect) +{ // RX interrupt + if((UCSR0A&0x1C)==0) // Check frame error, data overrun and parity error + { // received byte is ok to process + if(idx==0) + { // Let's try to sync at this point + if(UDR0==0x55) // If 1st byte is 0x55 it looks ok +======= else if(chan!=-1) // need to wait for start of frame { //servo values between 500us and 2420us will end up here @@ -1000,6 +1572,7 @@ static uint32_t random_id(uint16_t adress, uint8_t create_new) } } else +>>>>>>> refs/remotes/pascallanger/master { rx_buff[idx++]=UDR0; // Store received byte if(idx>=RXBUFFER_SIZE) @@ -1070,4 +1643,30 @@ static uint32_t random_id(uint16_t adress, uint8_t create_new) WDTCSR = 0; // Disable Watchdog interrupt } } +<<<<<<< HEAD +} + +//Serial timer +ISR(TIMER1_COMPB_vect) +{ // Timer1 compare B interrupt + idx=0; +} + +#if defined(TELEMETRY) +//Serial TX +ISR(USART_UDRE_vect) +{ // Transmit interrupt + uint8_t t = tx_tail; + if(tx_head!=t) + { + if(++t>=TXBUFFER_SIZE)//head + t=0; + UDR0=tx_buff[t]; + tx_tail=t; + } + if (t == tx_head) + UCSR0B &= ~(1<>>>>>> refs/remotes/pascallanger/master #endif diff --git a/Multiprotocol/NRF24l01_SPI.ino b/Multiprotocol/NRF24l01_SPI.ino index 8627efa..dc740c5 100644 --- a/Multiprotocol/NRF24l01_SPI.ino +++ b/Multiprotocol/NRF24l01_SPI.ino @@ -234,7 +234,11 @@ uint8_t NRF24L01_packet_ack() /////////////// // XN297 emulation layer +<<<<<<< HEAD +uint8_t xn297_scramble_enabled; +======= uint8_t xn297_scramble_enabled=XN297_SCRAMBLED; //enabled by default +>>>>>>> refs/remotes/pascallanger/master uint8_t xn297_addr_len; uint8_t xn297_tx_addr[5]; uint8_t xn297_rx_addr[5]; @@ -247,6 +251,16 @@ static const uint8_t xn297_scramble[] = { 0x1b, 0x5d, 0x19, 0x10, 0x24, 0xd3, 0xdc, 0x3f, 0x8e, 0xc5, 0x2f}; +<<<<<<< HEAD +const uint16_t PROGMEM xn297_crc_xorout[] = { + 0x0000, 0x3d5f, 0xa6f1, 0x3a23, 0xaa16, 0x1caf, + 0x62b2, 0xe0eb, 0x0821, 0xbe07, 0x5f1a, 0xaf15, + 0x4f0a, 0xad24, 0x5e48, 0xed34, 0x068c, 0xf2c9, + 0x1852, 0xdf36, 0x129d, 0xb17c, 0xd5f5, 0x70d7, + 0xb798, 0x5133, 0x67db, 0xd94e}; + +======= +>>>>>>> refs/remotes/pascallanger/master const uint16_t PROGMEM xn297_crc_xorout_scrambled[] = { 0x0000, 0x3448, 0x9BA7, 0x8BBB, 0x85E1, 0x3E8C, 0x451E, 0x18E6, 0x6B24, 0xE7AB, 0x3828, 0x814B, @@ -320,8 +334,14 @@ void XN297_SetRXAddr(const uint8_t* addr, uint8_t len) NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, buf, 5); } -void XN297_Configure(uint8_t flags) +void XN297_Configure(uint16_t flags) { +<<<<<<< HEAD + xn297_scramble_enabled = !(flags & BV(XN297_UNSCRAMBLED)); + xn297_crc = !!(flags & BV(NRF24L01_00_EN_CRC)); + flags &= ~(BV(NRF24L01_00_EN_CRC) | BV(NRF24L01_00_CRCO)); + NRF24L01_WriteReg(NRF24L01_00_CONFIG, flags & 0xFF); +======= xn297_crc = !!(flags & _BV(NRF24L01_00_EN_CRC)); flags &= ~(_BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO)); NRF24L01_WriteReg(NRF24L01_00_CONFIG, flags & 0xFF); @@ -330,6 +350,7 @@ void XN297_Configure(uint8_t flags) void XN297_SetScrambledMode(const u8 mode) { xn297_scramble_enabled = mode; +>>>>>>> refs/remotes/pascallanger/master } void XN297_WritePayload(uint8_t* msg, uint8_t len) @@ -391,6 +412,32 @@ void XN297_ReadPayload(uint8_t* msg, uint8_t len) // End of XN297 emulation /////////////// +<<<<<<< HEAD +// LT8910 emulation layer +uint8_t LT8910_buffer[64]; +uint8_t LT8910_buffer_start; +uint16_t LT8910_buffer_overhead_bits; +uint8_t LT8910_addr[8]; +uint8_t LT8910_addr_size; +uint8_t LT8910_Preamble_Len; +uint8_t LT8910_Tailer_Len; +uint8_t LT8910_CRC_Initial_Data; +uint8_t LT8910_Flags; +#define LT8910_CRC_ON 6 +#define LT8910_SCRAMBLE_ON 5 +#define LT8910_PACKET_LENGTH_EN 4 +#define LT8910_DATA_PACKET_TYPE_1 3 +#define LT8910_DATA_PACKET_TYPE_0 2 +#define LT8910_FEC_TYPE_1 1 +#define LT8910_FEC_TYPE_0 0 + +void LT8910_Config(uint8_t preamble_len, uint8_t trailer_len, uint8_t flags, uint8_t crc_init) +{ + //Preamble 1 to 8 bytes + LT8910_Preamble_Len=preamble_len; + //Trailer 4 to 18 bits + LT8910_Tailer_Len=trailer_len; +======= // LT8900 emulation layer uint8_t LT8900_buffer[64]; uint8_t LT8900_buffer_start; @@ -415,23 +462,37 @@ void LT8900_Config(uint8_t preamble_len, uint8_t trailer_len, uint8_t flags, uin LT8900_Preamble_Len=preamble_len; //Trailer 4 to 18 bits LT8900_Tailer_Len=trailer_len; +>>>>>>> refs/remotes/pascallanger/master //Flags // CRC_ON: 1 on, 0 off // SCRAMBLE_ON: 1 on, 0 off // PACKET_LENGTH_EN: 1 1st byte of payload is payload size // DATA_PACKET_TYPE: 00 NRZ, 01 Manchester, 10 8bit/10bit line code, 11 interleave data type // FEC_TYPE: 00 No FEC, 01 FEC13, 10 FEC23, 11 reserved +<<<<<<< HEAD + LT8910_Flags=flags; + //CRC init constant + LT8910_CRC_Initial_Data=crc_init; +} + +void LT8910_SetChannel(uint8_t channel) +======= LT8900_Flags=flags; //CRC init constant LT8900_CRC_Initial_Data=crc_init; } void LT8900_SetChannel(uint8_t channel) +>>>>>>> refs/remotes/pascallanger/master { NRF24L01_WriteReg(NRF24L01_05_RF_CH, channel +2); //NRF24L01 is 2400+channel but LT8900 is 2402+channel } +<<<<<<< HEAD +void LT8910_SetTxRxMode(enum TXRX_State mode) +======= void LT8900_SetTxRxMode(enum TXRX_State mode) +>>>>>>> refs/remotes/pascallanger/master { if(mode == TX_EN) { @@ -457,12 +518,35 @@ void LT8900_SetTxRxMode(enum TXRX_State mode) NRF24L01_SetTxRxMode(TXRX_OFF); } +<<<<<<< HEAD +void LT8910_BuildOverhead() +======= void LT8900_BuildOverhead() +>>>>>>> refs/remotes/pascallanger/master { uint8_t pos; //Build overhead //preamble +<<<<<<< HEAD + memset(LT8910_buffer,LT8910_addr[0]&0x01?0xAA:0x55,LT8910_Preamble_Len-1); + pos=LT8910_Preamble_Len-1; + //address + for(uint8_t i=0;i5?5:pos; +} + +void LT8910_SetAddress(uint8_t *address,uint8_t addr_size) +======= memset(LT8900_buffer,LT8900_addr[0]&0x01?0xAA:0x55,LT8900_Preamble_Len-1); pos=LT8900_Preamble_Len-1; //address @@ -480,10 +564,33 @@ void LT8900_BuildOverhead() } void LT8900_SetAddress(uint8_t *address,uint8_t addr_size) +>>>>>>> refs/remotes/pascallanger/master { uint8_t addr[5]; //Address size (SyncWord) 2 to 8 bytes, 16/32/48/64 bits +<<<<<<< HEAD + LT8910_addr_size=addr_size; + memcpy(LT8910_addr,address,LT8910_addr_size); + + //Build overhead + LT8910_BuildOverhead(); + + //Set NRF RX&TX address based on overhead content + NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, LT8910_buffer_start-2); + for(uint8_t i=0;i>>>>>> refs/remotes/pascallanger/master //Read payload NRF24L01_ReadPayload(buffer,end+1); //Check address + trail for(i=0;i>>>>>> refs/remotes/pascallanger/master for(i=pos;i>8)&0xFF; } //Check len +<<<<<<< HEAD + if(LT8910_Flags&_BV(LT8910_PACKET_LENGTH_EN)) +======= if(LT8900_Flags&_BV(LT8900_PACKET_LENGTH_EN)) +>>>>>>> refs/remotes/pascallanger/master { crc=crc16_update(crc,buffer[pos]); if(bit_reverse(len)!=buffer[pos++]) @@ -533,7 +652,11 @@ uint8_t LT8900_ReadPayload(uint8_t* msg, uint8_t len) msg[i]=bit_reverse(buffer[pos++]); } //Check CRC +<<<<<<< HEAD + if(LT8910_Flags&_BV(LT8910_CRC_ON)) +======= if(LT8900_Flags&_BV(LT8900_CRC_ON)) +>>>>>>> refs/remotes/pascallanger/master { if(buffer[pos++]!=((crc>>8)&0xFF)) return 0; // wrong CRC... if(buffer[pos]!=(crc&0xFF)) return 0; // wrong CRC... @@ -542,12 +665,21 @@ uint8_t LT8900_ReadPayload(uint8_t* msg, uint8_t len) return 1; } +<<<<<<< HEAD +void LT8910_WritePayload(uint8_t* msg, uint8_t len) +{ + unsigned int crc=LT8910_CRC_Initial_Data,a,mask; + uint8_t i, pos=0,tmp, buffer[64], pos_final,shift; + //Add packet len + if(LT8910_Flags&_BV(LT8910_PACKET_LENGTH_EN)) +======= void LT8900_WritePayload(uint8_t* msg, uint8_t len) { unsigned int crc=LT8900_CRC_Initial_Data,a,mask; uint8_t i, pos=0,tmp, buffer[64], pos_final,shift; //Add packet len if(LT8900_Flags&_BV(LT8900_PACKET_LENGTH_EN)) +>>>>>>> refs/remotes/pascallanger/master { tmp=bit_reverse(len); buffer[pos++]=tmp; @@ -561,12 +693,27 @@ void LT8900_WritePayload(uint8_t* msg, uint8_t len) crc=crc16_update(crc,tmp); } //Add CRC +<<<<<<< HEAD + if(LT8910_Flags&_BV(LT8910_CRC_ON)) +======= if(LT8900_Flags&_BV(LT8900_CRC_ON)) +>>>>>>> refs/remotes/pascallanger/master { buffer[pos++]=crc>>8; buffer[pos++]=crc; } //Shift everything to fit behind the trailer (4 to 18 bits) +<<<<<<< HEAD + shift=LT8910_buffer_overhead_bits&0x7; + pos_final=LT8910_buffer_overhead_bits/8; + mask=~(0xFF<<(8-shift)); + LT8910_buffer[pos_final+pos]=0xFF; + for(i=pos-1;i!=0xFF;i--) + { + a=buffer[i]<<(8-shift); + LT8910_buffer[pos_final+i]=(LT8910_buffer[pos_final+i]&mask>>8)|a>>8; + LT8910_buffer[pos_final+i+1]=(LT8910_buffer[pos_final+i+1]&mask)|a; +======= shift=LT8900_buffer_overhead_bits&0x7; pos_final=LT8900_buffer_overhead_bits/8; mask=~(0xFF<<(8-shift)); @@ -576,10 +723,17 @@ void LT8900_WritePayload(uint8_t* msg, uint8_t len) a=buffer[i]<<(8-shift); LT8900_buffer[pos_final+i]=(LT8900_buffer[pos_final+i]&mask>>8)|a>>8; LT8900_buffer[pos_final+i+1]=(LT8900_buffer[pos_final+i+1]&mask)|a; +>>>>>>> refs/remotes/pascallanger/master } if(shift) pos++; //Send everything +<<<<<<< HEAD + NRF24L01_WritePayload(LT8910_buffer+LT8910_buffer_start,pos_final+pos-LT8910_buffer_start); +} +// End of LT8910 emulation +======= NRF24L01_WritePayload(LT8900_buffer+LT8900_buffer_start,pos_final+pos-LT8900_buffer_start); } // End of LT8900 emulation +>>>>>>> refs/remotes/pascallanger/master diff --git a/Multiprotocol/Nrf24l01_bluefly.ino b/Multiprotocol/Nrf24l01_bluefly.ino new file mode 100644 index 0000000..3a7f918 --- /dev/null +++ b/Multiprotocol/Nrf24l01_bluefly.ino @@ -0,0 +1,150 @@ +/* + This project is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Deviation is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Deviation. If not, see . + */ + +#if defined(BlueFly_NRF24L01_INO) +#include "iface_nrf24l01.h" + +#define BIND_BlueFly_COUNT 800 + +#define TXID_BlueFly_SIZE 5 + +#define PAYLOAD_BlueFly_SIZE 12 +// available frequency must be in between 2402 and 2477 +static uint8_t hopping_frequency_start; + +static uint8_t bluefly_binding_adr_rf[TXID_BlueFly_SIZE]={0x32,0xaa,0x45,0x45,0x78}; // fixed binding ids for all planes + +static uint8_t bind_payload[PAYLOAD_BlueFly_SIZE]; + +static unsigned int ch_data_bluefly[8]; + + +static void bluefly_binding_packet(void) +{ + int i; + for (i = 0; i < TXID_BlueFly_SIZE; ++i) + bind_payload[i] = rx_tx_addr[i]; + bind_payload[i++] = hopping_frequency_start; + for (; i < PAYLOAD_BlueFly_SIZE; ++i) bind_payload[i] = 0x55; +} + +static void bluefly_init() { + NRF24L01_Initialize(); + + NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable p0 rx + NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknoledgement + NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_addr, 5); + NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, rx_tx_addr, 5); + NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, PAYLOAD_BlueFly_SIZE); // payload size = 12 + NRF24L01_WriteReg(NRF24L01_05_RF_CH, 81); // binding packet must be set in channel 81 + + // 2-bytes CRC, radio on + NRF24L01_WriteReg(NRF24L01_00_CONFIG, BV(NRF24L01_00_EN_CRC) | BV(NRF24L01_00_CRCO) | BV(NRF24L01_00_PWR_UP)); + NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x03); // 5-byte RX/TX address (byte -2) + NRF24L01_SetBitrate(NRF24L01_BR_250K); // BlueFly - 250kbps + NRF24L01_SetPower(); + NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit +} + +// HiSky channel sequence: AILE ELEV THRO RUDD GEAR PITCH, channel data value is from 0 to 1000 +static void bluefly_ch_data() { + uint32_t temp; + int i; + for (i = 0; i< 8; ++i) { + temp = (uint32_t)Servo_data[ch[i]] * 300/PPM_MAX + 500; // 200-800 range + if (temp < 0) + ch_data_bluefly[i] = 0; + else if (temp > 1000) + ch_data_bluefly[i] = 1000; + else + ch_data_bluefly[i] = (unsigned int)temp; + + packet[i] = (uint8_t)ch_data_bluefly[i]; + } + + packet[8] = (uint8_t)((ch_data_bluefly[0]>>8)&0x0003); + packet[8] |= (uint8_t)((ch_data_bluefly[1]>>6)&0x000c); + packet[8] |= (uint8_t)((ch_data_bluefly[2]>>4)&0x0030); + packet[8] |= (uint8_t)((ch_data_bluefly[3]>>2)&0x00c0); + + packet[9] = (uint8_t)((ch_data_bluefly[4]>>8)&0x0003); + packet[9] |= (uint8_t)((ch_data_bluefly[5]>>6)&0x000c); + packet[9] |= (uint8_t)((ch_data_bluefly[6]>>4)&0x0030); + packet[9] |= (uint8_t)((ch_data_bluefly[7]>>2)&0x00c0); + + unsigned char l, h, t; + l = h = 0xff; + for (int i=0; i<10; ++i) { + h ^= packet[i]; + h ^= h >> 4; + t = h; + h = l; + l = t; + t = (l<<4) | (l>>4); + h ^= ((t<<2) | (t>>6)) & 0x1f; + h ^= t & 0xf0; + l ^= ((t<<1) | (t>>7)) & 0xe0; + } + // Checksum + packet[10] = h; + packet[11] = l; +} + +static uint16_t bluefly_cb() { + switch(phase++) { + case 0: + bluefly_ch_data(); + break; + case 1: + NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_addr, 5); + NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency_start + hopping_frequency_no*2); + hopping_frequency_no++; + hopping_frequency_no %= 15; + NRF24L01_FlushTx(); + NRF24L01_WritePayload(packet, PAYLOAD_BlueFly_SIZE); + break; + case 2: + break; + case 3: + if (bind_phase>0) { + bind_phase--; + if (! bind_phase) { BIND_DONE; } + NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, bluefly_binding_adr_rf, 5); + NRF24L01_WriteReg(NRF24L01_05_RF_CH, 81); + NRF24L01_FlushTx(); + NRF24L01_WritePayload(bind_payload, PAYLOAD_BlueFly_SIZE); + } + break; + case 4: + break; + case 5: + NRF24L01_SetPower(); + /* FALLTHROUGH */ + default: + phase = 0; + break; + } + return 1000; // send 1 binding packet and 1 data packet per 9ms +} + +static uint16_t BlueFly_setup() { + hopping_frequency_start = ((MProtocol_id >> 8) % 47) + 2; + bluefly_binding_packet(); + bluefly_init(); + if(IS_AUTOBIND_FLAG_on) { bind_phase = BIND_BlueFly_COUNT; } else { bind_phase = 0; } + + return 1000; +} +#endif diff --git a/Multiprotocol/Nrf24l01_cflie.ino b/Multiprotocol/Nrf24l01_cflie.ino new file mode 100644 index 0000000..d4b0208 --- /dev/null +++ b/Multiprotocol/Nrf24l01_cflie.ino @@ -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 . + */ + +/* 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 diff --git a/Multiprotocol/Nrf24l01_esky150.ino b/Multiprotocol/Nrf24l01_esky150.ino new file mode 100644 index 0000000..b3d9c43 --- /dev/null +++ b/Multiprotocol/Nrf24l01_esky150.ino @@ -0,0 +1,172 @@ +/* + This project is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Deviation is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Deviation. If not, see . + */ + +#if defined(ESKY150_NRF24L01_INO) +#include "iface_nrf24l01.h" + + +// Timeout for callback in uSec, 4.8ms=4800us for ESky150 +#define ESKY150_PERIOD 4800 +#define ESKY150_CHKTIME 100 // Time to wait for packet to be sent (no ACK, so very short) + +#define esky150_PAYLOADSIZE 15 +#define ADDR_esky150_SIZE 4 + +static uint32_t total_packets; +enum { + ESKY150_INIT2 = 0, + ESKY150_DATA +}; + + +static uint8_t esky150_packet_ack() { + switch (NRF24L01_ReadReg(NRF24L01_07_STATUS) & (BV(NRF24L01_07_TX_DS) | BV(NRF24L01_07_MAX_RT))) { + case BV(NRF24L01_07_TX_DS): return PKT_ACKED; + case BV(NRF24L01_07_MAX_RT): return PKT_TIMEOUT; + } + return PKT_PENDING; +} + +// 2-bytes CRC +#define CRC_CONFIG (BV(NRF24L01_00_EN_CRC) | BV(NRF24L01_00_CRCO)) +static uint16_t esky150_init() { + uint8_t rx_addr[ADDR_esky150_SIZE] = { 0x73, 0x73, 0x74, 0x63 }; + uint8_t tx_addr[ADDR_esky150_SIZE] = { 0x71, 0x0A, 0x31, 0xF4 }; + NRF24L01_Initialize(); + + NRF24L01_WriteReg(NRF24L01_00_CONFIG, CRC_CONFIG); + NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknoledgement + NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0 + NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, ADDR_esky150_SIZE-2); // 4-byte RX/TX address + NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0); // Disable retransmit + NRF24L01_SetPower(); + NRF24L01_SetBitrate(NRF24L01_BR_2M); + NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, rx_addr, ADDR_esky150_SIZE); + NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, tx_addr, ADDR_esky150_SIZE); + + + NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit + NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, esky150_PAYLOADSIZE); // bytes of data payload for pipe 0 + + + NRF24L01_Activate(0x73); + NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 1); // Dynamic payload for data pipe 0 + // Enable: Dynamic Payload Length, Payload with ACK , W_TX_PAYLOAD_NOACK + NRF24L01_WriteReg(NRF24L01_1D_FEATURE, BV(NRF2401_1D_EN_DPL) | BV(NRF2401_1D_EN_ACK_PAY) | BV(NRF2401_1D_EN_DYN_ACK)); + + // Delay 50 ms + return 50000; +} + + +static uint16_t esky150_init2() { + NRF24L01_FlushTx(); + NRF24L01_FlushRx(); + packet_sent = 0; + packet_count = 0; + rf_ch_num = 0; + + // Turn radio power on + NRF24L01_SetTxRxMode(TX_EN); + NRF24L01_WriteReg(NRF24L01_00_CONFIG, CRC_CONFIG | BV(NRF24L01_00_PWR_UP)); + // delayMicroseconds(150); + return 150; +} + + +static void calc_fh_channels(uint32_t seed) { + // Use channels 2..79 + uint8_t first = seed % 37 + 2; + uint8_t second = first + 40; + hopping_frequency[0] = first; // 0x22; + hopping_frequency[1] = second; // 0x4a; +} + + +static uint8_t convert_channel(uint8_t num) { + uint32_t ch = Servo_data[num]; + if (ch < PPM_MIN) { ch = PPM_MIN; } + else if (ch > PPM_MAX) { ch = PPM_MAX; } + return (uint8_t) ((ch * 500 / PPM_MAX) + 1500); +} +static void read_controls(uint8_t* throttle, uint8_t* aileron, uint8_t* elevator, uint8_t* rudder) { + *throttle = convert_channel(THROTTLE); + *aileron = convert_channel(AILERON); + *elevator = convert_channel(ELEVATOR); + *rudder = convert_channel(RUDDER); +} + + +static void esky150_send_packet() { + uint8_t rf_ch = hopping_frequency[rf_ch_num]; + rf_ch_num = 1 - rf_ch_num; + + read_controls(&throttle, &aileron, &elevator, &rudder); + + packet[0] = hopping_frequency[0]; + packet[1] = hopping_frequency[1]; + packet[2] = (throttle >> 8) & 0xFF; + packet[3] = throttle & 0xFF; + packet[4] = (aileron >> 8) & 0xFF; + packet[5] = aileron & 0xFF; + packet[6] = (elevator >> 8) & 0xFF; + packet[7] = elevator & 0xFF; + packet[8] = (rudder >> 8) & 0xFF; + packet[9] = rudder & 0xFF; + // Constant values 00 d8 18 f8 + packet[10] = 0x00; + packet[11] = 0xd8; + packet[12] = 0x18; + packet[13] = 0xf8; + uint8_t sum = 0; + for (int i = 0; i < 14; ++i) sum += packet[i]; + packet[14] = sum; + + packet_sent = 0; + NRF24L01_WriteReg(NRF24L01_05_RF_CH, rf_ch); + NRF24L01_FlushTx(); + NRF24L01_WritePayload(packet, sizeof(packet)); + ++total_packets; + packet_sent = 1; +} + +static uint16_t esky150_callback() { + uint16_t timeout = ESKY150_PERIOD; + switch (phase) { + case ESKY150_INIT2: + timeout = esky150_init2(); + phase = ESKY150_DATA; + break; + case ESKY150_DATA: + if (packet_count == 4) + packet_count = 0; + else { + if (packet_sent && esky150_packet_ack() != PKT_ACKED) { + return ESKY150_CHKTIME; + } + esky150_send_packet(); + } + break; + } + return timeout; +} + +static uint16_t esky150_setup() { + total_packets = 0; + uint16_t timeout = esky150_init(); + + return timeout; +} +#endif diff --git a/Multiprotocol/Nrf24l01_fbl100.ino b/Multiprotocol/Nrf24l01_fbl100.ino new file mode 100644 index 0000000..f25e368 --- /dev/null +++ b/Multiprotocol/Nrf24l01_fbl100.ino @@ -0,0 +1,282 @@ +/* + This project is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + + Deviation is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with Deviation. If not, see . + + rewrite v977/v966 protocol to improve reliability + */ + +#if defined(FBL100_NRF24L01_INO) +#include "iface_nrf24l01.h" + +#define BIND_FBL_COUNT 800 +#define FBL_SIZE 5 +#define FREQUENCE_FBL_NUM 20 + +static uint8_t binding_fbl_adr_rf[5]; // fixed binding ids for all planes + +static uint8_t bind_fbl_buf_array[4][10]; + +static unsigned int fbl_data[8]; + + +// HiSky protocol uses TX id as an address for nRF24L01, and uses frequency hopping sequence +// which does not depend on this id and is passed explicitly in binding sequence. So we are free +// to generate this sequence as we wish. It should be in the range [02..77] +static void calc_fbl_channels() { + int idx = 0; + uint32_t rnd = MProtocol_id; + while (idx < FREQUENCE_FBL_NUM) { + int i; + int count_2_26 = 0, count_27_50 = 0, count_51_74 = 0; + rnd = rnd * 0x0019660D + 0x3C6EF35F; // Randomization + + // Use least-significant byte. 73 is prime, so channels 76..77 are unused + uint8_t next_ch = ((rnd >> 8) % 73) + 2; + // Keep the distance 2 between the channels - either odd or even + if (((next_ch ^ MProtocol_id) & 0x01 )== 0) { continue; } + // Check that it's not duplicate and spread uniformly + for (i = 0; i < idx; i++) { + if(hopping_frequency[i] == next_ch) { break; } + if(hopping_frequency[i] <= 26) { count_2_26++; } + else if (hopping_frequency[i] <= 50) { count_27_50++; } + else { count_51_74++; } + } + if (i != idx) { continue; } + if ((next_ch <= 26 && count_2_26 < 8) ||(next_ch >= 27 && next_ch <= 50 && count_27_50 < 8) ||(next_ch >= 51 && count_51_74 < 8)) { + hopping_frequency[idx++] = next_ch; + } + } +} + +static void fbl100_build_binding_packet(void) { + uint8_t i; + unsigned int sum; + uint8_t sum_l,sum_h; + + sum = 0; + for(i=0;i<5;i++) { sum += rx_tx_addr[i]; } + sum_l = (uint8_t)sum; + sum >>= 8; + sum_h = (uint8_t)sum; + bind_fbl_buf_array[0][0] = 0xff; + bind_fbl_buf_array[0][1] = 0xaa; + bind_fbl_buf_array[0][2] = 0x55; + for(i=3;i<8;i++) { bind_fbl_buf_array[0][i] = rx_tx_addr[i-3]; } + + for(i=1;i<4;i++) { + bind_fbl_buf_array[i][0] = sum_l; + bind_fbl_buf_array[i][1] = sum_h; + bind_fbl_buf_array[i][2] = i-1; + } + for(i=0;i<7;i++) { bind_fbl_buf_array[1][i+3] = hopping_frequency[i]; } + for(i=0;i<7;i++) { bind_fbl_buf_array[2][i+3] = hopping_frequency[i+7]; } + for(i=0;i<6;i++) { bind_fbl_buf_array[3][i+3] = hopping_frequency[i+14]; } + + binding_idx = 0; +} + +static void hp100_build_binding_packet(void) { + memcpy(packet, rx_tx_addr, 5); + packet[5] = hopping_frequency[0]; // start address + for (uint8_t i = 6; i < 12; i++) { packet[i] = 0x55; } +} + +static void config_nrf24l01() { + NRF24L01_Initialize(); + + NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable p0 rx + NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // 0:No Auto Acknoledgement; 1:Auto Acknoledgement + NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, packet_length); // fbl100/v922's packet size = 10, hp100 = 12 + // 2-bytes CRC, radio off + NRF24L01_WriteReg(NRF24L01_00_CONFIG, BV(NRF24L01_00_EN_CRC) | BV(NRF24L01_00_CRCO) | BV(NRF24L01_00_PWR_UP)); + NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x03); // 5-byte RX/TX address (byte -2) + NRF24L01_SetBitrate(sub_protocol == HP100? NRF24L01_BR_250K:NRF24L01_BR_1M); //hp100:250kbps; fbl100: 1Mbps + NRF24L01_SetPower(); + + NRF24L01_FlushTx(); + NRF24L01_FlushRx(); + NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); +} + +// FBL100 channel sequence: AILE ELEV THRO RUDD GEAR PITH, channel data value is from 0 to 1000 +static void fbl100_build_ch_data() { + uint32_t temp; + uint8_t i; + for (i = 0; i< 8; i++) { + temp = (uint32_t)Servo_data[i] * 500/PPM_MAX + 500; + if (i == 2) { temp = 1000 -temp; } // It is clear that fbl100's thro stick is made reversely,so I adjust it here on purposely + if (temp < 0) { fbl_data[i] = 0; } + else if (temp > 1000) { fbl_data[i] = 1000; } + else { fbl_data[i] = (unsigned int)temp; } + packet[i] = (uint8_t)fbl_data[i]; + } + + packet[8] = (uint8_t)((fbl_data[0]>>8)&0x0003); + packet[8] |= (uint8_t)((fbl_data[1]>>6)&0x000c); + packet[8] |= (uint8_t)((fbl_data[2]>>4)&0x0030); + packet[8] |= (uint8_t)((fbl_data[3]>>2)&0x00c0); + + packet[9] = (uint8_t)((fbl_data[4]>>8)&0x0003); + packet[9] |= (uint8_t)((fbl_data[5]>>6)&0x000c); + packet[9] |= (uint8_t)((fbl_data[6]>>4)&0x0030); + packet[9] |= (uint8_t)((fbl_data[7]>>2)&0x00c0); +} + +static void hp100_build_ch_data() { + uint32_t temp; + uint8_t i; + for (i = 0; i< 8; i++) { + temp = (uint32_t)Servo_data[i] * 300/PPM_MAX + 500; + if (temp < 0) { temp = 0; } + else if (temp > 1000) { temp = 1000; } + if (i == 3 || i == 5) { temp = 1000 -temp; } // hp100's rudd and pit channel are made reversely,so I adjust them on purposely + + fbl_data[i] = (unsigned int)temp; + packet[i] = (uint8_t)fbl_data[i]; + } + + packet[8] = (uint8_t)((fbl_data[0]>>8)&0x0003); + packet[8] |= (uint8_t)((fbl_data[1]>>6)&0x000c); + packet[8] |= (uint8_t)((fbl_data[2]>>4)&0x0030); + packet[8] |= (uint8_t)((fbl_data[3]>>2)&0x00c0); + + packet[9] = (uint8_t)((fbl_data[4]>>8)&0x0003); + packet[9] |= (uint8_t)((fbl_data[5]>>6)&0x000c); + packet[9] |= (uint8_t)((fbl_data[6]>>4)&0x0030); + packet[9] |= (uint8_t)((fbl_data[7]>>2)&0x00c0); + + unsigned char l, h, t; + l=h=0xff; + for(i=0; i<10; i++ ) { + h ^= packet[i]; + h ^= h>>4; + t = h; + h = l; + l = t; + t = (l<<4) | (l>>4); + h^=((t<<2) | (t>>6)) & 0x1f; + h^=t&0xf0; + l^=((t<<1) | (t>>7)) & 0xe0; + } + packet[10] = h; + packet[11] = l; +} + + +static uint16_t fbl100_cb() { + switch(phase) { + case 0: + fbl100_build_ch_data(); + break; + case 1: + NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_addr, 5); + NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no]); + hopping_frequency_no++; + if (hopping_frequency_no >= FREQUENCE_FBL_NUM) { hopping_frequency_no = 0; } + break; + case 2: + NRF24L01_FlushTx(); + NRF24L01_WritePayload(packet, packet_length); + break; + case 3: + break; + case 4: + if (bind_phase>0) { + NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, binding_fbl_adr_rf, 5); + NRF24L01_WriteReg(NRF24L01_05_RF_CH, 81); + } + break; + case 5: + if (bind_phase >0) { + bind_phase--; + if (! bind_phase) { BIND_DONE; } // binding finished, change tx add + NRF24L01_FlushTx(); // must be invoked before NRF24L01_WritePayload() + NRF24L01_WritePayload(bind_fbl_buf_array[binding_idx], packet_length); + binding_idx++; + if (binding_idx >= 4) + binding_idx = 0; + } + break; + case 6: + break; + case 7: + NRF24L01_SetPower(); + break; + default: + break; + } + phase++; + if (phase >=9) { phase = 0; } // send 1 binding packet and 1 data packet per 9ms + return 1000; +} + +static uint16_t hp100_cb() { + switch(phase) { + case 0: + hp100_build_ch_data(); + break; + case 1: + NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_addr, 5); + NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[0] + hopping_frequency_no*2); + hopping_frequency_no++; + hopping_frequency_no %= 15; + NRF24L01_FlushTx(); + NRF24L01_WritePayload(packet, packet_length); + break; + case 2: + if(bind_phase>0) { hp100_build_binding_packet(); } + break; + case 3: + if (bind_phase>0) { + bind_phase--; + if (! bind_phase) { BIND_DONE; } + NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, binding_fbl_adr_rf, 5); + NRF24L01_WriteReg(NRF24L01_05_RF_CH, 81); + NRF24L01_FlushTx(); + NRF24L01_WritePayload(packet, packet_length); + } + break; + case 4: + break; + case 5: + NRF24L01_SetPower(); + break; + default: + break; + } + phase++; + if (phase >= 6) { phase = 0; } // send 1 binding packet and 1 data packet per 10ms + return 1000; +} + +static uint8_t fbl_setup() { + calc_fbl_channels(); + + printf("FH Seq: "); + for (int i = 0; i < FREQUENCE_FBL_NUM; ++i) { printf("%d, ", hopping_frequency[i]); } + printf("\r\n"); + + // debut init + if (sub_protocol == HP100) { + packet_length = 12; + binding_fbl_adr_rf[0] = 0x32; binding_fbl_adr_rf[1] = 0xaa; binding_fbl_adr_rf[2] = 0x45; + binding_fbl_adr_rf[3] = 0x45; binding_fbl_adr_rf[4] = 0x78; + } else { + packet_length = 10; + binding_fbl_adr_rf[0] = 0x12; binding_fbl_adr_rf[1] = 0x23; binding_fbl_adr_rf[2] = 0x23; + binding_fbl_adr_rf[3] = 0x45; binding_fbl_adr_rf[4] = 0x78; + fbl100_build_binding_packet(); + } + config_nrf24l01(); + + if(IS_AUTOBIND_FLAG_on) { bind_phase = BIND_FBL_COUNT; } + else { bind_phase = 0; } + +// CLOCK_StartTimer(1000, sub_protocol == HP100?hp100_cb:fbl100_cb); +} +#endif \ No newline at end of file diff --git a/Multiprotocol/Nrf24l01_h377.ino b/Multiprotocol/Nrf24l01_h377.ino new file mode 100644 index 0000000..439178d --- /dev/null +++ b/Multiprotocol/Nrf24l01_h377.ino @@ -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 . +*/ + +#if defined (H377_NRF24L01_INO) +#include "iface_nrf24l01.h" + +#define BIND_COUNT 800 + + +#define TXID_H377_SIZE 5 + +#define FREQUENCE_NUM_H377 20 +#define SET_NUM_H377 9 +// available frequency must be in between 2402 and 2477 + +static uint8_t binding_ch=0x50; +static uint8_t hopping_frequency_data[SET_NUM_H377] = {0x1c,0x1b,0x1d,0x11,0x0e,0x0d,0x01,0x1d,0x15}; + +static const uint8_t binding_adr_rf[5]={0x32,0xaa,0x45,0x45,0x78}; + +static uint8_t rf_adr_buf[5]; +static uint8_t rf_adr_buf_data[SET_NUM_H377][5] = { + {0xad,0x9a,0xa6,0x69,0xb2},//ansheng + {0x92,0x9a,0x9d,0x69,0x99},//dc59 + {0x92,0xb2,0x9d,0x69,0x9a},//small two + {0xad,0x9a,0x5a,0x69,0x96},//james_1 + {0x95,0x9a,0x52,0x69,0x99},//james_2 + {0x52,0x52,0x52,0x69,0xb9},//james_3 + {0x52,0x52,0x52,0x52,0x55},//small two_1 + {0x92,0xB2,0x9D,0x69,0x9A},//small two_2 + {0x96,0x9A,0x45,0x69,0xB2}//small two_3 +}; + +static uint8_t bind_buf_array[10]; +static uint8_t bind_buf_array_data[SET_NUM_H377][4] = { + {0xcf,0x1c,0x19,0x1a}, + {0xff,0x48,0x19,0x19}, + {0xf3,0x4d,0x19,0x19}, + {0x9e,0x1f,0x19,0x19}, + {0x8d,0x3d,0x19,0x19}, + {0xbd,0x23,0x19,0x19}, + {0xF3,0x28,0x19,0x19}, + {0xF3,0x4D,0x19,0x19}, + {0x82,0x8D,0x19,0x19} +}; + + +static unsigned int ch_data[8]; +static uint8_t payload[10]; +static uint8_t counter1ms; + +static int select_ch_id = 0; + +static void h377_binding_packet(void) { //bind_buf_array + uint8_t i; + counter1ms = 0; + hopping_frequency_no = 0; + + for(i=0;i<5;i++) + bind_buf_array[i] = rf_adr_buf[i]; + + bind_buf_array[5] = hopping_frequency[0]; + + for(i=0;i<4;i++) + bind_buf_array[i+6] = bind_buf_array_data[select_ch_id][i]; +} + +static void h377_init() { + NRF24L01_Initialize(); + + NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable p0 rx + NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknoledgement + NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rf_adr_buf, 5); + NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, rf_adr_buf, 5); + NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, 10); // payload size = 10 + //NRF24L01_WriteReg(NRF24L01_05_RF_CH, 81); // binding packet must be set in channel 81 + NRF24L01_WriteReg(NRF24L01_05_RF_CH, binding_ch); // binding packet must be set in channel 81 + + // 2-bytes CRC, radio off + NRF24L01_SetTxRxMode(TX_EN); + NRF24L01_WriteReg(NRF24L01_00_CONFIG, BV(NRF24L01_00_EN_CRC) | BV(NRF24L01_00_CRCO) | BV(NRF24L01_00_PWR_UP)); + NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x03); // 5-byte RX/TX address (byte -2) + NRF24L01_SetBitrate(0); // 1Mbps + NRF24L01_SetPower(); + NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit +} + +// H377 channel sequence: AILE ELEV THRO RUDD GEAR PITH, channel data value is from 0 to 1000 +static void h377_ch_data() { + uint32_t temp; + uint8_t i; + for (i = 0; i< 8; i++) { + temp = (uint32_t)Servo_data[i] * 450/PPM_MAX + 500; // max/min servo range is +-125% + if (i == 2) // It is clear that h377's thro stick is made reversely, so I adjust it here on purpose + temp = 1000 -temp; + //if (i == 0) // It is clear that h377's thro stick is made reversely, so I adjust it here on purpose + // temp = 1000 -temp; + //if (i == 1) // It is clear that h377's thro stick is made reversely, so I adjust it here on purpose + // temp = 1000 -temp; + if (temp < 0) + ch_data[i] = 0; + else if (temp > 1000) + ch_data[i] = 1000; + else + ch_data[i] = (unsigned int)temp; + payload[i] = (uint8_t)ch_data[i]; + } + payload[8] = (uint8_t)((ch_data[0]>>8)&0x0003); + payload[8] |= (uint8_t)((ch_data[1]>>6)&0x000c); + payload[8] |= (uint8_t)((ch_data[2]>>4)&0x0030); + payload[8] |= (uint8_t)((ch_data[3]>>2)&0x00c0); + + payload[9] = (uint8_t)((ch_data[4]>>8)&0x0003); + payload[9] |= (uint8_t)((ch_data[5]>>6)&0x000c); + payload[9] |= (uint8_t)((ch_data[6]>>4)&0x0030); + payload[9] |= (uint8_t)((ch_data[7]>>2)&0x00c0); +} + +static uint16_t h377_cb() { + counter1ms++; + if(counter1ms==1) { NRF24L01_FlushTx(); } + //------------------------- + else if(counter1ms==2) { + if (bind_phase>0) { + NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, (uint8_t *)binding_adr_rf, 5); + NRF24L01_WriteReg(NRF24L01_05_RF_CH, binding_ch); + } + } + else if(counter1ms==3) { + if (bind_phase >0) { + bind_phase--; + if (! bind_phase) { BIND_DONE; } // binding finished, change tx add + NRF24L01_WritePayload(bind_buf_array,10); + } + } + else if (counter1ms==4) { if (bind_phase > 0) { NRF24L01_FlushTx(); }} + //------------------------- + else if(counter1ms==5) { NRF24L01_SetPower(); } + //------------------------- + else if (counter1ms == 6) { + NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rf_adr_buf, 5); + NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no]); + hopping_frequency_no++; + if (hopping_frequency_no >= FREQUENCE_NUM_H377) { hopping_frequency_no = 0; } + } + else if (counter1ms == 7) { h377_ch_data(); } + else if(counter1ms>8) { + counter1ms = 0; + NRF24L01_WritePayload(payload,10); + } + return 1000; // send 1 binding packet and 1 data packet per 9ms +} + +// Linear feedback shift register with 32-bit Xilinx polinomial x^32 + x^22 + x^2 + x + 1 +static const uint32_t LFSR_FEEDBACK = 0x80200003ul; +static const uint32_t LFSR_INTAP = 32-1; + +static void update_lfsr(uint32_t *lfsr, uint8_t b) { + for (int i = 0; i < 8; ++i) { + *lfsr = (*lfsr >> 1) ^ ((-(*lfsr & 1u) & LFSR_FEEDBACK) ^ ~((uint32_t)(b & 1) << LFSR_INTAP)); + b >>= 1; + } +} + +// Generate internal id from TX id and manufacturer id (STM32 unique id) + + +static void H377_tx_id() { + for(int i=0;i<5;i++) + rf_adr_buf[i] = rf_adr_buf_data[select_ch_id][i]; + + hopping_frequency[0] = hopping_frequency_data[select_ch_id]; + + for (int i = 1; i < FREQUENCE_NUM_H377; i++) { + hopping_frequency[i] = hopping_frequency[i-1] + 3; + } +} + + + +static uint16_t h377_setup() { + select_ch_id = MProtocol_id_master%SET_NUM_H377; + + H377_tx_id();//rf_adr_buf hopping_frequency + + h377_binding_packet();//bind_buf_array (rf_adr_buf hopping_frequency) + + h377_init(); + + if(IS_AUTOBIND_FLAG_on) { + bind_phase = BIND_COUNT; + BIND_IN_PROGRESS; + } + else { bind_phase = 0; } + + return 1000; +} +#endif diff --git a/Multiprotocol/Nrf24l01_hm830.ino b/Multiprotocol/Nrf24l01_hm830.ino new file mode 100644 index 0000000..bb30d3a --- /dev/null +++ b/Multiprotocol/Nrf24l01_hm830.ino @@ -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 . + */ + +/* 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 \ No newline at end of file diff --git a/Multiprotocol/Nrf24l01_hontai.ino b/Multiprotocol/Nrf24l01_hontai.ino new file mode 100644 index 0000000..4408014 --- /dev/null +++ b/Multiprotocol/Nrf24l01_hontai.ino @@ -0,0 +1,272 @@ +/* + This project is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Deviation is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Deviation. If not, see . + */ + + +#if defined(HonTai_NRF24L01_INO) +#include "iface_nrf24l01.h" + +#define BIND_HT_COUNT 80 +#define PACKET_HT_PERIOD 13500 // Timeout for callback in uSec +//printf inside an interrupt handler is really dangerous +//this shouldn't be enabled even in debug builds without explicitly +//turning it on +#define dbgprintf if(0) printf + +#define INITIAL_HT_WAIT 500 +#define BIND_HT_PACKET_SIZE 10 +#define PACKET_HT_SIZE 12 +#define RF_BIND_HT_CHANNEL 0 + +enum { + FORMAT_HONTAI = 0, + FORMAT_JJRCX1, +}; + + +#define CHANNEL_LED AUX1 +#define CHANNEL_ARM AUX1 // for JJRC X1 +#define CHANNEL_FLIP AUX2 +#define CHANNEL_PICTURE AUX3 +#define CHANNEL_VIDEO AUX4 +#define CHANNEL_HEADLESS AUX5 +#define CHANNEL_RTH AUX6 +#define CHANNEL_CALIBRATE AUX7 + +enum { + HonTai_INIT1 = 0, + HonTai_BIND2, + HonTai_DATA +}; + +static uint8_t ht_txid[5]; + +static uint8_t rf_chan = 0; +static uint8_t rf_channels[][3] = {{0x05, 0x19, 0x28}, // Hontai + {0x0a, 0x1e, 0x2d}}; // JJRC X1 +static uint8_t rx_tx_ht_addr[] = {0xd2, 0xb5, 0x99, 0xb3, 0x4a}; +static uint8_t addr_vals[4][16] = { + {0x24, 0x26, 0x2a, 0x2c, 0x32, 0x34, 0x36, 0x4a, 0x4c, 0x4e, 0x54, 0x56, 0x5a, 0x64, 0x66, 0x6a}, + {0x92, 0x94, 0x96, 0x9a, 0xa4, 0xa6, 0xac, 0xb2, 0xb4, 0xb6, 0xca, 0xcc, 0xd2, 0xd4, 0xd6, 0xda}, + {0x93, 0x95, 0x99, 0x9b, 0xa5, 0xa9, 0xab, 0xad, 0xb3, 0xb5, 0xc9, 0xcb, 0xcd, 0xd3, 0xd5, 0xd9}, + {0x25, 0x29, 0x2b, 0x2d, 0x33, 0x35, 0x49, 0x4b, 0x4d, 0x59, 0x5b, 0x65, 0x69, 0x6b, 0x6d, 0x6e}}; + +// proudly swiped from http://www.drdobbs.com/implementing-the-ccitt-cyclical-redundan/199904926 +#define POLY 0x8408 +static uint16_t crc16(uint8_t *data_p, uint32_t length) +{ + uint8_t i; + uint32_t data; + uint32_t crc; + + crc = 0xffff; + + if (length == 0) return (~crc); + + length -= 2; + do { + for (i = 0, data = (uint8_t)0xff & *data_p++; + i < 8; + i++, data >>= 1) { + if ((crc & 0x0001) ^ (data & 0x0001)) + crc = (crc >> 1) ^ POLY; + else + crc >>= 1; + } + } while (--length); + + crc = ~crc; + data = crc; + crc = (crc << 8) | (data >> 8 & 0xFF); + *data_p++ = crc >> 8; + *data_p = crc & 0xff; + return crc; +} + +#define CHAN_RANGE (PPM_MAX - PPM_MIN) +static uint8_t scale_HT_channel(uint8_t ch, uint8_t start, uint8_t end) +{ + uint32_t range = end - start; + uint32_t chanval = Servo_data[ch]; + + if (chanval < PPM_MIN) chanval = PPM_MIN; + else if (chanval > PPM_MAX) chanval = PPM_MAX; + + uint32_t round = range < 0 ? 0 : CHAN_RANGE / range; // channels round up + if (start < 0) round = CHAN_RANGE / range / 2; // trims zero centered around zero + return (range * (chanval - PPM_MIN + round)) / CHAN_RANGE + start; +} + +#define GET_FLAG(ch, mask) (Servo_data[ch] > 0 ? mask : 0) +static void send_HT_packet(uint8_t bind) +{ + if (bind) { + memcpy(packet, ht_txid, 5); + memset(&packet[5], 0, 3); + } else { + if (sub_protocol == FORMAT_HONTAI) { + packet[0] = 0x0b; + } else { + packet[0] = GET_FLAG(CHANNEL_ARM, 0x02); + } + packet[1] = 0x00; + packet[2] = 0x00; + packet[3] = (scale_HT_channel(THROTTLE, 0, 127) << 1) // throttle + | GET_FLAG(CHANNEL_PICTURE, 0x01); + packet[4] = scale_HT_channel(AILERON, 63, 0); // aileron + if (sub_protocol == FORMAT_HONTAI) { + packet[4] |= GET_FLAG(CHANNEL_RTH, 0x80) + | GET_FLAG(CHANNEL_HEADLESS, 0x40); + } else { + packet[4] |= 0x80; // not sure what this bit does + } + packet[5] = scale_channel(CHANNEL2, 0, 63) // elevator + | GET_FLAG(CHANNEL_CALIBRATE, 0x80) + | GET_FLAG(CHANNEL_FLIP, 0x40); + packet[6] = scale_HT_channel(RUDDER, 0, 63) // rudder + | GET_FLAG(CHANNEL_VIDEO, 0x80); + packet[7] = scale_HT_channel(AILERON, -16, 16); // aileron trim + if (sub_protocol == FORMAT_HONTAI) { + packet[8] = scale_HT_channel(RUDDER, -16, 16); // rudder trim + } else { + packet[8] = 0xc0 // always in expert mode + | GET_FLAG(CHANNEL_RTH, 0x02) + | GET_FLAG(CHANNEL_HEADLESS, 0x01); + } + packet[9] = scale_HT_channel(ELEVATOR, -16, 16); // elevator trim + } + crc16(packet, bind ? BIND_HT_PACKET_SIZE : PACKET_HT_SIZE); + + // Power on, TX mode, 2byte CRC + if (sub_protocol == FORMAT_HONTAI) { + XN297_Configure(BV(NRF24L01_00_EN_CRC) | BV(NRF24L01_00_CRCO) | BV(NRF24L01_00_PWR_UP)); + } else { + NRF24L01_SetTxRxMode(TX_EN); + } + + NRF24L01_WriteReg(NRF24L01_05_RF_CH, bind ? RF_BIND_HT_CHANNEL : rf_channels[sub_protocol][rf_chan++]); + rf_chan %= sizeof(rf_channels); + + NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); + NRF24L01_FlushTx(); + + if (sub_protocol == FORMAT_HONTAI) { + XN297_WritePayload(packet, bind ? BIND_HT_PACKET_SIZE : PACKET_HT_SIZE); + } else { + NRF24L01_WritePayload(packet, bind ? BIND_HT_PACKET_SIZE : PACKET_HT_SIZE); + } + + NRF24L01_SetPower(); +} + +static void ht_init() +{ + NRF24L01_Initialize(); + + NRF24L01_SetTxRxMode(TX_EN); + + // SPI trace of stock TX has these writes to registers that don't appear in + // nRF24L01 or Beken 2421 datasheets. Uncomment if you have an XN297 chip? + // NRF24L01_WriteRegisterMulti(0x3f, "\x4c\x84\x67,\x9c,\x20", 5); + // NRF24L01_WriteRegisterMulti(0x3e, "\xc9\x9a\xb0,\x61,\xbb,\xab,\x9c", 7); + // NRF24L01_WriteRegisterMulti(0x39, "\x0b\xdf\xc4,\xa7,\x03,\xab,\x9c", 7); + + if (sub_protocol == FORMAT_HONTAI) { + XN297_SetTXAddr(rx_tx_ht_addr, sizeof(rx_tx_ht_addr)); + } else { + NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_ht_addr, sizeof(rx_tx_ht_addr)); + } + + NRF24L01_FlushTx(); + NRF24L01_FlushRx(); + NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit + NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknowldgement on all data pipes + NRF24L01_SetBitrate(NRF24L01_BR_1M); // 1Mbps + NRF24L01_SetPower(); + NRF24L01_Activate(0x73); // Activate feature register + if (sub_protocol == FORMAT_HONTAI) { + NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0x00); // no retransmits + NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 0x00); // Disable dynamic payload length on all pipes + NRF24L01_WriteReg(NRF24L01_1D_FEATURE, 0x00); + NRF24L01_Activate(0x73); // Deactivate feature register + } else { + NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0xff); // JJRC uses dynamic payload length + NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 0x3f); // match other stock settings even though AA disabled... + NRF24L01_WriteReg(NRF24L01_1D_FEATURE, 0x07); + } +} + +static void ht_init2() +{ + uint8_t data_tx_addr[] = {0x2a, 0xda, 0xa5, 0x25, 0x24}; + + data_tx_addr[0] = addr_vals[0][ ht_txid[3] & 0x0f]; + data_tx_addr[1] = addr_vals[1][(ht_txid[3] >> 4) & 0x0f]; + data_tx_addr[2] = addr_vals[2][ ht_txid[4] & 0x0f]; + data_tx_addr[3] = addr_vals[3][(ht_txid[4] >> 4) & 0x0f]; + + if (sub_protocol == FORMAT_HONTAI) { + XN297_SetTXAddr(data_tx_addr, sizeof(data_tx_addr)); + } else { + NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, data_tx_addr, sizeof(data_tx_addr)); + } +} + +static uint16_t ht_callback() +{ + switch (phase) { + case HonTai_INIT1: + phase = HonTai_BIND2; + break; + case HonTai_BIND2: + if (counter == 0) { + ht_init2(); + phase = HonTai_DATA; + BIND_DONE; + } else { + send_HT_packet(1); + counter -= 1; + } + break; + + case HonTai_DATA: + send_HT_packet(0); + break; + } + return PACKET_HT_PERIOD; +} + +static uint16_t ht_setup() +{ + counter = BIND_HT_COUNT; + + if (sub_protocol == FORMAT_HONTAI) { + ht_txid[0] = 0x4c; // first three bytes some kind of model id? - set same as stock tx + ht_txid[1] = 0x4b; + ht_txid[2] = 0x3a; + } else { + ht_txid[0] = 0x4b; // JJRC X1 + ht_txid[1] = 0x59; + ht_txid[2] = 0x3a; + } + ht_txid[3] = (MProtocol_id >> 8 ) & 0xff; + ht_txid[4] = MProtocol_id & 0xff; + + ht_init(); + phase = HonTai_INIT1; + + return INITIAL_HT_WAIT; +} +#endif + diff --git a/Multiprotocol/Nrf24l01_ne260.ino b/Multiprotocol/Nrf24l01_ne260.ino new file mode 100644 index 0000000..598c15b --- /dev/null +++ b/Multiprotocol/Nrf24l01_ne260.ino @@ -0,0 +1,272 @@ +/* + This project is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Deviation is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Deviation. If not, see . + */ +/* This code is based upon code from: + http://www.rcgroups.com/forums/showthread.php?t=1564343 + Author : Ferenc Szili (kile at the rcgroups.net forum) +*/ + + +#if defined(NE260_NRF24L01_INO) +#include "iface_nrf24l01.h" + +//////////////////////////////////////////////////////////// +/////////////////////// +// register bits +/////////////////////// + +// CONFIG +#define MASK_RX_DR 6 +#define MASK_TX_DS 5 +#define MASK_MAX_RT 4 +#define EN_CRC 3 +#define CRCO 2 +#define PWR_UP 1 +#define PRIM_RX 0 + +// EN_AA +#define ENAA_P5 5 +#define ENAA_P4 4 +#define ENAA_P3 3 +#define ENAA_P2 2 +#define ENAA_P1 1 +#define ENAA_P0 0 + +// EN_RXADDR +#define ERX_P5 5 +#define ERX_P4 4 +#define ERX_P3 3 +#define ERX_P2 2 +#define ERX_P1 1 +#define ERX_P0 0 + +// RF_SETUP +#define CONT_WAVE 7 +#define RF_DR_LOW 5 +#define PLL_LOCK 4 +#define RF_DR_HIGH 3 +#define RF_PWR_HIGH 2 +#define RF_PWR_LOW 1 +#define LNA_HCURR 0 // obsolete in nRF24L01+ + +// STATUS +#define RX_DR 6 +#define TX_DS 5 +#define MAX_RT 4 +#define TX_FULL 0 + +// FIFO_STATUS +#define TX_REUSE 6 +#define FIFO_TX_FULL 5 +#define TX_EMPTY 4 +#define RX_FULL 1 +#define RX_EMPTY 0 + +/////////////////////// +// register bit values +/////////////////////// + +// CONFIG +#define vMASK_RX_DR (1<<(MASK_RX_DR)) +#define vMASK_TX_DS (1<<(MASK_TX_DS)) +#define vMASK_MAX_RT (1<<(MASK_MAX_RT)) +#define vEN_CRC (1<<(EN_CRC)) +#define vCRCO (1<<(CRCO)) +#define vPWR_UP (1<<(PWR_UP)) +#define vPRIM_RX (1<<(PRIM_RX)) + +// EN_AA +#define vENAA_P5 (1<<(ENAA_P5)) +#define vENAA_P4 (1<<(ENAA_P4)) +#define vENAA_P3 (1<<(ENAA_P3)) +#define vENAA_P2 (1<<(ENAA_P2)) +#define vENAA_P1 (1<<(ENAA_P1)) +#define vENAA_P0 (1<<(ENAA_P0)) + +// EN_RXADDR +#define vERX_P5 (1<<(ERX_P5)) +#define vERX_P4 (1<<(ERX_P4)) +#define vERX_P3 (1<<(ERX_P3)) +#define vERX_P2 (1<<(ERX_P2)) +#define vERX_P1 (1<<(ERX_P1)) +#define vERX_P0 (1<<(ERX_P0)) + +// SETUP_AW -- address widths in bytes +#define vAW_3 1 +#define vAW_4 2 +#define vAW_5 3 + +// RF_SETUP +#define vCONT_WAVE (1<<(CONT_WAVE)) +#define vRF_DR_LOW (1<<(RF_DR_LOW)) +#define vPLL_LOCK (1<<(PLL_LOCK)) +#define vRF_DR_HIGH (1<<(RF_DR_HIGH)) +#define vRF_PWR_HIGH (1<<(RF_PWR_HIGH)) +#define vRF_PWR_LOW (1<<(RF_PWR_LOW)) +#define vLNA_HCURR (1<<(LNA_HCURR)) // obsolete in nRF24L01+ + +#define vRF_DR_1MBPS 0 +#define vRF_DR_2MBPS (1<<(RF_DR_HIGH)) +#define vRF_DR_250KBPS (1<<(RF_DR_LOW)) + +#define vRF_PWR_M18DBM 0x00 +#define vRF_PWR_M12DBM 0x02 +#define vRF_PWR_M6DBM 0x04 +#define vRF_PWR_0DBM 0x06 + +#define vARD_250us 0x00 +#define vARD_500us 0x10 +#define vARD_750us 0x20 +#define vARD_1000us 0x30 +#define vARD_1250us 0x40 +#define vARD_1500us 0x50 +#define vARD_1750us 0x60 +#define vARD_2000us 0x70 +#define vARD_2250us 0x80 +#define vARD_2500us 0x90 +#define vARD_2750us 0xA0 +#define vARD_3000us 0xB0 +#define vARD_3250us 0xC0 +#define vARD_3500us 0xD0 +#define vARD_3750us 0xE0 +#define vARD_4000us 0xF0 + +// STATUS +#define vRX_DR (1<<(RX_DR)) +#define vTX_DS (1<<(TX_DS)) +#define vMAX_RT (1<<(MAX_RT)) +#define vTX_FULL (1<<(TX_FULL)) + +#define RX_P_NO(stat) ((stat >> 1) & 7) +#define HAS_RX_PAYLOAD(stat) ((stat & 0b1110) < 0b1100) + +// FIFO_STATUS +#define vTX_REUSE (1<<(TX_REUSE)) +#define vTX_FULL (1<<(TX_FULL)) +#define vTX_EMPTY (1<<(TX_EMPTY)) +#define vRX_FULL (1<<(RX_FULL)) +#define vRX_EMPTY (1<<(RX_EMPTY)) +//////////////////////////////////////////////////////////// +uint8_t neChannel = 10; +uint8_t neChannelOffset = 0; +#define PACKET_NE_LENGTH 7 + +static uint16_t model_id = 0xA04A; + +uint8_t NE_ch[]={THROTTLE, RUDDER, ELEVATOR, AILERON, AUX1}; +uint8_t NEAddr[] = {0x34, 0x43, 0x10, 0x10, 0x01}; +enum { + NE260_BINDTX, + NE260_BINDRX, + NE260_DATA1, + NE260_DATA2, + NE260_DATA3, +}; + + +static void ne260_init() { + NRF24L01_Initialize(); + + NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, NEAddr, 5); // write the address + NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, NEAddr, 5); + + NRF24L01_WriteReg(NRF24L01_01_EN_AA, vENAA_P0); // enable auto acknoledge + NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, vARD_500us); // ARD=500us, ARC=disabled + NRF24L01_WriteReg(NRF24L01_06_RF_SETUP, vRF_DR_250KBPS | vLNA_HCURR | vRF_PWR_0DBM); // data rate, output power and noise cancel + NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, PACKET_NE_LENGTH); // RX payload length + NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, vERX_P0); // enable RX address + NRF24L01_WriteReg(NRF24L01_07_STATUS, vRX_DR | vTX_DS | vMAX_RT); // reset the IRQ flags +} + +static void send_data_packet() { + for(int i = 0; i < 4; i++) { + uint32_t value = (uint32_t)Servo_data[NE_ch[i]] * 0x40 / PPM_MAX + 0x40; + if (value > 0x7f) + value = 0x7f; + else if(value < 0) + value = 0; + packet[i] = value; + } + packet[4] = 0x55; + packet[5] = model_id & 0xff; + packet[6] = (model_id >> 8) & 0xff; + + NRF24L01_FlushTx(); + NRF24L01_WriteReg(NRF24L01_07_STATUS, vMAX_RT); + NRF24L01_WriteReg(NRF24L01_05_RF_CH, neChannel + neChannelOffset); + NRF24L01_WriteReg(NRF24L01_00_CONFIG, vEN_CRC | vCRCO | vPWR_UP); + // send a fresh packet to the nRF + NRF24L01_WritePayload((uint8_t*) packet, PACKET_NE_LENGTH); +} + +static void send_bind_packet() { + packet[0] = 0xAA; //throttle + packet[1] = 0xAA; //rudder + packet[2] = 0xAA; //elevator + packet[3] = 0xAA; //aileron + packet[4] = 0xAA; //command + packet[5] = model_id & 0xff; + packet[6] = (model_id >> 8) & 0xff; + + NRF24L01_WriteReg(NRF24L01_07_STATUS, vRX_DR | vTX_DS | vMAX_RT); // reset the status flags + NRF24L01_WriteReg(NRF24L01_05_RF_CH, neChannel + neChannelOffset); + NRF24L01_FlushTx(); + NRF24L01_WritePayload((uint8_t*) &packet, PACKET_NE_LENGTH); // send the bind packet +} + +static uint16_t ne260_cb() { + if (state == NE260_BINDTX) { + // do we have a packet? + if ((NRF24L01_ReadReg(NRF24L01_07_STATUS) & vRX_DR) != 0) { + // read the packet contents + NRF24L01_ReadPayload(packet, PACKET_NE_LENGTH); + + // is this the bind response packet? + if (strncmp("\x55\x55\x55\x55\x55", (char*) (packet + 1), 5) == 0 && *((uint16_t*)(packet + 6)) == model_id) { + // exit the bind loop + state = NE260_DATA1; + NRF24L01_FlushTx(); + NRF24L01_FlushRx(); + NRF24L01_SetTxRxMode(TX_EN); + return 2000; + } + } + NRF24L01_SetTxRxMode(TX_EN); + send_bind_packet(); + state = NE260_BINDRX; + return 500; + } else if (state == NE260_BINDRX) { + // switch to RX mode + while (!(NRF24L01_ReadReg(NRF24L01_07_STATUS) & (vMAX_RT | vTX_DS))) ; + NRF24L01_WriteReg(NRF24L01_07_STATUS, vTX_DS); + + NRF24L01_SetTxRxMode(RX_EN); + NRF24L01_FlushRx(); + state = NE260_BINDTX; + return 2000; + } + else if (state == NE260_DATA1) { neChannel = 10; state = NE260_DATA2; } + else if (state == NE260_DATA2) { neChannel = 30; state = NE260_DATA3; } + else if (state == NE260_DATA3) { neChannel = 50; state = NE260_DATA1; } + send_data_packet(); + return 2500; +} + +static uint16_t NE260_setup() { + ne260_init(); + state = NE260_BINDTX; + + return 10000; +} +#endif diff --git a/Multiprotocol/Nrf24l01_udi.ino b/Multiprotocol/Nrf24l01_udi.ino new file mode 100644 index 0000000..a8eac63 --- /dev/null +++ b/Multiprotocol/Nrf24l01_udi.ino @@ -0,0 +1,582 @@ +/* + This project is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Deviation is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Deviation. If not, see . + */ + +// Known UDI 2.4GHz protocol variants, all using BK2421 +// * UDI U819 coaxial 3ch helicoper +// * UDI U816/817/818 quadcopters +// - "V1" with orange LED on TX, U816 RX labeled '' , U817/U818 RX labeled 'UD-U817B' +// - "V2" with red LEDs on TX, U816 RX labeled '', U817/U818 RX labeled 'UD-U817OG' +// - "V3" with green LEDs on TX. Did not get my hands on yet. +// * U830 mini quadcopter with tilt steering ("Protocol 2014") +// * U839 nano quadcopter ("Protocol 2014") + +#if defined(UDI_NRF24L01_INO) +#include "iface_nrf24l01.h" + +#define BIND_UDI_COUNT 1000 + +// Timeout for callback in uSec, 4ms=4000us for UDI +// ??? +//#define PACKET_UDI_PERIOD 4000 + +#define BIND_PACKET_UDI_PERIOD 5000 +#define PACKET_UDI_PERIOD 15000 + +#define BIND_PACKETS_UDI_PER_CHANNEL 11 +#define PACKETS_UDI_PER_CHANNEL 11 + +#define NUM_UDI_RF_CHANNELS 16 + + +#define INITIAL_UDI_WAIT 50000 + +#define PACKET_UDI_CHKTIME 100 + +// For readability +enum { + UDI_CAMERA = 1, + UDI_VIDEO = 2, + UDI_MODE2 = 4, + UDI_FLIP360 = 8, + UDI_FLIP =16, + UDI_LIGHTS =32 +}; + +// This is maximum payload size used in UDI protocols +#define UDI_PAYLOADSIZE 16 + + + +static uint8_t payload_size; // Bytes in payload for selected variant +static uint8_t bind_channel; +static uint8_t packets_to_hop; +static uint8_t packets_to_check; // BIND_RX phase needs to receive/auto-ack more than one packet for RX to switch to next phase, it seems +static uint8_t packets_to_send; // Number of packets to send / check for in current bind phase +static uint8_t bind_step_success; // Indicates successfull transmission / receive of bind reply during current bind phase +static uint8_t tx_id[3]; +static uint8_t rx_id[3]; +static uint8_t randoms[3]; // 3 random bytes choosen by TX, sent in BIND packets. Lower nibble of first byte sets index in RF CH table to use for BIND2 + + +// +enum { + UDI_INIT2 = 0, + UDI_INIT2_NO_BIND, + UDI_BIND1_TX, + UDI_BIND1_RX, + UDI_BIND2_TX, + UDI_BIND2_RX, + UDI_DATA +}; + +enum { + PROTOOPTS_FORMAT = 0, + PROTOOPTS_STARTBIND, +}; +enum { + STARTBIND_NO = 0, + STARTBIND_YES = 1, +}; + +// This are frequency hopping tables for UDI protocols + +// uint8_t16 V1 (Orange LED) Bind CH 0x07 +// TX ID 0x57, 0x5A, 0x2D +static const uint8_t freq_hopping_uint8_t16_v1[NUM_UDI_RF_CHANNELS] = { + 0x07, 0x21, 0x49, 0x0B, 0x39, 0x10, 0x25, 0x42, + 0x1D, 0x31, 0x35, 0x14, 0x28, 0x3D, 0x18, 0x2D +}; + +// Protocol 2014 (uint8_t30,uint8_t39,...) BIND CH 0x23 (second entry) +// DATA: hops ~ every 0.361s (0.350 ... 0.372) +static const uint8_t freq_hopping_uint8_t39[NUM_UDI_RF_CHANNELS] = { + 0x08, 0x23, 0x48, 0x0D, 0x3B, 0x12, 0x27, 0x44, + 0x1F, 0x33, 0x37, 0x16, 0x2A, 0x3F, 0x1A, 0x2F +}; + +// Points to proper table +static const uint8_t * rf_udi_channels = NULL; + + +static uint8_t packet_udi_ack() +{ + switch (NRF24L01_ReadReg(NRF24L01_07_STATUS) & (BV(NRF24L01_07_TX_DS) | BV(NRF24L01_07_MAX_RT))) { + case BV(NRF24L01_07_TX_DS): return PKT_ACKED; + case BV(NRF24L01_07_MAX_RT): return PKT_TIMEOUT; + } + return PKT_PENDING; +} + +static void UDI_init() +{ + NRF24L01_Initialize(); + //NRF24L01_SetTxRxMode(TX_EN); + + switch (sub_protocol) { + case U816_V1: + rf_udi_channels = freq_hopping_uint8_t16_v1; + payload_size = 8; + break; + + case U816_V2: + rf_udi_channels = NULL; // NO HOPPING ! + payload_size = 7; + break; + + case U839_2014: + // UDI 2014 Protocol (uint8_t30, uint8_t39, all other new products ?) + rf_udi_channels = freq_hopping_uint8_t39; + payload_size = 8; + break; + } + + NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, payload_size); + NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x07); // Clear status bits + + if ((sub_protocol == U816_V1) || (sub_protocol == U816_V2)) { + NRF24L01_WriteReg(NRF24L01_06_RF_SETUP, 0x27); // + NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0x3A); // + NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x01); // 3 byte address + NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0 + NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x3F); // Auto-acknowledge on all data pipers, same as YD + if (sub_protocol == U816_V1) { + NRF24L01_WriteReg(NRF24L01_00_CONFIG, 0x7F); // + } else { + NRF24L01_WriteReg(NRF24L01_00_CONFIG, 0x7A); // + } + } else + if (sub_protocol == U839_2014) { + NRF24L01_WriteReg(NRF24L01_06_RF_SETUP, 0x0F); // 2Mbps air rate, 5dBm RF output power, high LNA gain + NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0x1A); // 500uS retransmit t/o, 10 tries (same as YD) + NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x01); // 3 byte address + NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0 + NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x3F); // Auto-acknowledge on all data pipers, same as YD + NRF24L01_WriteReg(NRF24L01_00_CONFIG, 0x0F); // Enable CRC, 2 byte CRC, PWR UP, PRIMARY RX + } + + NRF24L01_FlushTx(); + NRF24L01_FlushRx(); + uint8_t status = NRF24L01_ReadReg(NRF24L01_07_STATUS); + NRF24L01_WriteReg(NRF24L01_07_STATUS, status); + + status = NRF24L01_ReadReg(NRF24L01_07_STATUS); + NRF24L01_FlushTx(); + status = NRF24L01_ReadReg(NRF24L01_07_STATUS); + NRF24L01_WriteReg(NRF24L01_07_STATUS, status); + + // Implicit delay in callback + // delayMicroseconds(120) +} + +static void UDI_init2() +{ + NRF24L01_FlushTx(); + bind_step_success = 0; + packet_sent = 0; + + switch (sub_protocol) { + case U816_V1: + rf_ch_num = 0; + bind_channel = rf_udi_channels[rf_ch_num++]; + break; + case U816_V2: + rf_ch_num = 0x07; // This is actual channel. No hopping here + bind_channel = 0; + break; + case U839_2014: + rf_ch_num = 1; + bind_channel = rf_udi_channels[rf_ch_num++]; + break; + } + NRF24L01_WriteReg(NRF24L01_05_RF_CH, bind_channel); + + NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, (uint8_t *) "\xe7\x7e\xe7", 3); + NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, (uint8_t *) "\xe7\x7e\xe7", 3); + + // Turn radio power on + NRF24L01_SetTxRxMode(TX_EN); + uint8_t config = BV(NRF24L01_00_EN_CRC) | BV(NRF24L01_00_CRCO) | BV(NRF24L01_00_PWR_UP); + NRF24L01_WriteReg(NRF24L01_00_CONFIG, config); + // Implicit delay in callback + // delayMicroseconds(150); +} + +static void set_tx_id(uint32_t id) +{ + tx_id[0] = (id >> 16) & 0xFF; + tx_id[1] = (id >> 8) & 0xFF; + tx_id[2] = (id >> 0) & 0xFF; + +/* + uint32_t val = rand32(); randoms[0] = val & 0xff; randoms[1] = (val >> 8 ) & 0xff; randoms[2] = (val >> 16 ) & 0xff; +*/ + // FIXME + // This one has been observed, leads to RF CH 0x1F (#08) used for BIND2 + randoms[0] = 0x98; randoms[1] = 0x80; randoms[2] = 0x5B; +} + +static void add_pkt_checksum() +{ + // CHECKSUM was introduced with 2014 protocol + if (sub_protocol < U839_2014) return; + uint8_t sum = 0; + for (uint8_t i = 0; i < payload_size-1; ++i) sum += packet[i]; + packet[payload_size-1] = sum & 0x3f; // *sick* +} + + +static uint8_t convert_channel(uint8_t num, uint8_t chn_max, uint8_t sign_ofs) +{ + uint32_t ch = Servo_data[num]; + if (ch < PPM_MIN) { + ch = PPM_MIN; + } else if (ch > PPM_MAX) { + ch = PPM_MAX; + } + uint32_t chn_val; + if (sign_ofs) chn_val = (((ch * chn_max / PPM_MAX) + sign_ofs) >> 1); + else chn_val = (ch * chn_max / PPM_MAX); + if (chn_val < 0) chn_val = 0; + else if (chn_val > chn_max) chn_val = chn_max; + return (uint8_t) chn_val; +} + + +static void read_controls(uint8_t* throttle, uint8_t* rudder, uint8_t* elevator, uint8_t* aileron, + uint8_t* flags) +{ + // Protocol is registered AETRG, that is + // Aileron is channel 0, Elevator - 1, Throttle - 2, Rudder - 3 + // Sometimes due to imperfect calibration or mixer settings + // throttle can be less than PPM_MIN or larger than + // PPM_MAX. As we have no space here, we hard-limit + // channels values by min..max range + + // Channel 3: throttle is 0-100 + *throttle = convert_channel(THROTTLE, 0x64, 0); + + // Channel 4 + *rudder = convert_channel(RUDDER, 0x3f, 0x20); + + // Channel 2 + *elevator = convert_channel(ELEVATOR, 0x3f, 0x20); + + // Channel 1 + *aileron = convert_channel(AILERON, 0x3f, 0x20); + + // Channel 5 + if (Servo_data[AUX1] <= 0) *flags &= ~UDI_FLIP360; + else *flags |= UDI_FLIP360; + + // Channel 6 + if (Servo_data[AUX2] <= 0) *flags &= ~UDI_FLIP; + else *flags |= UDI_FLIP; + + // Channel 7 + if (Servo_data[AUX3] <= 0) *flags &= ~UDI_CAMERA; + else *flags |= UDI_CAMERA; + + // Channel 8 + if (Servo_data[AUX4] <= 0) *flags &= ~UDI_VIDEO; + else *flags |= UDI_VIDEO; + + // Channel 9 + if (Servo_data[AUX5] <= 0) *flags &= ~UDI_LIGHTS; + else *flags |= UDI_LIGHTS; + + // Channel 10 + if (Servo_data[AUX6] <= 0) *flags &= ~UDI_MODE2; + else *flags |= UDI_MODE2; +} + +static void send_udi_packet(uint8_t bind) +{ + packet[7] = 0x4A; + if (bind == 1) { + // Bind phase 1 + // MAGIC + packet[0] = 0x5A; // NOTE: Also 0xF3, when RX does not ACK packets (uint8_t39, only TX on) ... + // Current Address / TX ID + if (sub_protocol == U839_2014) { + // uint8_t39: Current RX/TX Addr + packet[1] = 0xE7; + packet[2] = 0x7E; + packet[3] = 0xE7; + } else { + // uint8_t16: ID Fixed per TX + packet[1] = tx_id[0]; + packet[2] = tx_id[1]; + packet[3] = tx_id[2]; + } + // Pseudo random values (lower nibble of packet[4] determines index of RF CH used in BIND2) + packet[4] = randoms[0]; + packet[5] = randoms[1]; + packet[6] = randoms[2]; + if (sub_protocol == U839_2014) { + packet[7] = (packet_counter < 4) ? 0x3f : 0x04; // first four packets use 0x3f here, then 0x04 + } + } else if (bind == 2) { + // Bind phase 2 + // MAGIC + packet[0] = 0xAA; + // Current Address (RX "ID", pseudorandom again) + packet[1] = rx_id[0]; + packet[2] = rx_id[1]; + packet[3] = rx_id[2]; + // Pseudo random values + packet[4] = randoms[0]; + packet[5] = randoms[1]; + packet[6] = randoms[2]; + if (sub_protocol == U839_2014) { + packet[7] = 0x04; + } + } else { + // regular packet + // Read channels (converts to required ranges) + read_controls(&throttle, &rudder, &elevator, &aileron, &flags); + // MAGIC + packet[0] = 0x55; + packet[1] = throttle; // throttle is 0-0x64 + // 3 Channels packed into 2 bytes (5bit per channel) + uint16_t encoded = (rudder << 11) | (elevator << 6) | (aileron << 1); + packet[2] = (encoded >> 8) & 0xff; + packet[3] = encoded & 0xff; + // Trims and flags (0x20 = center) + packet[4] = 0x20; // rudder trim 6bit + packet[5] = 0x20; // elev trim 6bit + packet[6] = 0x20; // ail trim 6bit + + if (flags & UDI_FLIP) packet[4] |= 0x80; // "Directional" flip + if (flags & UDI_LIGHTS) packet[4] |= 0x40; // Light on/off + + if (flags & UDI_MODE2) packet[5] |= 0x80; // High rate ("Mode2") + if (flags & UDI_FLIP360) packet[5] |= 0x40; // 360 degree flip + + if (flags & UDI_VIDEO) packet[6] |= 0x80; // Video recording on/off + if (flags & UDI_CAMERA) packet[6] |= 0x40; // Take picture + + // NOTE: Only newer protocols have this (handled by routine) + add_pkt_checksum(); + } + + uint8_t status = NRF24L01_ReadReg(NRF24L01_07_STATUS); + NRF24L01_WriteReg(NRF24L01_07_STATUS,status); + + if (packet_sent && bind && (status & BV(NRF24L01_07_TX_DS))) { + bind_step_success = 1; + } + + packet_sent = 0; + + // Check if its time to change channel + // This seems to be done by measuring time, + // not by counting packets, on UDI transmitters + // NOTE: Seems even in bind phase channels are changed + + // NOTE: Only hop in TX mode ??? + if (rf_udi_channels && (bind == 0) && (packets_to_hop-- == 0)) { + uint8_t rf_ch = rf_udi_channels[rf_ch_num]; + rf_ch_num++; + rf_ch_num %= NUM_UDI_RF_CHANNELS; + NRF24L01_WriteReg(NRF24L01_05_RF_CH, rf_ch); + + packets_to_hop = bind ? BIND_PACKETS_UDI_PER_CHANNEL : PACKETS_UDI_PER_CHANNEL; + } + NRF24L01_FlushTx(); + NRF24L01_WritePayload(packet, payload_size); + ++packet_counter; + packet_sent = 1; +} + + +static uint16_t UDI_callback() { + switch (phase) { + case UDI_INIT2: + UDI_init2(); + phase = UDI_BIND1_TX; + return 120; + break; + case UDI_INIT2_NO_BIND: + // Do nothing (stay forever) + // Cannot re-bind on UDI protocol since IDs are random + return 10000; // 10ms + break; + case UDI_BIND1_TX: + if (packet_sent && packet_udi_ack() == PKT_ACKED) { bind_step_success = 1; } + if (bind_step_success) { + // All fine, wait for reply of receiver + phase = UDI_BIND1_RX; + + NRF24L01_SetTxRxMode(RX_EN); + NRF24L01_FlushRx(); + + NRF24L01_WriteReg(NRF24L01_00_CONFIG, 0x0F); + bind_step_success = 0; + //packets_to_check = 12; // according to SPI traces on uint8_t17B RX it receives 12 packets (and answers with 5) + packets_to_check = 3; + } else { + send_udi_packet(1); + } + return BIND_PACKET_UDI_PERIOD; + break; + case UDI_BIND1_RX: + // Check if data has been received + if (NRF24L01_ReadReg(NRF24L01_07_STATUS) & BV(NRF24L01_07_RX_DR) ) { + uint8_t data[UDI_PAYLOADSIZE]; + NRF24L01_ReadPayload(data, payload_size); + NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x4E); // On original TX this is done on LAST packet check only ! + NRF24L01_FlushRx(); + + // Verify MAGIC and Random ID + // (may be reply to bind packet from other TX) + if ((data[0] == 0xA5) && + (data[4] == randoms[0]) && + (data[5] == randoms[1]) && + (data[6] == randoms[2]) && + (data[7] == randoms[2])) { + rx_id[0] = data[1]; + rx_id[1] = data[2]; + rx_id[2] = data[3]; + if (sub_protocol != U816_V2) { + rf_ch_num = randoms[0] & 0x0f; + } + bind_step_success = 1; + } + } + // RX seems to need more than one ACK + if (packets_to_check) packets_to_check--; + //NRF24L01_WriteReg(NRF24L01_00_CONFIG, 0x0F); + if (bind_step_success && !packets_to_check) { + // All fine, switch address and RF channel, + // send bind packets with channel hopping now + phase = UDI_BIND2_TX; + + packet_sent = 0; + packets_to_send = 4; + bind_step_success = 0; + + NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, rx_id, 3); + NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_id, 3); + + if (sub_protocol != U816_V2) { + // Switch RF channel + NRF24L01_WriteReg(NRF24L01_05_RF_CH, rf_udi_channels[rf_ch_num++]); + rf_ch_num %= NUM_UDI_RF_CHANNELS; + } + + NRF24L01_FlushTx(); + NRF24L01_FlushRx(); + NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x7E); + + NRF24L01_SetTxRxMode(TX_EN); + //NRF24L01_WriteReg(NRF24L01_00_CONFIG, 0x0E) + + return 10; // 10 µs (start sending immediately) + } + return BIND_PACKET_UDI_PERIOD; + break; + + case UDI_BIND2_TX: + if (packet_sent && packet_udi_ack() == PKT_ACKED) { + bind_step_success = 1; + } + send_udi_packet(2); + if (packets_to_send) --packets_to_send; + if (bind_step_success || !packets_to_send) { + // Seems the original TX ignores AACK, too ! + // U816 V1: 3 packets send, U839: 4 packets send + // All fine, wait for reply of receiver + phase = UDI_BIND2_RX; + + NRF24L01_SetTxRxMode(RX_EN); + NRF24L01_FlushRx(); + + NRF24L01_WriteReg(NRF24L01_00_CONFIG, 0x0F); + bind_step_success = 0; + packets_to_check = 14; // ??? + } + return bind_step_success ? 4000 : 12000; // 4ms if no packed acked yet, 12ms afterwards + // return 120; // FIXME: Varies for first three packets !!! + + break; + + case UDI_BIND2_RX: + // Check if data has been received + if (NRF24L01_ReadReg(NRF24L01_07_STATUS) & BV(NRF24L01_07_RX_DR) ) { + uint8_t data[UDI_PAYLOADSIZE]; + NRF24L01_ReadPayload(data, payload_size); + NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x4E); + NRF24L01_FlushRx(); + + // Verify MAGIC, RX Addr, Random ID + // (may be reply to bind packet from other TX) + if ((data[0] == 0xDD) && + (data[1] == rx_id[0]) && + (data[2] == rx_id[1]) && + (data[3] == rx_id[2]) && + (data[4] == randoms[0]) && + (data[5] == randoms[1]) && + (data[6] == randoms[2]) && + (data[7] == randoms[2])) { + bind_step_success = 1; + } + } + // RX seems to need more than one ACK + if (packets_to_check) packets_to_check--; + //NRF24L01_WriteReg(NRF24L01_00_CONFIG, 0x0F); + if (bind_step_success && !packets_to_check) { + phase = UDI_DATA; + NRF24L01_SetTxRxMode(TX_EN); + NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x7E); + NRF24L01_WriteReg(NRF24L01_00_CONFIG, 0x0E); + NRF24L01_FlushTx(); + + // Switch RF channel + if (sub_protocol == U816_V2) { + // FIXED RF Channel + NRF24L01_WriteReg(NRF24L01_05_RF_CH, rf_ch_num); + } else { + NRF24L01_WriteReg(NRF24L01_05_RF_CH, rf_udi_channels[rf_ch_num++]); + rf_ch_num %= NUM_UDI_RF_CHANNELS; + } + + flags = 0; + BIND_DONE; + } + return BIND_PACKET_UDI_PERIOD; + break; + case UDI_DATA: + if (packet_sent && packet_udi_ack() != PKT_ACKED) { + return PACKET_UDI_CHKTIME; + } + send_udi_packet(0); + break; + } + // Packet every 15ms + return PACKET_UDI_PERIOD; +} + +static uint16_t UDI_setup() +{ + packet_counter = 0; + UDI_init(); + phase = UDI_INIT2; + + // observed on U839 TX + set_tx_id(0x457C27); + + return INITIAL_UDI_WAIT; +} +#endif diff --git a/Multiprotocol/SHENQI_nrf24l01.ino b/Multiprotocol/SHENQI_nrf24l01.ino index 2ffc2fc..b8ab94b 100644 --- a/Multiprotocol/SHENQI_nrf24l01.ino +++ b/Multiprotocol/SHENQI_nrf24l01.ino @@ -1,3 +1,5 @@ +<<<<<<< HEAD +======= /* This project is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -13,6 +15,7 @@ along with Multiprotocol. If not, see . */ +>>>>>>> refs/remotes/pascallanger/master #if defined(SHENQI_NRF24L01_INO) #include "iface_nrf24l01.h" @@ -39,10 +42,17 @@ void SHENQI_init() NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x03); // 5 bytes rx/tx address +<<<<<<< HEAD + LT8910_Config(4, 8, _BV(LT8910_CRC_ON)|_BV(LT8910_PACKET_LENGTH_EN), 0xAA); + LT8910_SetChannel(2); + LT8910_SetAddress((uint8_t *)"\x9A\x9A\x9A\x9A",4); + LT8910_SetTxRxMode(RX_EN); +======= LT8900_Config(4, 8, _BV(LT8900_CRC_ON)|_BV(LT8900_PACKET_LENGTH_EN), 0xAA); LT8900_SetChannel(2); LT8900_SetAddress((uint8_t *)"\x9A\x9A\x9A\x9A",4); LT8900_SetTxRxMode(RX_EN); +>>>>>>> refs/remotes/pascallanger/master } void SHENQI_send_packet() @@ -51,6 +61,16 @@ void SHENQI_send_packet() if(packet_count==0) { uint8_t bind_addr[4]; +<<<<<<< HEAD + bind_addr[0]=0x9A; + bind_addr[1]=0x9A; + bind_addr[2]=rx_tx_addr[2]; + bind_addr[3]=rx_tx_addr[3]; + LT8910_SetAddress(bind_addr,4); + LT8910_SetChannel(2); + packet[1]=rx_tx_addr[1]; + packet[2]=rx_tx_addr[0]; +======= bind_addr[0]=rx_tx_addr[0]; bind_addr[1]=rx_tx_addr[1]; bind_addr[2]=0x9A; @@ -59,24 +79,39 @@ void SHENQI_send_packet() LT8900_SetChannel(2); packet[1]=rx_tx_addr[2]; packet[2]=rx_tx_addr[3]; +>>>>>>> refs/remotes/pascallanger/master packet_period=2508; } else { +<<<<<<< HEAD + LT8910_SetAddress(rx_tx_addr,4); + packet[1]=255-convert_channel_8b(RUDDER); + packet[2]=255-convert_channel_8b_scale(THROTTLE,0x60,0xA0); + uint8_t freq=pgm_read_byte_near(&SHENQI_Freq[hopping_frequency_no])+(rx_tx_addr[1]&0x0F); + LT8910_SetChannel(freq); +======= LT8900_SetAddress(rx_tx_addr,4); packet[1]=255-convert_channel_8b(RUDDER); packet[2]=255-convert_channel_8b_scale(THROTTLE,0x60,0xA0); uint8_t freq=pgm_read_byte_near(&SHENQI_Freq[hopping_frequency_no])+(rx_tx_addr[2]&0x0F); LT8900_SetChannel(freq); +>>>>>>> refs/remotes/pascallanger/master hopping_frequency_no++; if(hopping_frequency_no==60) hopping_frequency_no=0; packet_period=1750; } // Send packet + 1 retransmit - not sure why but needed (not present on original TX...) +<<<<<<< HEAD + LT8910_WritePayload(packet,3); + while(NRF24L01_packet_ack()!=PKT_ACKED); + LT8910_WritePayload(packet,3); +======= LT8900_WritePayload(packet,3); while(NRF24L01_packet_ack()!=PKT_ACKED); LT8900_WritePayload(packet,3); +>>>>>>> refs/remotes/pascallanger/master packet_count++; if(packet_count==7) @@ -94,6 +129,16 @@ uint16_t SHENQI_callback() SHENQI_send_packet(); else { +<<<<<<< HEAD + if( NRF24L01_ReadReg(NRF24L01_07_STATUS) & BV(NRF24L01_07_RX_DR)) + { + if(LT8910_ReadPayload(packet, 3)) + { + BIND_DONE; + rx_tx_addr[3]=packet[1]; + rx_tx_addr[2]=packet[2]; + LT8910_SetTxRxMode(TX_EN); +======= if( NRF24L01_ReadReg(NRF24L01_07_STATUS) & _BV(NRF24L01_07_RX_DR)) { if(LT8900_ReadPayload(packet, 3)) @@ -102,6 +147,7 @@ uint16_t SHENQI_callback() rx_tx_addr[0]=packet[1]; rx_tx_addr[1]=packet[2]; LT8900_SetTxRxMode(TX_EN); +>>>>>>> refs/remotes/pascallanger/master packet_period=14000; } NRF24L01_FlushRx(); @@ -116,7 +162,11 @@ uint16_t initSHENQI() SHENQI_init(); hopping_frequency_no = 0; packet_count=0; +<<<<<<< HEAD + packet_period=100; +======= packet_period=500; +>>>>>>> refs/remotes/pascallanger/master return 1000; } diff --git a/Multiprotocol/Telemetry.ino b/Multiprotocol/Telemetry.ino index e9590b7..ad5e419 100644 --- a/Multiprotocol/Telemetry.ino +++ b/Multiprotocol/Telemetry.ino @@ -1,3 +1,178 @@ +<<<<<<< HEAD +//************************************* +// FrSky Telemetry serial code * +// By Midelic on RCGroups * +//************************************* + +#if defined TELEMETRY + #if defined FRSKYX_CC2500_INO + #define SPORT_TELEMETRY + #endif + #if defined FRSKY_CC2500_INO + #define HUB_TELEMETRY + #endif + #if defined SPORT_TELEMETRY + #define SPORT_TELEMETRY + #define SPORT_TIME 12000 + uint32_t last=0; + uint8_t sport_counter=0; + uint8_t RxBt=0; + uint8_t rssi; + uint8_t ADC2; + #endif + #if defined HUB_TELEMETRY + #define MAX_PKTX 10 + uint8_t pktx[MAX_PKTX]; + uint8_t index; + uint8_t prev_index; + uint8_t pass = 0; + #endif + #define USER_MAX_BYTES 6 + uint8_t frame[18]; + + void frskySendStuffed() + { + Serial_write(0x7E); + for (uint8_t i = 0; i < 9; i++) + { + if ((frame[i] == 0x7e) || (frame[i] == 0x7d)) + { + Serial_write(0x7D); + frame[i] ^= 0x20; + } + Serial_write(frame[i]); + } + Serial_write(0x7E); + } + + void compute_RSSIdbm(){ + + RSSI_dBm = (((uint16_t)(pktt[len-2])*18)>>5); + if(pktt[len-2] >=128) + RSSI_dBm -= 82; + else + RSSI_dBm += 65; + } + + void frsky_check_telemetry(uint8_t *pkt,uint8_t len) + { + if(pkt[1] != rx_tx_addr[3] || pkt[2] != rx_tx_addr[2] || len != pkt[0] + 3) + {//only packets with the required id and packet length + for(uint8_t i=3;i<6;i++) + pktt[i]=0; + return; + } + else + { + for (uint8_t i=3;i0) + telemetry_counter=(telemetry_counter+1)%32; + } + } + + void frsky_link_frame() + { + frame[0] = 0xFE; + if ((cur_protocol[0]&0x1F)==MODE_FRSKY) + { + compute_RSSIdbm(); + frame[1] = pktt[3]; + frame[2] = pktt[4]; + frame[3] = (uint8_t)RSSI_dBm; + frame[4] = pktt[5]*2; + } + else + if ((cur_protocol[0]&0x1F)==MODE_HUBSAN) + { + frame[1] = v_lipo*2; //v_lipo; common 0x2A=42/10=4.2V + frame[2] = frame[1]; + frame[3] = 0x00; + frame[4] = (uint8_t)RSSI_dBm; + } + frame[5] = frame[6] = frame[7] = frame[8] = 0; + frskySendStuffed(); + } + + #if defined HUB_TELEMETRY + void frsky_user_frame() + { + uint8_t indexx = 0, c=0, j=8, n=0, i; + + if(pktt[6]>0 && pktt[6]<=MAX_PKTX) + {//only valid hub frames + frame[0] = 0xFD; + frame[1] = 0; + frame[2] = pktt[7]; + + switch(pass) + { + case 0: + indexx=pktt[6]; + for(i=0;i>>>>>> refs/remotes/pascallanger/master 7E 98 10 05 F1 20 23 0F 00 A6 SWR_ID 7E 98 10 01 F1 33 00 00 00 C9 RSSI_ID 7E 98 10 04 F1 58 00 00 00 A1 BATT_ID @@ -241,15 +417,24 @@ pkt[6]|(counter++)|00 01 02 03 04 05 06 07 08 09 7E BA 10 03 F1 E2 00 00 00 18 ADC2_ID +<<<<<<< HEAD + Telemetry frames(RF) SPORT info 15 bytes + SPORT frame 6+3 bytes +======= Telemetry frames(RF) SPORT info 15 bytes payload SPORT frame valid 6+3 bytes +>>>>>>> refs/remotes/pascallanger/master [00] PKLEN 0E 0E 0E 0E [01] TXID1 DD DD DD DD [02] TXID2 6D 6D 6D 6D [03] CONST 02 02 02 02 [04] RS/RB 2C D0 2C CE //D0;CE=2*RSSI;....2C = RX battery voltage(5V from Bec) +<<<<<<< HEAD + [05] ????? 03 10 21 32 //TX/RX telemetry hand-shake bytes +======= [05] HD-SK 03 10 21 32 //TX/RX telemetry hand-shake bytes +>>>>>>> refs/remotes/pascallanger/master [06] NO.BT 00 00 06 03 //No.of valid SPORT frame bytes in the frame [07] STRM1 00 00 7E 00 [08] STRM2 00 00 1A 00 @@ -257,6 +442,146 @@ pkt[6]|(counter++)|00 01 02 03 04 05 06 07 08 09 [10] STRM4 03 03 03 03 [11] STRM5 F1 F1 F1 F1 [12] STRM6 D1 D1 D0 D0 +<<<<<<< HEAD + [13] CHKSUM1 + [14] CHKSUM2 + */ + + + void sportSend(uint8_t *p) + { + uint16_t crc_s = 0; + Serial_write(0x7e);//+9 + for (uint8_t i = 0; i < 9; i++) + { + if (i == 8) + p[i] = 0xff - crc_s; + if ((p[i] == 0x7e) || (p[i] == 0x7d)) + { + Serial_write(0x7d); + Serial_write(0x20 ^ p[i]); + } + else + Serial_write(p[i]); + if (i>0) + { + crc_s += p[i]; //0-1FF + crc_s += crc_s >> 8; //0-100 + crc_s &= 0x00ff; + } + } + } + + void sportIdle() + { + Serial_write(0x7e); + } + + void sportSendFrame() + { + //at the moment only SWR RSSI,RxBt and A2. + sport_counter = (sport_counter + 1) %9; + + for (uint8_t i=5;i<8;i++) + frame[i]=0; + + switch (sport_counter) + { + case 0: // SWR + frame[0] = 0x98; + frame[1] = 0x10; + frame[2] = 0x05; + frame[3] = 0xf1; + frame[4] = 0x20;//dummy values if swr 20230f00 + frame[5] = 0x23; + frame[6] = 0x0F; + frame[7] = 0x00; + break; + case 1: // RSSI + frame[0] = 0x98; + frame[1] = 0x10; + frame[2] = 0x01; + frame[3] = 0xf1; + frame[4] = rssi; + break; + case 2: //BATT + frame[0] = 0x98; + frame[1] = 0x10; + frame[2] = 0x04; + frame[3] = 0xf1; + frame[4] = RxBt;//a1; + break; + case 3: //ADC2(A2) + frame[0] = 0x1A; + frame[1] = 0x10; + frame[2] = 0x03; + frame[3] = 0xf1; + frame[4] = ADC2;//a2;; + break; + default: + sportIdle(); + return; + } + sportSend(frame); + } + + void process_sport_data()//only for ADC2 + { + uint8_t j=7; + if(pktt[6]>0 && pktt[6]<=USER_MAX_BYTES) + { + for(uint8_t i=0;i<6;i++) + if(pktt[j++]==0x03) + if(pktt[j]==0xF1) + { + ADC2=pktt[j+1]; + break; + } + pktt[6]=0;//new frame + } + } + #endif + + + void frskyUpdate() + { + if(telemetry_link && (cur_protocol[0]&0x1F) != MODE_FRSKYX ) + { + frsky_link_frame(); + telemetry_link=0; + return; + } + #if defined HUB_TELEMETRY + if(!telemetry_link && (cur_protocol[0]&0x1F) != MODE_HUBSAN && (cur_protocol[0]&0x1F) != MODE_FRSKYX) + { + frsky_user_frame(); + return; + } + #endif + #if defined SPORT_TELEMETRY + if ((cur_protocol[0]&0x1F)==MODE_FRSKYX) + { + if(telemetry_link) + { + process_sport_data(); + if(pktt[4]>0x36) + rssi=pktt[4]/2; + else + RxBt=pktt[4]; + telemetry_link=0; + } + uint32_t now = micros(); + if ((now - last) > SPORT_TIME) + { + sportSendFrame(); + last = now; + } + } + #endif + } + +#endif +======= [13] CHKSUM1 --|2 CRC bytes sent by RX (calculated on RX side crc16/table) [14] CHKSUM2 --| +2 appended bytes automatically RSSI and LQI/CRC bytes(len=0x0E+3); @@ -824,3 +1149,4 @@ ISR(TIMER0_OVF_vect) #endif // BASH_SERIAL #endif // TELEMETRY +>>>>>>> refs/remotes/pascallanger/master diff --git a/Multiprotocol/YD717_nrf24l01.ino b/Multiprotocol/YD717_nrf24l01.ino index 4e6a634..e3a3756 100644 --- a/Multiprotocol/YD717_nrf24l01.ino +++ b/Multiprotocol/YD717_nrf24l01.ino @@ -34,6 +34,16 @@ #define YD717_PAYLOADSIZE 8 // receive data pipes set to this size, but unused +<<<<<<< HEAD +enum { + YD717_INIT1 = 0, + YD717_BIND2, + YD717_BIND3, + YD717_DATA +}; + +======= +>>>>>>> refs/remotes/pascallanger/master static void __attribute__((unused)) yd717_send_packet(uint8_t bind) { uint8_t rudder_trim, elevator_trim, aileron_trim; @@ -139,6 +149,11 @@ static void __attribute__((unused)) yd717_init() NRF24L01_WriteReg(NRF24L01_1D_FEATURE, 0x07); // Set feature bits on NRF24L01_Activate(0x73); +<<<<<<< HEAD +static void __attribute__((unused)) YD717_init1() +{ +======= +>>>>>>> refs/remotes/pascallanger/master // for bind packets set address to prearranged value known to receiver uint8_t bind_rx_tx_addr[] = {0x65, 0x65, 0x65, 0x65, 0x65}; @@ -153,6 +168,16 @@ static void __attribute__((unused)) yd717_init() NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, bind_rx_tx_addr, 5); } +<<<<<<< HEAD +static void __attribute__((unused)) YD717_init2() +{ + // set rx/tx address for data phase + NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, rx_tx_addr, 5); + NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_addr, 5); +} + +======= +>>>>>>> refs/remotes/pascallanger/master uint16_t yd717_callback() { if(IS_BIND_DONE_on) diff --git a/Multiprotocol/_Config.h b/Multiprotocol/_Config.h index dc194e2..17c740a 100644 --- a/Multiprotocol/_Config.h +++ b/Multiprotocol/_Config.h @@ -13,6 +13,85 @@ along with Multiprotocol. If not, see . */ +<<<<<<< HEAD +/** Multiprotocol module configuration file ***/ + +//Uncomment your TX type +#define TARANIS //TARANIS TAER (1100<->1900µs) +//#define TX_ER9X //ER9X AETR (988<->2012µs) +//#define TX_DEVO7 //DEVO7 EATR (1120<->1920µs) +//#define TX_SPEKTRUM //Spektrum TAER (1100<->1900µs) +//#define TX_HISKY //HISKY AETR (1100<->1900µs) + +//Uncomment to enable telemetry +#define TELEMETRY + +//Comment if a module is not installed +#define A7105_INSTALLED +#define CYRF6936_INSTALLED +//#define CC2500_INSTALLED +#define NFR24L01_INSTALLED + +//Comment a protocol to exclude it from compilation +#ifdef A7105_INSTALLED + #define JOYSWAY_A7105_INO + + #define FLYSKY_A7105_INO + #define HUBSAN_A7105_INO +#endif +#ifdef CYRF6936_INSTALLED + #define J6PRO_CYRF6936_INO + #define WK2x01_CYRF6936_INO + + #define DEVO_CYRF6936_INO + #define DSM2_CYRF6936_INO +#endif +#ifdef CC2500_INSTALLED + #define SKYARTEC_CC2500_INO + + #define FRSKY_CC2500_INO + #define FRSKYX_CC2500_INO +#endif +#ifdef NFR24L01_INSTALLED + #define HM830_NRF24L01_INO + #define CFlie_NRF24L01_INO + #define H377_NRF24L01_INO + #define ESKY150_NRF24L01_INO + #define HonTai_NRF24L01_INO + #define UDI_NRF24L01_INO + #define NE260_NRF24L01_INO + #define BlueFly_NRF24L01_INO //probleme gene id + #define FBL100_NRF24L01_INO // finir id + + #define BAYANG_NRF24L01_INO + #define CG023_NRF24L01_INO + #define CX10_NRF24L01_INO + #define ESKY_NRF24L01_INO + #define HISKY_NRF24L01_INO + #define KN_NRF24L01_INO + #define SLT_NRF24L01_INO + #define SYMAX_NRF24L01_INO + #define V2X2_NRF24L01_INO + #define YD717_NRF24L01_INO + #define MT99XX_NRF24L01_INO + #define MJXQ_NRF24L01_INO + #define SHENQI_NRF24L01_INO + #define FY326_NRF24L01_INO +#endif + +//Update this table to set which protocol and all associated settings are called for the corresponding dial number +const PPM_Parameters PPM_prot[15]= { +// Dial Protocol Sub protocol RX_Num Power Auto Bind Option +/* 1 */ {MODE_FLYSKY, Flysky , 0 , P_HIGH , AUTOBIND , 0 }, +/* 2 */ {MODE_HUBSAN, 0 , 0 , P_HIGH , NO_AUTOBIND , 0 }, +/* 3 */ {MODE_FRSKY , 0 , 0 , P_HIGH , NO_AUTOBIND , 0xD7 }, // D7 fine tuning +/* 4 */ {MODE_HISKY , Hisky , 0 , P_HIGH , NO_AUTOBIND , 0 }, +/* 5 */ {MODE_V2X2 , 0 , 0 , P_HIGH , NO_AUTOBIND , 0 }, +/* 6 */ {MODE_DSM2 , DSM2 , 0 , P_HIGH , NO_AUTOBIND , 6 }, // 6 channels @ 11ms +/* 7 */ {MODE_DEVO , 0 , 0 , P_HIGH , NO_AUTOBIND , 0 }, +/* 8 */ {MODE_YD717 , YD717 , 0 , P_HIGH , NO_AUTOBIND , 0 }, +/* 9 */ {MODE_KN , FEILUN , 0 , P_HIGH , AUTOBIND , 0 }, +======= /**********************************************/ /** Multiprotocol module configuration file ***/ /**********************************************/ @@ -155,6 +234,7 @@ const PPM_Parameters PPM_prot[15]= { /* 7 */ {MODE_DEVO , 0 , 0 , P_HIGH , NO_AUTOBIND , 0 }, /* 8 */ {MODE_YD717 , YD717 , 0 , P_HIGH , NO_AUTOBIND , 0 }, /* 9 */ {MODE_KN , WLTOYS , 0 , P_HIGH , NO_AUTOBIND , 0 }, +>>>>>>> refs/remotes/pascallanger/master /* 10 */ {MODE_SYMAX , SYMAX , 0 , P_HIGH , NO_AUTOBIND , 0 }, /* 11 */ {MODE_SLT , 0 , 0 , P_HIGH , NO_AUTOBIND , 0 }, /* 12 */ {MODE_CX10 , CX10_BLUE , 0 , P_HIGH , NO_AUTOBIND , 0 }, @@ -162,7 +242,11 @@ const PPM_Parameters PPM_prot[15]= { /* 14 */ {MODE_BAYANG, 0 , 0 , P_HIGH , NO_AUTOBIND , 0 }, /* 15 */ {MODE_SYMAX , SYMAX5C , 0 , P_HIGH , NO_AUTOBIND , 0 } }; +<<<<<<< HEAD +/* Available protocols and associated sub protocols: +======= /* Available protocols and associated sub protocols to pick and choose from +>>>>>>> refs/remotes/pascallanger/master MODE_FLYSKY Flysky V9X9 @@ -170,18 +254,28 @@ const PPM_Parameters PPM_prot[15]= { V912 MODE_HUBSAN NONE +<<<<<<< HEAD + MODE_FRSKY +======= MODE_FRSKYD +>>>>>>> refs/remotes/pascallanger/master NONE MODE_HISKY Hisky HK310 MODE_V2X2 NONE +<<<<<<< HEAD + MODE_DSM2 + DSM2 + DSMX +======= MODE_DSM DSM2_22 DSM2_11 DSMX_22 DSMX_11 +>>>>>>> refs/remotes/pascallanger/master MODE_DEVO NONE MODE_YD717 @@ -214,20 +308,137 @@ const PPM_Parameters PPM_prot[15]= { MODE_BAYANG NONE MODE_FRSKYX +<<<<<<< HEAD + NONE +======= CH_16 CH_8 +>>>>>>> refs/remotes/pascallanger/master MODE_ESKY NONE MODE_MT99XX MT99 H7 YZ +<<<<<<< HEAD +======= LS +>>>>>>> refs/remotes/pascallanger/master MODE_MJXQ WLH08 X600 X800 H26D +<<<<<<< HEAD + MODE_SHENQI + NONE + MODE_FY326 + FY326 + FY319 + +RX_Num value between 0 and 15 + +Power P_HIGH or P_LOW + +Auto Bind AUTOBIND or NO_AUTOBIND + +Option value between 0 and 255. 0xD7 or 0x00 for Frsky fine tuning. +*/ + +//****************** +//TX definitions with timing endpoints and channels order + +// Turnigy PPM and channels +#if defined(TX_ER9X) + #define PPM_MAX 2140 + #define PPM_MIN 860 + #define PPM_MAX_100 2012 + #define PPM_MIN_100 988 + #define AETR +#endif + +// Devo PPM and channels +#if defined(TX_DEVO7) + #define PPM_MAX 2100 + #define PPM_MIN 900 + #define PPM_MAX_100 1920 + #define PPM_MIN_100 1120 + #define EATR +#endif + +// SPEKTRUM PPM and channels +#if defined(TX_SPEKTRUM) + #define PPM_MAX 2000 + #define PPM_MIN 1000 + #define PPM_MAX_100 1900 + #define PPM_MIN_100 1100 + #define TAER +#endif + +// TARANIS PPM and channels +#if defined(TARANIS) + #define PPM_MAX 2000 + #define PPM_MIN 1000 + #define PPM_MAX_100 1900 + #define PPM_MIN_100 1100 + #define EATR +#endif + +// HISKY +#if defined(TX_HISKY) + #define PPM_MAX 2000 + #define PPM_MIN 1000 + #define PPM_MAX_100 1900 + #define PPM_MIN_100 1100 + #define AETR +#endif + +#if defined(EATR) + enum chan_order{ + ELEVATOR=0, + AILERON, + THROTTLE, + RUDDER, + }; +#endif + +#if defined(TAER) + enum chan_order{ + THROTTLE=0, + AILERON, + ELEVATOR, + RUDDER, + }; +#endif + +#if defined(AETR) + enum chan_order{ + AILERON =0, + ELEVATOR, + THROTTLE, + RUDDER, + }; +#endif +enum chan_orders{ + AUX1 =4, + AUX2, + AUX3, + AUX4, + AUX5, + AUX6, + AUX7, + AUX8, + AUX9 +}; + +#define PPM_MIN_COMMAND 1250 +#define PPM_SWITCH 1550 +#define PPM_MAX_COMMAND 1750 + +//Uncoment the desired serial speed +#define BAUD 100000 +//#define BAUD 125000 +======= E010 MODE_SHENQI NONE @@ -260,4 +471,5 @@ const PPM_Parameters PPM_prot[15]= { // As an exxample, it's usefull for the WLTOYS F929/F939/F949/F959 (all using the Flysky protocol) which requires a bind at each power up. // Option: the value is between -127 and +127. -// The option value is only valid for some protocols, read this page for more information: https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/blob/master/Protocols_Details.md \ No newline at end of file +// The option value is only valid for some protocols, read this page for more information: https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/blob/master/Protocols_Details.md +>>>>>>> refs/remotes/pascallanger/master diff --git a/Multiprotocol/iface_nrf24l01.h b/Multiprotocol/iface_nrf24l01.h index cc8b6fe..6aab6c1 100644 --- a/Multiprotocol/iface_nrf24l01.h +++ b/Multiprotocol/iface_nrf24l01.h @@ -103,8 +103,13 @@ enum { //#define NOP 0xFF // XN297 emulation layer +<<<<<<< HEAD +#define XN297_UNSCRAMBLED 8 + +======= enum { XN297_UNSCRAMBLED = 0, XN297_SCRAMBLED }; +>>>>>>> refs/remotes/pascallanger/master #endif \ No newline at end of file diff --git a/Multiprotocol/multi.lua b/Multiprotocol/multi.lua new file mode 100644 index 0000000..07721ae --- /dev/null +++ b/Multiprotocol/multi.lua @@ -0,0 +1,94 @@ +-- Multiprotocole Midelic et Pascallanger +local debut = 0 +local tps = 0 +local tpsact = 1024 +local mix, mixe +local channel + +local inp = { + { "Protocole", VALUE, 1, 26, 2 }, + { "Switch", SOURCE } +} +-- 6 7 8 15 16 17 24 25 26 +-- 4 5 12 13 14 21 22 23 +-- 1 2 3 9 10 11 18 19 20 +local out = { "Bind", "Gaz", "Aile", "Prof", "Dir" } + +local function run_func(proto, sw) + -- test mixage lua + if debut == 0 then + -- passage en lua + for channel = 0, 3, 1 do + local mix = model.getMix(channel, 0) + mix_source = mix["source"] + if mix_source < 33 or 1 then + model.deleteMix(channel, 0) + mix["source"] = channel + 34 + mix["name"] = "Lua " + model.insertMix(channel, 0, mix) + end + end + end + -- inter install + channel = 4 + mix = { name="Raz Bind", source=33, weight=100, switch=0, multiplex=REPLACE } + count = model.getMixesCount(channel + 0) + if count == 0 and inter == 1 then + model.insertMix(channel + 0, 0, mix) + elseif count == 1 and inter == 0 then + mixe = model.getMix(channel, 0) + if mixe["name"] == mix["name"] then + model.deleteMix(channel, 0) + end + end + + -- delais init + if proto ~= debut then + tps = getTime() + 250 -- delai pour mini 12 cycle PPM + tpsact = 1024 + debut = proto + end + + local gaz = 1024 + local ail = 0 + local dir = 0 + local pro = 0 + + if tpsact == 0 and sw < 100 then + -- reprise valeur input + pro = getValue(1) + ail = getValue(2) + gaz = getValue(3) + dir = getValue(4) + elseif tpsact ~= 0 then + -- decallage pour position memo (centre) + if proto > 4 then proto = proto + 1 end + + -- calcul position + -- decallage pour > 18 + if proto > 18 then + ail = 1024 + proto = proto - 18 + end + -- decallage pour > 9 + if proto > 9 then + ail = -1024 + proto = proto - 9 + end + + if proto < 4 then pro = -1024 end + if proto > 6 then pro = 1024 end + + if proto % 3 == 1 then dir = -1024 end + if proto % 3 == 0 then dir = 1024 end + + if tps < getTime() then + tpsact = tpsact - 512 + if tpsact>-20 then tps = getTime() + 250 end + end + sw = tpsact + end + + return sw, gaz, ail, pro, dir +end +return { run=run_func, input=inp, output=out} diff --git a/Multiprotocol/multiprotocol.h b/Multiprotocol/multiprotocol.h new file mode 100644 index 0000000..672b922 --- /dev/null +++ b/Multiprotocol/multiprotocol.h @@ -0,0 +1,485 @@ +/* + This project is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Multiprotocol is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Multiprotocol. If not, see . + */ + +// Check selected board type +#ifndef XMEGA + #if not defined(ARDUINO_AVR_PRO) && not defined(ARDUINO_AVR_MINI) && not defined(ARDUINO_AVR_NANO) + #error You must select the board type "Arduino Pro or Pro Mini" or "Arduino Mini" + #endif + #if F_CPU != 16000000L || not defined(__AVR_ATmega328P__) + #error You must select the processor type "ATmega328(5V, 16MHz)" + #endif +#endif + +//****************** +// Protocols +//****************** +enum PROTOCOLS +{ + MODE_SERIAL = 0, // Serial commands + MODE_FLYSKY = 1, // =>A7105 + MODE_HUBSAN = 2, // =>A7105 + MODE_FRSKYD = 3, // =>CC2500 + MODE_HISKY = 4, // =>NRF24L01 + MODE_V2X2 = 5, // =>NRF24L01 + MODE_DSM = 6, // =>CYRF6936 + MODE_DEVO = 7, // =>CYRF6936 + MODE_YD717 = 8, // =>NRF24L01 + MODE_KN = 9, // =>NRF24L01 + MODE_SYMAX = 10, // =>NRF24L01 + MODE_SLT = 11, // =>NRF24L01 + MODE_CX10 = 12, // =>NRF24L01 + MODE_CG023 = 13, // =>NRF24L01 + MODE_BAYANG = 14, // =>NRF24L01 + MODE_FRSKYX = 15, // =>CC2500 + MODE_ESKY = 16, // =>NRF24L01 + MODE_MT99XX = 17, // =>NRF24L01 + MODE_MJXQ = 18, // =>NRF24L01 + MODE_SHENQI = 19, // =>NRF24L01 + MODE_FY326 = 20, // =>NRF24L01 + MODE_SFHSS = 21, // =>CC2500 + MODE_J6PRO = 22, // =>CYRF6936 + MODE_FQ777 = 23, // =>NRF24L01 + MODE_ASSAN = 24, // =>NRF24L01 + MODE_FRSKYV = 25, // =>CC2500 + MODE_HONTAI = 26, // =>NRF24L01 + MODE_OPENLRS = 27, // =>OpenLRS hardware +}; + +enum Flysky +{ + Flysky = 0, + V9X9 = 1, + V6X6 = 2, + V912 = 3 +}; +enum Hisky +{ + Hisky = 0, + HK310 = 1 +}; +enum DSM +{ + DSM2_22 = 0, + DSM2_11 = 1, + DSMX_22 = 2, + DSMX_11 = 3, + DSM_AUTO = 4 +}; +enum YD717 +{ + YD717 = 0, + SKYWLKR = 1, + SYMAX4 = 2, + XINXUN = 3, + NIHUI = 4 +}; +enum KN +{ + WLTOYS = 0, + FEILUN = 1 +}; +enum SYMAX +{ + SYMAX = 0, + SYMAX5C = 1 +}; +enum CX10 +{ + CX10_GREEN = 0, + CX10_BLUE = 1, // also compatible with CX10-A, CX12 + DM007 = 2, + Q282 = 3, + JC3015_1 = 4, + JC3015_2 = 5, + MK33041 = 6, + Q242 = 7 +}; +enum CG023 +{ + CG023 = 0, + YD829 = 1, + H8_3D = 2 +}; +enum MT99XX +{ + MT99 = 0, + H7 = 1, + YZ = 2, + LS = 3 +}; +enum MJXQ +{ + WLH08 = 0, + X600 = 1, + X800 = 2, + H26D = 3, + E010 = 4 +}; +enum FRSKYX +{ + CH_16 = 0, + CH_8 = 1, +}; +enum HONTAI +{ + FORMAT_HONTAI = 0, + FORMAT_JJRCX1 = 1, + FORMAT_X5C1 = 2 +}; + +#define NONE 0 +#define P_HIGH 1 +#define P_LOW 0 +#define AUTOBIND 1 +#define NO_AUTOBIND 0 + +struct PPM_Parameters +{ + uint8_t protocol : 6; + uint8_t sub_proto : 3; + uint8_t rx_num : 4; + uint8_t power : 1; + uint8_t autobind : 1; + uint8_t option; +}; + +// Macros +#define NOP() __asm__ __volatile__("nop") + +//******************* +//*** Timer *** +//******************* +#ifdef XMEGA + #define TIFR1 TCC1.INTFLAGS + #define OCF1A_bm TC1_CCAIF_bm + #define OCR1A TCC1.CCA + #define TCNT1 TCC1.CNT + #define UDR0 USARTC0.DATA + #define OCF1B_bm TC1_CCBIF_bm + #define OCR1B TCC1.CCB + #define TIMSK1 TCC1.INTCTRLB + #define SET_TIMSK1_OCIE1B TIMSK1 = (TIMSK1 & 0xF3) | 0x04 + #define CLR_TIMSK1_OCIE1B TIMSK1 &= 0xF3 +#else + #define OCF1A_bm _BV(OCF1A) + #define OCF1B_bm _BV(OCF1B) + #define SET_TIMSK1_OCIE1B TIMSK1 |= _BV(OCIE1B) + #define CLR_TIMSK1_OCIE1B TIMSK1 &=~_BV(OCIE1B) +#endif + +//*************** +//*** Flags *** +//*************** +#define RX_FLAG_on protocol_flags |= _BV(0) +#define RX_FLAG_off protocol_flags &= ~_BV(0) +#define IS_RX_FLAG_on ( ( protocol_flags & _BV(0) ) !=0 ) +// +#define CHANGE_PROTOCOL_FLAG_on protocol_flags |= _BV(1) +#define CHANGE_PROTOCOL_FLAG_off protocol_flags &= ~_BV(1) +#define IS_CHANGE_PROTOCOL_FLAG_on ( ( protocol_flags & _BV(1) ) !=0 ) +// +#define POWER_FLAG_on protocol_flags |= _BV(2) +#define POWER_FLAG_off protocol_flags &= ~_BV(2) +#define IS_POWER_FLAG_on ( ( protocol_flags & _BV(2) ) !=0 ) +// +#define RANGE_FLAG_on protocol_flags |= _BV(3) +#define RANGE_FLAG_off protocol_flags &= ~_BV(3) +#define IS_RANGE_FLAG_on ( ( protocol_flags & _BV(3) ) !=0 ) +// +#define AUTOBIND_FLAG_on protocol_flags |= _BV(4) +#define AUTOBIND_FLAG_off protocol_flags &= ~_BV(4) +#define IS_AUTOBIND_FLAG_on ( ( protocol_flags & _BV(4) ) !=0 ) +// +#define BIND_BUTTON_FLAG_on protocol_flags |= _BV(5) +#define BIND_BUTTON_FLAG_off protocol_flags &= ~_BV(5) +#define IS_BIND_BUTTON_FLAG_on ( ( protocol_flags & _BV(5) ) !=0 ) +//PPM RX OK +#define PPM_FLAG_off protocol_flags &= ~_BV(6) +#define PPM_FLAG_on protocol_flags |= _BV(6) +#define IS_PPM_FLAG_on ( ( protocol_flags & _BV(6) ) !=0 ) +//Bind flag +#define BIND_IN_PROGRESS protocol_flags &= ~_BV(7) +#define BIND_DONE protocol_flags |= _BV(7) +#define IS_BIND_DONE_on ( ( protocol_flags & _BV(7) ) !=0 ) +// +#define BAD_PROTO_off protocol_flags2 &= ~_BV(0) +#define BAD_PROTO_on protocol_flags2 |= _BV(0) +#define IS_BAD_PROTO_on ( ( protocol_flags2 & _BV(0) ) !=0 ) +// +#define RX_DONOTUPDTAE_off protocol_flags2 &= ~_BV(1) +#define RX_DONOTUPDTAE_on protocol_flags2 |= _BV(1) +#define IS_RX_DONOTUPDTAE_on ( ( protocol_flags2 & _BV(1) ) !=0 ) +// +#define RX_MISSED_BUFF_off protocol_flags2 &= ~_BV(2) +#define RX_MISSED_BUFF_on protocol_flags2 |= _BV(2) +#define IS_RX_MISSED_BUFF_on ( ( protocol_flags2 & _BV(2) ) !=0 ) +//TX Pause +#define TX_MAIN_PAUSE_off protocol_flags2 &= ~_BV(3) +#define TX_MAIN_PAUSE_on protocol_flags2 |= _BV(3) +#define IS_TX_MAIN_PAUSE_on ( ( protocol_flags2 & _BV(3) ) !=0 ) +#define TX_RX_PAUSE_off protocol_flags2 &= ~_BV(4) +#define TX_RX_PAUSE_on protocol_flags2 |= _BV(4) +#define IS_TX_RX_PAUSE_on ( ( protocol_flags2 & _BV(4) ) !=0 ) +#define IS_TX_PAUSE_on ( ( protocol_flags2 & (_BV(4)|_BV(3)) ) !=0 ) + +//******************** +//*** Blink timing *** +//******************** +#define BLINK_BIND_TIME 100 +#define BLINK_SERIAL_TIME 500 +#define BLINK_BAD_PROTO_TIME_LOW 1000 +#define BLINK_BAD_PROTO_TIME_HIGH 50 + +//******************* +//*** AUX flags *** +//******************* +#define GET_FLAG(ch, mask) ( ch ? mask : 0) +#define Servo_AUX1 Servo_AUX & _BV(0) +#define Servo_AUX2 Servo_AUX & _BV(1) +#define Servo_AUX3 Servo_AUX & _BV(2) +#define Servo_AUX4 Servo_AUX & _BV(3) +#define Servo_AUX5 Servo_AUX & _BV(4) +#define Servo_AUX6 Servo_AUX & _BV(5) +#define Servo_AUX7 Servo_AUX & _BV(6) +#define Servo_AUX8 Servo_AUX & _BV(7) + +//************************ +//*** Power settings *** +//************************ +enum { + TXPOWER_100uW, + TXPOWER_300uW, + TXPOWER_1mW, + TXPOWER_3mW, + TXPOWER_10mW, + TXPOWER_30mW, + TXPOWER_100mW, + TXPOWER_150mW +}; + +// A7105 power +// Power amp is ~+16dBm so: +enum A7105_POWER +{ + A7105_POWER_0 = 0x00<<3 | 0x00, // TXPOWER_100uW = -23dBm == PAC=0 TBG=0 + A7105_POWER_1 = 0x00<<3 | 0x01, // TXPOWER_300uW = -20dBm == PAC=0 TBG=1 + A7105_POWER_2 = 0x00<<3 | 0x02, // TXPOWER_1mW = -16dBm == PAC=0 TBG=2 + A7105_POWER_3 = 0x00<<3 | 0x04, // TXPOWER_3mW = -11dBm == PAC=0 TBG=4 + A7105_POWER_4 = 0x01<<3 | 0x05, // TXPOWER_10mW = -6dBm == PAC=1 TBG=5 + A7105_POWER_5 = 0x02<<3 | 0x07, // TXPOWER_30mW = 0dBm == PAC=2 TBG=7 + A7105_POWER_6 = 0x03<<3 | 0x07, // TXPOWER_100mW = 1dBm == PAC=3 TBG=7 + A7105_POWER_7 = 0x03<<3 | 0x07 // TXPOWER_150mW = 1dBm == PAC=3 TBG=7 +}; +#define A7105_HIGH_POWER A7105_POWER_7 +#define A7105_LOW_POWER A7105_POWER_3 +#define A7105_RANGE_POWER A7105_POWER_0 +#define A7105_BIND_POWER A7105_POWER_0 + +// NRF Power +// Power setting is 0..3 for nRF24L01 +// Claimed power amp for nRF24L01 from eBay is 20dBm. +enum NRF_POWER +{ // Raw w 20dBm PA + NRF_POWER_0 = 0x00, // 0 : -18dBm (16uW) 2dBm (1.6mW) + NRF_POWER_1 = 0x01, // 1 : -12dBm (60uW) 8dBm (6mW) + NRF_POWER_2 = 0x02, // 2 : -6dBm (250uW) 14dBm (25mW) + NRF_POWER_3 = 0x03 // 3 : 0dBm (1mW) 20dBm (100mW) +}; +#define NRF_HIGH_POWER NRF_POWER_2 +#define NRF_LOW_POWER NRF_POWER_1 +#define NRF_RANGE_POWER NRF_POWER_0 +#define NRF_BIND_POWER NRF_POWER_0 + +// CC2500 power output from the chip itself +// The numbers do not take into account any outside amplifier +enum CC2500_POWER +{ + CC2500_POWER_0 = 0x00, // –55dbm or less + CC2500_POWER_1 = 0x50, // -30dbm + CC2500_POWER_2 = 0x44, // –28dbm + CC2500_POWER_3 = 0xC0, // –26dbm + CC2500_POWER_4 = 0x84, // –24dbm + CC2500_POWER_5 = 0x81, // –22dbm + CC2500_POWER_6 = 0x46, // –20dbm + CC2500_POWER_7 = 0x93, // –18dbm + CC2500_POWER_8 = 0x55, // –16dbm + CC2500_POWER_9 = 0x8D, // –14dbm + CC2500_POWER_10 = 0xC6, // -12dbm + CC2500_POWER_11 = 0x97, // -10dbm + CC2500_POWER_12 = 0x6E, // -8dbm + CC2500_POWER_13 = 0x7F, // -6dbm + CC2500_POWER_14 = 0xA9, // -4dbm + CC2500_POWER_15 = 0xBB, // -2dbm + CC2500_POWER_16 = 0xFE, // 0dbm + CC2500_POWER_17 = 0xFF // +1dbm +}; +#define CC2500_HIGH_POWER CC2500_POWER_16 +#define CC2500_LOW_POWER CC2500_POWER_13 +#define CC2500_RANGE_POWER CC2500_POWER_1 +#define CC2500_BIND_POWER CC2500_POWER_1 + +// CYRF power +enum CYRF_POWER +{ + CYRF_POWER_0 = 0x00, // -35dbm + CYRF_POWER_1 = 0x01, // -30dbm + CYRF_POWER_2 = 0x02, // -24dbm + CYRF_POWER_3 = 0x03, // -18dbm + CYRF_POWER_4 = 0x04, // -13dbm + CYRF_POWER_5 = 0x05, // -5dbm + CYRF_POWER_6 = 0x06, // 0dbm + CYRF_POWER_7 = 0x07 // +4dbm +}; +#define CYRF_HIGH_POWER CYRF_POWER_7 +#define CYRF_LOW_POWER CYRF_POWER_3 +#define CYRF_RANGE_POWER CYRF_POWER_1 // 1/30 of the full power distance +#define CYRF_BIND_POWER CYRF_POWER_0 + +enum TXRX_State { + TXRX_OFF, + TX_EN, + RX_EN +}; + +// Packet ack status values +enum { + PKT_PENDING = 0, + PKT_ACKED, + PKT_TIMEOUT +}; + +// baudrate defines for serial +#define SPEED_100K 0 +#define SPEED_9600 1 +#define SPEED_57600 2 +#define SPEED_125K 3 + +//**************************************** +//*** MULTI protocol serial definition *** +//**************************************** +/* +************************** +16 channels serial protocol +************************** +Serial: 100000 Baud 8e2 _ xxxx xxxx p -- + Total of 26 bytes + Stream[0] = 0x55 sub_protocol values are 0..31 + Stream[0] = 0x54 sub_protocol values are 32..63 + header + Stream[1] = sub_protocol|BindBit|RangeCheckBit|AutoBindBit; + sub_protocol is 0..31 (bits 0..4), value should be added with 32 if Stream[0] = 0x54 + => Reserved 0 + Flysky 1 + Hubsan 2 + FrskyD 3 + Hisky 4 + V2x2 5 + DSM 6 + Devo 7 + YD717 8 + KN 9 + SymaX 10 + SLT 11 + CX10 12 + CG023 13 + Bayang 14 + FrskyX 15 + ESky 16 + MT99XX 17 + MJXQ 18 + SHENQI 19 + FY326 20 + SFHSS 21 + J6PRO 22 + FQ777 23 + ASSAN 24 + FrskyV 25 + HONTAI 26 + OpenLRS 27 + BindBit=> 0x80 1=Bind/0=No + AutoBindBit=> 0x40 1=Yes /0=No + RangeCheck=> 0x20 1=Yes /0=No + Stream[2] = RxNum | Power | Type; + RxNum value is 0..15 (bits 0..3) + Type is 0..7 <<4 (bit 4..6) + sub_protocol==Flysky + Flysky 0 + V9x9 1 + V6x6 2 + V912 3 + sub_protocol==Hisky + Hisky 0 + HK310 1 + sub_protocol==DSM + DSM2_22 0 + DSM2_11 1 + DSMX_22 2 + DSMX_11 3 + sub_protocol==YD717 + YD717 0 + SKYWLKR 1 + SYMAX4 2 + XINXUN 3 + NIHUI 4 + sub_protocol==KN + WLTOYS 0 + FEILUN 1 + sub_protocol==SYMAX + SYMAX 0 + SYMAX5C 1 + sub_protocol==CX10 + CX10_GREEN 0 + CX10_BLUE 1 // also compatible with CX10-A, CX12 + DM007 2 + Q282 3 + JC3015_1 4 + JC3015_2 5 + MK33041 6 + Q242 7 + sub_protocol==CG023 + CG023 0 + YD829 1 + H8_3D 2 + sub_protocol==MT99XX + MT99 0 + H7 1 + YZ 2 + LS 3 + sub_protocol==MJXQ + WLH08 0 + X600 1 + X800 2 + H26D 3 + E010 4 + sub_protocol==FRSKYX + CH_16 0 + CH_8 1 + sub_protocol==HONTAI + FORMAT_HONTAI 0 + FORMAT_JJRCX1 1 + FORMAT_X5C1 2 + Power value => 0x80 0=High/1=Low + Stream[3] = option_protocol; + option_protocol value is -127..127 + Stream[4] to [25] = Channels + 16 Channels on 11 bits (0..2047) + 0 -125% + 204 -100% + 1024 0% + 1843 +100% + 2047 +125% + Channels bits are concatenated to fit in 22 bytes like in SBUS protocol +*/ diff --git a/Multiprotocol/opentx-multi-2015-24-12.bin b/Multiprotocol/opentx-multi-2015-24-12.bin new file mode 100644 index 0000000..fe1836e Binary files /dev/null and b/Multiprotocol/opentx-multi-2015-24-12.bin differ diff --git a/Multiprotocol/opentx.bin b/Multiprotocol/opentx.bin new file mode 100644 index 0000000..8e886c4 Binary files /dev/null and b/Multiprotocol/opentx.bin differ diff --git a/README.md b/README.md index aacc3a4..a1f3bad 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,12 @@ +<<<<<<< HEAD +# DIY-Multiprotocol-TX-Module +======= # Overview of the MPTM The **Multiprotocol Tx Module** (or **MPTM**) is a 2.4GHz transmitter module which enables almost any TX to control lot of different models available on the market. The source code is partly based on the [Deviation TX project](http://www.deviationtx.com), thanks to all the developers for their great job on protocols. +>>>>>>> refs/remotes/pascallanger/master ## Quicklinks * [Download latest releases of the firmware](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/releases) @@ -11,6 +15,193 @@ The source code is partly based on the [Deviation TX project](http://www.deviati * [The old documentation](docs/README-old.md) * [Documentation to-do list](docs/Documentation_To_Do_List.md) +<<<<<<< HEAD +Fork du projet https://github.com/pascallanger/DIY-Multiprotocol-TX-Module + +Afin d'ajouter : +- Une sélection du protocole via les manches de la radio +- Un rebind hardware en PPM +- La radio TARANIS (TAERB, B = rebind ;-) ) et redéclaration des radios +- Un script "LUA" afin de faciliter la position des manches + + + +Programme des évolutions : +- Ajout du de la télémetrie TARANIS à l'aide du projet https://github.com/shadow974/TxAdapter + + (Attention, il faut rajouter un transistor afin d'inverser et amplifier le signal) + + +#Schematic +![Screenshot](http://static.rcgroups.net/forums/attachments/4/0/8/5/8/3/a8443844-119-multiprotocol_diagram_rotary_serial_2.jpg) + +Notes: +- Attention: All modules are 3.3V only, never power them with 5V. +- For serial, the dial switch is not needed and the bind button optionnal +- Ajout d'un switch + transistor sur le TX +![Alt text](telemetryFRSKY.jpg) + + +#Protocoles ajoutés mais non testés (Issue de Deviation) +##CYRF6936 RF Module +###J6PRO +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12 +---|---|---|---|---|---|---|---|---|---|---|--- +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12 + +###WK2x01 +Autobind + +####Sub_protocol WK2401 +CH1|CH2|CH3|CH4 +---|---|---|--- +CH1|CH2|CH3|CH4 + + +####Sub_protocol WK2601 +Option: + + 0 = 5+1 + 2 = 6+1 + ..1 = Hélicoptère (. = autres options pour ce mode) + .01 = Hélicoptère normal + .11 = Hélicoptère avec pit inversé + 0.1 = Pitch curve -100 + 1.1 = Pitch curve 100 + +CH1|CH2|CH3|CH4|CH5|CH6|CH7 +---|---|---|---|---|---|--- +CH1|CH2|CH3|CH4|???|CONF|Gyro & Rudder mix + +CONF: Option 1 = Rate Throtle + + Option 2 = Pitch + + +####Sub_protocol WK2801 +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8 +---|---|---|---|---|---|---|--- +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8 + + +##A7105 RF Module +###Joysway +CH1|CH2|CH3|CH4 +---|---|---|--- +A|E|T|R + +##CC2500 RF Module +###SKYARTEC +CH1|CH2|CH3|CH4|CH5|CH6|CH7 +---|---|---|---|---|---|--- + ? | ? | ? | ? | ? | ? | ? + +##NRF24L01 RF Module +###BLUEFLY +Autobind + +CH1|CH2|CH3|CH4|CH5|CH6 +---|---|---|---|---|--- +A|E|T|R|GEAR|PITCH + +###CFLIE +Modele: CrazyFlie Nano quad + +Autobind + +CH1|CH2|CH3|CH4 +---|---|---|--- +A|E|T|R + +###ESKY150 + +Autobind + +CH1|CH2|CH3|CH4 +---|---|---|--- +A|E|T|R + +###FBL100 +Autobind + +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8 +---|---|---|---|---|---|---|--- + ? | ? | ? | ? | ? | ? | ? | ? + +####Sub_protocol HP100 +Same channels assignement as above. + +###Fy326 +Autobind + +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9 +---|---|---|---|---|---|---|---|--- +A|E|T|R|FLIP|HEADLESS|RTH|Calibrate|Expert + +####Sub_protocol FY319 +Same channels assignement as above. + +###H377 +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8 +---|---|---|---|---|---|---|--- +A|E|T|R|CH5|CH6|CH7|CH8 + +###HM830 +Modele: HM Hobby HM830 RC Paper Airplane + +Autobind + +CH1|CH2|CH3|CH4|CH5 +---|---|---|--- +A|Turbo|T|Trim|Bouton + +###HONTAI +Autobind + +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11 +---|---|---|---|---|---|---|---|---|---|--- +A|E|T|R|LED|FLIP|PICTURE|VIDEO|HEADLESS|RTH|Calibrate + +####Sub_protocol JJRCX1 +Modele: JJRC X1 + +CH5|CH6|CH7|CH8|CH9|CH10|CH11 +---|---|---|---|---|---|---|---|---|---|--- +ARM|FLIP|PICTURE|VIDEO|HEADLESS|RTH|Calibrate + +###NE260 +Modele: Nine Eagles SoloPro + +Autobind + +CH1|CH2|CH3|CH4 +---|---|---|--- +A|E|T|R + +###UDI +Modele: Known UDI 2.4GHz protocol variants, all using BK2421 +* UDI U819 coaxial 3ch helicoper +* UDI U816/817/818 quadcopters + - "V1" with orange LED on TX, U816 RX labeled '' , U817/U818 RX labeled 'UD-U817B' + - "V2" with red LEDs on TX, U816 RX labeled '', U817/U818 RX labeled 'UD-U817OG' + - "V3" with green LEDs on TX. Did not get my hands on yet. +* U830 mini quadcopter with tilt steering ("Protocol 2014") +* U839 nano quadcopter ("Protocol 2014") + +Autobind + +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10 +---|---|---|---|---|---|---|---|---|--- +A|E|T|R|FLIP 360|FLIP|VIDEO|LED|MODE 2 + +####Sub_protocol U816_V1 (orange) +####Sub_protocol U816_V2 (red) +####Sub_protocol U839_2014 +Same channels assignement as above. + + +###D'autres à venir +======= ## Outline of the documentation 1. Introduction (this page) 1. [Available protocols](docs/Protocol_Details.md) @@ -119,3 +310,4 @@ A very big thanks to all the people who have shared their time so graciously to * hexfet – from Deviation-tx Your help would be greatly appreciated. If protocol reverse-engineering and dev is not your thing then any help with testing and contributing to the documentation would be amazing. Given the number of different Tx/module hardware/RF module/protocol/model combinations the process of testing and documenting is a major bottleneck for the developers. Anything you can do to help will free them up to do even greater things. +>>>>>>> refs/remotes/pascallanger/master diff --git a/sync.ffs_db b/sync.ffs_db new file mode 100644 index 0000000..e2cbf55 Binary files /dev/null and b/sync.ffs_db differ diff --git a/taranis_switches.png b/taranis_switches.png new file mode 100644 index 0000000..d1645d2 Binary files /dev/null and b/taranis_switches.png differ diff --git a/telemetryFRSKY.fzz b/telemetryFRSKY.fzz new file mode 100644 index 0000000..0a6f49a Binary files /dev/null and b/telemetryFRSKY.fzz differ diff --git a/telemetryFRSKY.jpg b/telemetryFRSKY.jpg new file mode 100644 index 0000000..5876793 Binary files /dev/null and b/telemetryFRSKY.jpg differ